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) 2013 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
typedef_valid_identifier(const char * str)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
typedef_list_cb(mdb_ctf_id_t id,void * arg)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 *
typedef_join_strings(int nstr,const mdb_arg_t * args,int flags)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
typedef_list(void)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
typedef_destroy(void)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
typedef_create(const char * arg)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
typedef_parse_member(char * defn,char ** next,parse_node_t ** pnp)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
typedef_parse(char * defn,const char * name,parse_root_t ** prp)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
typedef_validate(parse_root_t * pr)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
typedef_add(parse_root_t * pr)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
typedef_readfile(const char * file)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\n");
560 return (ret);
561 }
562
563 /* ARGSUSED */
564 int
cmd_typedef(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)565 cmd_typedef(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
566 {
567 mdb_ctf_id_t id;
568 int i;
569 int destroy = 0, list = 0;
570 const char *cmode = NULL, *rfile = NULL;
571 const char *dst, *src;
572 char *dup;
573 parse_root_t *pr;
574
575 if (flags & DCMD_ADDRSPEC)
576 return (DCMD_USAGE);
577
578 i = mdb_getopts(argc, argv,
579 'd', MDB_OPT_SETBITS, TRUE, &destroy,
580 'l', MDB_OPT_SETBITS, TRUE, &list,
581 'c', MDB_OPT_STR, &cmode,
582 'r', MDB_OPT_STR, &rfile, NULL);
583
584 argc -= i;
585 argv += i;
586
587 /*
588 * All our options are mutually exclusive currently.
589 */
590 i = 0;
591 if (destroy)
592 i++;
593 if (cmode != NULL)
594 i++;
595 if (list)
596 i++;
597 if (rfile != NULL)
598 i++;
599 if (i > 1)
600 return (DCMD_USAGE);
601
602 if ((destroy || cmode != NULL || list || rfile != NULL) && argc != 0)
603 return (DCMD_USAGE);
604
605 if (destroy)
606 return (typedef_destroy());
607
608 if (cmode)
609 return (typedef_create(cmode));
610
611 if (list)
612 return (typedef_list());
613
614 if (rfile)
615 return (typedef_readfile(rfile));
616
617 if (argc < 2)
618 return (DCMD_USAGE);
619
620 /*
621 * Check to see if we are defining a struct or union. Note that we have
622 * to distinguish between struct foo and struct {. All typedef structs
623 * are annonymous structs that are only known by their typedef name. The
624 * same is true with unions. The problem that we have to deal with is
625 * that the ';' character in mdb causes mdb to begin another command. To
626 * work around that fact we require users to put the whole struct
627 * definition in a pair of "" or ''.
628 */
629 if (argc == 2 && strchr(argv[0].a_un.a_str, '{') != NULL) {
630 dup = mdb_alloc(strlen(argv[0].a_un.a_str) + 1,
631 UM_GC | UM_SLEEP);
632 (void) strcpy(dup, argv[0].a_un.a_str);
633 if (typedef_parse(dup, argv[1].a_un.a_str, &pr) == DCMD_ERR)
634 return (DCMD_ERR);
635 if (typedef_add(pr) == DCMD_ERR)
636 return (DCMD_ERR);
637
638 return (DCMD_OK);
639 }
640
641 /*
642 * Someone could give us something like struct foobar or unsigned int or
643 * even long double imaginary. In this case we end up conjoining all
644 * arguments except the last one into one large string that we look up.
645 */
646 if (argc - 1 == 1) {
647 src = argv[0].a_un.a_str;
648 } else {
649 src = typedef_join_strings(argc - 2, argv, UM_GC | UM_SLEEP);
650 }
651
652 dst = argv[argc-1].a_un.a_str;
653
654 if (mdb_ctf_lookup_by_name(dst, &id) != -1) {
655 mdb_printf("%s already exists\n", dst);
656 return (DCMD_ERR);
657 }
658
659 if (mdb_ctf_lookup_by_name(src, &id) != 0) {
660 mdb_printf("%s does not exist\n", src);
661 return (DCMD_ERR);
662 }
663
664 if (mdb_ctf_add_typedef(dst, &id, NULL) != 0) {
665 mdb_printf("failed to create typedef\n");
666 return (DCMD_ERR);
667 }
668
669 return (DCMD_OK);
670 }
671
672 static char typedef_desc[] =
673 "::typedef operates like the C typedef keyword and creates a synthetic type\n"
674 "that is usable across mdb just like a type that is embedded in CTF data.\n"
675 "This includes familiar dcmds like ::print as well as mdb's tab completion\n"
676 "engine. The \"type\" argument can either be a named structure or union\n"
677 "declaration, like \"struct proc { int p_id; }\" declartion, an anonymous\n"
678 "structure or union declaration, like \"struct { int count; }\", or simply\n"
679 "the name of an existing type, like \"uint64_t\". Either form may refer to\n"
680 "other types already defined in CTF or a previous ::typedef invocation. When\n"
681 "debugging binaries without CTF, definitions for intrinsic types may be\n"
682 "created using the -c option. See the OPTIONS section for more information.\n"
683 "If a named struct or union is used, then a type will be created for it just\n"
684 "like in C. This may be used to mimic a forward declaration and an example of\n"
685 "this is in the EXAMPLES section. Regardless of whether a struct or union is\n"
686 "anonymous or named, the \"name\" argument is always required.\n"
687 "\n"
688 "When declaring anonymous structures and unions, the entire definition must\n"
689 "be enclosed within \"\" or ''. The ';' is used by mdb to separate commands\n"
690 "in a similar fashion to the shell. The ';' cannot be escaped, therefore\n"
691 "quoting your argument is necessary. See the EXAMPLES sections for examples\n"
692 "of what this looks like.\n"
693 "\n"
694 "All member and type names must be valid C identifiers. They must start with\n"
695 "an underscore or a letter. Subsequent characters are allowed to be letters,\n"
696 "numbers, or an underscore.\n"
697 "\n"
698 "Declaring arrays and any number of pointers in anonymous structures is \n"
699 "supported. However the following C features are not supported: \n"
700 " o function pointers (use a void * instead)\n"
701 " o bitfields (use an integer of the appropriate size instead)\n"
702 " o packed structures (all structures currently use their natural alignment)\n"
703 "\n"
704 "::typedef also allows you to read type definitions from a file. Definitions\n"
705 "can be read from any ELF file that has a CTF section that libctf can parse.\n"
706 "You can check if a file has such a section with elfdump(1). If a binary or\n"
707 "core dump does not have any type information, but you do have it elsewhere,\n"
708 "then you can use ::typedef -r to read in that type information.\n"
709 "\n";
710
711 static char typedef_opts[] =
712 " -c model create intrinsic types based on the specified data model.\n"
713 " The INTRINSICS section lists the built-in types and typedefs.\n"
714 " The following data models are supported:\n"
715 " o LP64 - Traditional illumos 64-bit program\n"
716 " o LP32 - Traditional illumos 32-bit program.\n"
717 " o ILP32 - An alternate name for LP32.\n"
718 " -d delete all synthetic types\n"
719 " -l list all synthetic types\n"
720 " -r file import type definitions (CTF) from another ELF file\n"
721 "\n";
722
723 static char typedef_examps[] =
724 " ::typedef -c LP64\n"
725 " ::typedef uint64_t bender_t\n"
726 " ::typedef struct proc new_proc_t\n"
727 " ::typedef \"union { int frodo; char sam; long gandalf; }\" ringbearer_t;\n"
728 " ::typedef \"struct { uintptr_t stone[7]; void **white; }\" gift_t\n"
729 " ::typedef \"struct list { struct list *l_next; struct list *l_prev; }\" "
730 "list_t\n"
731 " ::typedef -r /var/tmp/qemu-system-x86_64\n"
732 "\n";
733
734 static char typedef_intrins[] =
735 "The following C types and <stdint.h> typedefs are provided when \n"
736 "::typedef -c is used\n"
737 "\n"
738 " signed unsigned void\n"
739 " char short int\n"
740 " long long long signed char\n"
741 " signed short signed int signed long\n"
742 " singed long long unsigned char unsigned short\n"
743 " unsigned int unsigned long unsigned long long\n"
744 " _Bool float double\n"
745 " long double float imaginary double imaginary\n"
746 " long double imaginary float complex\n"
747 " double complex long double complex\n"
748 "\n"
749 " int8_t int16_t int32_t\n"
750 " int64_t intptr_t uint8_t\n"
751 " uint16_t uint32_t uint64_t\n"
752 " uchar_t ushort_t uint_t\n"
753 " ulong_t u_longlong_t ptrdiff_t\n"
754 " uintptr_t\n"
755 "\n";
756
757 void
cmd_typedef_help(void)758 cmd_typedef_help(void)
759 {
760 mdb_printf("%s", typedef_desc);
761 (void) mdb_dec_indent(2);
762 mdb_printf("%<b>OPTIONS%</b>\n");
763 (void) mdb_inc_indent(2);
764 mdb_printf("%s", typedef_opts);
765 (void) mdb_dec_indent(2);
766 mdb_printf("%<b>EXAMPLES%</b>\n");
767 (void) mdb_inc_indent(2);
768 mdb_printf("%s", typedef_examps);
769 (void) mdb_dec_indent(2);
770 mdb_printf("%<b>INTRINSICS%</b>\n");
771 (void) mdb_inc_indent(2);
772 mdb_printf("%s", typedef_intrins);
773 }
774