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