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 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 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 * 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 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 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 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 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 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 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 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 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); 5612becb8cdSRobert Mustacchi } 5622becb8cdSRobert Mustacchi 5632becb8cdSRobert Mustacchi static int 5642becb8cdSRobert Mustacchi typedef_writefile(const char *file) 5652becb8cdSRobert Mustacchi { 5662becb8cdSRobert Mustacchi int ret; 5672becb8cdSRobert Mustacchi 5682becb8cdSRobert Mustacchi ret = mdb_ctf_synthetics_to_file(file); 5692becb8cdSRobert Mustacchi if (ret != DCMD_OK) 5702becb8cdSRobert Mustacchi mdb_warn("failed to write synthetics to file %s", file); 5710a47c91cSRobert Mustacchi return (ret); 5720a47c91cSRobert Mustacchi } 5730a47c91cSRobert Mustacchi 5740a47c91cSRobert Mustacchi /* ARGSUSED */ 5750a47c91cSRobert Mustacchi int 5760a47c91cSRobert Mustacchi cmd_typedef(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 5770a47c91cSRobert Mustacchi { 5780a47c91cSRobert Mustacchi mdb_ctf_id_t id; 5790a47c91cSRobert Mustacchi int i; 5800a47c91cSRobert Mustacchi int destroy = 0, list = 0; 5812becb8cdSRobert Mustacchi const char *cmode = NULL, *rfile = NULL, *wfile = NULL; 5820a47c91cSRobert Mustacchi const char *dst, *src; 5830a47c91cSRobert Mustacchi char *dup; 5840a47c91cSRobert Mustacchi parse_root_t *pr; 5850a47c91cSRobert Mustacchi 5860a47c91cSRobert Mustacchi if (flags & DCMD_ADDRSPEC) 5870a47c91cSRobert Mustacchi return (DCMD_USAGE); 5880a47c91cSRobert Mustacchi 5890a47c91cSRobert Mustacchi i = mdb_getopts(argc, argv, 5900a47c91cSRobert Mustacchi 'd', MDB_OPT_SETBITS, TRUE, &destroy, 5910a47c91cSRobert Mustacchi 'l', MDB_OPT_SETBITS, TRUE, &list, 5920a47c91cSRobert Mustacchi 'c', MDB_OPT_STR, &cmode, 5932becb8cdSRobert Mustacchi 'r', MDB_OPT_STR, &rfile, 5942becb8cdSRobert Mustacchi 'w', MDB_OPT_STR, &wfile, NULL); 5950a47c91cSRobert Mustacchi 5960a47c91cSRobert Mustacchi argc -= i; 5970a47c91cSRobert Mustacchi argv += i; 5980a47c91cSRobert Mustacchi 5990a47c91cSRobert Mustacchi /* 6000a47c91cSRobert Mustacchi * All our options are mutually exclusive currently. 6010a47c91cSRobert Mustacchi */ 6020a47c91cSRobert Mustacchi i = 0; 6030a47c91cSRobert Mustacchi if (destroy) 6040a47c91cSRobert Mustacchi i++; 6050a47c91cSRobert Mustacchi if (cmode != NULL) 6060a47c91cSRobert Mustacchi i++; 6070a47c91cSRobert Mustacchi if (list) 6080a47c91cSRobert Mustacchi i++; 6090a47c91cSRobert Mustacchi if (rfile != NULL) 6100a47c91cSRobert Mustacchi i++; 6112becb8cdSRobert Mustacchi if (wfile != NULL) 6122becb8cdSRobert Mustacchi i++; 6130a47c91cSRobert Mustacchi if (i > 1) 6140a47c91cSRobert Mustacchi return (DCMD_USAGE); 6150a47c91cSRobert Mustacchi 6162becb8cdSRobert Mustacchi if ((destroy || cmode != NULL || list || rfile != NULL || 6172becb8cdSRobert Mustacchi wfile != NULL) && argc != 0) 6180a47c91cSRobert Mustacchi return (DCMD_USAGE); 6190a47c91cSRobert Mustacchi 6200a47c91cSRobert Mustacchi if (destroy) 6210a47c91cSRobert Mustacchi return (typedef_destroy()); 6220a47c91cSRobert Mustacchi 6230a47c91cSRobert Mustacchi if (cmode) 6240a47c91cSRobert Mustacchi return (typedef_create(cmode)); 6250a47c91cSRobert Mustacchi 6260a47c91cSRobert Mustacchi if (list) 6270a47c91cSRobert Mustacchi return (typedef_list()); 6280a47c91cSRobert Mustacchi 6290a47c91cSRobert Mustacchi if (rfile) 6300a47c91cSRobert Mustacchi return (typedef_readfile(rfile)); 6310a47c91cSRobert Mustacchi 6322becb8cdSRobert Mustacchi if (wfile) 6332becb8cdSRobert Mustacchi return (typedef_writefile(wfile)); 6342becb8cdSRobert Mustacchi 6350a47c91cSRobert Mustacchi if (argc < 2) 6360a47c91cSRobert Mustacchi return (DCMD_USAGE); 6370a47c91cSRobert Mustacchi 6380a47c91cSRobert Mustacchi /* 6390a47c91cSRobert Mustacchi * Check to see if we are defining a struct or union. Note that we have 6400a47c91cSRobert Mustacchi * to distinguish between struct foo and struct {. All typedef structs 6410a47c91cSRobert Mustacchi * are annonymous structs that are only known by their typedef name. The 6420a47c91cSRobert Mustacchi * same is true with unions. The problem that we have to deal with is 6430a47c91cSRobert Mustacchi * that the ';' character in mdb causes mdb to begin another command. To 6440a47c91cSRobert Mustacchi * work around that fact we require users to put the whole struct 6450a47c91cSRobert Mustacchi * definition in a pair of "" or ''. 6460a47c91cSRobert Mustacchi */ 6470a47c91cSRobert Mustacchi if (argc == 2 && strchr(argv[0].a_un.a_str, '{') != NULL) { 6480a47c91cSRobert Mustacchi dup = mdb_alloc(strlen(argv[0].a_un.a_str) + 1, 6490a47c91cSRobert Mustacchi UM_GC | UM_SLEEP); 6500a47c91cSRobert Mustacchi (void) strcpy(dup, argv[0].a_un.a_str); 6510a47c91cSRobert Mustacchi if (typedef_parse(dup, argv[1].a_un.a_str, &pr) == DCMD_ERR) 6520a47c91cSRobert Mustacchi return (DCMD_ERR); 6530a47c91cSRobert Mustacchi if (typedef_add(pr) == DCMD_ERR) 6540a47c91cSRobert Mustacchi return (DCMD_ERR); 6550a47c91cSRobert Mustacchi 6560a47c91cSRobert Mustacchi return (DCMD_OK); 6570a47c91cSRobert Mustacchi } 6580a47c91cSRobert Mustacchi 6590a47c91cSRobert Mustacchi /* 6600a47c91cSRobert Mustacchi * Someone could give us something like struct foobar or unsigned int or 6610a47c91cSRobert Mustacchi * even long double imaginary. In this case we end up conjoining all 6620a47c91cSRobert Mustacchi * arguments except the last one into one large string that we look up. 6630a47c91cSRobert Mustacchi */ 6640a47c91cSRobert Mustacchi if (argc - 1 == 1) { 6650a47c91cSRobert Mustacchi src = argv[0].a_un.a_str; 6660a47c91cSRobert Mustacchi } else { 6670a47c91cSRobert Mustacchi src = typedef_join_strings(argc - 2, argv, UM_GC | UM_SLEEP); 6680a47c91cSRobert Mustacchi } 6690a47c91cSRobert Mustacchi 6700a47c91cSRobert Mustacchi dst = argv[argc-1].a_un.a_str; 6710a47c91cSRobert Mustacchi 6720a47c91cSRobert Mustacchi if (mdb_ctf_lookup_by_name(dst, &id) != -1) { 6730a47c91cSRobert Mustacchi mdb_printf("%s already exists\n", dst); 6740a47c91cSRobert Mustacchi return (DCMD_ERR); 6750a47c91cSRobert Mustacchi } 6760a47c91cSRobert Mustacchi 6770a47c91cSRobert Mustacchi if (mdb_ctf_lookup_by_name(src, &id) != 0) { 6780a47c91cSRobert Mustacchi mdb_printf("%s does not exist\n", src); 6790a47c91cSRobert Mustacchi return (DCMD_ERR); 6800a47c91cSRobert Mustacchi } 6810a47c91cSRobert Mustacchi 6820a47c91cSRobert Mustacchi if (mdb_ctf_add_typedef(dst, &id, NULL) != 0) { 6830a47c91cSRobert Mustacchi mdb_printf("failed to create typedef\n"); 6840a47c91cSRobert Mustacchi return (DCMD_ERR); 6850a47c91cSRobert Mustacchi } 6860a47c91cSRobert Mustacchi 6870a47c91cSRobert Mustacchi return (DCMD_OK); 6880a47c91cSRobert Mustacchi } 6890a47c91cSRobert Mustacchi 6900a47c91cSRobert Mustacchi static char typedef_desc[] = 6910a47c91cSRobert Mustacchi "::typedef operates like the C typedef keyword and creates a synthetic type\n" 6920a47c91cSRobert Mustacchi "that is usable across mdb just like a type that is embedded in CTF data.\n" 6930a47c91cSRobert Mustacchi "This includes familiar dcmds like ::print as well as mdb's tab completion\n" 6940a47c91cSRobert Mustacchi "engine. The \"type\" argument can either be a named structure or union\n" 6950a47c91cSRobert Mustacchi "declaration, like \"struct proc { int p_id; }\" declartion, an anonymous\n" 6960a47c91cSRobert Mustacchi "structure or union declaration, like \"struct { int count; }\", or simply\n" 6970a47c91cSRobert Mustacchi "the name of an existing type, like \"uint64_t\". Either form may refer to\n" 6980a47c91cSRobert Mustacchi "other types already defined in CTF or a previous ::typedef invocation. When\n" 6990a47c91cSRobert Mustacchi "debugging binaries without CTF, definitions for intrinsic types may be\n" 7000a47c91cSRobert Mustacchi "created using the -c option. See the OPTIONS section for more information.\n" 7010a47c91cSRobert Mustacchi "If a named struct or union is used, then a type will be created for it just\n" 7020a47c91cSRobert Mustacchi "like in C. This may be used to mimic a forward declaration and an example of\n" 7030a47c91cSRobert Mustacchi "this is in the EXAMPLES section. Regardless of whether a struct or union is\n" 7040a47c91cSRobert Mustacchi "anonymous or named, the \"name\" argument is always required.\n" 7050a47c91cSRobert Mustacchi "\n" 7060a47c91cSRobert Mustacchi "When declaring anonymous structures and unions, the entire definition must\n" 7070a47c91cSRobert Mustacchi "be enclosed within \"\" or ''. The ';' is used by mdb to separate commands\n" 7080a47c91cSRobert Mustacchi "in a similar fashion to the shell. The ';' cannot be escaped, therefore\n" 7090a47c91cSRobert Mustacchi "quoting your argument is necessary. See the EXAMPLES sections for examples\n" 7100a47c91cSRobert Mustacchi "of what this looks like.\n" 7110a47c91cSRobert Mustacchi "\n" 7120a47c91cSRobert Mustacchi "All member and type names must be valid C identifiers. They must start with\n" 7130a47c91cSRobert Mustacchi "an underscore or a letter. Subsequent characters are allowed to be letters,\n" 7140a47c91cSRobert Mustacchi "numbers, or an underscore.\n" 7150a47c91cSRobert Mustacchi "\n" 7160a47c91cSRobert Mustacchi "Declaring arrays and any number of pointers in anonymous structures is \n" 7170a47c91cSRobert Mustacchi "supported. However the following C features are not supported: \n" 7180a47c91cSRobert Mustacchi " o function pointers (use a void * instead)\n" 7190a47c91cSRobert Mustacchi " o bitfields (use an integer of the appropriate size instead)\n" 7200a47c91cSRobert Mustacchi " o packed structures (all structures currently use their natural alignment)\n" 7210a47c91cSRobert Mustacchi "\n" 7220a47c91cSRobert Mustacchi "::typedef also allows you to read type definitions from a file. Definitions\n" 7232becb8cdSRobert Mustacchi "can be read from any ELF file that has a CTF section that libctf can parse\n" 7242becb8cdSRobert Mustacchi "or any raw CTF data files, such as those that can be created with ::typedef.\n" 7250a47c91cSRobert Mustacchi "You can check if a file has such a section with elfdump(1). If a binary or\n" 7260a47c91cSRobert Mustacchi "core dump does not have any type information, but you do have it elsewhere,\n" 7270a47c91cSRobert Mustacchi "then you can use ::typedef -r to read in that type information.\n" 7282becb8cdSRobert Mustacchi "\n" 7292becb8cdSRobert Mustacchi "All built up definitions may be exported as a valid CTF container that can\n" 7302becb8cdSRobert Mustacchi "be used again with ::typedef -r or anything that uses libctf. To write them\n" 7312becb8cdSRobert Mustacchi "out, use ::typedef -w and specify the name of a file. For more information\n" 732*bbf21555SRichard Lowe "on the CTF file format, see ctf(5).\n" 7330a47c91cSRobert Mustacchi "\n"; 7340a47c91cSRobert Mustacchi 7350a47c91cSRobert Mustacchi static char typedef_opts[] = 7360a47c91cSRobert Mustacchi " -c model create intrinsic types based on the specified data model.\n" 7370a47c91cSRobert Mustacchi " The INTRINSICS section lists the built-in types and typedefs.\n" 7380a47c91cSRobert Mustacchi " The following data models are supported:\n" 7392becb8cdSRobert Mustacchi " o LP64 - Traditional illumos 64-bit program.\n" 7400a47c91cSRobert Mustacchi " o LP32 - Traditional illumos 32-bit program.\n" 7410a47c91cSRobert Mustacchi " o ILP32 - An alternate name for LP32.\n" 7420a47c91cSRobert Mustacchi " -d delete all synthetic types\n" 7430a47c91cSRobert Mustacchi " -l list all synthetic types\n" 7440a47c91cSRobert Mustacchi " -r file import type definitions (CTF) from another ELF file\n" 7452becb8cdSRobert Mustacchi " -w file write all synthetic type definitions out to file\n" 7460a47c91cSRobert Mustacchi "\n"; 7470a47c91cSRobert Mustacchi 7480a47c91cSRobert Mustacchi static char typedef_examps[] = 7490a47c91cSRobert Mustacchi " ::typedef -c LP64\n" 7500a47c91cSRobert Mustacchi " ::typedef uint64_t bender_t\n" 7510a47c91cSRobert Mustacchi " ::typedef struct proc new_proc_t\n" 7520a47c91cSRobert Mustacchi " ::typedef \"union { int frodo; char sam; long gandalf; }\" ringbearer_t;\n" 7530a47c91cSRobert Mustacchi " ::typedef \"struct { uintptr_t stone[7]; void **white; }\" gift_t\n" 7540a47c91cSRobert Mustacchi " ::typedef \"struct list { struct list *l_next; struct list *l_prev; }\" " 7550a47c91cSRobert Mustacchi "list_t\n" 7560a47c91cSRobert Mustacchi " ::typedef -r /var/tmp/qemu-system-x86_64\n" 7572becb8cdSRobert Mustacchi " ::typedef -w defs.ctf" 7580a47c91cSRobert Mustacchi "\n"; 7590a47c91cSRobert Mustacchi 7600a47c91cSRobert Mustacchi static char typedef_intrins[] = 7610a47c91cSRobert Mustacchi "The following C types and <stdint.h> typedefs are provided when \n" 7620a47c91cSRobert Mustacchi "::typedef -c is used\n" 7630a47c91cSRobert Mustacchi "\n" 7640a47c91cSRobert Mustacchi " signed unsigned void\n" 7650a47c91cSRobert Mustacchi " char short int\n" 7660a47c91cSRobert Mustacchi " long long long signed char\n" 7670a47c91cSRobert Mustacchi " signed short signed int signed long\n" 7680a47c91cSRobert Mustacchi " singed long long unsigned char unsigned short\n" 7690a47c91cSRobert Mustacchi " unsigned int unsigned long unsigned long long\n" 7700a47c91cSRobert Mustacchi " _Bool float double\n" 7710a47c91cSRobert Mustacchi " long double float imaginary double imaginary\n" 7720a47c91cSRobert Mustacchi " long double imaginary float complex\n" 7730a47c91cSRobert Mustacchi " double complex long double complex\n" 7740a47c91cSRobert Mustacchi "\n" 7750a47c91cSRobert Mustacchi " int8_t int16_t int32_t\n" 7760a47c91cSRobert Mustacchi " int64_t intptr_t uint8_t\n" 7770a47c91cSRobert Mustacchi " uint16_t uint32_t uint64_t\n" 7780a47c91cSRobert Mustacchi " uchar_t ushort_t uint_t\n" 7790a47c91cSRobert Mustacchi " ulong_t u_longlong_t ptrdiff_t\n" 7800a47c91cSRobert Mustacchi " uintptr_t\n" 7810a47c91cSRobert Mustacchi "\n"; 7820a47c91cSRobert Mustacchi 7830a47c91cSRobert Mustacchi void 7840a47c91cSRobert Mustacchi cmd_typedef_help(void) 7850a47c91cSRobert Mustacchi { 7860a47c91cSRobert Mustacchi mdb_printf("%s", typedef_desc); 7870a47c91cSRobert Mustacchi (void) mdb_dec_indent(2); 7880a47c91cSRobert Mustacchi mdb_printf("%<b>OPTIONS%</b>\n"); 7890a47c91cSRobert Mustacchi (void) mdb_inc_indent(2); 7900a47c91cSRobert Mustacchi mdb_printf("%s", typedef_opts); 7910a47c91cSRobert Mustacchi (void) mdb_dec_indent(2); 7920a47c91cSRobert Mustacchi mdb_printf("%<b>EXAMPLES%</b>\n"); 7930a47c91cSRobert Mustacchi (void) mdb_inc_indent(2); 7940a47c91cSRobert Mustacchi mdb_printf("%s", typedef_examps); 7950a47c91cSRobert Mustacchi (void) mdb_dec_indent(2); 7960a47c91cSRobert Mustacchi mdb_printf("%<b>INTRINSICS%</b>\n"); 7970a47c91cSRobert Mustacchi (void) mdb_inc_indent(2); 7980a47c91cSRobert Mustacchi mdb_printf("%s", typedef_intrins); 7990a47c91cSRobert Mustacchi } 800