10a47c91cSRobert Mustacchi /*
20a47c91cSRobert Mustacchi * This file and its contents are supplied under the terms of the
30a47c91cSRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0.
40a47c91cSRobert Mustacchi * You may only use this file in accordance with the terms of version
50a47c91cSRobert Mustacchi * 1.0 of the CDDL.
60a47c91cSRobert Mustacchi *
70a47c91cSRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this
80a47c91cSRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at
90a47c91cSRobert Mustacchi * http://www.illumos.org/license/CDDL.
100a47c91cSRobert Mustacchi */
110a47c91cSRobert Mustacchi
120a47c91cSRobert Mustacchi /*
132becb8cdSRobert Mustacchi * Copyright (c) 2015 Joyent, Inc. All rights reserved.
140a47c91cSRobert Mustacchi */
150a47c91cSRobert Mustacchi
160a47c91cSRobert Mustacchi /*
170a47c91cSRobert Mustacchi * ::typedef exists to allow a user to create and import auxiliary CTF
180a47c91cSRobert Mustacchi * information for the currently running target. ::typedef is similar to the C
190a47c91cSRobert Mustacchi * typedef keyword. However, ::typedef has no illusions of grandeur. It is not a
200a47c91cSRobert Mustacchi * standards complaint version of C's typedef. For specifics on what it does and
210a47c91cSRobert Mustacchi * does not support, please see the help message for ::typedef later on in this
220a47c91cSRobert Mustacchi * file.
230a47c91cSRobert Mustacchi *
240a47c91cSRobert Mustacchi * In addition to allowing the user to create types, it has a notion of a
250a47c91cSRobert Mustacchi * built-in set of types that a compiler might provide. Currently ::typedef
260a47c91cSRobert Mustacchi * supports both the standard illumos 32-bit and 64-bit environments, mainly
270a47c91cSRobert Mustacchi * LP32 and LP64. These are not present by default; it is up to the user to
280a47c91cSRobert Mustacchi * request that they be inserted.
290a47c91cSRobert Mustacchi *
300a47c91cSRobert Mustacchi * To facilitate this, ::typedef adds all of its type information to an
310a47c91cSRobert Mustacchi * auxiliary CTF container that is a part of the global mdb state. This is
320a47c91cSRobert Mustacchi * abstracted away from ::typedef by the mdb_ctf_* apis. This container is
330a47c91cSRobert Mustacchi * referred to as the synthetic container, as it holds these synthetic types.
340a47c91cSRobert Mustacchi * The synthetic container does not have a parent CTF container. This is rather
350a47c91cSRobert Mustacchi * important to its operation, as a user can end up referencing types that come
360a47c91cSRobert Mustacchi * from many different such containers (eg. different kernel modules). As such,
370a47c91cSRobert Mustacchi * whenever a type is referenced that we do not know about, we search all of the
380a47c91cSRobert Mustacchi * CTF containers that mdb knows about it. If we find it, then that type is
390a47c91cSRobert Mustacchi * imported (along with all of its dependent types) into the synthetic
400a47c91cSRobert Mustacchi * container.
410a47c91cSRobert Mustacchi *
420a47c91cSRobert Mustacchi * Finally, ::typedef can source CTF information from external files with the -r
430a47c91cSRobert Mustacchi * option. This will copy in every type from their container into the synthetic
440a47c91cSRobert Mustacchi * container, because of this the parent and child relationship between
450a47c91cSRobert Mustacchi * containers with parents cannot be maintained.
460a47c91cSRobert Mustacchi */
470a47c91cSRobert Mustacchi
480a47c91cSRobert Mustacchi #include <mdb/mdb_modapi.h>
490a47c91cSRobert Mustacchi #include <mdb/mdb_ctf.h>
500a47c91cSRobert Mustacchi #include <mdb/mdb_list.h>
510a47c91cSRobert Mustacchi #include <mdb/mdb_nv.h>
520a47c91cSRobert Mustacchi
530a47c91cSRobert Mustacchi struct parse_node;
540a47c91cSRobert Mustacchi
550a47c91cSRobert Mustacchi #define PN_F_POINTER 0x01
560a47c91cSRobert Mustacchi #define PN_F_ARRAY 0x02
570a47c91cSRobert Mustacchi
580a47c91cSRobert Mustacchi typedef struct parse_node {
590a47c91cSRobert Mustacchi mdb_list_t pn_list; /* list entry, must be first */
600a47c91cSRobert Mustacchi char *pn_type; /* name of base type */
610a47c91cSRobert Mustacchi char *pn_name; /* name of the member */
620a47c91cSRobert Mustacchi int pn_flags; /* flags */
630a47c91cSRobert Mustacchi int pn_nptrs; /* number of pointers */
640a47c91cSRobert Mustacchi int pn_asub; /* value of array subscript */
650a47c91cSRobert Mustacchi } parse_node_t;
660a47c91cSRobert Mustacchi
670a47c91cSRobert Mustacchi typedef struct parse_root {
680a47c91cSRobert Mustacchi mdb_list_t pr_nodes; /* list of members */
690a47c91cSRobert Mustacchi int pr_kind; /* CTF_K_* */
700a47c91cSRobert Mustacchi const char *pr_name; /* entity name */
710a47c91cSRobert Mustacchi const char *pr_tname; /* entity typedef */
720a47c91cSRobert Mustacchi } parse_root_t;
730a47c91cSRobert Mustacchi
740a47c91cSRobert Mustacchi static int
typedef_valid_identifier(const char * str)750a47c91cSRobert Mustacchi typedef_valid_identifier(const char *str)
760a47c91cSRobert Mustacchi {
770a47c91cSRobert Mustacchi /*
780a47c91cSRobert Mustacchi * We can't use the standard ctype.h functions because those aren't
790a47c91cSRobert Mustacchi * necessairly available in kmdb. On the flip side, we only care about
800a47c91cSRobert Mustacchi * ascii characters here so that isn't too bad.
810a47c91cSRobert Mustacchi *
820a47c91cSRobert Mustacchi * C Identifiers have to start with a letter or a _. Afterwards they can
830a47c91cSRobert Mustacchi * be alphanumeric or an _.
840a47c91cSRobert Mustacchi */
850a47c91cSRobert Mustacchi
860a47c91cSRobert Mustacchi if (*str == '\0')
870a47c91cSRobert Mustacchi return (1);
880a47c91cSRobert Mustacchi
890a47c91cSRobert Mustacchi if (*str != '_' &&
900a47c91cSRobert Mustacchi (*str < 'A' || *str > 'Z') &&
910a47c91cSRobert Mustacchi (*str < 'a' || *str > 'z'))
920a47c91cSRobert Mustacchi return (1);
930a47c91cSRobert Mustacchi str++;
940a47c91cSRobert Mustacchi
950a47c91cSRobert Mustacchi while (*str != '\0') {
960a47c91cSRobert Mustacchi if (*str != '_' &&
970a47c91cSRobert Mustacchi (*str < '0' || *str > '9') &&
980a47c91cSRobert Mustacchi (*str < 'A' || *str > 'Z') &&
990a47c91cSRobert Mustacchi (*str < 'a' || *str > 'z'))
1000a47c91cSRobert Mustacchi return (1);
1010a47c91cSRobert Mustacchi str++;
1020a47c91cSRobert Mustacchi }
1030a47c91cSRobert Mustacchi
1040a47c91cSRobert Mustacchi return (0);
1050a47c91cSRobert Mustacchi }
1060a47c91cSRobert Mustacchi
1070a47c91cSRobert Mustacchi /*ARGSUSED*/
1080a47c91cSRobert Mustacchi static int
typedef_list_cb(mdb_ctf_id_t id,void * arg)1090a47c91cSRobert Mustacchi typedef_list_cb(mdb_ctf_id_t id, void *arg)
1100a47c91cSRobert Mustacchi {
1110a47c91cSRobert Mustacchi char buf[MDB_SYM_NAMLEN];
1120a47c91cSRobert Mustacchi
1130a47c91cSRobert Mustacchi /*
1140a47c91cSRobert Mustacchi * The user may have created an anonymous structure or union as part of
1150a47c91cSRobert Mustacchi * running ::typedef. If this is the case, we passed a NULL pointer for
1160a47c91cSRobert Mustacchi * the name into the ctf routines. When we go back and ask for the name
1170a47c91cSRobert Mustacchi * of that, ctf goes through and loops through all the declarations.
1180a47c91cSRobert Mustacchi * This, however correctly, gives us back something undesirable to the
1190a47c91cSRobert Mustacchi * user, eg. the name is simply 'struct' and 'union'. Because a typedef
1200a47c91cSRobert Mustacchi * will always have a non-anonymous name for that, we instead opt to
1210a47c91cSRobert Mustacchi * not include these anonymous names. ctf usefully includes a space as
1220a47c91cSRobert Mustacchi * part of that name.
1230a47c91cSRobert Mustacchi */
1240a47c91cSRobert Mustacchi (void) mdb_ctf_type_name(id, buf, sizeof (buf));
1250a47c91cSRobert Mustacchi if (strcmp("struct ", buf) != 0 && strcmp("union ", buf) != 0)
1260a47c91cSRobert Mustacchi mdb_printf("%s\n", buf);
1270a47c91cSRobert Mustacchi return (0);
1280a47c91cSRobert Mustacchi }
1290a47c91cSRobert Mustacchi
1300a47c91cSRobert Mustacchi static char *
typedef_join_strings(int nstr,const mdb_arg_t * args,int flags)1310a47c91cSRobert Mustacchi typedef_join_strings(int nstr, const mdb_arg_t *args, int flags)
1320a47c91cSRobert Mustacchi {
1330a47c91cSRobert Mustacchi int i, size = 0;
1340a47c91cSRobert Mustacchi char *ret, *sptr;
1350a47c91cSRobert Mustacchi
1360a47c91cSRobert Mustacchi for (i = 0; i <= nstr; i++) {
1370a47c91cSRobert Mustacchi /* Always account for the space or the null terminator */
1380a47c91cSRobert Mustacchi size += strlen(args[i].a_un.a_str) + 1;
1390a47c91cSRobert Mustacchi }
1400a47c91cSRobert Mustacchi ret = mdb_alloc(sizeof (char) * size, flags);
1410a47c91cSRobert Mustacchi if (ret == NULL)
1420a47c91cSRobert Mustacchi return (NULL);
1430a47c91cSRobert Mustacchi sptr = ret;
1440a47c91cSRobert Mustacchi for (i = 0; i <= nstr; i++) {
1450a47c91cSRobert Mustacchi (void) strcpy(sptr, args[i].a_un.a_str);
1460a47c91cSRobert Mustacchi sptr += strlen(args[i].a_un.a_str);
1470a47c91cSRobert Mustacchi *sptr = ' ';
1480a47c91cSRobert Mustacchi sptr++;
1490a47c91cSRobert Mustacchi }
1500a47c91cSRobert Mustacchi *sptr = '\0';
1510a47c91cSRobert Mustacchi
1520a47c91cSRobert Mustacchi return (ret);
1530a47c91cSRobert Mustacchi }
1540a47c91cSRobert Mustacchi
1550a47c91cSRobert Mustacchi static int
typedef_list(void)1560a47c91cSRobert Mustacchi typedef_list(void)
1570a47c91cSRobert Mustacchi {
1580a47c91cSRobert Mustacchi (void) mdb_ctf_type_iter(MDB_CTF_SYNTHETIC_ITER, typedef_list_cb,
1590a47c91cSRobert Mustacchi NULL);
1600a47c91cSRobert Mustacchi return (DCMD_OK);
1610a47c91cSRobert Mustacchi }
1620a47c91cSRobert Mustacchi
1630a47c91cSRobert Mustacchi static int
typedef_destroy(void)1640a47c91cSRobert Mustacchi typedef_destroy(void)
1650a47c91cSRobert Mustacchi {
1660a47c91cSRobert Mustacchi if (mdb_ctf_synthetics_reset() != 0) {
1670a47c91cSRobert Mustacchi mdb_warn("failed to reset synthetic types");
1680a47c91cSRobert Mustacchi return (DCMD_ERR);
1690a47c91cSRobert Mustacchi }
1700a47c91cSRobert Mustacchi return (DCMD_OK);
1710a47c91cSRobert Mustacchi }
1720a47c91cSRobert Mustacchi
1730a47c91cSRobert Mustacchi /*
1740a47c91cSRobert Mustacchi * We've been asked to create the basic types that exist. We accept the
1750a47c91cSRobert Mustacchi * following strings to indicate what we should create.
1760a47c91cSRobert Mustacchi * - LP32, ILP32 (case insensitive)
1770a47c91cSRobert Mustacchi * - LP64
1780a47c91cSRobert Mustacchi */
1790a47c91cSRobert Mustacchi static int
typedef_create(const char * arg)1800a47c91cSRobert Mustacchi typedef_create(const char *arg)
1810a47c91cSRobert Mustacchi {
1820a47c91cSRobert Mustacchi int kind;
1830a47c91cSRobert Mustacchi
1840a47c91cSRobert Mustacchi if (strcasecmp(arg, "LP32") == 0 || strcasecmp(arg, "ILP32") == 0) {
1850a47c91cSRobert Mustacchi kind = SYNTHETIC_ILP32;
1860a47c91cSRobert Mustacchi } else if (strcasecmp(arg, "LP64") == 0) {
1870a47c91cSRobert Mustacchi kind = SYNTHETIC_LP64;
1880a47c91cSRobert Mustacchi } else {
1890a47c91cSRobert Mustacchi mdb_printf("invalid data model: %s\n", arg);
1900a47c91cSRobert Mustacchi return (DCMD_USAGE);
1910a47c91cSRobert Mustacchi }
1920a47c91cSRobert Mustacchi
1930a47c91cSRobert Mustacchi if (mdb_ctf_synthetics_create_base(kind) != 0) {
1940a47c91cSRobert Mustacchi mdb_printf("failed to create intrinsic types, maybe "
1950a47c91cSRobert Mustacchi "they already exist\n");
1960a47c91cSRobert Mustacchi return (DCMD_ERR);
1970a47c91cSRobert Mustacchi }
1980a47c91cSRobert Mustacchi
1990a47c91cSRobert Mustacchi return (DCMD_OK);
2000a47c91cSRobert Mustacchi }
2010a47c91cSRobert Mustacchi
2020a47c91cSRobert Mustacchi /*
2030a47c91cSRobert Mustacchi * Search the current arguments for a complete member declaration. This function
2040a47c91cSRobert Mustacchi * modifies the value of defn based on what's necessary for parsing. It returns
2050a47c91cSRobert Mustacchi * the appropriate parse node in pnp.
2060a47c91cSRobert Mustacchi */
2070a47c91cSRobert Mustacchi static int
typedef_parse_member(char * defn,char ** next,parse_node_t ** pnp)2080a47c91cSRobert Mustacchi typedef_parse_member(char *defn, char **next, parse_node_t **pnp)
2090a47c91cSRobert Mustacchi {
2100a47c91cSRobert Mustacchi char *c, *name, *array;
2110a47c91cSRobert Mustacchi int nptrs = 0;
2120a47c91cSRobert Mustacchi parse_node_t *pn;
2130a47c91cSRobert Mustacchi
2140a47c91cSRobert Mustacchi c = strchr(defn, ';');
2150a47c91cSRobert Mustacchi if (c == NULL) {
2160a47c91cSRobert Mustacchi mdb_printf("Cannot find semi-colon to delineate the end "
2170a47c91cSRobert Mustacchi "of a member.\n");
2180a47c91cSRobert Mustacchi return (DCMD_ERR);
2190a47c91cSRobert Mustacchi }
2200a47c91cSRobert Mustacchi *c = '\0';
2210a47c91cSRobert Mustacchi *next = c + 1;
2220a47c91cSRobert Mustacchi
2230a47c91cSRobert Mustacchi c = strrchr(defn, ' ');
2240a47c91cSRobert Mustacchi if (c == NULL) {
2250a47c91cSRobert Mustacchi mdb_printf("Missing both a name and a type declaration for "
2260a47c91cSRobert Mustacchi "a member. Instead, found '%s'\n", defn);
2270a47c91cSRobert Mustacchi return (DCMD_ERR);
2280a47c91cSRobert Mustacchi }
2290a47c91cSRobert Mustacchi *c = '\0';
2300a47c91cSRobert Mustacchi name = c + 1;
2310a47c91cSRobert Mustacchi c--;
2320a47c91cSRobert Mustacchi while (*c == '*' || *c == ' ') {
2330a47c91cSRobert Mustacchi if (*c == '*')
2340a47c91cSRobert Mustacchi nptrs++;
2350a47c91cSRobert Mustacchi c--;
2360a47c91cSRobert Mustacchi }
2370a47c91cSRobert Mustacchi *(c + 1) = '\0';
2380a47c91cSRobert Mustacchi
2390a47c91cSRobert Mustacchi pn = mdb_zalloc(sizeof (parse_node_t), UM_SLEEP | UM_GC);
2400a47c91cSRobert Mustacchi pn->pn_type = defn;
2410a47c91cSRobert Mustacchi
2420a47c91cSRobert Mustacchi /*
2430a47c91cSRobert Mustacchi * Go through and prepare the name field. Note that we still have to
2440a47c91cSRobert Mustacchi * check if this is a pointer or an array. We also need to strip the
2450a47c91cSRobert Mustacchi * ending semi-colon.
2460a47c91cSRobert Mustacchi */
2470a47c91cSRobert Mustacchi while (*name == '*') {
2480a47c91cSRobert Mustacchi name++;
2490a47c91cSRobert Mustacchi nptrs++;
2500a47c91cSRobert Mustacchi }
2510a47c91cSRobert Mustacchi
2520a47c91cSRobert Mustacchi if ((c = strchr(name, '[')) != NULL) {
2530a47c91cSRobert Mustacchi array = c;
2540a47c91cSRobert Mustacchi if ((c = strchr(array, ']')) == NULL) {
2550a47c91cSRobert Mustacchi mdb_printf("Found the beginning of an array size "
2560a47c91cSRobert Mustacchi "but no closing ']' in %s\n", array);
2570a47c91cSRobert Mustacchi return (DCMD_ERR);
2580a47c91cSRobert Mustacchi }
2590a47c91cSRobert Mustacchi *array = '\0';
2600a47c91cSRobert Mustacchi array++;
2610a47c91cSRobert Mustacchi *c = '\0';
2620a47c91cSRobert Mustacchi pn->pn_flags |= PN_F_ARRAY;
2630a47c91cSRobert Mustacchi pn->pn_asub = mdb_strtoull(array);
2640a47c91cSRobert Mustacchi if (pn->pn_asub < 0) {
2650a47c91cSRobert Mustacchi mdb_printf("Array lengths cannot be negative\n");
2660a47c91cSRobert Mustacchi return (DCMD_ERR);
2670a47c91cSRobert Mustacchi }
2680a47c91cSRobert Mustacchi }
2690a47c91cSRobert Mustacchi
2700a47c91cSRobert Mustacchi if (typedef_valid_identifier(name) != 0) {
2710a47c91cSRobert Mustacchi mdb_printf("The name %s is not a valid C identifier.\n",
2720a47c91cSRobert Mustacchi name);
2730a47c91cSRobert Mustacchi return (DCMD_ERR);
2740a47c91cSRobert Mustacchi }
2750a47c91cSRobert Mustacchi
2760a47c91cSRobert Mustacchi if (nptrs) {
2770a47c91cSRobert Mustacchi pn->pn_flags |= PN_F_POINTER;
2780a47c91cSRobert Mustacchi pn->pn_nptrs = nptrs;
2790a47c91cSRobert Mustacchi }
2800a47c91cSRobert Mustacchi pn->pn_name = name;
2810a47c91cSRobert Mustacchi
2820a47c91cSRobert Mustacchi *pnp = pn;
2830a47c91cSRobert Mustacchi return (DCMD_OK);
2840a47c91cSRobert Mustacchi }
2850a47c91cSRobert Mustacchi
2860a47c91cSRobert Mustacchi /*
2870a47c91cSRobert Mustacchi * We're going to parse out our types here. Note that we are not strictly
2880a47c91cSRobert Mustacchi * speaking a truely ANSI C compliant parser. Currently we support normal
2890a47c91cSRobert Mustacchi * declarations except for the following:
2900a47c91cSRobert Mustacchi * o function pointers
2910a47c91cSRobert Mustacchi * o bit-fields
2920a47c91cSRobert Mustacchi */
2930a47c91cSRobert Mustacchi static int
typedef_parse(char * defn,const char * name,parse_root_t ** prp)2940a47c91cSRobert Mustacchi typedef_parse(char *defn, const char *name, parse_root_t **prp)
2950a47c91cSRobert Mustacchi {
2960a47c91cSRobert Mustacchi int len, ret;
2970a47c91cSRobert Mustacchi const char *kind, *basename;
2980a47c91cSRobert Mustacchi char *c, *brace;
2990a47c91cSRobert Mustacchi parse_root_t *pr;
3000a47c91cSRobert Mustacchi parse_node_t *pn;
3010a47c91cSRobert Mustacchi mdb_ctf_id_t id;
3020a47c91cSRobert Mustacchi
3030a47c91cSRobert Mustacchi pr = mdb_zalloc(sizeof (parse_root_t), UM_SLEEP | UM_GC);
3040a47c91cSRobert Mustacchi basename = defn;
3050a47c91cSRobert Mustacchi
3060a47c91cSRobert Mustacchi c = strchr(defn, ' ');
3070a47c91cSRobert Mustacchi if (c == NULL) {
3080a47c91cSRobert Mustacchi mdb_printf("Invalid structure definition. Structure "
3090a47c91cSRobert Mustacchi "must start with either 'struct {' or 'union {'\n");
3100a47c91cSRobert Mustacchi return (DCMD_ERR);
3110a47c91cSRobert Mustacchi }
3120a47c91cSRobert Mustacchi *c = '\0';
3130a47c91cSRobert Mustacchi
3140a47c91cSRobert Mustacchi if (strcmp(defn, "struct") == 0)
3150a47c91cSRobert Mustacchi pr->pr_kind = CTF_K_STRUCT;
3160a47c91cSRobert Mustacchi else if (strcmp(defn, "union") == 0)
3170a47c91cSRobert Mustacchi pr->pr_kind = CTF_K_UNION;
3180a47c91cSRobert Mustacchi else {
3190a47c91cSRobert Mustacchi mdb_printf("Invalid start of definition. "
3200a47c91cSRobert Mustacchi "Expected 'struct' or 'union'. "
3210a47c91cSRobert Mustacchi "Found: '%s'\n", defn);
3220a47c91cSRobert Mustacchi return (DCMD_ERR);
3230a47c91cSRobert Mustacchi }
3240a47c91cSRobert Mustacchi
3250a47c91cSRobert Mustacchi /*
3260a47c91cSRobert Mustacchi * We transform this back to a space so we can validate that a
3270a47c91cSRobert Mustacchi * non-anonymous struct or union name is valid.
3280a47c91cSRobert Mustacchi */
3290a47c91cSRobert Mustacchi *c = ' ';
3300a47c91cSRobert Mustacchi
3310a47c91cSRobert Mustacchi kind = defn;
3320a47c91cSRobert Mustacchi defn = c + 1;
3330a47c91cSRobert Mustacchi while (*defn == ' ')
3340a47c91cSRobert Mustacchi defn++;
3350a47c91cSRobert Mustacchi
3360a47c91cSRobert Mustacchi /* Check whether this is anonymous or not */
3370a47c91cSRobert Mustacchi if (*defn != '{') {
3380a47c91cSRobert Mustacchi brace = strchr(defn, '{');
3390a47c91cSRobert Mustacchi c = brace;
3400a47c91cSRobert Mustacchi if (c == NULL) {
3410a47c91cSRobert Mustacchi mdb_printf("Missing opening brace for %s definition. "
3420a47c91cSRobert Mustacchi "Expected '{'. "
3430a47c91cSRobert Mustacchi "Found: '%c'\n", kind, *defn);
3440a47c91cSRobert Mustacchi return (DCMD_ERR);
3450a47c91cSRobert Mustacchi }
3460a47c91cSRobert Mustacchi *c = '\0';
3470a47c91cSRobert Mustacchi c--;
3480a47c91cSRobert Mustacchi while (*c == ' ')
3490a47c91cSRobert Mustacchi c--;
3500a47c91cSRobert Mustacchi *(c+1) = '\0';
3510a47c91cSRobert Mustacchi if (typedef_valid_identifier(defn) != 0) {
3520a47c91cSRobert Mustacchi mdb_printf("The name %s is not a valid C identifier.\n",
3530a47c91cSRobert Mustacchi defn);
3540a47c91cSRobert Mustacchi return (DCMD_ERR);
3550a47c91cSRobert Mustacchi }
3560a47c91cSRobert Mustacchi
3570a47c91cSRobert Mustacchi if (mdb_ctf_lookup_by_name(basename, &id) != CTF_ERR) {
3580a47c91cSRobert Mustacchi mdb_printf("type name %s already in use\n", basename);
3590a47c91cSRobert Mustacchi return (DCMD_ERR);
3600a47c91cSRobert Mustacchi }
3610a47c91cSRobert Mustacchi
3620a47c91cSRobert Mustacchi pr->pr_name = defn;
3630a47c91cSRobert Mustacchi defn = brace;
3640a47c91cSRobert Mustacchi } else {
3650a47c91cSRobert Mustacchi pr->pr_name = NULL;
3660a47c91cSRobert Mustacchi }
3670a47c91cSRobert Mustacchi
3680a47c91cSRobert Mustacchi defn++;
3690a47c91cSRobert Mustacchi while (*defn == ' ')
3700a47c91cSRobert Mustacchi defn++;
3710a47c91cSRobert Mustacchi
3720a47c91cSRobert Mustacchi len = strlen(defn);
3730a47c91cSRobert Mustacchi if (defn[len-1] != '}') {
3740a47c91cSRobert Mustacchi mdb_printf("Missing closing brace for %s declaration. "
3750a47c91cSRobert Mustacchi "Expected '}'.\n");
3760a47c91cSRobert Mustacchi return (DCMD_ERR);
3770a47c91cSRobert Mustacchi }
3780a47c91cSRobert Mustacchi defn[len-1] = '\0';
3790a47c91cSRobert Mustacchi
3800a47c91cSRobert Mustacchi /*
3810a47c91cSRobert Mustacchi * Start walking all the arguments, looking for a terminating semicolon
3820a47c91cSRobert Mustacchi * for type definitions.
3830a47c91cSRobert Mustacchi */
3840a47c91cSRobert Mustacchi for (;;) {
3850a47c91cSRobert Mustacchi ret = typedef_parse_member(defn, &c, &pn);
3860a47c91cSRobert Mustacchi if (ret == DCMD_ERR)
3870a47c91cSRobert Mustacchi return (DCMD_ERR);
3880a47c91cSRobert Mustacchi
3890a47c91cSRobert Mustacchi mdb_list_append(&pr->pr_nodes, pn);
3900a47c91cSRobert Mustacchi
3910a47c91cSRobert Mustacchi while (*c == ' ')
3920a47c91cSRobert Mustacchi c++;
3930a47c91cSRobert Mustacchi
3940a47c91cSRobert Mustacchi if (*c == '\0')
3950a47c91cSRobert Mustacchi break;
3960a47c91cSRobert Mustacchi
3970a47c91cSRobert Mustacchi defn = c;
3980a47c91cSRobert Mustacchi }
3990a47c91cSRobert Mustacchi
4000a47c91cSRobert Mustacchi pr->pr_tname = name;
4010a47c91cSRobert Mustacchi *prp = pr;
4020a47c91cSRobert Mustacchi
4030a47c91cSRobert Mustacchi return (DCMD_OK);
4040a47c91cSRobert Mustacchi }
4050a47c91cSRobert Mustacchi
4060a47c91cSRobert Mustacchi /*
4070a47c91cSRobert Mustacchi * Make sure that none of the member names overlap and that the type names don't
4080a47c91cSRobert Mustacchi * already exist. If we have an array entry that is a VLA, make sure it is the
4090a47c91cSRobert Mustacchi * last member and not the only member.
4100a47c91cSRobert Mustacchi */
4110a47c91cSRobert Mustacchi static int
typedef_validate(parse_root_t * pr)4120a47c91cSRobert Mustacchi typedef_validate(parse_root_t *pr)
4130a47c91cSRobert Mustacchi {
4140a47c91cSRobert Mustacchi mdb_nv_t nv;
4150a47c91cSRobert Mustacchi parse_node_t *pn;
4160a47c91cSRobert Mustacchi mdb_ctf_id_t id;
4170a47c91cSRobert Mustacchi int count = 0;
4180a47c91cSRobert Mustacchi
4190a47c91cSRobert Mustacchi (void) mdb_nv_create(&nv, UM_SLEEP | UM_GC);
4200a47c91cSRobert Mustacchi for (pn = mdb_list_next(&pr->pr_nodes); pn != NULL;
4210a47c91cSRobert Mustacchi pn = mdb_list_next(pn)) {
4220a47c91cSRobert Mustacchi count++;
4230a47c91cSRobert Mustacchi if (mdb_nv_lookup(&nv, pn->pn_name) != NULL) {
4240a47c91cSRobert Mustacchi mdb_printf("duplicate name detected: %s\n",
4250a47c91cSRobert Mustacchi pn->pn_name);
4260a47c91cSRobert Mustacchi return (DCMD_ERR);
4270a47c91cSRobert Mustacchi }
4280a47c91cSRobert Mustacchi
4290a47c91cSRobert Mustacchi /*
4300a47c91cSRobert Mustacchi * Our parse tree won't go away before the nv, so it's simpler
4310a47c91cSRobert Mustacchi * to just mark everything external.
4320a47c91cSRobert Mustacchi */
4330a47c91cSRobert Mustacchi (void) mdb_nv_insert(&nv, pn->pn_name, NULL, 0, MDB_NV_EXTNAME);
4340a47c91cSRobert Mustacchi
4350a47c91cSRobert Mustacchi if (pn->pn_flags & PN_F_ARRAY && pn->pn_asub == 0) {
4360a47c91cSRobert Mustacchi if (pr->pr_kind != CTF_K_STRUCT) {
4370a47c91cSRobert Mustacchi mdb_printf("Flexible array members are only "
4380a47c91cSRobert Mustacchi "valid in structs.\n");
4390a47c91cSRobert Mustacchi return (DCMD_ERR);
4400a47c91cSRobert Mustacchi }
4410a47c91cSRobert Mustacchi
4420a47c91cSRobert Mustacchi if (&pn->pn_list != pr->pr_nodes.ml_prev) {
4430a47c91cSRobert Mustacchi mdb_printf("Flexible array entries are only "
4440a47c91cSRobert Mustacchi "allowed to be the last entry in a "
4450a47c91cSRobert Mustacchi "struct\n");
4460a47c91cSRobert Mustacchi return (DCMD_ERR);
4470a47c91cSRobert Mustacchi }
4480a47c91cSRobert Mustacchi
4490a47c91cSRobert Mustacchi if (count == 1) {
4500a47c91cSRobert Mustacchi mdb_printf("Structs must have members aside "
4510a47c91cSRobert Mustacchi "from a flexible member\n");
4520a47c91cSRobert Mustacchi return (DCMD_ERR);
4530a47c91cSRobert Mustacchi }
4540a47c91cSRobert Mustacchi }
4550a47c91cSRobert Mustacchi }
4560a47c91cSRobert Mustacchi
4570a47c91cSRobert Mustacchi if (mdb_ctf_lookup_by_name(pr->pr_tname, &id) != CTF_ERR) {
4580a47c91cSRobert Mustacchi mdb_printf("typedef name %s already exists\n", pr->pr_tname);
4590a47c91cSRobert Mustacchi return (DCMD_ERR);
4600a47c91cSRobert Mustacchi }
4610a47c91cSRobert Mustacchi
4620a47c91cSRobert Mustacchi return (DCMD_OK);
4630a47c91cSRobert Mustacchi }
4640a47c91cSRobert Mustacchi
4650a47c91cSRobert Mustacchi static int
typedef_add(parse_root_t * pr)4660a47c91cSRobert Mustacchi typedef_add(parse_root_t *pr)
4670a47c91cSRobert Mustacchi {
4680a47c91cSRobert Mustacchi parse_node_t *pn;
4690a47c91cSRobert Mustacchi mdb_ctf_id_t id, aid, tid, pid;
4700a47c91cSRobert Mustacchi mdb_ctf_arinfo_t ar;
4710a47c91cSRobert Mustacchi int ii;
4720a47c91cSRobert Mustacchi
4730a47c91cSRobert Mustacchi /* Pre-flight checks */
4740a47c91cSRobert Mustacchi if (typedef_validate(pr) == DCMD_ERR)
4750a47c91cSRobert Mustacchi return (DCMD_ERR);
4760a47c91cSRobert Mustacchi
4770a47c91cSRobert Mustacchi if (pr->pr_kind == CTF_K_STRUCT) {
4780a47c91cSRobert Mustacchi if (mdb_ctf_add_struct(pr->pr_name, &id) != 0) {
4790a47c91cSRobert Mustacchi mdb_printf("failed to create struct for %s\n",
4800a47c91cSRobert Mustacchi pr->pr_tname);
4810a47c91cSRobert Mustacchi return (DCMD_ERR);
4820a47c91cSRobert Mustacchi }
4830a47c91cSRobert Mustacchi } else {
4840a47c91cSRobert Mustacchi if (mdb_ctf_add_union(pr->pr_name, &id) != 0) {
4850a47c91cSRobert Mustacchi mdb_printf("failed to create union for %s\n",
4860a47c91cSRobert Mustacchi pr->pr_tname);
4870a47c91cSRobert Mustacchi return (DCMD_ERR);
4880a47c91cSRobert Mustacchi }
4890a47c91cSRobert Mustacchi }
4900a47c91cSRobert Mustacchi
4910a47c91cSRobert Mustacchi for (pn = mdb_list_next(&pr->pr_nodes); pn != NULL;
4920a47c91cSRobert Mustacchi pn = mdb_list_next(pn)) {
4930a47c91cSRobert Mustacchi
4940a47c91cSRobert Mustacchi if (mdb_ctf_lookup_by_name(pn->pn_type, &tid) == CTF_ERR) {
4950a47c91cSRobert Mustacchi mdb_printf("failed to add member %s: type %s does "
4960a47c91cSRobert Mustacchi "not exist\n", pn->pn_name, pn->pn_type);
4970a47c91cSRobert Mustacchi goto destroy;
4980a47c91cSRobert Mustacchi }
4990a47c91cSRobert Mustacchi
5000a47c91cSRobert Mustacchi if (pn->pn_flags & PN_F_POINTER) {
5010a47c91cSRobert Mustacchi for (ii = 0; ii < pn->pn_nptrs; ii++) {
5020a47c91cSRobert Mustacchi if (mdb_ctf_add_pointer(&tid,
5030a47c91cSRobert Mustacchi &pid) != 0) {
5040a47c91cSRobert Mustacchi mdb_printf("failed to add a pointer "
5050a47c91cSRobert Mustacchi "type as part of member: %s\n",
5060a47c91cSRobert Mustacchi pn->pn_name);
5070a47c91cSRobert Mustacchi goto destroy;
5080a47c91cSRobert Mustacchi }
5090a47c91cSRobert Mustacchi tid = pid;
5100a47c91cSRobert Mustacchi }
5110a47c91cSRobert Mustacchi }
5120a47c91cSRobert Mustacchi
5130a47c91cSRobert Mustacchi if (pn->pn_flags & PN_F_ARRAY) {
5140a47c91cSRobert Mustacchi if (mdb_ctf_lookup_by_name("long", &aid) != 0) {
5150a47c91cSRobert Mustacchi mdb_printf("failed to lookup the type 'long' "
5160a47c91cSRobert Mustacchi "for array indexes, are you running mdb "
5170a47c91cSRobert Mustacchi "without a target or using ::typedef -c?");
5180a47c91cSRobert Mustacchi goto destroy;
5190a47c91cSRobert Mustacchi }
5200a47c91cSRobert Mustacchi
5210a47c91cSRobert Mustacchi ar.mta_contents = tid;
5220a47c91cSRobert Mustacchi ar.mta_index = aid;
5230a47c91cSRobert Mustacchi ar.mta_nelems = pn->pn_asub;
5240a47c91cSRobert Mustacchi
5250a47c91cSRobert Mustacchi if (mdb_ctf_add_array(&ar, &tid) != 0) {
5260a47c91cSRobert Mustacchi mdb_printf("failed to create array type for "
5270a47c91cSRobert Mustacchi "memeber%s\n", pn->pn_name);
5280a47c91cSRobert Mustacchi goto destroy;
5290a47c91cSRobert Mustacchi }
5300a47c91cSRobert Mustacchi }
5310a47c91cSRobert Mustacchi
5320a47c91cSRobert Mustacchi if (mdb_ctf_add_member(&id, pn->pn_name, &tid, NULL) ==
5330a47c91cSRobert Mustacchi CTF_ERR) {
5340a47c91cSRobert Mustacchi mdb_printf("failed to create member %s\n",
5350a47c91cSRobert Mustacchi pn->pn_name);
5360a47c91cSRobert Mustacchi goto destroy;
5370a47c91cSRobert Mustacchi }
5380a47c91cSRobert Mustacchi }
5390a47c91cSRobert Mustacchi
5400a47c91cSRobert Mustacchi if (mdb_ctf_add_typedef(pr->pr_tname, &id, NULL) != 0) {
5410a47c91cSRobert Mustacchi mdb_printf("failed to add typedef for %s\n",
5420a47c91cSRobert Mustacchi pr->pr_tname);
5430a47c91cSRobert Mustacchi goto destroy;
5440a47c91cSRobert Mustacchi }
5450a47c91cSRobert Mustacchi
5460a47c91cSRobert Mustacchi return (DCMD_OK);
5470a47c91cSRobert Mustacchi
5480a47c91cSRobert Mustacchi destroy:
5490a47c91cSRobert Mustacchi return (mdb_ctf_type_delete(&id));
5500a47c91cSRobert Mustacchi }
5510a47c91cSRobert Mustacchi
5520a47c91cSRobert Mustacchi static int
typedef_readfile(const char * file)5530a47c91cSRobert Mustacchi typedef_readfile(const char *file)
5540a47c91cSRobert Mustacchi {
5550a47c91cSRobert Mustacchi int ret;
5560a47c91cSRobert Mustacchi
5570a47c91cSRobert Mustacchi ret = mdb_ctf_synthetics_from_file(file);
5580a47c91cSRobert Mustacchi if (ret != DCMD_OK)
5592becb8cdSRobert Mustacchi mdb_warn("failed to create synthetics from file %s\n", file);
5602becb8cdSRobert Mustacchi return (ret);
5612becb8cd