xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_typedef.c (revision 2becb8cdf9cd77e1a76224f216be15d6ae3b9ec9)
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 
53 struct parse_node;
54 
55 #define	PN_F_POINTER	0x01
56 #define	PN_F_ARRAY	0x02
57 
58 typedef 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 
67 typedef 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 
74 static int
75 typedef_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*/
108 static int
109 typedef_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 
130 static char *
131 typedef_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 
155 static int
156 typedef_list(void)
157 {
158 	(void) mdb_ctf_type_iter(MDB_CTF_SYNTHETIC_ITER, typedef_list_cb,
159 	    NULL);
160 	return (DCMD_OK);
161 }
162 
163 static int
164 typedef_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  */
179 static int
180 typedef_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  */
207 static int
208 typedef_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  */
293 static int
294 typedef_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  */
411 static int
412 typedef_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 
465 static int
466 typedef_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 
548 destroy:
549 	return (mdb_ctf_type_delete(&id));
550 }
551 
552 static int
553 typedef_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 
563 static int
564 typedef_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 */
575 int
576 cmd_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 
690 static 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 
735 static 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 
748 static 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 
760 static 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 
783 void
784 cmd_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