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.
14*46f52c84SRobert Mustacchi  * Copyright 2022 Oxide Computer Company
150a47c91cSRobert Mustacchi  */
160a47c91cSRobert Mustacchi 
170a47c91cSRobert Mustacchi /*
180a47c91cSRobert Mustacchi  * ::typedef exists to allow a user to create and import auxiliary CTF
190a47c91cSRobert Mustacchi  * information for the currently running target. ::typedef is similar to the C
200a47c91cSRobert Mustacchi  * typedef keyword. However, ::typedef has no illusions of grandeur. It is not a
210a47c91cSRobert Mustacchi  * standards complaint version of C's typedef. For specifics on what it does and
220a47c91cSRobert Mustacchi  * does not support, please see the help message for ::typedef later on in this
230a47c91cSRobert Mustacchi  * file.
240a47c91cSRobert Mustacchi  *
250a47c91cSRobert Mustacchi  * In addition to allowing the user to create types, it has a notion of a
260a47c91cSRobert Mustacchi  * built-in set of types that a compiler might provide. Currently ::typedef
270a47c91cSRobert Mustacchi  * supports both the standard illumos 32-bit and 64-bit environments, mainly
280a47c91cSRobert Mustacchi  * LP32 and LP64. These are not present by default; it is up to the user to
290a47c91cSRobert Mustacchi  * request that they be inserted.
300a47c91cSRobert Mustacchi  *
310a47c91cSRobert Mustacchi  * To facilitate this, ::typedef adds all of its type information to an
320a47c91cSRobert Mustacchi  * auxiliary CTF container that is a part of the global mdb state. This is
330a47c91cSRobert Mustacchi  * abstracted away from ::typedef by the mdb_ctf_* apis. This container is
340a47c91cSRobert Mustacchi  * referred to as the synthetic container, as it holds these synthetic types.
350a47c91cSRobert Mustacchi  * The synthetic container does not have a parent CTF container. This is rather
360a47c91cSRobert Mustacchi  * important to its operation, as a user can end up referencing types that come
370a47c91cSRobert Mustacchi  * from many different such containers (eg. different kernel modules). As such,
380a47c91cSRobert Mustacchi  * whenever a type is referenced that we do not know about, we search all of the
390a47c91cSRobert Mustacchi  * CTF containers that mdb knows about it. If we find it, then that type is
400a47c91cSRobert Mustacchi  * imported (along with all of its dependent types) into the synthetic
410a47c91cSRobert Mustacchi  * container.
420a47c91cSRobert Mustacchi  *
430a47c91cSRobert Mustacchi  * Finally, ::typedef can source CTF information from external files with the -r
440a47c91cSRobert Mustacchi  * option. This will copy in every type from their container into the synthetic
450a47c91cSRobert Mustacchi  * container, because of this the parent and child relationship between
460a47c91cSRobert Mustacchi  * containers with parents cannot be maintained.
470a47c91cSRobert Mustacchi  */
480a47c91cSRobert Mustacchi 
490a47c91cSRobert Mustacchi #include <mdb/mdb_modapi.h>
50*46f52c84SRobert Mustacchi #include <mdb/mdb_string.h>
510a47c91cSRobert Mustacchi #include <mdb/mdb_ctf.h>
520a47c91cSRobert Mustacchi #include <mdb/mdb_list.h>
530a47c91cSRobert Mustacchi #include <mdb/mdb_nv.h>
540a47c91cSRobert Mustacchi 
550a47c91cSRobert Mustacchi struct parse_node;
560a47c91cSRobert Mustacchi 
570a47c91cSRobert Mustacchi #define	PN_F_POINTER	0x01
580a47c91cSRobert Mustacchi #define	PN_F_ARRAY	0x02
590a47c91cSRobert Mustacchi 
600a47c91cSRobert Mustacchi typedef struct parse_node {
610a47c91cSRobert Mustacchi 	mdb_list_t		pn_list;	/* list entry, must be first */
620a47c91cSRobert Mustacchi 	char			*pn_type;	/* name of base type */
630a47c91cSRobert Mustacchi 	char			*pn_name;	/* name of the member */
640a47c91cSRobert Mustacchi 	int			pn_flags;	/* flags */
650a47c91cSRobert Mustacchi 	int			pn_nptrs;	/* number of pointers */
660a47c91cSRobert Mustacchi 	int			pn_asub;	/* value of array subscript */
670a47c91cSRobert Mustacchi } parse_node_t;
680a47c91cSRobert Mustacchi 
690a47c91cSRobert Mustacchi typedef struct parse_root {
700a47c91cSRobert Mustacchi 	mdb_list_t	pr_nodes;	/* list of members */
710a47c91cSRobert Mustacchi 	int		pr_kind;	/* CTF_K_* */
720a47c91cSRobert Mustacchi 	const char	*pr_name;	/* entity name */
730a47c91cSRobert Mustacchi 	const char	*pr_tname;	/* entity typedef */
740a47c91cSRobert Mustacchi } parse_root_t;
750a47c91cSRobert Mustacchi 
760a47c91cSRobert Mustacchi static int
typedef_valid_identifier(const char * str)770a47c91cSRobert Mustacchi typedef_valid_identifier(const char *str)
780a47c91cSRobert Mustacchi {
790a47c91cSRobert Mustacchi 	/*
800a47c91cSRobert Mustacchi 	 * We can't use the standard ctype.h functions because those aren't
810a47c91cSRobert Mustacchi 	 * necessairly available in kmdb. On the flip side, we only care about
820a47c91cSRobert Mustacchi 	 * ascii characters here so that isn't too bad.
830a47c91cSRobert Mustacchi 	 *
840a47c91cSRobert Mustacchi 	 * C Identifiers have to start with a letter or a _. Afterwards they can
850a47c91cSRobert Mustacchi 	 * be alphanumeric or an _.
860a47c91cSRobert Mustacchi 	 */
870a47c91cSRobert Mustacchi 
880a47c91cSRobert Mustacchi 	if (*str == '\0')
890a47c91cSRobert Mustacchi 		return (1);
900a47c91cSRobert Mustacchi 
910a47c91cSRobert Mustacchi 	if (*str != '_' &&
920a47c91cSRobert Mustacchi 	    (*str < 'A' || *str > 'Z') &&
930a47c91cSRobert Mustacchi 	    (*str < 'a' || *str > 'z'))
940a47c91cSRobert Mustacchi 		return (1);
950a47c91cSRobert Mustacchi 	str++;
960a47c91cSRobert Mustacchi 
970a47c91cSRobert Mustacchi 	while (*str != '\0') {
980a47c91cSRobert Mustacchi 		if (*str != '_' &&
990a47c91cSRobert Mustacchi 		    (*str < '0' || *str > '9') &&
1000a47c91cSRobert Mustacchi 		    (*str < 'A' || *str > 'Z') &&
1010a47c91cSRobert Mustacchi 		    (*str < 'a' || *str > 'z'))
1020a47c91cSRobert Mustacchi 			return (1);
1030a47c91cSRobert Mustacchi 		str++;
1040a47c91cSRobert Mustacchi 	}
1050a47c91cSRobert Mustacchi 
1060a47c91cSRobert Mustacchi 	return (0);
1070a47c91cSRobert Mustacchi }
1080a47c91cSRobert Mustacchi 
1090a47c91cSRobert Mustacchi /*ARGSUSED*/
1100a47c91cSRobert Mustacchi static int
typedef_list_cb(mdb_ctf_id_t id,void * arg)1110a47c91cSRobert Mustacchi typedef_list_cb(mdb_ctf_id_t id, void *arg)
1120a47c91cSRobert Mustacchi {
1130a47c91cSRobert Mustacchi 	char buf[MDB_SYM_NAMLEN];
1140a47c91cSRobert Mustacchi 
1150a47c91cSRobert Mustacchi 	/*
1160a47c91cSRobert Mustacchi 	 * The user may have created an anonymous structure or union as part of
1170a47c91cSRobert Mustacchi 	 * running ::typedef. If this is the case, we passed a NULL pointer for
1180a47c91cSRobert Mustacchi 	 * the name into the ctf routines. When we go back and ask for the name
1190a47c91cSRobert Mustacchi 	 * of that, ctf goes through and loops through all the declarations.
1200a47c91cSRobert Mustacchi 	 * This, however correctly, gives us back something undesirable to the
1210a47c91cSRobert Mustacchi 	 * user, eg. the name is simply 'struct' and 'union'. Because a typedef
1220a47c91cSRobert Mustacchi 	 * will always have a non-anonymous name for that, we instead opt to
1230a47c91cSRobert Mustacchi 	 * not include these anonymous names. ctf usefully includes a space as
1240a47c91cSRobert Mustacchi 	 * part of that name.
1250a47c91cSRobert Mustacchi 	 */
1260a47c91cSRobert Mustacchi 	(void) mdb_ctf_type_name(id, buf, sizeof (buf));
1270a47c91cSRobert Mustacchi 	if (strcmp("struct ", buf) != 0 && strcmp("union ", buf) != 0)
1280a47c91cSRobert Mustacchi 		mdb_printf("%s\n", buf);
1290a47c91cSRobert Mustacchi 	return (0);
1300a47c91cSRobert Mustacchi }
1310a47c91cSRobert Mustacchi 
1320a47c91cSRobert Mustacchi static char *
typedef_join_strings(int nstr,const mdb_arg_t * args,int flags)1330a47c91cSRobert Mustacchi typedef_join_strings(int nstr, const mdb_arg_t *args, int flags)
1340a47c91cSRobert Mustacchi {
1350a47c91cSRobert Mustacchi 	int i, size = 0;
1360a47c91cSRobert Mustacchi 	char *ret, *sptr;
1370a47c91cSRobert Mustacchi 
1380a47c91cSRobert Mustacchi 	for (i = 0; i <= nstr; i++) {
1390a47c91cSRobert Mustacchi 		/* Always account for the space or the null terminator */
1400a47c91cSRobert Mustacchi 		size += strlen(args[i].a_un.a_str) + 1;
1410a47c91cSRobert Mustacchi 	}
1420a47c91cSRobert Mustacchi 	ret = mdb_alloc(sizeof (char) * size, flags);
1430a47c91cSRobert Mustacchi 	if (ret == NULL)
1440a47c91cSRobert Mustacchi 		return (NULL);
1450a47c91cSRobert Mustacchi 	sptr = ret;
1460a47c91cSRobert Mustacchi 	for (i = 0; i <= nstr; i++) {
1470a47c91cSRobert Mustacchi 		(void) strcpy(sptr, args[i].a_un.a_str);
1480a47c91cSRobert Mustacchi 		sptr += strlen(args[i].a_un.a_str);
1490a47c91cSRobert Mustacchi 		*sptr = ' ';
1500a47c91cSRobert Mustacchi 		sptr++;
1510a47c91cSRobert Mustacchi 	}
1520a47c91cSRobert Mustacchi 	*sptr = '\0';
1530a47c91cSRobert Mustacchi 
1540a47c91cSRobert Mustacchi 	return (ret);
1550a47c91cSRobert Mustacchi }
1560a47c91cSRobert Mustacchi 
1570a47c91cSRobert Mustacchi static int
typedef_list(void)1580a47c91cSRobert Mustacchi typedef_list(void)
1590a47c91cSRobert Mustacchi {
1600a47c91cSRobert Mustacchi 	(void) mdb_ctf_type_iter(MDB_CTF_SYNTHETIC_ITER, typedef_list_cb,
1610a47c91cSRobert Mustacchi 	    NULL);
1620a47c91cSRobert Mustacchi 	return (DCMD_OK);
1630a47c91cSRobert Mustacchi }
1640a47c91cSRobert Mustacchi 
1650a47c91cSRobert Mustacchi static int
typedef_destroy(void)1660a47c91cSRobert Mustacchi typedef_destroy(void)
1670a47c91cSRobert Mustacchi {
1680a47c91cSRobert Mustacchi 	if (mdb_ctf_synthetics_reset() != 0) {
1690a47c91cSRobert Mustacchi 		mdb_warn("failed to reset synthetic types");
1700a47c91cSRobert Mustacchi 		return (DCMD_ERR);
1710a47c91cSRobert Mustacchi 	}
1720a47c91cSRobert Mustacchi 	return (DCMD_OK);
1730a47c91cSRobert Mustacchi }
1740a47c91cSRobert Mustacchi 
1750a47c91cSRobert Mustacchi /*
1760a47c91cSRobert Mustacchi  * We've been asked to create the basic types that exist. We accept the
1770a47c91cSRobert Mustacchi  * following strings to indicate what we should create.
1780a47c91cSRobert Mustacchi  * - LP32, ILP32 (case insensitive)
1790a47c91cSRobert Mustacchi  * - LP64
1800a47c91cSRobert Mustacchi  */
1810a47c91cSRobert Mustacchi static int
typedef_create(const char * arg)1820a47c91cSRobert Mustacchi typedef_create(const char *arg)
1830a47c91cSRobert Mustacchi {
1840a47c91cSRobert Mustacchi 	int kind;
1850a47c91cSRobert Mustacchi 
1860a47c91cSRobert Mustacchi 	if (strcasecmp(arg, "LP32") == 0 || strcasecmp(arg, "ILP32") == 0) {
1870a47c91cSRobert Mustacchi 		kind = SYNTHETIC_ILP32;
1880a47c91cSRobert Mustacchi 	} else if (strcasecmp(arg, "LP64") == 0) {
1890a47c91cSRobert Mustacchi 		kind = SYNTHETIC_LP64;
1900a47c91cSRobert Mustacchi 	} else {
1910a47c91cSRobert Mustacchi 		mdb_printf("invalid data model: %s\n", arg);
1920a47c91cSRobert Mustacchi 		return (DCMD_USAGE);
1930a47c91cSRobert Mustacchi 	}
1940a47c91cSRobert Mustacchi 
1950a47c91cSRobert Mustacchi 	if (mdb_ctf_synthetics_create_base(kind) != 0) {
1960a47c91cSRobert Mustacchi 		mdb_printf("failed to create intrinsic types, maybe "
1970a47c91cSRobert Mustacchi 		    "they already exist\n");
1980a47c91cSRobert Mustacchi 		return (DCMD_ERR);
1990a47c91cSRobert Mustacchi 	}
2000a47c91cSRobert Mustacchi 
2010a47c91cSRobert Mustacchi 	return (DCMD_OK);
2020a47c91cSRobert Mustacchi }
2030a47c91cSRobert Mustacchi 
2040a47c91cSRobert Mustacchi /*
2050a47c91cSRobert Mustacchi  * Search the current arguments for a complete member declaration. This function
2060a47c91cSRobert Mustacchi  * modifies the value of defn based on what's necessary for parsing. It returns
2070a47c91cSRobert Mustacchi  * the appropriate parse node in pnp.
2080a47c91cSRobert Mustacchi  */
2090a47c91cSRobert Mustacchi static int
typedef_parse_member(char * defn,char ** next,parse_node_t ** pnp)2100a47c91cSRobert Mustacchi typedef_parse_member(char *defn, char **next, parse_node_t **pnp)
2110a47c91cSRobert Mustacchi {
2120a47c91cSRobert Mustacchi 	char *c, *name, *array;
2130a47c91cSRobert Mustacchi 	int nptrs = 0;
2140a47c91cSRobert Mustacchi 	parse_node_t *pn;
2150a47c91cSRobert Mustacchi 
2160a47c91cSRobert Mustacchi 	c = strchr(defn, ';');
2170a47c91cSRobert Mustacchi 	if (c == NULL) {
2180a47c91cSRobert Mustacchi 		mdb_printf("Cannot find semi-colon to delineate the end "
2190a47c91cSRobert Mustacchi 		    "of a member.\n");
2200a47c91cSRobert Mustacchi 		return (DCMD_ERR);
2210a47c91cSRobert Mustacchi 	}
2220a47c91cSRobert Mustacchi 	*c = '\0';
2230a47c91cSRobert Mustacchi 	*next = c + 1;
2240a47c91cSRobert Mustacchi 
2250a47c91cSRobert Mustacchi 	c = strrchr(defn, ' ');
2260a47c91cSRobert Mustacchi 	if (c == NULL) {
2270a47c91cSRobert Mustacchi 		mdb_printf("Missing both a name and a type declaration for "
2280a47c91cSRobert Mustacchi 		    "a member. Instead, found '%s'\n", defn);
2290a47c91cSRobert Mustacchi 		return (DCMD_ERR);
2300a47c91cSRobert Mustacchi 	}
2310a47c91cSRobert Mustacchi 	*c = '\0';
2320a47c91cSRobert Mustacchi 	name = c + 1;
2330a47c91cSRobert Mustacchi 	c--;
2340a47c91cSRobert Mustacchi 	while (*c == '*' || *c == ' ') {
2350a47c91cSRobert Mustacchi 		if (*c == '*')
2360a47c91cSRobert Mustacchi 			nptrs++;
2370a47c91cSRobert Mustacchi 		c--;
2380a47c91cSRobert Mustacchi 	}
2390a47c91cSRobert Mustacchi 	*(c + 1) = '\0';
2400a47c91cSRobert Mustacchi 
2410a47c91cSRobert Mustacchi 	pn = mdb_zalloc(sizeof (parse_node_t), UM_SLEEP | UM_GC);
2420a47c91cSRobert Mustacchi 	pn->pn_type = defn;
2430a47c91cSRobert Mustacchi 
2440a47c91cSRobert Mustacchi 	/*
2450a47c91cSRobert Mustacchi 	 * Go through and prepare the name field. Note that we still have to
2460a47c91cSRobert Mustacchi 	 * check if this is a pointer or an array. We also need to strip the
2470a47c91cSRobert Mustacchi 	 * ending semi-colon.
2480a47c91cSRobert Mustacchi 	 */
2490a47c91cSRobert Mustacchi 	while (*name == '*') {
2500a47c91cSRobert Mustacchi 		name++;
2510a47c91cSRobert Mustacchi 		nptrs++;
2520a47c91cSRobert Mustacchi 	}
2530a47c91cSRobert Mustacchi 
2540a47c91cSRobert Mustacchi 	if ((c = strchr(name, '[')) != NULL) {
2550a47c91cSRobert Mustacchi 		array = c;
2560a47c91cSRobert Mustacchi 		if ((c = strchr(array, ']')) == NULL) {
2570a47c91cSRobert Mustacchi 			mdb_printf("Found the beginning of an array size "
2580a47c91cSRobert Mustacchi 			    "but no closing ']' in %s\n", array);
2590a47c91cSRobert Mustacchi 			return (DCMD_ERR);
2600a47c91cSRobert Mustacchi 		}
2610a47c91cSRobert Mustacchi 		*array = '\0';
2620a47c91cSRobert Mustacchi 		array++;
2630a47c91cSRobert Mustacchi 		*c = '\0';
2640a47c91cSRobert Mustacchi 		pn->pn_flags |= PN_F_ARRAY;
265*46f52c84SRobert Mustacchi 		pn->pn_asub = mdb_strtoullx(array, MDB_STRTOULL_F_BASE_C);
2660a47c91cSRobert Mustacchi 		if (pn->pn_asub < 0) {
2670a47c91cSRobert Mustacchi 			mdb_printf("Array lengths cannot be negative\n");
2680a47c91cSRobert Mustacchi 			return (DCMD_ERR);
2690a47c91cSRobert Mustacchi 		}
2700a47c91cSRobert Mustacchi 	}
2710a47c91cSRobert Mustacchi 
2720a47c91cSRobert Mustacchi 	if (typedef_valid_identifier(name) != 0) {
2730a47c91cSRobert Mustacchi 		mdb_printf("The name %s is not a valid C identifier.\n",
2740a47c91cSRobert Mustacchi 		    name);
2750a47c91cSRobert Mustacchi 		return (DCMD_ERR);
2760a47c91cSRobert Mustacchi 	}
2770a47c91cSRobert Mustacchi 
2780a47c91cSRobert Mustacchi 	if (nptrs) {
2790a47c91cSRobert Mustacchi 		pn->pn_flags |= PN_F_POINTER;
2800a47c91cSRobert Mustacchi 		pn->pn_nptrs = nptrs;
2810a47c91cSRobert Mustacchi 	}
2820a47c91cSRobert Mustacchi 	pn->pn_name = name;
2830a47c91cSRobert Mustacchi 
2840a47c91cSRobert Mustacchi 	*pnp = pn;
2850a47c91cSRobert Mustacchi 	return (DCMD_OK);
2860a47c91cSRobert Mustacchi }
2870a47c91cSRobert Mustacchi 
2880a47c91cSRobert Mustacchi /*
2890a47c91cSRobert Mustacchi  * We're going to parse out our types here. Note that we are not strictly
2900a47c91cSRobert Mustacchi  * speaking a truely ANSI C compliant parser. Currently we support normal
2910a47c91cSRobert Mustacchi  * declarations except for the following:
2920a47c91cSRobert Mustacchi  *   o function pointers
2930a47c91cSRobert Mustacchi  *   o bit-fields
2940a47c91cSRobert Mustacchi  */
2950a47c91cSRobert Mustacchi static int
typedef_parse(char * defn,const char * name,parse_root_t ** prp)2960a47c91cSRobert Mustacchi typedef_parse(char *defn, const char *name, parse_root_t **prp)
2970a47c91cSRobert Mustacchi {
2980a47c91cSRobert Mustacchi 	int len, ret;
2990a47c91cSRobert Mustacchi 	const char *kind, *basename;
3000a47c91cSRobert Mustacchi 	char *c, *brace;
3010a47c91cSRobert Mustacchi 	parse_root_t *pr;
3020a47c91cSRobert Mustacchi 	parse_node_t *pn;
3030a47c91cSRobert Mustacchi 	mdb_ctf_id_t id;
3040a47c91cSRobert Mustacchi 
3050a47c91cSRobert Mustacchi 	pr = mdb_zalloc(sizeof (parse_root_t), UM_SLEEP | UM_GC);
3060a47c91cSRobert Mustacchi 	basename = defn;
3070a47c91cSRobert Mustacchi 
3080a47c91cSRobert Mustacchi 	c = strchr(defn, ' ');
3090a47c91cSRobert Mustacchi 	if (c == NULL) {
3100a47c91cSRobert Mustacchi 		mdb_printf("Invalid structure definition. Structure "
3110a47c91cSRobert Mustacchi 		    "must start with either 'struct {' or 'union {'\n");
3120a47c91cSRobert Mustacchi 		return (DCMD_ERR);
3130a47c91cSRobert Mustacchi 	}
3140a47c91cSRobert Mustacchi 	*c = '\0';
3150a47c91cSRobert Mustacchi 
3160a47c91cSRobert Mustacchi 	if (strcmp(defn, "struct") == 0)
3170a47c91cSRobert Mustacchi 		pr->pr_kind = CTF_K_STRUCT;
3180a47c91cSRobert Mustacchi 	else if (strcmp(defn, "union") == 0)
3190a47c91cSRobert Mustacchi 		pr->pr_kind = CTF_K_UNION;
3200a47c91cSRobert Mustacchi 	else {
3210a47c91cSRobert Mustacchi 		mdb_printf("Invalid start of definition. "
3220a47c91cSRobert Mustacchi 		    "Expected 'struct' or 'union'. "
3230a47c91cSRobert Mustacchi 		    "Found: '%s'\n", defn);
3240a47c91cSRobert Mustacchi 		return (DCMD_ERR);
3250a47c91cSRobert Mustacchi 	}
3260a47c91cSRobert Mustacchi 
3270a47c91cSRobert Mustacchi 	/*
3280a47c91cSRobert Mustacchi 	 * We transform this back to a space so we can validate that a
3290a47c91cSRobert Mustacchi 	 * non-anonymous struct or union name is valid.
3300a47c91cSRobert Mustacchi 	 */
3310a47c91cSRobert Mustacchi 	*c = ' ';
3320a47c91cSRobert Mustacchi 
3330a47c91cSRobert Mustacchi 	kind = defn;
3340a47c91cSRobert Mustacchi 	defn = c + 1;
3350a47c91cSRobert Mustacchi 	while (*defn == ' ')
3360a47c91cSRobert Mustacchi 		defn++;
3370a47c91cSRobert Mustacchi 
3380a47c91cSRobert Mustacchi 	/* Check whether this is anonymous or not */
3390a47c91cSRobert Mustacchi 	if (*defn != '{') {
3400a47c91cSRobert Mustacchi 		brace = strchr(defn, '{');
3410a47c91cSRobert Mustacchi 		c = brace;
3420a47c91cSRobert Mustacchi 		if (c == NULL) {
3430a47c91cSRobert Mustacchi 			mdb_printf("Missing opening brace for %s definition. "
3440a47c91cSRobert Mustacchi 			    "Expected '{'. "
3450a47c91cSRobert Mustacchi 			    "Found: '%c'\n", kind, *defn);
3460a47c91cSRobert Mustacchi 			return (DCMD_ERR);
3470a47c91cSRobert Mustacchi 		}
3480a47c91cSRobert Mustacchi 		*c = '\0';
3490a47c91cSRobert Mustacchi 		c--;
3500a47c91cSRobert Mustacchi 		while (*c == ' ')
3510a47c91cSRobert Mustacchi 			c--;
3520a47c91cSRobert Mustacchi 		*(c+1) = '\0';
3530a47c91cSRobert Mustacchi 		if (typedef_valid_identifier(defn) != 0) {
3540a47c91cSRobert Mustacchi 			mdb_printf("The name %s is not a valid C identifier.\n",
3550a47c91cSRobert Mustacchi 			    defn);
3560a47c91cSRobert Mustacchi 			return (DCMD_ERR);
3570a47c91cSRobert Mustacchi 		}
3580a47c91cSRobert Mustacchi 
3590a47c91cSRobert Mustacchi 		if (mdb_ctf_lookup_by_name(basename, &id) != CTF_ERR) {
3600a47c91cSRobert Mustacchi 			mdb_printf("type name %s already in use\n", basename);
3610a47c91cSRobert Mustacchi 			return (DCMD_ERR);
3620a47c91cSRobert Mustacchi 		}
3630a47c91cSRobert Mustacchi 
3640a47c91cSRobert Mustacchi 		pr->pr_name = defn;
3650a47c91cSRobert Mustacchi 		defn = brace;
3660a47c91cSRobert Mustacchi 	} else {
3670a47c91cSRobert Mustacchi 		pr->pr_name = NULL;
3680a47c91cSRobert Mustacchi 	}
3690a47c91cSRobert Mustacchi 
3700a47c91cSRobert Mustacchi 	defn++;
3710a47c91cSRobert Mustacchi 	while (*defn == ' ')
3720a47c91cSRobert Mustacchi 		defn++;
3730a47c91cSRobert Mustacchi 
3740a47c91cSRobert Mustacchi 	len = strlen(defn);
3750a47c91cSRobert Mustacchi 	if (defn[len-1] != '}') {
3760a47c91cSRobert Mustacchi 		mdb_printf("Missing closing brace for %s declaration. "
3770a47c91cSRobert Mustacchi 		    "Expected '}'.\n");
3780a47c91cSRobert Mustacchi 		return (DCMD_ERR);
3790a47c91cSRobert Mustacchi 	}
3800a47c91cSRobert Mustacchi 	defn[len-1] = '\0';
3810a47c91cSRobert Mustacchi 
3820a47c91cSRobert Mustacchi 	/*
3830a47c91cSRobert Mustacchi 	 * Start walking all the arguments, looking for a terminating semicolon
3840a47c91cSRobert Mustacchi 	 * for type definitions.
3850a47c91cSRobert Mustacchi 	 */
3860a47c91cSRobert Mustacchi 	for (;;) {
3870a47c91cSRobert Mustacchi 		ret = typedef_parse_member(defn, &c, &pn);
3880a47c91cSRobert Mustacchi 		if (ret == DCMD_ERR)
3890a47c91cSRobert Mustacchi 			return (DCMD_ERR);
3900a47c91cSRobert Mustacchi 
3910a47c91cSRobert Mustacchi 		mdb_list_append(&pr->pr_nodes, pn);
3920a47c91cSRobert Mustacchi 
3930a47c91cSRobert Mustacchi 		while (*c == ' ')
3940a47c91cSRobert Mustacchi 			c++;
3950a47c91cSRobert Mustacchi 
3960a47c91cSRobert Mustacchi 		if (*c == '\0')
3970a47c91cSRobert Mustacchi 			break;
3980a47c91cSRobert Mustacchi 
3990a47c91cSRobert Mustacchi 		defn = c;
4000a47c91cSRobert Mustacchi 	}
4010a47c91cSRobert Mustacchi 
4020a47c91cSRobert Mustacchi 	pr->pr_tname = name;
4030a47c91cSRobert Mustacchi 	*prp = pr;
4040a47c91cSRobert Mustacchi 
4050a47c91cSRobert Mustacchi 	return (DCMD_OK);
4060a47c91cSRobert Mustacchi }
4070a47c91cSRobert Mustacchi 
4080a47c91cSRobert Mustacchi /*
4090a47c91cSRobert Mustacchi  * Make sure that none of the member names overlap and that the type names don't
4100a47c91cSRobert Mustacchi  * already exist. If we have an array entry that is a VLA, make sure it is the
4110a47c91cSRobert Mustacchi  * last member and not the only member.
4120a47c91cSRobert Mustacchi  */
4130a47c91cSRobert Mustacchi static int
typedef_validate(parse_root_t * pr)4140a47c91cSRobert Mustacchi typedef_validate(parse_root_t *pr)
4150a47c91cSRobert Mustacchi {
4160a47c91cSRobert Mustacchi 	mdb_nv_t nv;
4170a47c91cSRobert Mustacchi 	parse_node_t *pn;
4180a47c91cSRobert Mustacchi 	mdb_ctf_id_t id;
4190a47c91cSRobert Mustacchi 	int count = 0;
4200a47c91cSRobert Mustacchi 
4210a47c91cSRobert Mustacchi 	(void) mdb_nv_create(&nv, UM_SLEEP | UM_GC);
4220a47c91cSRobert Mustacchi 	for (pn = mdb_list_next(&pr->pr_nodes); pn != NULL;
4230a47c91cSRobert Mustacchi 	    pn = mdb_list_next(pn)) {
4240a47c91cSRobert Mustacchi 		count++;
4250a47c91cSRobert Mustacchi 		if (mdb_nv_lookup(&nv, pn->pn_name) != NULL) {
4260a47c91cSRobert Mustacchi 			mdb_printf("duplicate name detected: %s\n",
4270a47c91cSRobert Mustacchi 			    pn->pn_name);
4280a47c91cSRobert Mustacchi 			return (DCMD_ERR);
4290a47c91cSRobert Mustacchi 		}
4300a47c91cSRobert Mustacchi 
4310a47c91cSRobert Mustacchi 		/*
4320a47c91cSRobert Mustacchi 		 * Our parse tree won't go away before the nv, so it's simpler
4330a47c91cSRobert Mustacchi 		 * to just mark everything external.
4340a47c91cSRobert Mustacchi 		 */
4350a47c91cSRobert Mustacchi 		(void) mdb_nv_insert(&nv, pn->pn_name, NULL, 0, MDB_NV_EXTNAME);
4360a47c91cSRobert Mustacchi 
4370a47c91cSRobert Mustacchi 		if (pn->pn_flags & PN_F_ARRAY && pn->pn_asub == 0) {
4380a47c91cSRobert Mustacchi 			if (pr->pr_kind != CTF_K_STRUCT) {
4390a47c91cSRobert Mustacchi 				mdb_printf("Flexible array members are only "
4400a47c91cSRobert Mustacchi 				    "valid in structs.\n");
4410a47c91cSRobert Mustacchi 				return (DCMD_ERR);
4420a47c91cSRobert Mustacchi 			}
4430a47c91cSRobert Mustacchi 
4440a47c91cSRobert Mustacchi 			if (&pn->pn_list != pr->pr_nodes.ml_prev) {
4450a47c91cSRobert Mustacchi 				mdb_printf("Flexible array entries are only "
4460a47c91cSRobert Mustacchi 				    "allowed to be the last entry in a "
4470a47c91cSRobert Mustacchi 				    "struct\n");
4480a47c91cSRobert Mustacchi 				return (DCMD_ERR);
4490a47c91cSRobert Mustacchi 			}
4500a47c91cSRobert Mustacchi 
4510a47c91cSRobert Mustacchi 			if (count == 1) {
4520a47c91cSRobert Mustacchi 				mdb_printf("Structs must have members aside "
4530a47c91cSRobert Mustacchi 				    "from a flexible member\n");
4540a47c91cSRobert Mustacchi 				return (DCMD_ERR);
4550a47c91cSRobert Mustacchi 			}
4560a47c91cSRobert Mustacchi 		}
4570a47c91cSRobert Mustacchi 	}
4580a47c91cSRobert Mustacchi 
4590a47c91cSRobert Mustacchi 	if (mdb_ctf_lookup_by_name(pr->pr_tname, &id) != CTF_ERR) {
4600a47c91cSRobert Mustacchi 		mdb_printf("typedef name %s already exists\n", pr->pr_tname);
4610a47c91cSRobert Mustacchi 		return (DCMD_ERR);
4620a47c91cSRobert Mustacchi 	}
4630a47c91cSRobert Mustacchi 
4640a47c91cSRobert Mustacchi 	return (DCMD_OK);
4650a47c91cSRobert Mustacchi }
4660a47c91cSRobert Mustacchi 
4670a47c91cSRobert Mustacchi static int
typedef_add(parse_root_t * pr)4680a47c91cSRobert Mustacchi typedef_add(parse_root_t *pr)
4690a47c91cSRobert Mustacchi {
4700a47c91cSRobert Mustacchi 	parse_node_t *pn;
4710a47c91cSRobert Mustacchi 	mdb_ctf_id_t id, aid, tid, pid;
4720a47c91cSRobert Mustacchi 	mdb_ctf_arinfo_t ar;
4730a47c91cSRobert Mustacchi 	int ii;
4740a47c91cSRobert Mustacchi 
4750a47c91cSRobert Mustacchi 	/* Pre-flight checks */
4760a47c91cSRobert Mustacchi 	if (typedef_validate(pr) == DCMD_ERR)
4770a47c91cSRobert Mustacchi 		return (DCMD_ERR);
4780a47c91cSRobert Mustacchi 
4790a47c91cSRobert Mustacchi 	if (pr->pr_kind == CTF_K_STRUCT) {
4800a47c91cSRobert Mustacchi 		if (mdb_ctf_add_struct(pr->pr_name, &id) != 0) {
4810a47c91cSRobert Mustacchi 			mdb_printf("failed to create struct for %s\n",
4820a47c91cSRobert Mustacchi 			    pr->pr_tname);
4830a47c91cSRobert Mustacchi 			return (DCMD_ERR);
4840a47c91cSRobert Mustacchi 		}
4850a47c91cSRobert Mustacchi 	} else {
4860a47c91cSRobert Mustacchi 		if (mdb_ctf_add_union(pr->pr_name, &id) != 0) {
4870a47c91cSRobert Mustacchi 			mdb_printf("failed to create union for %s\n",
4880a47c91cSRobert Mustacchi 			    pr->pr_tname);
4890a47c91cSRobert Mustacchi 			return (DCMD_ERR);
4900a47c91cSRobert Mustacchi 		}
4910a47c91cSRobert Mustacchi 	}
4920a47c91cSRobert Mustacchi 
4930a47c91cSRobert Mustacchi 	for (pn = mdb_list_next(&pr->pr_nodes); pn != NULL;
4940a47c91cSRobert Mustacchi 	    pn = mdb_list_next(pn)) {
4950a47c91cSRobert Mustacchi 
4960a47c91cSRobert Mustacchi 		if (mdb_ctf_lookup_by_name(pn->pn_type, &tid) == CTF_ERR) {
4970a47c91cSRobert Mustacchi 			mdb_printf("failed to add member %s: type %s does "
4980a47c91cSRobert Mustacchi 			    "not exist\n", pn->pn_name, pn->pn_type);
4990a47c91cSRobert Mustacchi 			goto destroy;
5000a47c91cSRobert Mustacchi 		}
5010a47c91cSRobert Mustacchi 
5020a47c91cSRobert Mustacchi 		if (pn->pn_flags & PN_F_POINTER) {
5030a47c91cSRobert Mustacchi 			for (ii = 0; ii < pn->pn_nptrs; ii++) {
5040a47c91cSRobert Mustacchi 				if (mdb_ctf_add_pointer(&tid,
5050a47c91cSRobert Mustacchi 				    &pid) != 0) {
5060a47c91cSRobert Mustacchi 					mdb_printf("failed to add a pointer "
5070a47c91cSRobert Mustacchi 					    "type as part of member: %s\n",
5080a47c91cSRobert Mustacchi 					    pn->pn_name);
5090a47c91cSRobert Mustacchi 					goto destroy;
5100a47c91cSRobert Mustacchi 				}
5110a47c91cSRobert Mustacchi 				tid = pid;
5120a47c91cSRobert Mustacchi 			}
5130a47c91cSRobert Mustacchi 		}
5140a47c91cSRobert Mustacchi 
5150a47c91cSRobert Mustacchi 		if (pn->pn_flags & PN_F_ARRAY) {
5160a47c91cSRobert Mustacchi 			if (mdb_ctf_lookup_by_name("long", &aid) != 0) {
5170a47c91cSRobert Mustacchi 				mdb_printf("failed to lookup the type 'long' "
5180a47c91cSRobert Mustacchi 				    "for array indexes, are you running mdb "
5190a47c91cSRobert Mustacchi 				    "without a target or using ::typedef -c?");
5200a47c91cSRobert Mustacchi 				goto destroy;
5210a47c91cSRobert Mustacchi 			}
5220a47c91cSRobert Mustacchi 
5230a47c91cSRobert Mustacchi 			ar.mta_contents = tid;
5240a47c91cSRobert Mustacchi 			ar.mta_index = aid;
5250a47c91cSRobert Mustacchi 			ar.mta_nelems = pn->pn_asub;
5260a47c91cSRobert Mustacchi 
5270a47c91cSRobert Mustacchi 			if (mdb_ctf_add_array(&ar, &tid) != 0) {
5280a47c91cSRobert Mustacchi 				mdb_printf("failed to create array type for "
5290a47c91cSRobert Mustacchi 				    "memeber%s\n", pn->pn_name);
5300a47c91cSRobert Mustacchi 				goto destroy;
5310a47c91cSRobert Mustacchi 			}
5320a47c91cSRobert Mustacchi 		}
5330a47c91cSRobert Mustacchi 
5340a47c91cSRobert Mustacchi 		if (mdb_ctf_add_member(&id, pn->pn_name, &tid, NULL) ==
5350a47c91cSRobert Mustacchi 		    CTF_ERR) {
5360a47c91cSRobert Mustacchi 			mdb_printf("failed to create member %s\n",
5370a47c91cSRobert Mustacchi 			    pn->pn_name);
5380a47c91cSRobert Mustacchi 			goto destroy;
5390a47c91cSRobert Mustacchi 		}
5400a47c91cSRobert Mustacchi 	}
5410a47c91cSRobert Mustacchi 
5420a47c91cSRobert Mustacchi 	if (mdb_ctf_add_typedef(pr->pr_tname, &id, NULL) != 0) {
5430a47c91cSRobert Mustacchi 		mdb_printf("failed to add typedef for %s\n",
5440a47c91cSRobert Mustacchi 		    pr->pr_tname);
5450a47c91cSRobert Mustacchi 		goto destroy;
5460a47c91cSRobert Mustacchi 	}
5470a47c91cSRobert Mustacchi 
5480a47c91cSRobert Mustacchi 	return (DCMD_OK);
5490a47c91cSRobert Mustacchi 
5500a47c91cSRobert Mustacchi destroy:
5510a47c91cSRobert Mustacchi 	return (mdb_ctf_type_delete(&id));
5520a47c91cSRobert Mustacchi }
5530a47c91cSRobert Mustacchi 
5540a47c91cSRobert Mustacchi static int
typedef_readfile(const char * file)5550a47c91cSRobert Mustacchi typedef_readfile(const char *file)
5560a47c91cSRobert Mustacchi {
5570a47c91cSRobert Mustacchi 	int ret;
5580a47c91cSRobert Mustacchi 
5590a47c91cSRobert Mustacchi 	ret = mdb_ctf_synthetics_from_file(file);
5600a47c91cSRobert Mustacchi 	if (ret != DCMD_OK)
5612becb8cdSRobert Mustacchi 		mdb_warn("failed to create synthetics from file %s\n", file);
5622becb8cdSRobert Mustacchi 	return (ret);
5632becb8cdSRobert Mustacchi }
5642becb8cdSRobert Mustacchi 
5652becb8cdSRobert Mustacchi static int
typedef_writefile(const char * file)5662becb8cdSRobert Mustacchi typedef_writefile(const char *file)
5672becb8cdSRobert Mustacchi {
5682becb8cdSRobert Mustacchi 	int ret;
5692becb8cdSRobert Mustacchi 
5702becb8cdSRobert Mustacchi 	ret = mdb_ctf_synthetics_to_file(file);
5712becb8cdSRobert Mustacchi 	if (ret != DCMD_OK)
5722becb8cdSRobert Mustacchi 		mdb_warn("failed to write synthetics to file %s", file);
5730a47c91cSRobert Mustacchi 	return (ret);
5740a47c91cSRobert Mustacchi }
5750a47c91cSRobert Mustacchi 
5760a47c91cSRobert Mustacchi /* ARGSUSED */
5770a47c91cSRobert Mustacchi int
cmd_typedef(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)5780a47c91cSRobert Mustacchi cmd_typedef(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5790a47c91cSRobert Mustacchi {
5800a47c91cSRobert Mustacchi 	mdb_ctf_id_t id;
5810a47c91cSRobert Mustacchi 	int i;
5820a47c91cSRobert Mustacchi 	int destroy = 0, list = 0;
5832becb8cdSRobert Mustacchi 	const char *cmode = NULL, *rfile = NULL, *wfile = NULL;
5840a47c91cSRobert Mustacchi 	const char *dst, *src;
5850a47c91cSRobert Mustacchi 	char *dup;
5860a47c91cSRobert Mustacchi 	parse_root_t *pr;
5870a47c91cSRobert Mustacchi 
5880a47c91cSRobert Mustacchi 	if (flags & DCMD_ADDRSPEC)
5890a47c91cSRobert Mustacchi 		return (DCMD_USAGE);
5900a47c91cSRobert Mustacchi 
5910a47c91cSRobert Mustacchi 	i = mdb_getopts(argc, argv,
5920a47c91cSRobert Mustacchi 	    'd', MDB_OPT_SETBITS, TRUE, &destroy,
5930a47c91cSRobert Mustacchi 	    'l', MDB_OPT_SETBITS, TRUE, &list,
5940a47c91cSRobert Mustacchi 	    'c', MDB_OPT_STR, &cmode,
5952becb8cdSRobert Mustacchi 	    'r', MDB_OPT_STR, &rfile,
5962becb8cdSRobert Mustacchi 	    'w', MDB_OPT_STR, &wfile, NULL);
5970a47c91cSRobert Mustacchi 
5980a47c91cSRobert Mustacchi 	argc -= i;
5990a47c91cSRobert Mustacchi 	argv += i;
6000a47c91cSRobert Mustacchi 
6010a47c91cSRobert Mustacchi 	/*
6020a47c91cSRobert Mustacchi 	 * All our options are mutually exclusive currently.
6030a47c91cSRobert Mustacchi 	 */
6040a47c91cSRobert Mustacchi 	i = 0;
6050a47c91cSRobert Mustacchi 	if (destroy)
6060a47c91cSRobert Mustacchi 		i++;
6070a47c91cSRobert Mustacchi 	if (cmode != NULL)
6080a47c91cSRobert Mustacchi 		i++;
6090a47c91cSRobert Mustacchi 	if (list)
6100a47c91cSRobert Mustacchi 		i++;
6110a47c91cSRobert Mustacchi 	if (rfile != NULL)
6120a47c91cSRobert Mustacchi 		i++;
6132becb8cdSRobert Mustacchi 	if (wfile != NULL)
6142becb8cdSRobert Mustacchi 		i++;
6150a47c91cSRobert Mustacchi 	if (i > 1)
6160a47c91cSRobert Mustacchi 		return (DCMD_USAGE);
6170a47c91cSRobert Mustacchi 
6182becb8cdSRobert Mustacchi 	if ((destroy || cmode != NULL || list || rfile != NULL ||
6192becb8cdSRobert Mustacchi 	    wfile != NULL) && argc != 0)
6200a47c91cSRobert Mustacchi 		return (DCMD_USAGE);
6210a47c91cSRobert Mustacchi 
6220a47c91cSRobert Mustacchi 	if (destroy)
6230a47c91cSRobert Mustacchi 		return (typedef_destroy());
6240a47c91cSRobert Mustacchi 
6250a47c91cSRobert Mustacchi 	if (cmode)
6260a47c91cSRobert Mustacchi 		return (typedef_create(cmode));
6270a47c91cSRobert Mustacchi 
6280a47c91cSRobert Mustacchi 	if (list)
6290a47c91cSRobert Mustacchi 		return (typedef_list());
6300a47c91cSRobert Mustacchi 
6310a47c91cSRobert Mustacchi 	if (rfile)
6320a47c91cSRobert Mustacchi 		return (typedef_readfile(rfile));
6330a47c91cSRobert Mustacchi 
6342becb8cdSRobert Mustacchi 	if (wfile)
6352becb8cdSRobert Mustacchi 		return (typedef_writefile(wfile));
6362becb8cdSRobert Mustacchi 
6370a47c91cSRobert Mustacchi 	if (argc < 2)
6380a47c91cSRobert Mustacchi 		return (DCMD_USAGE);
6390a47c91cSRobert Mustacchi 
6400a47c91cSRobert Mustacchi 	/*
6410a47c91cSRobert Mustacchi 	 * Check to see if we are defining a struct or union. Note that we have
6420a47c91cSRobert Mustacchi 	 * to distinguish between struct foo and struct {. All typedef structs
6430a47c91cSRobert Mustacchi 	 * are annonymous structs that are only known by their typedef name. The
6440a47c91cSRobert Mustacchi 	 * same is true with unions. The problem that we have to deal with is
6450a47c91cSRobert Mustacchi 	 * that the ';' character in mdb causes mdb to begin another command. To
6460a47c91cSRobert Mustacchi 	 * work around that fact we require users to put the whole struct
6470a47c91cSRobert Mustacchi 	 * definition in a pair of "" or ''.
6480a47c91cSRobert Mustacchi 	 */
6490a47c91cSRobert Mustacchi 	if (argc == 2 && strchr(argv[0].a_un.a_str, '{') != NULL) {
6500a47c91cSRobert Mustacchi 		dup = mdb_alloc(strlen(argv[0].a_un.a_str) + 1,
6510a47c91cSRobert Mustacchi 		    UM_GC | UM_SLEEP);
6520a47c91cSRobert Mustacchi 		(void) strcpy(dup, argv[0].a_un.a_str);
6530a47c91cSRobert Mustacchi 		if (typedef_parse(dup, argv[1].a_un.a_str, &pr) == DCMD_ERR)
6540a47c91cSRobert Mustacchi 			return (DCMD_ERR);
6550a47c91cSRobert Mustacchi 		if (typedef_add(pr) == DCMD_ERR)
6560a47c91cSRobert Mustacchi 			return (DCMD_ERR);
6570a47c91cSRobert Mustacchi 
6580a47c91cSRobert Mustacchi 		return (DCMD_OK);
6590a47c91cSRobert Mustacchi 	}
6600a47c91cSRobert Mustacchi 
6610a47c91cSRobert Mustacchi 	/*
6620a47c91cSRobert Mustacchi 	 * Someone could give us something like struct foobar or unsigned int or
6630a47c91cSRobert Mustacchi 	 * even long double imaginary. In this case we end up conjoining all
6640a47c91cSRobert Mustacchi 	 * arguments except the last one into one large string that we look up.
6650a47c91cSRobert Mustacchi 	 */
6660a47c91cSRobert Mustacchi 	if (argc - 1 == 1) {
6670a47c91cSRobert Mustacchi 		src = argv[0].a_un.a_str;
6680a47c91cSRobert Mustacchi 	} else {
6690a47c91cSRobert Mustacchi 		src = typedef_join_strings(argc - 2, argv, UM_GC | UM_SLEEP);
6700a47c91cSRobert Mustacchi 	}
6710a47c91cSRobert Mustacchi 
6720a47c91cSRobert Mustacchi 	dst = argv[argc-1].a_un.a_str;
6730a47c91cSRobert Mustacchi 
6740a47c91cSRobert Mustacchi 	if (mdb_ctf_lookup_by_name(dst, &id) != -1) {
6750a47c91cSRobert Mustacchi 		mdb_printf("%s already exists\n", dst);
6760a47c91cSRobert Mustacchi 		return (DCMD_ERR);
6770a47c91cSRobert Mustacchi 	}
6780a47c91cSRobert Mustacchi 
6790a47c91cSRobert Mustacchi 	if (mdb_ctf_lookup_by_name(src, &id) != 0)  {
6800a47c91cSRobert Mustacchi 		mdb_printf("%s does not exist\n", src);
6810a47c91cSRobert Mustacchi 		return (DCMD_ERR);
6820a47c91cSRobert Mustacchi 	}
6830a47c91cSRobert Mustacchi 
6840a47c91cSRobert Mustacchi 	if (mdb_ctf_add_typedef(dst, &id, NULL) != 0) {
6850a47c91cSRobert Mustacchi 		mdb_printf("failed to create typedef\n");
6860a47c91cSRobert Mustacchi 		return (DCMD_ERR);
6870a47c91cSRobert Mustacchi 	}
6880a47c91cSRobert Mustacchi 
6890a47c91cSRobert Mustacchi 	return (DCMD_OK);
6900a47c91cSRobert Mustacchi }
6910a47c91cSRobert Mustacchi 
6920a47c91cSRobert Mustacchi static char typedef_desc[] =
6930a47c91cSRobert Mustacchi "::typedef operates like the C typedef keyword and creates a synthetic type\n"
6940a47c91cSRobert Mustacchi "that is usable across mdb just like a type that is embedded in CTF data.\n"
6950a47c91cSRobert Mustacchi "This includes familiar dcmds like ::print as well as mdb's tab completion\n"
6960a47c91cSRobert Mustacchi "engine. The \"type\" argument can either be a named structure or union\n"
6970a47c91cSRobert Mustacchi "declaration, like \"struct proc { int p_id; }\" declartion, an anonymous\n"
6980a47c91cSRobert Mustacchi "structure or union declaration, like \"struct { int count; }\", or simply\n"
6990a47c91cSRobert Mustacchi "the name of an existing type, like \"uint64_t\". Either form may refer to\n"
7000a47c91cSRobert Mustacchi "other types already defined in CTF or a previous ::typedef invocation. When\n"
7010a47c91cSRobert Mustacchi "debugging binaries without CTF, definitions for intrinsic types may be\n"
7020a47c91cSRobert Mustacchi "created using the -c option. See the OPTIONS section for more information.\n"
7030a47c91cSRobert Mustacchi "If a named struct or union is used, then a type will be created for it just\n"
7040a47c91cSRobert Mustacchi "like in C. This may be used to mimic a forward declaration and an example of\n"
7050a47c91cSRobert Mustacchi "this is in the EXAMPLES section. Regardless of whether a struct or union is\n"
7060a47c91cSRobert Mustacchi "anonymous or named, the \"name\" argument is always required.\n"
7070a47c91cSRobert Mustacchi "\n"
7080a47c91cSRobert Mustacchi "When declaring anonymous structures and unions, the entire definition must\n"
7090a47c91cSRobert Mustacchi "be enclosed within \"\" or ''. The ';' is used by mdb to separate commands\n"
7100a47c91cSRobert Mustacchi "in a similar fashion to the shell. The ';' cannot be escaped, therefore\n"
7110a47c91cSRobert Mustacchi "quoting your argument is necessary. See the EXAMPLES sections for examples\n"
7120a47c91cSRobert Mustacchi "of what this looks like.\n"
7130a47c91cSRobert Mustacchi "\n"
7140a47c91cSRobert Mustacchi "All member and type names must be valid C identifiers. They must start with\n"
7150a47c91cSRobert Mustacchi "an underscore or a letter. Subsequent characters are allowed to be letters,\n"
716*46f52c84SRobert Mustacchi "numbers, or an underscore. When specifying an array, mdb's default base is\n"
717*46f52c84SRobert Mustacchi "not used. Instead, base 10 is assumed to make it easier to use declarations\n"
718*46f52c84SRobert Mustacchi "from C files and transform them. (Other features remain.)\n"
7190a47c91cSRobert Mustacchi "\n"
7200a47c91cSRobert Mustacchi "Declaring arrays and any number of pointers in anonymous structures is \n"
7210a47c91cSRobert Mustacchi "supported. However the following C features are not supported: \n"
7220a47c91cSRobert Mustacchi "  o function pointers (use a void * instead)\n"
7230a47c91cSRobert Mustacchi "  o bitfields (use an integer of the appropriate size instead)\n"
7240a47c91cSRobert Mustacchi "  o packed structures (all structures currently use their natural alignment)\n"
7250a47c91cSRobert Mustacchi "\n"
7260a47c91cSRobert Mustacchi "::typedef also allows you to read type definitions from a file. Definitions\n"
7272becb8cdSRobert Mustacchi "can be read from any ELF file that has a CTF section that libctf can parse\n"
7282becb8cdSRobert Mustacchi "or any raw CTF data files, such as those that can be created with ::typedef.\n"
7290a47c91cSRobert Mustacchi "You can check if a file has such a section with elfdump(1). If a binary or\n"
7300a47c91cSRobert Mustacchi "core dump does not have any type information, but you do have it elsewhere,\n"
7310a47c91cSRobert Mustacchi "then you can use ::typedef -r to read in that type information.\n"
7322becb8cdSRobert Mustacchi "\n"
7332becb8cdSRobert Mustacchi "All built up definitions may be exported as a valid CTF container that can\n"
7342becb8cdSRobert Mustacchi "be used again with ::typedef -r or anything that uses libctf. To write them\n"
7352becb8cdSRobert Mustacchi "out, use ::typedef -w and specify the name of a file. For more information\n"
736bbf21555SRichard Lowe "on the CTF file format, see ctf(5).\n"
7370a47c91cSRobert Mustacchi "\n";
7380a47c91cSRobert Mustacchi 
7390a47c91cSRobert Mustacchi static char typedef_opts[] =
7400a47c91cSRobert Mustacchi "  -c model   create intrinsic types based on the specified data model.\n"
7410a47c91cSRobert Mustacchi "             The INTRINSICS section lists the built-in types and typedefs.\n"
7420a47c91cSRobert Mustacchi "             The following data models are supported:\n"
7432becb8cdSRobert Mustacchi "                 o LP64  - Traditional illumos 64-bit program.\n"
7440a47c91cSRobert Mustacchi "                 o LP32  - Traditional illumos 32-bit program.\n"
7450a47c91cSRobert Mustacchi "                 o ILP32 - An alternate name for LP32.\n"
7460a47c91cSRobert Mustacchi "  -d         delete all synthetic types\n"
7470a47c91cSRobert Mustacchi "  -l         list all synthetic types\n"
7480a47c91cSRobert Mustacchi "  -r file    import type definitions (CTF) from another ELF file\n"
7492becb8cdSRobert Mustacchi "  -w file    write all synthetic type definitions out to file\n"
7500a47c91cSRobert Mustacchi "\n";
7510a47c91cSRobert Mustacchi 
7520a47c91cSRobert Mustacchi static char typedef_examps[] =
7530a47c91cSRobert Mustacchi "  ::typedef -c LP64\n"
7540a47c91cSRobert Mustacchi "  ::typedef uint64_t bender_t\n"
7550a47c91cSRobert Mustacchi "  ::typedef struct proc new_proc_t\n"
7560a47c91cSRobert Mustacchi "  ::typedef \"union { int frodo; char sam; long gandalf; }\" ringbearer_t;\n"
7570a47c91cSRobert Mustacchi "  ::typedef \"struct { uintptr_t stone[7]; void **white; }\" gift_t\n"
7580a47c91cSRobert Mustacchi "  ::typedef \"struct list { struct list *l_next; struct list *l_prev; }\" "
7590a47c91cSRobert Mustacchi "list_t\n"
7600a47c91cSRobert Mustacchi "  ::typedef -r /var/tmp/qemu-system-x86_64\n"
761*46f52c84SRobert Mustacchi "  ::typedef -w defs.ctf\n"
7620a47c91cSRobert Mustacchi "\n";
7630a47c91cSRobert Mustacchi 
7640a47c91cSRobert Mustacchi static char typedef_intrins[] =
7650a47c91cSRobert Mustacchi "The following C types and <stdint.h> typedefs are provided when \n"
7660a47c91cSRobert Mustacchi "::typedef -c is used\n"
7670a47c91cSRobert Mustacchi "\n"
7680a47c91cSRobert Mustacchi "       signed              unsigned              void\n"
7690a47c91cSRobert Mustacchi "       char                short                 int\n"
7700a47c91cSRobert Mustacchi "       long                long long             signed char\n"
7710a47c91cSRobert Mustacchi "       signed short        signed int            signed long\n"
7720a47c91cSRobert Mustacchi "       singed long long    unsigned char         unsigned short\n"
7730a47c91cSRobert Mustacchi "       unsigned int        unsigned long         unsigned long long\n"
7740a47c91cSRobert Mustacchi "       _Bool               float                 double\n"
7750a47c91cSRobert Mustacchi "       long double         float imaginary       double imaginary\n"
7760a47c91cSRobert Mustacchi "       long double imaginary                     float complex\n"
7770a47c91cSRobert Mustacchi "       double complex                            long double complex\n"
7780a47c91cSRobert Mustacchi "\n"
7790a47c91cSRobert Mustacchi "       int8_t              int16_t               int32_t\n"
7800a47c91cSRobert Mustacchi "       int64_t             intptr_t              uint8_t\n"
7810a47c91cSRobert Mustacchi "       uint16_t            uint32_t              uint64_t\n"
7820a47c91cSRobert Mustacchi "       uchar_t             ushort_t              uint_t\n"
7830a47c91cSRobert Mustacchi "       ulong_t             u_longlong_t          ptrdiff_t\n"
7840a47c91cSRobert Mustacchi "       uintptr_t\n"
7850a47c91cSRobert Mustacchi "\n";
7860a47c91cSRobert Mustacchi 
7870a47c91cSRobert Mustacchi void
cmd_typedef_help(void)7880a47c91cSRobert Mustacchi cmd_typedef_help(void)
7890a47c91cSRobert Mustacchi {
7900a47c91cSRobert Mustacchi 	mdb_printf("%s", typedef_desc);
7910a47c91cSRobert Mustacchi 	(void) mdb_dec_indent(2);
7920a47c91cSRobert Mustacchi 	mdb_printf("%<b>OPTIONS%</b>\n");
7930a47c91cSRobert Mustacchi 	(void) mdb_inc_indent(2);
7940a47c91cSRobert Mustacchi 	mdb_printf("%s", typedef_opts);
7950a47c91cSRobert Mustacchi 	(void) mdb_dec_indent(2);
7960a47c91cSRobert Mustacchi 	mdb_printf("%<b>EXAMPLES%</b>\n");
7970a47c91cSRobert Mustacchi 	(void) mdb_inc_indent(2);
7980a47c91cSRobert Mustacchi 	mdb_printf("%s", typedef_examps);
7990a47c91cSRobert Mustacchi 	(void) mdb_dec_indent(2);
8000a47c91cSRobert Mustacchi 	mdb_printf("%<b>INTRINSICS%</b>\n");
8010a47c91cSRobert Mustacchi 	(void) mdb_inc_indent(2);
8020a47c91cSRobert Mustacchi 	mdb_printf("%s", typedef_intrins);
8030a47c91cSRobert Mustacchi }
804