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