1/*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source.  A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12/*
13 * Copyright (c) 2015 Joyent, Inc. All rights reserved.
14 */
15
16/*
17 * ::typedef exists to allow a user to create and import auxiliary CTF
18 * information for the currently running target. ::typedef is similar to the C
19 * typedef keyword. However, ::typedef has no illusions of grandeur. It is not a
20 * standards complaint version of C's typedef. For specifics on what it does and
21 * does not support, please see the help message for ::typedef later on in this
22 * file.
23 *
24 * In addition to allowing the user to create types, it has a notion of a
25 * built-in set of types that a compiler might provide. Currently ::typedef
26 * supports both the standard illumos 32-bit and 64-bit environments, mainly
27 * LP32 and LP64. These are not present by default; it is up to the user to
28 * request that they be inserted.
29 *
30 * To facilitate this, ::typedef adds all of its type information to an
31 * auxiliary CTF container that is a part of the global mdb state. This is
32 * abstracted away from ::typedef by the mdb_ctf_* apis. This container is
33 * referred to as the synthetic container, as it holds these synthetic types.
34 * The synthetic container does not have a parent CTF container. This is rather
35 * important to its operation, as a user can end up referencing types that come
36 * from many different such containers (eg. different kernel modules). As such,
37 * whenever a type is referenced that we do not know about, we search all of the
38 * CTF containers that mdb knows about it. If we find it, then that type is
39 * imported (along with all of its dependent types) into the synthetic
40 * container.
41 *
42 * Finally, ::typedef can source CTF information from external files with the -r
43 * option. This will copy in every type from their container into the synthetic
44 * container, because of this the parent and child relationship between
45 * containers with parents cannot be maintained.
46 */
47
48#include <mdb/mdb_modapi.h>
49#include <mdb/mdb_ctf.h>
50#include <mdb/mdb_list.h>
51#include <mdb/mdb_nv.h>
52
53struct parse_node;
54
55#define	PN_F_POINTER	0x01
56#define	PN_F_ARRAY	0x02
57
58typedef struct parse_node {
59	mdb_list_t		pn_list;	/* list entry, must be first */
60	char			*pn_type;	/* name of base type */
61	char			*pn_name;	/* name of the member */
62	int			pn_flags;	/* flags */
63	int			pn_nptrs;	/* number of pointers */
64	int			pn_asub;	/* value of array subscript */
65} parse_node_t;
66
67typedef struct parse_root {
68	mdb_list_t	pr_nodes;	/* list of members */
69	int		pr_kind;	/* CTF_K_* */
70	const char	*pr_name;	/* entity name */
71	const char	*pr_tname;	/* entity typedef */
72} parse_root_t;
73
74static int
75typedef_valid_identifier(const char *str)
76{
77	/*
78	 * We can't use the standard ctype.h functions because those aren't
79	 * necessairly available in kmdb. On the flip side, we only care about
80	 * ascii characters here so that isn't too bad.
81	 *
82	 * C Identifiers have to start with a letter or a _. Afterwards they can
83	 * be alphanumeric or an _.
84	 */
85
86	if (*str == '\0')
87		return (1);
88
89	if (*str != '_' &&
90	    (*str < 'A' || *str > 'Z') &&
91	    (*str < 'a' || *str > 'z'))
92		return (1);
93	str++;
94
95	while (*str != '\0') {
96		if (*str != '_' &&
97		    (*str < '0' || *str > '9') &&
98		    (*str < 'A' || *str > 'Z') &&
99		    (*str < 'a' || *str > 'z'))
100			return (1);
101		str++;
102	}
103
104	return (0);
105}
106
107/*ARGSUSED*/
108static int
109typedef_list_cb(mdb_ctf_id_t id, void *arg)
110{
111	char buf[MDB_SYM_NAMLEN];
112
113	/*
114	 * The user may have created an anonymous structure or union as part of
115	 * running ::typedef. If this is the case, we passed a NULL pointer for
116	 * the name into the ctf routines. When we go back and ask for the name
117	 * of that, ctf goes through and loops through all the declarations.
118	 * This, however correctly, gives us back something undesirable to the
119	 * user, eg. the name is simply 'struct' and 'union'. Because a typedef
120	 * will always have a non-anonymous name for that, we instead opt to
121	 * not include these anonymous names. ctf usefully includes a space as
122	 * part of that name.
123	 */
124	(void) mdb_ctf_type_name(id, buf, sizeof (buf));
125	if (strcmp("struct ", buf) != 0 && strcmp("union ", buf) != 0)
126		mdb_printf("%s\n", buf);
127	return (0);
128}
129
130static char *
131typedef_join_strings(int nstr, const mdb_arg_t *args, int flags)
132{
133	int i, size = 0;
134	char *ret, *sptr;
135
136	for (i = 0; i <= nstr; i++) {
137		/* Always account for the space or the null terminator */
138		size += strlen(args[i].a_un.a_str) + 1;
139	}
140	ret = mdb_alloc(sizeof (char) * size, flags);
141	if (ret == NULL)
142		return (NULL);
143	sptr = ret;
144	for (i = 0; i <= nstr; i++) {
145		(void) strcpy(sptr, args[i].a_un.a_str);
146		sptr += strlen(args[i].a_un.a_str);
147		*sptr = ' ';
148		sptr++;
149	}
150	*sptr = '\0';
151
152	return (ret);
153}
154
155static int
156typedef_list(void)
157{
158	(void) mdb_ctf_type_iter(MDB_CTF_SYNTHETIC_ITER, typedef_list_cb,
159	    NULL);
160	return (DCMD_OK);
161}
162
163static int
164typedef_destroy(void)
165{
166	if (mdb_ctf_synthetics_reset() != 0) {
167		mdb_warn("failed to reset synthetic types");
168		return (DCMD_ERR);
169	}
170	return (DCMD_OK);
171}
172
173/*
174 * We've been asked to create the basic types that exist. We accept the
175 * following strings to indicate what we should create.
176 * - LP32, ILP32 (case insensitive)
177 * - LP64
178 */
179static int
180typedef_create(const char *arg)
181{
182	int kind;
183
184	if (strcasecmp(arg, "LP32") == 0 || strcasecmp(arg, "ILP32") == 0) {
185		kind = SYNTHETIC_ILP32;
186	} else if (strcasecmp(arg, "LP64") == 0) {
187		kind = SYNTHETIC_LP64;
188	} else {
189		mdb_printf("invalid data model: %s\n", arg);
190		return (DCMD_USAGE);
191	}
192
193	if (mdb_ctf_synthetics_create_base(kind) != 0) {
194		mdb_printf("failed to create intrinsic types, maybe "
195		    "they already exist\n");
196		return (DCMD_ERR);
197	}
198
199	return (DCMD_OK);
200}
201
202/*
203 * Search the current arguments for a complete member declaration. This function
204 * modifies the value of defn based on what's necessary for parsing. It returns
205 * the appropriate parse node in pnp.
206 */
207static int
208typedef_parse_member(char *defn, char **next, parse_node_t **pnp)
209{
210	char *c, *name, *array;
211	int nptrs = 0;
212	parse_node_t *pn;
213
214	c = strchr(defn, ';');
215	if (c == NULL) {
216		mdb_printf("Cannot find semi-colon to delineate the end "
217		    "of a member.\n");
218		return (DCMD_ERR);
219	}
220	*c = '\0';
221	*next = c + 1;
222
223	c = strrchr(defn, ' ');
224	if (c == NULL) {
225		mdb_printf("Missing both a name and a type declaration for "
226		    "a member. Instead, found '%s'\n", defn);
227		return (DCMD_ERR);
228	}
229	*c = '\0';
230	name = c + 1;
231	c--;
232	while (*c == '*' || *c == ' ') {
233		if (*c == '*')
234			nptrs++;
235		c--;
236	}
237	*(c + 1) = '\0';
238
239	pn = mdb_zalloc(sizeof (parse_node_t), UM_SLEEP | UM_GC);
240	pn->pn_type = defn;
241
242	/*
243	 * Go through and prepare the name field. Note that we still have to
244	 * check if this is a pointer or an array. We also need to strip the
245	 * ending semi-colon.
246	 */
247	while (*name == '*') {
248		name++;
249		nptrs++;
250	}
251
252	if ((c = strchr(name, '[')) != NULL) {
253		array = c;
254		if ((c = strchr(array, ']')) == NULL) {
255			mdb_printf("Found the beginning of an array size "
256			    "but no closing ']' in %s\n", array);
257			return (DCMD_ERR);
258		}
259		*array = '\0';
260		array++;
261		*c = '\0';
262		pn->pn_flags |= PN_F_ARRAY;
263		pn->pn_asub = mdb_strtoull(array);
264		if (pn->pn_asub < 0) {
265			mdb_printf("Array lengths cannot be negative\n");
266			return (DCMD_ERR);
267		}
268	}
269
270	if (typedef_valid_identifier(name) != 0) {
271		mdb_printf("The name %s is not a valid C identifier.\n",
272		    name);
273		return (DCMD_ERR);
274	}
275
276	if (nptrs) {
277		pn->pn_flags |= PN_F_POINTER;
278		pn->pn_nptrs = nptrs;
279	}
280	pn->pn_name = name;
281
282	*pnp = pn;
283	return (DCMD_OK);
284}
285
286/*
287 * We're going to parse out our types here. Note that we are not strictly
288 * speaking a truely ANSI C compliant parser. Currently we support normal
289 * declarations except for the following:
290 *   o function pointers
291 *   o bit-fields
292 */
293static int
294typedef_parse(char *defn, const char *name, parse_root_t **prp)
295{
296	int len, ret;
297	const char *kind, *basename;
298	char *c, *brace;
299	parse_root_t *pr;
300	parse_node_t *pn;
301	mdb_ctf_id_t id;
302
303	pr = mdb_zalloc(sizeof (parse_root_t), UM_SLEEP | UM_GC);
304	basename = defn;
305
306	c = strchr(defn, ' ');
307	if (c == NULL) {
308		mdb_printf("Invalid structure definition. Structure "
309		    "must start with either 'struct {' or 'union {'\n");
310		return (DCMD_ERR);
311	}
312	*c = '\0';
313
314	if (strcmp(defn, "struct") == 0)
315		pr->pr_kind = CTF_K_STRUCT;
316	else if (strcmp(defn, "union") == 0)
317		pr->pr_kind = CTF_K_UNION;
318	else {
319		mdb_printf("Invalid start of definition. "
320		    "Expected 'struct' or 'union'. "
321		    "Found: '%s'\n", defn);
322		return (DCMD_ERR);
323	}
324
325	/*
326	 * We transform this back to a space so we can validate that a
327	 * non-anonymous struct or union name is valid.
328	 */
329	*c = ' ';
330
331	kind = defn;
332	defn = c + 1;
333	while (*defn == ' ')
334		defn++;
335
336	/* Check whether this is anonymous or not */
337	if (*defn != '{') {
338		brace = strchr(defn, '{');
339		c = brace;
340		if (c == NULL) {
341			mdb_printf("Missing opening brace for %s definition. "
342			    "Expected '{'. "
343			    "Found: '%c'\n", kind, *defn);
344			return (DCMD_ERR);
345		}
346		*c = '\0';
347		c--;
348		while (*c == ' ')
349			c--;
350		*(c+1) = '\0';
351		if (typedef_valid_identifier(defn) != 0) {
352			mdb_printf("The name %s is not a valid C identifier.\n",
353			    defn);
354			return (DCMD_ERR);
355		}
356
357		if (mdb_ctf_lookup_by_name(basename, &id) != CTF_ERR) {
358			mdb_printf("type name %s already in use\n", basename);
359			return (DCMD_ERR);
360		}
361
362		pr->pr_name = defn;
363		defn = brace;
364	} else {
365		pr->pr_name = NULL;
366	}
367
368	defn++;
369	while (*defn == ' ')
370		defn++;
371
372	len = strlen(defn);
373	if (defn[len-1] != '}') {
374		mdb_printf("Missing closing brace for %s declaration. "
375		    "Expected '}'.\n");
376		return (DCMD_ERR);
377	}
378	defn[len-1] = '\0';
379
380	/*
381	 * Start walking all the arguments, looking for a terminating semicolon
382	 * for type definitions.
383	 */
384	for (;;) {
385		ret = typedef_parse_member(defn, &c, &pn);
386		if (ret == DCMD_ERR)
387			return (DCMD_ERR);
388
389		mdb_list_append(&pr->pr_nodes, pn);
390
391		while (*c == ' ')
392			c++;
393
394		if (*c == '\0')
395			break;
396
397		defn = c;
398	}
399
400	pr->pr_tname = name;
401	*prp = pr;
402
403	return (DCMD_OK);
404}
405
406/*
407 * Make sure that none of the member names overlap and that the type names don't
408 * already exist. If we have an array entry that is a VLA, make sure it is the
409 * last member and not the only member.
410 */
411static int
412typedef_validate(parse_root_t *pr)
413{
414	mdb_nv_t nv;
415	parse_node_t *pn;
416	mdb_ctf_id_t id;
417	int count = 0;
418
419	(void) mdb_nv_create(&nv, UM_SLEEP | UM_GC);
420	for (pn = mdb_list_next(&pr->pr_nodes); pn != NULL;
421	    pn = mdb_list_next(pn)) {
422		count++;
423		if (mdb_nv_lookup(&nv, pn->pn_name) != NULL) {
424			mdb_printf("duplicate name detected: %s\n",
425			    pn->pn_name);
426			return (DCMD_ERR);
427		}
428
429		/*
430		 * Our parse tree won't go away before the nv, so it's simpler
431		 * to just mark everything external.
432		 */
433		(void) mdb_nv_insert(&nv, pn->pn_name, NULL, 0, MDB_NV_EXTNAME);
434
435		if (pn->pn_flags & PN_F_ARRAY && pn->pn_asub == 0) {
436			if (pr->pr_kind != CTF_K_STRUCT) {
437				mdb_printf("Flexible array members are only "
438				    "valid in structs.\n");
439				return (DCMD_ERR);
440			}
441
442			if (&pn->pn_list != pr->pr_nodes.ml_prev) {
443				mdb_printf("Flexible array entries are only "
444				    "allowed to be the last entry in a "
445				    "struct\n");
446				return (DCMD_ERR);
447			}
448
449			if (count == 1) {
450				mdb_printf("Structs must have members aside "
451				    "from a flexible member\n");
452				return (DCMD_ERR);
453			}
454		}
455	}
456
457	if (mdb_ctf_lookup_by_name(pr->pr_tname, &id) != CTF_ERR) {
458		mdb_printf("typedef name %s already exists\n", pr->pr_tname);
459		return (DCMD_ERR);
460	}
461
462	return (DCMD_OK);
463}
464
465static int
466typedef_add(parse_root_t *pr)
467{
468	parse_node_t *pn;
469	mdb_ctf_id_t id, aid, tid, pid;
470	mdb_ctf_arinfo_t ar;
471	int ii;
472
473	/* Pre-flight checks */
474	if (typedef_validate(pr) == DCMD_ERR)
475		return (DCMD_ERR);
476
477	if (pr->pr_kind == CTF_K_STRUCT) {
478		if (mdb_ctf_add_struct(pr->pr_name, &id) != 0) {
479			mdb_printf("failed to create struct for %s\n",
480			    pr->pr_tname);
481			return (DCMD_ERR);
482		}
483	} else {
484		if (mdb_ctf_add_union(pr->pr_name, &id) != 0) {
485			mdb_printf("failed to create union for %s\n",
486			    pr->pr_tname);
487			return (DCMD_ERR);
488		}
489	}
490
491	for (pn = mdb_list_next(&pr->pr_nodes); pn != NULL;
492	    pn = mdb_list_next(pn)) {
493
494		if (mdb_ctf_lookup_by_name(pn->pn_type, &tid) == CTF_ERR) {
495			mdb_printf("failed to add member %s: type %s does "
496			    "not exist\n", pn->pn_name, pn->pn_type);
497			goto destroy;
498		}
499
500		if (pn->pn_flags & PN_F_POINTER) {
501			for (ii = 0; ii < pn->pn_nptrs; ii++) {
502				if (mdb_ctf_add_pointer(&tid,
503				    &pid) != 0) {
504					mdb_printf("failed to add a pointer "
505					    "type as part of member: %s\n",
506					    pn->pn_name);
507					goto destroy;
508				}
509				tid = pid;
510			}
511		}
512
513		if (pn->pn_flags & PN_F_ARRAY) {
514			if (mdb_ctf_lookup_by_name("long", &aid) != 0) {
515				mdb_printf("failed to lookup the type 'long' "
516				    "for array indexes, are you running mdb "
517				    "without a target or using ::typedef -c?");
518				goto destroy;
519			}
520
521			ar.mta_contents = tid;
522			ar.mta_index = aid;
523			ar.mta_nelems = pn->pn_asub;
524
525			if (mdb_ctf_add_array(&ar, &tid) != 0) {
526				mdb_printf("failed to create array type for "
527				    "memeber%s\n", pn->pn_name);
528				goto destroy;
529			}
530		}
531
532		if (mdb_ctf_add_member(&id, pn->pn_name, &tid, NULL) ==
533		    CTF_ERR) {
534			mdb_printf("failed to create member %s\n",
535			    pn->pn_name);
536			goto destroy;
537		}
538	}
539
540	if (mdb_ctf_add_typedef(pr->pr_tname, &id, NULL) != 0) {
541		mdb_printf("failed to add typedef for %s\n",
542		    pr->pr_tname);
543		goto destroy;
544	}
545
546	return (DCMD_OK);
547
548destroy:
549	return (mdb_ctf_type_delete(&id));
550}
551
552static int
553typedef_readfile(const char *file)
554{
555	int ret;
556
557	ret = mdb_ctf_synthetics_from_file(file);
558	if (ret != DCMD_OK)
559		mdb_warn("failed to create synthetics from file %s\n", file);
560	return (ret);
561}
562
563static int
564typedef_writefile(const char *file)
565{
566	int ret;
567
568	ret = mdb_ctf_synthetics_to_file(file);
569	if (ret != DCMD_OK)
570		mdb_warn("failed to write synthetics to file %s", file);
571	return (ret);
572}
573
574/* ARGSUSED */
575int
576cmd_typedef(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
577{
578	mdb_ctf_id_t id;
579	int i;
580	int destroy = 0, list = 0;
581	const char *cmode = NULL, *rfile = NULL, *wfile = NULL;
582	const char *dst, *src;
583	char *dup;
584	parse_root_t *pr;
585
586	if (flags & DCMD_ADDRSPEC)
587		return (DCMD_USAGE);
588
589	i = mdb_getopts(argc, argv,
590	    'd', MDB_OPT_SETBITS, TRUE, &destroy,
591	    'l', MDB_OPT_SETBITS, TRUE, &list,
592	    'c', MDB_OPT_STR, &cmode,
593	    'r', MDB_OPT_STR, &rfile,
594	    'w', MDB_OPT_STR, &wfile, NULL);
595
596	argc -= i;
597	argv += i;
598
599	/*
600	 * All our options are mutually exclusive currently.
601	 */
602	i = 0;
603	if (destroy)
604		i++;
605	if (cmode != NULL)
606		i++;
607	if (list)
608		i++;
609	if (rfile != NULL)
610		i++;
611	if (wfile != NULL)
612		i++;
613	if (i > 1)
614		return (DCMD_USAGE);
615
616	if ((destroy || cmode != NULL || list || rfile != NULL ||
617	    wfile != NULL) && argc != 0)
618		return (DCMD_USAGE);
619
620	if (destroy)
621		return (typedef_destroy());
622
623	if (cmode)
624		return (typedef_create(cmode));
625
626	if (list)
627		return (typedef_list());
628
629	if (rfile)
630		return (typedef_readfile(rfile));
631
632	if (wfile)
633		return (typedef_writefile(wfile));
634
635	if (argc < 2)
636		return (DCMD_USAGE);
637
638	/*
639	 * Check to see if we are defining a struct or union. Note that we have
640	 * to distinguish between struct foo and struct {. All typedef structs
641	 * are annonymous structs that are only known by their typedef name. The
642	 * same is true with unions. The problem that we have to deal with is
643	 * that the ';' character in mdb causes mdb to begin another command. To
644	 * work around that fact we require users to put the whole struct
645	 * definition in a pair of "" or ''.
646	 */
647	if (argc == 2 && strchr(argv[0].a_un.a_str, '{') != NULL) {
648		dup = mdb_alloc(strlen(argv[0].a_un.a_str) + 1,
649		    UM_GC | UM_SLEEP);
650		(void) strcpy(dup, argv[0].a_un.a_str);
651		if (typedef_parse(dup, argv[1].a_un.a_str, &pr) == DCMD_ERR)
652			return (DCMD_ERR);
653		if (typedef_add(pr) == DCMD_ERR)
654			return (DCMD_ERR);
655
656		return (DCMD_OK);
657	}
658
659	/*
660	 * Someone could give us something like struct foobar or unsigned int or
661	 * even long double imaginary. In this case we end up conjoining all
662	 * arguments except the last one into one large string that we look up.
663	 */
664	if (argc - 1 == 1) {
665		src = argv[0].a_un.a_str;
666	} else {
667		src = typedef_join_strings(argc - 2, argv, UM_GC | UM_SLEEP);
668	}
669
670	dst = argv[argc-1].a_un.a_str;
671
672	if (mdb_ctf_lookup_by_name(dst, &id) != -1) {
673		mdb_printf("%s already exists\n", dst);
674		return (DCMD_ERR);
675	}
676
677	if (mdb_ctf_lookup_by_name(src, &id) != 0)  {
678		mdb_printf("%s does not exist\n", src);
679		return (DCMD_ERR);
680	}
681
682	if (mdb_ctf_add_typedef(dst, &id, NULL) != 0) {
683		mdb_printf("failed to create typedef\n");
684		return (DCMD_ERR);
685	}
686
687	return (DCMD_OK);
688}
689
690static char typedef_desc[] =
691"::typedef operates like the C typedef keyword and creates a synthetic type\n"
692"that is usable across mdb just like a type that is embedded in CTF data.\n"
693"This includes familiar dcmds like ::print as well as mdb's tab completion\n"
694"engine. The \"type\" argument can either be a named structure or union\n"
695"declaration, like \"struct proc { int p_id; }\" declartion, an anonymous\n"
696"structure or union declaration, like \"struct { int count; }\", or simply\n"
697"the name of an existing type, like \"uint64_t\". Either form may refer to\n"
698"other types already defined in CTF or a previous ::typedef invocation. When\n"
699"debugging binaries without CTF, definitions for intrinsic types may be\n"
700"created using the -c option. See the OPTIONS section for more information.\n"
701"If a named struct or union is used, then a type will be created for it just\n"
702"like in C. This may be used to mimic a forward declaration and an example of\n"
703"this is in the EXAMPLES section. Regardless of whether a struct or union is\n"
704"anonymous or named, the \"name\" argument is always required.\n"
705"\n"
706"When declaring anonymous structures and unions, the entire definition must\n"
707"be enclosed within \"\" or ''. The ';' is used by mdb to separate commands\n"
708"in a similar fashion to the shell. The ';' cannot be escaped, therefore\n"
709"quoting your argument is necessary. See the EXAMPLES sections for examples\n"
710"of what this looks like.\n"
711"\n"
712"All member and type names must be valid C identifiers. They must start with\n"
713"an underscore or a letter. Subsequent characters are allowed to be letters,\n"
714"numbers, or an underscore.\n"
715"\n"
716"Declaring arrays and any number of pointers in anonymous structures is \n"
717"supported. However the following C features are not supported: \n"
718"  o function pointers (use a void * instead)\n"
719"  o bitfields (use an integer of the appropriate size instead)\n"
720"  o packed structures (all structures currently use their natural alignment)\n"
721"\n"
722"::typedef also allows you to read type definitions from a file. Definitions\n"
723"can be read from any ELF file that has a CTF section that libctf can parse\n"
724"or any raw CTF data files, such as those that can be created with ::typedef.\n"
725"You can check if a file has such a section with elfdump(1). If a binary or\n"
726"core dump does not have any type information, but you do have it elsewhere,\n"
727"then you can use ::typedef -r to read in that type information.\n"
728"\n"
729"All built up definitions may be exported as a valid CTF container that can\n"
730"be used again with ::typedef -r or anything that uses libctf. To write them\n"
731"out, use ::typedef -w and specify the name of a file. For more information\n"
732"on the CTF file format, see ctf(4).\n"
733"\n";
734
735static char typedef_opts[] =
736"  -c model   create intrinsic types based on the specified data model.\n"
737"             The INTRINSICS section lists the built-in types and typedefs.\n"
738"             The following data models are supported:\n"
739"                 o LP64  - Traditional illumos 64-bit program.\n"
740"                 o LP32  - Traditional illumos 32-bit program.\n"
741"                 o ILP32 - An alternate name for LP32.\n"
742"  -d         delete all synthetic types\n"
743"  -l         list all synthetic types\n"
744"  -r file    import type definitions (CTF) from another ELF file\n"
745"  -w file    write all synthetic type definitions out to file\n"
746"\n";
747
748static char typedef_examps[] =
749"  ::typedef -c LP64\n"
750"  ::typedef uint64_t bender_t\n"
751"  ::typedef struct proc new_proc_t\n"
752"  ::typedef \"union { int frodo; char sam; long gandalf; }\" ringbearer_t;\n"
753"  ::typedef \"struct { uintptr_t stone[7]; void **white; }\" gift_t\n"
754"  ::typedef \"struct list { struct list *l_next; struct list *l_prev; }\" "
755"list_t\n"
756"  ::typedef -r /var/tmp/qemu-system-x86_64\n"
757"  ::typedef -w defs.ctf"
758"\n";
759
760static char typedef_intrins[] =
761"The following C types and <stdint.h> typedefs are provided when \n"
762"::typedef -c is used\n"
763"\n"
764"       signed              unsigned              void\n"
765"       char                short                 int\n"
766"       long                long long             signed char\n"
767"       signed short        signed int            signed long\n"
768"       singed long long    unsigned char         unsigned short\n"
769"       unsigned int        unsigned long         unsigned long long\n"
770"       _Bool               float                 double\n"
771"       long double         float imaginary       double imaginary\n"
772"       long double imaginary                     float complex\n"
773"       double complex                            long double complex\n"
774"\n"
775"       int8_t              int16_t               int32_t\n"
776"       int64_t             intptr_t              uint8_t\n"
777"       uint16_t            uint32_t              uint64_t\n"
778"       uchar_t             ushort_t              uint_t\n"
779"       ulong_t             u_longlong_t          ptrdiff_t\n"
780"       uintptr_t\n"
781"\n";
782
783void
784cmd_typedef_help(void)
785{
786	mdb_printf("%s", typedef_desc);
787	(void) mdb_dec_indent(2);
788	mdb_printf("%<b>OPTIONS%</b>\n");
789	(void) mdb_inc_indent(2);
790	mdb_printf("%s", typedef_opts);
791	(void) mdb_dec_indent(2);
792	mdb_printf("%<b>EXAMPLES%</b>\n");
793	(void) mdb_inc_indent(2);
794	mdb_printf("%s", typedef_examps);
795	(void) mdb_dec_indent(2);
796	mdb_printf("%<b>INTRINSICS%</b>\n");
797	(void) mdb_inc_indent(2);
798	mdb_printf("%s", typedef_intrins);
799}
800