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