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) 2018, Joyent, Inc.
14 */
15
16 /*
17 * Dump information about CTF containers.
18 */
19
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <libctf.h>
23 #include <libgen.h>
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <stddef.h>
27 #include <sys/sysmacros.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/note.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <err.h>
36
37 #define MAX_NAMELEN (512)
38
39 typedef enum ctfdump_arg {
40 CTFDUMP_OBJECTS = 0x001,
41 CTFDUMP_FUNCTIONS = 0x002,
42 CTFDUMP_HEADER = 0x004,
43 CTFDUMP_LABELS = 0x008,
44 CTFDUMP_STRINGS = 0x010,
45 CTFDUMP_STATS = 0x020,
46 CTFDUMP_TYPES = 0x040,
47 CTFDUMP_DEFAULT = 0x07f,
48 CTFDUMP_OUTPUT = 0x080,
49 CTFDUMP_SOURCE = 0x100,
50 } ctfdump_arg_t;
51
52 typedef struct ctfdump_stat {
53 ulong_t cs_ndata; /* number of data objects */
54 ulong_t cs_nfuncs; /* number of functions */
55 ulong_t cs_nfuncargs; /* number of function args */
56 ulong_t cs_nfuncmax; /* largest number of args */
57 ulong_t cs_ntypes[CTF_K_MAX]; /* number of types */
58 ulong_t cs_nsmembs; /* number of struct members */
59 ulong_t cs_nsmax; /* largest number of members */
60 ulong_t cs_structsz; /* sum of structures sizes */
61 ulong_t cs_sszmax; /* largest structure */
62 ulong_t cs_numembs; /* number of union members */
63 ulong_t cs_numax; /* largest number of members */
64 ulong_t cs_unionsz; /* sum of unions sizes */
65 ulong_t cs_uszmax; /* largest union */
66 ulong_t cs_nemembs; /* number of enum members */
67 ulong_t cs_nemax; /* largest number of members */
68 ulong_t cs_nstrings; /* number of strings */
69 ulong_t cs_strsz; /* string size */
70 ulong_t cs_strmax; /* longest string */
71 } ctfdump_stat_t;
72
73 typedef struct {
74 char ci_name[MAX_NAMELEN];
75 ctf_id_t ci_id;
76 ulong_t ci_symidx;
77 ctf_funcinfo_t ci_funcinfo;
78 } ctf_idname_t;
79
80 static ctf_idname_t *idnames;
81 static const char *g_progname;
82 static ctfdump_arg_t g_dump;
83 static ctf_file_t *g_fp;
84 static ctfdump_stat_t g_stats;
85 static ctf_id_t *g_fargc;
86 static int g_nfargc;
87
88 static int g_exit = 0;
89
90 static const char *ctfdump_fpenc[] = {
91 NULL,
92 "SINGLE",
93 "DOUBLE",
94 "COMPLEX",
95 "DCOMPLEX",
96 "LDCOMPLEX",
97 "LDOUBLE",
98 "INTERVAL",
99 "DINTERVAL",
100 "LDINTERVAL",
101 "IMAGINARY",
102 "DIMAGINARY",
103 "LDIMAGINARY"
104 };
105
106 /*
107 * When stats are requested, we have to go through everything. To make our lives
108 * easier, we'll just always allow the code to print everything out, but only
109 * output it if we have actually enabled that section.
110 */
111 static void
ctfdump_printf(ctfdump_arg_t arg,const char * fmt,...)112 ctfdump_printf(ctfdump_arg_t arg, const char *fmt, ...)
113 {
114 va_list ap;
115
116 if ((arg & g_dump) == 0)
117 return;
118
119 va_start(ap, fmt);
120 (void) vfprintf(stdout, fmt, ap);
121 va_end(ap);
122 }
123
124 static void
ctfdump_fatal(const char * fmt,...)125 ctfdump_fatal(const char *fmt, ...)
126 {
127 va_list ap;
128
129 (void) fprintf(stderr, "%s: ", g_progname);
130 va_start(ap, fmt);
131 (void) vfprintf(stderr, fmt, ap);
132 va_end(ap);
133
134 exit(1);
135 }
136
137 static void
ctfdump_usage(const char * fmt,...)138 ctfdump_usage(const char *fmt, ...)
139 {
140 if (fmt != NULL) {
141 va_list ap;
142 (void) fprintf(stderr, "%s: ", g_progname);
143 va_start(ap, fmt);
144 (void) vfprintf(stderr, fmt, ap);
145 va_end(ap);
146 }
147
148 (void) fprintf(stderr, "Usage: %s [-cdfhlsSt] [-p parent] [-u outfile] "
149 "file\n"
150 "\n"
151 "\t-c dump C-style output\n"
152 "\t-d dump object data\n"
153 "\t-f dump function data\n"
154 "\t-h dump the CTF header\n"
155 "\t-l dump the label table\n"
156 "\t-p use parent to supply additional information\n"
157 "\t-s dump the string table\n"
158 "\t-S dump statistics about the CTF container\n"
159 "\t-t dump type information\n"
160 "\t-u dump uncompressed CTF data to outfile\n",
161 g_progname);
162 }
163
164 static void
ctfdump_title(ctfdump_arg_t arg,const char * header)165 ctfdump_title(ctfdump_arg_t arg, const char *header)
166 {
167 static const char line[] = "----------------------------------------"
168 "----------------------------------------";
169 ctfdump_printf(arg, "\n- %s %.*s\n\n", header, (int)78 - strlen(header),
170 line);
171 }
172
173 static int
ctfdump_objects_cb(const char * name,ctf_id_t id,ulong_t symidx,void * arg)174 ctfdump_objects_cb(const char *name, ctf_id_t id, ulong_t symidx, void *arg)
175 {
176 _NOTE(ARGUNUSED(arg));
177
178 int len;
179
180 len = snprintf(NULL, 0, " [%lu] %ld", g_stats.cs_ndata, id);
181 ctfdump_printf(CTFDUMP_OBJECTS, " [%lu] %ld %*s%s (%lu)\n",
182 g_stats.cs_ndata, id, MAX(15 - len, 0), "", name, symidx);
183 g_stats.cs_ndata++;
184 return (0);
185 }
186
187 static void
ctfdump_objects(void)188 ctfdump_objects(void)
189 {
190 ctfdump_title(CTFDUMP_OBJECTS, "Data Objects");
191 if (ctf_object_iter(g_fp, ctfdump_objects_cb, NULL) == CTF_ERR) {
192 warnx("failed to dump objects: %s",
193 ctf_errmsg(ctf_errno(g_fp)));
194 g_exit = 1;
195 }
196 }
197
198 static void
ctfdump_fargs_grow(int nargs)199 ctfdump_fargs_grow(int nargs)
200 {
201 if (g_nfargc < nargs) {
202 g_fargc = realloc(g_fargc, sizeof (ctf_id_t) * nargs);
203 if (g_fargc == NULL)
204 ctfdump_fatal("failed to get memory for %d "
205 "ctf_id_t's\n", nargs);
206 g_nfargc = nargs;
207 }
208 }
209
210 static int
ctfdump_functions_cb(const char * name,ulong_t symidx,ctf_funcinfo_t * ctc,void * arg)211 ctfdump_functions_cb(const char *name, ulong_t symidx, ctf_funcinfo_t *ctc,
212 void *arg)
213 {
214 _NOTE(ARGUNUSED(arg));
215 int i;
216
217 if (ctc->ctc_argc != 0) {
218 ctfdump_fargs_grow(ctc->ctc_argc);
219 if (ctf_func_args(g_fp, symidx, g_nfargc, g_fargc) == CTF_ERR)
220 ctfdump_fatal("failed to get arguments for function "
221 "%s: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
222 }
223
224 ctfdump_printf(CTFDUMP_FUNCTIONS,
225 " [%lu] %s (%lu) returns: %ld args: (", g_stats.cs_nfuncs, name,
226 symidx, ctc->ctc_return);
227 for (i = 0; i < ctc->ctc_argc; i++)
228 ctfdump_printf(CTFDUMP_FUNCTIONS, "%ld%s", g_fargc[i],
229 i + 1 == ctc->ctc_argc ? "" : ", ");
230 if (ctc->ctc_flags & CTF_FUNC_VARARG)
231 ctfdump_printf(CTFDUMP_FUNCTIONS, "%s...",
232 ctc->ctc_argc == 0 ? "" : ", ");
233 ctfdump_printf(CTFDUMP_FUNCTIONS, ")\n");
234
235 g_stats.cs_nfuncs++;
236 g_stats.cs_nfuncargs += ctc->ctc_argc;
237 g_stats.cs_nfuncmax = MAX(ctc->ctc_argc, g_stats.cs_nfuncmax);
238
239 return (0);
240 }
241
242 static void
ctfdump_functions(void)243 ctfdump_functions(void)
244 {
245 ctfdump_title(CTFDUMP_FUNCTIONS, "Functions");
246
247 if (ctf_function_iter(g_fp, ctfdump_functions_cb, NULL) == CTF_ERR) {
248 warnx("failed to dump functions: %s",
249 ctf_errmsg(ctf_errno(g_fp)));
250 g_exit = 1;
251 }
252 }
253
254 static void
ctfdump_header(void)255 ctfdump_header(void)
256 {
257 const ctf_header_t *hp;
258 const char *parname, *parlabel;
259
260 ctfdump_title(CTFDUMP_HEADER, "CTF Header");
261 ctf_dataptr(g_fp, (const void **)&hp, NULL);
262 ctfdump_printf(CTFDUMP_HEADER, " cth_magic = 0x%04x\n",
263 hp->cth_magic);
264 ctfdump_printf(CTFDUMP_HEADER, " cth_version = %u\n",
265 hp->cth_version);
266 ctfdump_printf(CTFDUMP_HEADER, " cth_flags = 0x%02x\n",
267 ctf_flags(g_fp));
268 parname = ctf_parent_name(g_fp);
269 parlabel = ctf_parent_label(g_fp);
270 ctfdump_printf(CTFDUMP_HEADER, " cth_parlabel = %s\n",
271 parlabel == NULL ? "(anon)" : parlabel);
272 ctfdump_printf(CTFDUMP_HEADER, " cth_parname = %s\n",
273 parname == NULL ? "(anon)" : parname);
274 ctfdump_printf(CTFDUMP_HEADER, " cth_lbloff = %u\n",
275 hp->cth_lbloff);
276 ctfdump_printf(CTFDUMP_HEADER, " cth_objtoff = %u\n",
277 hp->cth_objtoff);
278 ctfdump_printf(CTFDUMP_HEADER, " cth_funcoff = %u\n",
279 hp->cth_funcoff);
280 ctfdump_printf(CTFDUMP_HEADER, " cth_typeoff = %u\n",
281 hp->cth_typeoff);
282 ctfdump_printf(CTFDUMP_HEADER, " cth_stroff = %u\n",
283 hp->cth_stroff);
284 ctfdump_printf(CTFDUMP_HEADER, " cth_strlen = %u\n",
285 hp->cth_strlen);
286 }
287
288 static int
ctfdump_labels_cb(const char * name,const ctf_lblinfo_t * li,void * arg)289 ctfdump_labels_cb(const char *name, const ctf_lblinfo_t *li, void *arg)
290 {
291 _NOTE(ARGUNUSED(arg));
292 ctfdump_printf(CTFDUMP_LABELS, " %5ld %s\n", li->ctb_typeidx, name);
293 return (0);
294 }
295
296 static void
ctfdump_labels(void)297 ctfdump_labels(void)
298 {
299 ctfdump_title(CTFDUMP_LABELS, "Label Table");
300 if (ctf_label_iter(g_fp, ctfdump_labels_cb, NULL) == CTF_ERR) {
301 warnx("failed to dump labels: %s",
302 ctf_errmsg(ctf_errno(g_fp)));
303 g_exit = 1;
304 }
305 }
306
307 static int
ctfdump_strings_cb(const char * s,void * arg)308 ctfdump_strings_cb(const char *s, void *arg)
309 {
310 size_t len = strlen(s) + 1;
311 ulong_t *stroff = arg;
312 ctfdump_printf(CTFDUMP_STRINGS, " [%lu] %s\n", *stroff,
313 *s == '\0' ? "\\0" : s);
314 *stroff = *stroff + len;
315 g_stats.cs_nstrings++;
316 g_stats.cs_strsz += len;
317 g_stats.cs_strmax = MAX(g_stats.cs_strmax, len);
318 return (0);
319 }
320
321 static void
ctfdump_strings(void)322 ctfdump_strings(void)
323 {
324 ulong_t stroff = 0;
325
326 ctfdump_title(CTFDUMP_STRINGS, "String Table");
327 if (ctf_string_iter(g_fp, ctfdump_strings_cb, &stroff) == CTF_ERR) {
328 warnx("failed to dump strings: %s",
329 ctf_errmsg(ctf_errno(g_fp)));
330 g_exit = 1;
331 }
332 }
333
334 static void
ctfdump_stat_int(const char * name,ulong_t value)335 ctfdump_stat_int(const char *name, ulong_t value)
336 {
337 ctfdump_printf(CTFDUMP_STATS, " %-36s= %lu\n", name, value);
338 }
339
340 static void
ctfdump_stat_fp(const char * name,float value)341 ctfdump_stat_fp(const char *name, float value)
342 {
343 ctfdump_printf(CTFDUMP_STATS, " %-36s= %.2f\n", name, value);
344 }
345
346 static void
ctfdump_stats(void)347 ctfdump_stats(void)
348 {
349 int i;
350 ulong_t sum;
351
352 ctfdump_title(CTFDUMP_STATS, "CTF Statistics");
353
354 ctfdump_stat_int("total number of data objects", g_stats.cs_ndata);
355 ctfdump_printf(CTFDUMP_STATS, "\n");
356 ctfdump_stat_int("total number of functions", g_stats.cs_nfuncs);
357 ctfdump_stat_int("total number of function arguments",
358 g_stats.cs_nfuncargs);
359 ctfdump_stat_int("maximum argument list length", g_stats.cs_nfuncmax);
360 if (g_stats.cs_nfuncs != 0)
361 ctfdump_stat_fp("average argument list length",
362 (float)g_stats.cs_nfuncargs / (float)g_stats.cs_nfuncs);
363 ctfdump_printf(CTFDUMP_STATS, "\n");
364
365 sum = 0;
366 for (i = 0; i < CTF_K_MAX; i++)
367 sum += g_stats.cs_ntypes[i];
368 ctfdump_stat_int("total number of types", sum);
369 ctfdump_stat_int("total number of integers",
370 g_stats.cs_ntypes[CTF_K_INTEGER]);
371 ctfdump_stat_int("total number of floats",
372 g_stats.cs_ntypes[CTF_K_FLOAT]);
373 ctfdump_stat_int("total number of pointers",
374 g_stats.cs_ntypes[CTF_K_POINTER]);
375 ctfdump_stat_int("total number of arrays",
376 g_stats.cs_ntypes[CTF_K_ARRAY]);
377 ctfdump_stat_int("total number of func types",
378 g_stats.cs_ntypes[CTF_K_FUNCTION]);
379 ctfdump_stat_int("total number of structs",
380 g_stats.cs_ntypes[CTF_K_STRUCT]);
381 ctfdump_stat_int("total number of unions",
382 g_stats.cs_ntypes[CTF_K_UNION]);
383 ctfdump_stat_int("total number of enums",
384 g_stats.cs_ntypes[CTF_K_ENUM]);
385 ctfdump_stat_int("total number of forward tags",
386 g_stats.cs_ntypes[CTF_K_FORWARD]);
387 ctfdump_stat_int("total number of typedefs",
388 g_stats.cs_ntypes[CTF_K_TYPEDEF]);
389 ctfdump_stat_int("total number of volatile types",
390 g_stats.cs_ntypes[CTF_K_VOLATILE]);
391 ctfdump_stat_int("total number of const types",
392 g_stats.cs_ntypes[CTF_K_CONST]);
393 ctfdump_stat_int("total number of restrict types",
394 g_stats.cs_ntypes[CTF_K_RESTRICT]);
395 ctfdump_stat_int("total number of unknowns (holes)",
396 g_stats.cs_ntypes[CTF_K_UNKNOWN]);
397
398 ctfdump_printf(CTFDUMP_STATS, "\n");
399 ctfdump_stat_int("total number of struct members", g_stats.cs_nsmembs);
400 ctfdump_stat_int("maximum number of struct members", g_stats.cs_nsmax);
401 ctfdump_stat_int("total size of all structs", g_stats.cs_structsz);
402 ctfdump_stat_int("maximum size of a struct", g_stats.cs_sszmax);
403 if (g_stats.cs_ntypes[CTF_K_STRUCT] != 0) {
404 ctfdump_stat_fp("average number of struct members",
405 (float)g_stats.cs_nsmembs /
406 (float)g_stats.cs_ntypes[CTF_K_STRUCT]);
407 ctfdump_stat_fp("average size of a struct",
408 (float)g_stats.cs_structsz /
409 (float)g_stats.cs_ntypes[CTF_K_STRUCT]);
410 }
411 ctfdump_printf(CTFDUMP_STATS, "\n");
412 ctfdump_stat_int("total number of union members", g_stats.cs_numembs);
413 ctfdump_stat_int("maximum number of union members", g_stats.cs_numax);
414 ctfdump_stat_int("total size of all unions", g_stats.cs_unionsz);
415 ctfdump_stat_int("maximum size of a union", g_stats.cs_uszmax);
416 if (g_stats.cs_ntypes[CTF_K_UNION] != 0) {
417 ctfdump_stat_fp("average number of union members",
418 (float)g_stats.cs_numembs /
419 (float)g_stats.cs_ntypes[CTF_K_UNION]);
420 ctfdump_stat_fp("average size of a union",
421 (float)g_stats.cs_unionsz /
422 (float)g_stats.cs_ntypes[CTF_K_UNION]);
423 }
424 ctfdump_printf(CTFDUMP_STATS, "\n");
425
426 ctfdump_stat_int("total number of enum members", g_stats.cs_nemembs);
427 ctfdump_stat_int("maximum number of enum members", g_stats.cs_nemax);
428 if (g_stats.cs_ntypes[CTF_K_ENUM] != 0) {
429 ctfdump_stat_fp("average number of enum members",
430 (float)g_stats.cs_nemembs /
431 (float)g_stats.cs_ntypes[CTF_K_ENUM]);
432 }
433 ctfdump_printf(CTFDUMP_STATS, "\n");
434
435 ctfdump_stat_int("total number of strings", g_stats.cs_nstrings);
436 ctfdump_stat_int("bytes of string data", g_stats.cs_strsz);
437 ctfdump_stat_int("maximum string length", g_stats.cs_strmax);
438 if (g_stats.cs_nstrings != 0)
439 ctfdump_stat_fp("average string length",
440 (float)g_stats.cs_strsz / (float)g_stats.cs_nstrings);
441 ctfdump_printf(CTFDUMP_STATS, "\n");
442 }
443
444 static void
ctfdump_intenc_name(ctf_encoding_t * cte,char * buf,int len)445 ctfdump_intenc_name(ctf_encoding_t *cte, char *buf, int len)
446 {
447 int off = 0;
448 boolean_t space = B_FALSE;
449
450 if (cte->cte_format == 0 || (cte->cte_format &
451 ~(CTF_INT_SIGNED | CTF_INT_CHAR | CTF_INT_BOOL |
452 CTF_INT_VARARGS)) != 0) {
453 (void) snprintf(buf, len, "0x%x", cte->cte_format);
454 return;
455 }
456
457 if (cte->cte_format & CTF_INT_SIGNED) {
458 off += snprintf(buf + off, MAX(len - off, 0), "%sSIGNED",
459 space == B_TRUE ? " " : "");
460 space = B_TRUE;
461 }
462
463 if (cte->cte_format & CTF_INT_CHAR) {
464 off += snprintf(buf + off, MAX(len - off, 0), "%sCHAR",
465 space == B_TRUE ? " " : "");
466 space = B_TRUE;
467 }
468
469 if (cte->cte_format & CTF_INT_BOOL) {
470 off += snprintf(buf + off, MAX(len - off, 0), "%sBOOL",
471 space == B_TRUE ? " " : "");
472 space = B_TRUE;
473 }
474
475 if (cte->cte_format & CTF_INT_VARARGS) {
476 off += snprintf(buf + off, MAX(len - off, 0), "%sVARARGS",
477 space == B_TRUE ? " " : "");
478 space = B_TRUE;
479 }
480 }
481
482 static int
ctfdump_member_cb(const char * member,ctf_id_t type,ulong_t off,void * arg)483 ctfdump_member_cb(const char *member, ctf_id_t type, ulong_t off, void *arg)
484 {
485 int *count = arg;
486 ctfdump_printf(CTFDUMP_TYPES, "\t%s type=%ld off=%lu\n", member, type,
487 off);
488 *count = *count + 1;
489 return (0);
490 }
491
492 static int
ctfdump_enum_cb(const char * name,int value,void * arg)493 ctfdump_enum_cb(const char *name, int value, void *arg)
494 {
495 int *count = arg;
496 ctfdump_printf(CTFDUMP_TYPES, "\t%s = %d\n", name, value);
497 *count = *count + 1;
498 return (0);
499 }
500
501 static int
ctfdump_types_cb(ctf_id_t id,boolean_t root,void * arg)502 ctfdump_types_cb(ctf_id_t id, boolean_t root, void *arg)
503 {
504 _NOTE(ARGUNUSED(arg));
505 int kind, i, count;
506 ctf_id_t ref;
507 char name[MAX_NAMELEN], ienc[128];
508 const char *encn;
509 ctf_funcinfo_t ctc;
510 ctf_arinfo_t ar;
511 ctf_encoding_t cte;
512 ssize_t size;
513
514 if ((kind = ctf_type_kind(g_fp, id)) == CTF_ERR)
515 ctfdump_fatal("encountered malformed ctf, type %s does not "
516 "have a kind: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
517
518 if (ctf_type_name(g_fp, id, name, sizeof (name)) == NULL) {
519 if (ctf_errno(g_fp) != ECTF_NOPARENT)
520 ctfdump_fatal("type %ld missing name: %s\n", id,
521 ctf_errmsg(ctf_errno(g_fp)));
522 (void) snprintf(name, sizeof (name), "(unknown %s)",
523 ctf_kind_name(g_fp, kind));
524 }
525
526 g_stats.cs_ntypes[kind]++;
527 if (root == B_TRUE)
528 ctfdump_printf(CTFDUMP_TYPES, " <%ld> ", id);
529 else
530 ctfdump_printf(CTFDUMP_TYPES, " [%ld] ", id);
531
532 switch (kind) {
533 case CTF_K_UNKNOWN:
534 break;
535 case CTF_K_INTEGER:
536 if (ctf_type_encoding(g_fp, id, &cte) == CTF_ERR)
537 ctfdump_fatal("failed to get encoding information "
538 "for %s: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
539 ctfdump_intenc_name(&cte, ienc, sizeof (ienc));
540 ctfdump_printf(CTFDUMP_TYPES,
541 "%s encoding=%s offset=%u bits=%u",
542 name, ienc, cte.cte_offset, cte.cte_bits);
543 break;
544 case CTF_K_FLOAT:
545 if (ctf_type_encoding(g_fp, id, &cte) == CTF_ERR)
546 ctfdump_fatal("failed to get encoding information "
547 "for %s: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
548 if (cte.cte_format < 1 || cte.cte_format > 12)
549 encn = "unknown";
550 else
551 encn = ctfdump_fpenc[cte.cte_format];
552 ctfdump_printf(CTFDUMP_TYPES, "%s encoding=%s offset=%u "
553 "bits=%u", name, encn, cte.cte_offset, cte.cte_bits);
554 break;
555 case CTF_K_POINTER:
556 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
557 ctfdump_fatal("failed to get reference type for %s: "
558 "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
559 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name,
560 ref);
561 break;
562 case CTF_K_ARRAY:
563 if (ctf_array_info(g_fp, id, &ar) == CTF_ERR)
564 ctfdump_fatal("failed to get array information for "
565 "%s: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
566 ctfdump_printf(CTFDUMP_TYPES, "%s contents: %ld, index: %ld",
567 name, ar.ctr_contents, ar.ctr_index);
568 break;
569 case CTF_K_FUNCTION:
570 if (ctf_func_info_by_id(g_fp, id, &ctc) == CTF_ERR)
571 ctfdump_fatal("failed to get function info for %s: "
572 "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
573 if (ctc.ctc_argc > 0) {
574 ctfdump_fargs_grow(ctc.ctc_argc);
575 if (ctf_func_args_by_id(g_fp, id, g_nfargc, g_fargc) ==
576 CTF_ERR)
577 ctfdump_fatal("failed to get function "
578 "arguments for %s: %s\n", name,
579 ctf_errmsg(ctf_errno(g_fp)));
580 }
581 ctfdump_printf(CTFDUMP_TYPES,
582 "%s returns: %ld args: (", name, ctc.ctc_return);
583 for (i = 0; i < ctc.ctc_argc; i++) {
584 ctfdump_printf(CTFDUMP_TYPES, "%ld%s", g_fargc[i],
585 i + 1 == ctc.ctc_argc ? "" : ", ");
586 }
587 if (ctc.ctc_flags & CTF_FUNC_VARARG)
588 ctfdump_printf(CTFDUMP_TYPES, "%s...",
589 ctc.ctc_argc == 0 ? "" : ", ");
590 ctfdump_printf(CTFDUMP_TYPES, ")");
591 break;
592 case CTF_K_STRUCT:
593 case CTF_K_UNION:
594 size = ctf_type_size(g_fp, id);
595 if (size == CTF_ERR)
596 ctfdump_fatal("failed to get size of %s: %s\n", name,
597 ctf_errmsg(ctf_errno(g_fp)));
598 ctfdump_printf(CTFDUMP_TYPES, "%s (%zd bytes)\n", name, size);
599 count = 0;
600 if (ctf_member_iter(g_fp, id, ctfdump_member_cb, &count) != 0)
601 ctfdump_fatal("failed to iterate members of %s: %s\n",
602 name, ctf_errmsg(ctf_errno(g_fp)));
603 if (kind == CTF_K_STRUCT) {
604 g_stats.cs_nsmembs += count;
605 g_stats.cs_nsmax = MAX(count, g_stats.cs_nsmax);
606 g_stats.cs_structsz += size;
607 g_stats.cs_sszmax = MAX(size, g_stats.cs_sszmax);
608 } else {
609 g_stats.cs_numembs += count;
610 g_stats.cs_numax = MAX(count, g_stats.cs_numax);
611 g_stats.cs_unionsz += size;
612 g_stats.cs_uszmax = MAX(count, g_stats.cs_uszmax);
613 }
614 break;
615 case CTF_K_ENUM:
616 ctfdump_printf(CTFDUMP_TYPES, "%s\n", name);
617 count = 0;
618 if (ctf_enum_iter(g_fp, id, ctfdump_enum_cb, &count) != 0)
619 ctfdump_fatal("failed to iterate enumerators of %s: "
620 "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
621 g_stats.cs_nemembs += count;
622 g_stats.cs_nemax = MAX(g_stats.cs_nemax, count);
623 break;
624 case CTF_K_FORWARD:
625 ctfdump_printf(CTFDUMP_TYPES, "forward %s\n", name);
626 break;
627 case CTF_K_TYPEDEF:
628 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
629 ctfdump_fatal("failed to get reference type for %s: "
630 "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
631 ctfdump_printf(CTFDUMP_TYPES, "typedef %s refers to %ld", name,
632 ref);
633 break;
634 case CTF_K_VOLATILE:
635 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
636 ctfdump_fatal("failed to get reference type for %s: "
637 "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
638 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name,
639 ref);
640 break;
641 case CTF_K_CONST:
642 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
643 ctfdump_fatal("failed to get reference type for %s: "
644 "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
645 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name,
646 ref);
647 break;
648 case CTF_K_RESTRICT:
649 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
650 ctfdump_fatal("failed to get reference type for %s: "
651 "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
652 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name,
653 ref);
654 break;
655 default:
656 ctfdump_fatal("encountered unknown kind for type %s: %d\n",
657 name, kind);
658 }
659
660 ctfdump_printf(CTFDUMP_TYPES, "\n");
661
662 return (0);
663 }
664
665 static void
ctfdump_types(void)666 ctfdump_types(void)
667 {
668 ctfdump_title(CTFDUMP_TYPES, "Types");
669
670 if (ctf_type_iter(g_fp, B_TRUE, ctfdump_types_cb, NULL) == CTF_ERR) {
671 warnx("failed to dump types: %s",
672 ctf_errmsg(ctf_errno(g_fp)));
673 g_exit = 1;
674 }
675 }
676
677 /*
678 * C-style output. This is designed mainly for comparison purposes, and doesn't
679 * produce directly valid C:
680 *
681 * - the declarations are sorted alphabetically not semantically
682 * - anonymous enums without other users are elided (e.g. IDCS_PROBE_SENT)
683 * - doubly-pointed-to functions are wrong (e.g. in kiconv_ops_t)
684 * - anon unions declared within SOUs aren't expanded
685 * - function arguments aren't expanded recursively
686 */
687
688 static void
ctfsrc_refname(ctf_id_t id,char * buf,size_t bufsize)689 ctfsrc_refname(ctf_id_t id, char *buf, size_t bufsize)
690 {
691 ctf_id_t ref;
692
693 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) {
694 ctfdump_fatal("failed to get reference type for %ld: "
695 "%s\n", id, ctf_errmsg(ctf_errno(g_fp)));
696 }
697
698 (void) ctf_type_name(g_fp, ref, buf, bufsize);
699 }
700
701 static int
ctfsrc_member_cb(const char * member,ctf_id_t type,ulong_t off,void * arg)702 ctfsrc_member_cb(const char *member, ctf_id_t type, ulong_t off, void *arg)
703 {
704 _NOTE(ARGUNUSED(arg));
705 char name[MAX_NAMELEN];
706
707 if (ctf_type_cname(g_fp, type, name, sizeof (name), member) == NULL) {
708 if (ctf_errno(g_fp) != ECTF_NOPARENT) {
709 ctfdump_fatal("type %ld missing name: %s\n", type,
710 ctf_errmsg(ctf_errno(g_fp)));
711 }
712
713 (void) snprintf(name, sizeof (name), "unknown_t %s", member);
714 }
715
716 /*
717 * A byte offset is friendlier, but we'll print bits too if it's not
718 * aligned (i.e. a bitfield).
719 */
720 if (off % NBBY != 0) {
721 (void) printf("\t%s; /* offset: %lu bytes (%lu bits) */\n",
722 name, off / NBBY, off);
723 } else {
724 (void) printf("\t%s; /* offset: %lu bytes */\n",
725 name, off / NBBY);
726 }
727 return (0);
728 }
729
730 static int
ctfsrc_enum_cb(const char * name,int value,void * arg)731 ctfsrc_enum_cb(const char *name, int value, void *arg)
732 {
733 _NOTE(ARGUNUSED(arg));
734 (void) printf("\t%s = %d,\n", name, value);
735 return (0);
736 }
737
738 static int
is_anon_refname(const char * refname)739 is_anon_refname(const char *refname)
740 {
741 return ((strcmp(refname, "struct ") == 0 ||
742 strcmp(refname, "union ") == 0 ||
743 strcmp(refname, "enum ") == 0));
744 }
745
746 static int
ctfsrc_collect_types_cb(ctf_id_t id,boolean_t root,void * arg)747 ctfsrc_collect_types_cb(ctf_id_t id, boolean_t root, void *arg)
748 {
749 _NOTE(ARGUNUSED(root, arg));
750 (void) ctf_type_name(g_fp, id, idnames[id].ci_name,
751 sizeof (idnames[id].ci_name));
752 idnames[id].ci_id = id;
753 return (0);
754 }
755
756 static void
ctfsrc_type(ctf_id_t id,const char * name)757 ctfsrc_type(ctf_id_t id, const char *name)
758 {
759 char refname[MAX_NAMELEN];
760 ctf_id_t ref;
761 ssize_t size;
762 int kind;
763
764 if ((kind = ctf_type_kind(g_fp, id)) == CTF_ERR) {
765 ctfdump_fatal("encountered malformed ctf, type %s does not "
766 "have a kind: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
767 }
768
769 switch (kind) {
770 case CTF_K_STRUCT:
771 case CTF_K_UNION:
772 /*
773 * Delay printing anonymous SOUs; a later typedef will usually
774 * pick them up.
775 */
776 if (is_anon_refname(name))
777 break;
778
779 if ((size = ctf_type_size(g_fp, id)) == CTF_ERR) {
780 ctfdump_fatal("failed to get size of %s: %s\n", name,
781 ctf_errmsg(ctf_errno(g_fp)));
782 }
783
784 (void) printf("%s { /* 0x%x bytes */\n", name, size);
785
786 if (ctf_member_iter(g_fp, id, ctfsrc_member_cb, NULL) != 0) {
787 ctfdump_fatal("failed to iterate members of %s: %s\n",
788 name, ctf_errmsg(ctf_errno(g_fp)));
789 }
790
791 (void) printf("};\n\n");
792 break;
793 case CTF_K_ENUM:
794 /*
795 * This will throw away any anon enum that isn't followed by a
796 * typedef...
797 */
798 if (is_anon_refname(name))
799 break;
800
801 (void) printf("%s {\n", name);
802
803 if (ctf_enum_iter(g_fp, id, ctfsrc_enum_cb, NULL) != 0) {
804 ctfdump_fatal("failed to iterate enumerators of %s: "
805 "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
806 }
807
808 (void) printf("};\n\n");
809 break;
810 case CTF_K_TYPEDEF:
811 ctfsrc_refname(id, refname, sizeof (refname));
812
813 if (!is_anon_refname(refname)) {
814 (void) ctf_type_cname(g_fp,
815 ctf_type_reference(g_fp, id), refname,
816 sizeof (refname), name);
817
818 (void) printf("typedef %s;\n\n", refname);
819 break;
820 }
821
822 ref = ctf_type_reference(g_fp, id);
823
824 if (ctf_type_kind(g_fp, ref) == CTF_K_ENUM) {
825 (void) printf("typedef enum {\n");
826
827 if (ctf_enum_iter(g_fp, ref,
828 ctfsrc_enum_cb, NULL) != 0) {
829 ctfdump_fatal("failed to iterate enumerators "
830 "of %s: %s\n", refname,
831 ctf_errmsg(ctf_errno(g_fp)));
832 }
833
834 (void) printf("} %s;\n\n", name);
835 } else {
836 if ((size = ctf_type_size(g_fp, ref)) == CTF_ERR) {
837 ctfdump_fatal("failed to get size of %s: %s\n",
838 refname, ctf_errmsg(ctf_errno(g_fp)));
839 }
840
841 (void) printf("typedef %s{ /* 0x%zx bytes */\n",
842 refname, size);
843
844 if (ctf_member_iter(g_fp, ref,
845 ctfsrc_member_cb, NULL) != 0) {
846 ctfdump_fatal("failed to iterate members "
847 "of %s: %s\n", refname,
848 ctf_errmsg(ctf_errno(g_fp)));
849 }
850
851 (void) printf("} %s;\n\n", name);
852 }
853
854 break;
855 case CTF_K_FORWARD:
856 (void) printf("%s;\n\n", name);
857 break;
858 case CTF_K_UNKNOWN:
859 case CTF_K_INTEGER:
860 case CTF_K_FLOAT:
861 case CTF_K_POINTER:
862 case CTF_K_ARRAY:
863 case CTF_K_FUNCTION:
864 case CTF_K_VOLATILE:
865 case CTF_K_CONST:
866 case CTF_K_RESTRICT:
867 break;
868 default:
869 ctfdump_fatal("encountered unknown kind for type %s: %d\n",
870 name, kind);
871 break;
872 }
873 }
874
875 static int
ctfsrc_collect_objects_cb(const char * name,ctf_id_t id,ulong_t symidx,void * arg)876 ctfsrc_collect_objects_cb(const char *name, ctf_id_t id,
877 ulong_t symidx, void *arg)
878 {
879 size_t *count = arg;
880
881 /* local static vars can have an unknown ID */
882 if (id == 0)
883 return (0);
884
885 (void) strlcpy(idnames[*count].ci_name, name,
886 sizeof (idnames[*count].ci_name));
887 idnames[*count].ci_id = id;
888 idnames[*count].ci_symidx = symidx;
889 *count = *count + 1;
890 return (0);
891 }
892
893 static void
ctfsrc_object(ctf_id_t id,const char * name)894 ctfsrc_object(ctf_id_t id, const char *name)
895 {
896 char tname[MAX_NAMELEN];
897
898 if (ctf_type_cname(g_fp, id, tname, sizeof (tname), name) == NULL) {
899 if (ctf_errno(g_fp) != ECTF_NOPARENT) {
900 ctfdump_fatal("type %ld missing name: %s\n", id,
901 ctf_errmsg(ctf_errno(g_fp)));
902 }
903 (void) snprintf(tname, sizeof (tname), "unknown_t %s", name);
904 }
905
906 (void) printf("extern %s;\n", tname);
907 }
908
909 static int
ctfsrc_collect_functions_cb(const char * name,ulong_t symidx,ctf_funcinfo_t * ctc,void * arg)910 ctfsrc_collect_functions_cb(const char *name, ulong_t symidx,
911 ctf_funcinfo_t *ctc, void *arg)
912 {
913 size_t *count = arg;
914
915 (void) strlcpy(idnames[*count].ci_name, name,
916 sizeof (idnames[*count].ci_name));
917 bcopy(ctc, &idnames[*count].ci_funcinfo, sizeof (*ctc));
918 idnames[*count].ci_id = 0;
919 idnames[*count].ci_symidx = symidx;
920 *count = *count + 1;
921 return (0);
922 }
923
924 static void
ctfsrc_function(ctf_idname_t * idn)925 ctfsrc_function(ctf_idname_t *idn)
926 {
927 ctf_funcinfo_t *cfi = &idn->ci_funcinfo;
928 char name[MAX_NAMELEN] = "unknown_t";
929
930 (void) ctf_type_name(g_fp, cfi->ctc_return, name, sizeof (name));
931
932 (void) printf("extern %s %s(", name, idn->ci_name);
933
934 if (cfi->ctc_argc != 0) {
935 ctfdump_fargs_grow(cfi->ctc_argc);
936 if (ctf_func_args(g_fp, idn->ci_symidx,
937 g_nfargc, g_fargc) == CTF_ERR) {
938 ctfdump_fatal("failed to get arguments for function "
939 "%s: %s\n", idn->ci_name,
940 ctf_errmsg(ctf_errno(g_fp)));
941 }
942
943 size_t i;
944 for (i = 0; i < cfi->ctc_argc; i++) {
945 ctf_id_t aid = g_fargc[i];
946
947 name[0] = '\0';
948
949 (void) ctf_type_name(g_fp, aid, name, sizeof (name));
950
951 (void) printf("%s%s", name,
952 i + 1 == cfi->ctc_argc ? "" : ", ");
953 }
954 } else {
955 if (!(cfi->ctc_flags & CTF_FUNC_VARARG))
956 (void) printf("void");
957 }
958
959 if (cfi->ctc_flags & CTF_FUNC_VARARG)
960 (void) printf("%s...", cfi->ctc_argc == 0 ? "" : ", ");
961
962 (void) printf(");\n");
963 }
964
965 static int
idname_compare(const void * lhs,const void * rhs)966 idname_compare(const void *lhs, const void *rhs)
967 {
968 return (strcmp(((ctf_idname_t *)lhs)->ci_name,
969 ((ctf_idname_t *)rhs)->ci_name));
970 }
971
972 static void
ctfdump_source(void)973 ctfdump_source(void)
974 {
975 ulong_t nr_syms = ctf_nr_syms(g_fp);
976 ctf_id_t max_id = ctf_max_id(g_fp);
977 size_t count = 0;
978
979 (void) printf("/* Types */\n\n");
980
981 if ((idnames = calloc(max_id + 1, sizeof (idnames[0]))) == NULL) {
982 ctfdump_fatal("failed to alloc idnames: %s\n",
983 strerror(errno));
984 }
985
986 if (ctf_type_iter(g_fp, B_FALSE, ctfsrc_collect_types_cb,
987 idnames) == CTF_ERR) {
988 warnx("failed to collect types: %s",
989 ctf_errmsg(ctf_errno(g_fp)));
990 g_exit = 1;
991 }
992
993 qsort(idnames, max_id, sizeof (ctf_idname_t), idname_compare);
994
995 size_t i;
996 for (i = 0; i < max_id; i++) {
997 if (idnames[i].ci_id != 0)
998 ctfsrc_type(idnames[i].ci_id, idnames[i].ci_name);
999 }
1000
1001 free(idnames);
1002
1003 (void) printf("\n\n/* Data Objects */\n\n");
1004
1005 if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) {
1006 ctfdump_fatal("failed to alloc idnames: %s\n",
1007 strerror(errno));
1008 }
1009
1010 if (ctf_object_iter(g_fp, ctfsrc_collect_objects_cb,
1011 &count) == CTF_ERR) {
1012 warnx("failed to collect objects: %s",
1013 ctf_errmsg(ctf_errno(g_fp)));
1014 g_exit = 1;
1015 }
1016
1017 qsort(idnames, count, sizeof (ctf_idname_t), idname_compare);
1018
1019 for (i = 0; i < count; i++)
1020 ctfsrc_object(idnames[i].ci_id, idnames[i].ci_name);
1021
1022 free(idnames);
1023
1024 (void) printf("\n\n/* Functions */\n\n");
1025
1026 if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) {
1027 ctfdump_fatal("failed to alloc idnames: %s\n",
1028 strerror(errno));
1029 }
1030
1031 count = 0;
1032
1033 if (ctf_function_iter(g_fp, ctfsrc_collect_functions_cb,
1034 &count) == CTF_ERR) {
1035 warnx("failed to collect functions: %s",
1036 ctf_errmsg(ctf_errno(g_fp)));
1037 g_exit = 1;
1038 }
1039
1040 qsort(idnames, count, sizeof (ctf_idname_t), idname_compare);
1041
1042 for (i = 0; i < count; i++)
1043 ctfsrc_function(&idnames[i]);
1044
1045 free(idnames);
1046 }
1047
1048 static void
ctfdump_output(const char * out)1049 ctfdump_output(const char *out)
1050 {
1051 int fd, ret;
1052 const void *data;
1053 size_t len;
1054
1055 ctf_dataptr(g_fp, &data, &len);
1056 if ((fd = open(out, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
1057 ctfdump_fatal("failed to open output file %s: %s\n", out,
1058 strerror(errno));
1059
1060 while (len > 0) {
1061 ret = write(fd, data, len);
1062 if (ret == -1 && errno == EINTR)
1063 continue;
1064 else if (ret == -1 && (errno == EFAULT || errno == EBADF))
1065 abort();
1066 else if (ret == -1)
1067 ctfdump_fatal("failed to write to %s: %s\n", out,
1068 strerror(errno));
1069 data = ((char *)data) + ret;
1070 len -= ret;
1071 }
1072
1073 do {
1074 ret = close(fd);
1075 } while (ret == -1 && errno == EINTR);
1076 if (ret != 0 && errno == EBADF)
1077 abort();
1078 if (ret != 0)
1079 ctfdump_fatal("failed to close %s: %s\n", out, strerror(errno));
1080 }
1081
1082 int
main(int argc,char * argv[])1083 main(int argc, char *argv[])
1084 {
1085 int c, fd, err;
1086 const char *ufile = NULL, *parent = NULL;
1087
1088 g_progname = basename(argv[0]);
1089 while ((c = getopt(argc, argv, ":cdfhlp:sStu:")) != -1) {
1090 switch (c) {
1091 case 'c':
1092 g_dump |= CTFDUMP_SOURCE;
1093 break;
1094 case 'd':
1095 g_dump |= CTFDUMP_OBJECTS;
1096 break;
1097 case 'f':
1098 g_dump |= CTFDUMP_FUNCTIONS;
1099 break;
1100 case 'h':
1101 g_dump |= CTFDUMP_HEADER;
1102 break;
1103 case 'l':
1104 g_dump |= CTFDUMP_LABELS;
1105 break;
1106 case 'p':
1107 parent = optarg;
1108 break;
1109 case 's':
1110 g_dump |= CTFDUMP_STRINGS;
1111 break;
1112 case 'S':
1113 g_dump |= CTFDUMP_STATS;
1114 break;
1115 case 't':
1116 g_dump |= CTFDUMP_TYPES;
1117 break;
1118 case 'u':
1119 g_dump |= CTFDUMP_OUTPUT;
1120 ufile = optarg;
1121 break;
1122 case '?':
1123 ctfdump_usage("Unknown option: -%c\n", optopt);
1124 return (2);
1125 case ':':
1126 ctfdump_usage("Option -%c requires an operand\n",
1127 optopt);
1128 return (2);
1129 }
1130 }
1131
1132 argc -= optind;
1133 argv += optind;
1134
1135 if ((g_dump & CTFDUMP_SOURCE) && !!(g_dump & ~CTFDUMP_SOURCE)) {
1136 ctfdump_usage("-c must be specified on its own\n");
1137 return (2);
1138 }
1139
1140 /*
1141 * Dump all information except C source by default.
1142 */
1143 if (g_dump == 0)
1144 g_dump = CTFDUMP_DEFAULT;
1145
1146 if (argc != 1) {
1147 ctfdump_usage("no file to dump\n");
1148 return (2);
1149 }
1150
1151 if ((fd = open(argv[0], O_RDONLY)) < 0)
1152 ctfdump_fatal("failed to open file %s: %s\n", argv[0],
1153 strerror(errno));
1154
1155 g_fp = ctf_fdopen(fd, &err);
1156 if (g_fp == NULL)
1157 ctfdump_fatal("failed to open file %s: %s\n", argv[0],
1158 ctf_errmsg(err));
1159
1160 /*
1161 * Check to see if this file needs a parent. If it does not and we were
1162 * given one, that should be an error. If it does need one and the
1163 * parent is not specified, that is fine, we just won't know how to
1164 * find child types. If we are given a parent, check at least that the
1165 * labels match.
1166 */
1167 if (ctf_parent_name(g_fp) == NULL) {
1168 if (parent != NULL)
1169 ctfdump_fatal("cannot use %s as a parent file, %s is "
1170 "not a child\n", parent, argv[0]);
1171 } else if (parent != NULL) {
1172 const char *explabel, *label;
1173 ctf_file_t *pfp = ctf_open(parent, &err);
1174
1175 if (pfp == NULL)
1176 ctfdump_fatal("failed to open parent file %s: %s\n",
1177 parent, ctf_errmsg(err));
1178
1179 /*
1180 * Before we import the parent into the child, check that the
1181 * labels match. While there is also the notion of the parent
1182 * name, it's less straightforward to match that. Require that
1183 * labels match.
1184 */
1185 explabel = ctf_parent_label(g_fp);
1186 label = ctf_label_topmost(pfp);
1187 if (explabel == NULL || label == NULL ||
1188 strcmp(explabel, label) != 0) {
1189 if (label == NULL)
1190 label = "<missing>";
1191 if (explabel == NULL)
1192 explabel = "<missing>";
1193 ctfdump_fatal("label mismatch between parent %s and "
1194 "child %s, parent has %s, child expects %s\n",
1195 parent, argv[0], label, explabel);
1196 }
1197
1198 if (ctf_import(g_fp, pfp) != 0)
1199 ctfdump_fatal("failed to import parent %s: %s\n",
1200 parent, ctf_errmsg(ctf_errno(g_fp)));
1201 }
1202
1203 if (g_dump & CTFDUMP_SOURCE) {
1204 ctfdump_source();
1205 return (0);
1206 }
1207
1208 /*
1209 * If stats is set, we must run through everything exect CTFDUMP_OUTPUT.
1210 * We also do CTFDUMP_STATS last as a result.
1211 */
1212 if (g_dump & CTFDUMP_HEADER)
1213 ctfdump_header();
1214
1215 if (g_dump & (CTFDUMP_LABELS | CTFDUMP_STATS))
1216 ctfdump_labels();
1217
1218 if (g_dump & (CTFDUMP_OBJECTS | CTFDUMP_STATS))
1219 ctfdump_objects();
1220
1221 if (g_dump & (CTFDUMP_FUNCTIONS | CTFDUMP_STATS))
1222 ctfdump_functions();
1223
1224 if (g_dump & (CTFDUMP_TYPES | CTFDUMP_STATS))
1225 ctfdump_types();
1226
1227 if (g_dump & (CTFDUMP_STRINGS | CTFDUMP_STATS))
1228 ctfdump_strings();
1229
1230 if (g_dump & CTFDUMP_STATS)
1231 ctfdump_stats();
1232
1233 if (g_dump & CTFDUMP_OUTPUT)
1234 ctfdump_output(ufile);
1235
1236 return (g_exit);
1237 }
1238