cut: add -Wall
[unleashed.git] / bin / ctfdump / ctfdump.c
blobaf4c0d21408d40b6ea18728d7d00ef7970ec82c0
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.
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.
13 * Copyright (c) 2015, Joyent, Inc.
17 * Dump information about CTF containers. This was inspired by the original
18 * ctfdump written in tools/ctf, but this has been reimplemented in terms of
19 * libctf.
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <libctf.h>
25 #include <libgen.h>
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <stddef.h>
29 #include <sys/sysmacros.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <string.h>
36 typedef enum ctfdump_arg {
37 CTFDUMP_OBJECTS = 0x01,
38 CTFDUMP_FUNCTIONS = 0x02,
39 CTFDUMP_HEADER = 0x04,
40 CTFDUMP_LABELS = 0x08,
41 CTFDUMP_STRINGS = 0x10,
42 CTFDUMP_STATS = 0x20,
43 CTFDUMP_TYPES = 0x40,
44 CTFDUMP_DEFAULT = 0x7f,
45 CTFDUMP_OUTPUT = 0x80,
46 CTFDUMP_ALL = 0xff
47 } ctfdump_arg_t;
49 typedef struct ctfdump_stat {
50 ulong_t cs_ndata; /* number of data objects */
51 ulong_t cs_nfuncs; /* number of functions */
52 ulong_t cs_nfuncargs; /* number of function args */
53 ulong_t cs_nfuncmax; /* largest number of args */
54 ulong_t cs_ntypes[CTF_K_MAX]; /* number of types */
55 ulong_t cs_nsmembs; /* number of struct members */
56 ulong_t cs_nsmax; /* largest number of members */
57 ulong_t cs_structsz; /* sum of structures sizes */
58 ulong_t cs_sszmax; /* largest structure */
59 ulong_t cs_numembs; /* number of union members */
60 ulong_t cs_numax; /* largest number of members */
61 ulong_t cs_unionsz; /* sum of unions sizes */
62 ulong_t cs_uszmax; /* largest union */
63 ulong_t cs_nemembs; /* number of enum members */
64 ulong_t cs_nemax; /* largest number of members */
65 ulong_t cs_nstrings; /* number of strings */
66 ulong_t cs_strsz; /* string size */
67 ulong_t cs_strmax; /* longest string */
68 } ctfdump_stat_t;
70 static const char *g_progname;
71 static ctfdump_arg_t g_dump;
72 static ctf_file_t *g_fp;
73 static ctfdump_stat_t g_stats;
74 static ctf_id_t *g_fargc;
75 static int g_nfargc;
77 static int g_exit = 0;
79 static const char *ctfdump_fpenc[] = {
80 NULL,
81 "SINGLE",
82 "DOUBLE",
83 "COMPLEX",
84 "DCOMPLEX",
85 "LDCOMPLEX",
86 "LDOUBLE",
87 "INTERVAL",
88 "DINTERVAL",
89 "LDINTERVAL",
90 "IMAGINARY",
91 "DIMAGINARY",
92 "LDIMAGINARY"
96 * When stats are requested, we have to go through everything. To make our lives
97 * easier, we'll just always allow the code to print everything out, but only
98 * output it if we have actually enabled that section.
100 static void __attribute__((__format__(printf, 2, 3)))
101 ctfdump_printf(ctfdump_arg_t arg, const char *fmt, ...)
103 va_list ap;
105 if ((arg & g_dump) == 0)
106 return;
108 va_start(ap, fmt);
109 vfprintf(stdout, fmt, ap);
110 va_end(ap);
113 static void __attribute__((__format__(printf, 1, 2)))
114 ctfdump_warn(const char *fmt, ...)
116 va_list ap;
118 (void) fprintf(stderr, "%s: ", g_progname);
119 va_start(ap, fmt);
120 vfprintf(stderr, fmt, ap);
121 va_end(ap);
124 static void __attribute__((__format__(printf, 1, 2)))
125 ctfdump_fatal(const char *fmt, ...)
127 va_list ap;
129 (void) fprintf(stderr, "%s: ", g_progname);
130 va_start(ap, fmt);
131 vfprintf(stderr, fmt, ap);
132 va_end(ap);
134 exit(1);
137 static void __attribute__((__format__(printf, 1, 2)))
138 ctfdump_usage(const char *fmt, ...)
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);
148 (void) fprintf(stderr, "Usage: %s [-dfhlsSt] [-p parent] [-u outfile] "
149 "file\n"
150 "\n"
151 "\t-d dump object data\n"
152 "\t-f dump function data\n"
153 "\t-h dump the CTF header\n"
154 "\t-l dump the label table\n"
155 "\t-p use parent to supply additional information\n"
156 "\t-s dump the string table\n"
157 "\t-S dump statistics about the CTF container\n"
158 "\t-t dump type information\n"
159 "\t-u dump uncompressed CTF data to outfile\n",
160 g_progname);
163 static void
164 ctfdump_title(ctfdump_arg_t arg, const char *header)
166 static const char line[] = "----------------------------------------"
167 "----------------------------------------";
168 ctfdump_printf(arg, "\n- %s %.*s\n\n", header,
169 (int)(78 - strlen(header)), line);
172 static int
173 ctfdump_objects_cb(const char *name, ctf_id_t id, ulong_t symidx, void *arg)
175 int len;
177 len = snprintf(NULL, 0, " [%lu] %lu", g_stats.cs_ndata, id);
178 ctfdump_printf(CTFDUMP_OBJECTS, " [%lu] %lu %*s%s (%lu)\n",
179 g_stats.cs_ndata, id, MAX(15 - len, 0), "", name, symidx);
180 g_stats.cs_ndata++;
181 return (0);
184 static void
185 ctfdump_objects(void)
187 ctfdump_title(CTFDUMP_OBJECTS, "Data Objects");
188 if (ctf_object_iter(g_fp, ctfdump_objects_cb, NULL) == CTF_ERR) {
189 ctfdump_warn("failed to dump objects: %s\n",
190 ctf_errmsg(ctf_errno(g_fp)));
191 g_exit = 1;
195 static void
196 ctfdump_fargs_grow(int nargs)
198 if (g_nfargc < nargs) {
199 g_fargc = reallocarray(g_fargc, nargs, sizeof (ctf_id_t));
200 if (g_fargc == NULL)
201 ctfdump_fatal("failed to get memory for %d "
202 "ctf_id_t's\n", nargs);
203 g_nfargc = nargs;
207 static int
208 ctfdump_functions_cb(const char *name, ulong_t symidx, ctf_funcinfo_t *ctc,
209 void *arg)
211 int i;
213 if (ctc->ctc_argc != 0) {
214 ctfdump_fargs_grow(ctc->ctc_argc);
215 if (ctf_func_args(g_fp, symidx, g_nfargc, g_fargc) == CTF_ERR)
216 ctfdump_fatal("failed to get arguments for function "
217 "%s: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
220 ctfdump_printf(CTFDUMP_FUNCTIONS,
221 " [%lu] %s (%lu) returns: %lu args: (", g_stats.cs_nfuncs, name,
222 symidx, ctc->ctc_return);
223 for (i = 0; i < ctc->ctc_argc; i++)
224 ctfdump_printf(CTFDUMP_FUNCTIONS, "%lu%s", g_fargc[i],
225 i + 1 == ctc->ctc_argc ? "" : ", ");
226 if (ctc->ctc_flags & CTF_FUNC_VARARG)
227 ctfdump_printf(CTFDUMP_FUNCTIONS, "%s...",
228 ctc->ctc_argc == 0 ? "" : ", ");
229 ctfdump_printf(CTFDUMP_FUNCTIONS, ")\n");
231 g_stats.cs_nfuncs++;
232 g_stats.cs_nfuncargs += ctc->ctc_argc;
233 g_stats.cs_nfuncmax = MAX(ctc->ctc_argc, g_stats.cs_nfuncmax);
235 return (0);
238 static void
239 ctfdump_functions(void)
241 ctfdump_title(CTFDUMP_FUNCTIONS, "Functions");
243 if (ctf_function_iter(g_fp, ctfdump_functions_cb, NULL) == CTF_ERR) {
244 ctfdump_warn("failed to dump functions: %s\n",
245 ctf_errmsg(ctf_errno(g_fp)));
246 g_exit = 1;
250 static void
251 ctfdump_header(void)
253 const ctf_header_t *hp;
254 const char *parname, *parlabel;
256 ctfdump_title(CTFDUMP_HEADER, "CTF Header");
257 ctf_dataptr(g_fp, (const void **)&hp, NULL);
258 ctfdump_printf(CTFDUMP_HEADER, " cth_magic = 0x%04x\n",
259 hp->cth_magic);
260 ctfdump_printf(CTFDUMP_HEADER, " cth_version = %u\n",
261 hp->cth_version);
262 ctfdump_printf(CTFDUMP_HEADER, " cth_flags = 0x%02x\n",
263 ctf_flags(g_fp));
264 parname = ctf_parent_name(g_fp);
265 parlabel = ctf_parent_label(g_fp);
266 ctfdump_printf(CTFDUMP_HEADER, " cth_parlabel = %s\n",
267 parlabel == NULL ? "(anon)" : parlabel);
268 ctfdump_printf(CTFDUMP_HEADER, " cth_parname = %s\n",
269 parname == NULL ? "(anon)" : parname);
270 ctfdump_printf(CTFDUMP_HEADER, " cth_lbloff = %u\n",
271 hp->cth_lbloff);
272 ctfdump_printf(CTFDUMP_HEADER, " cth_objtoff = %u\n",
273 hp->cth_objtoff);
274 ctfdump_printf(CTFDUMP_HEADER, " cth_funcoff = %u\n",
275 hp->cth_funcoff);
276 ctfdump_printf(CTFDUMP_HEADER, " cth_typeoff = %u\n",
277 hp->cth_typeoff);
278 ctfdump_printf(CTFDUMP_HEADER, " cth_stroff = %u\n",
279 hp->cth_stroff);
280 ctfdump_printf(CTFDUMP_HEADER, " cth_strlen = %u\n",
281 hp->cth_strlen);
284 static int
285 ctfdump_labels_cb(const char *name, const ctf_lblinfo_t *li, void *arg)
287 ctfdump_printf(CTFDUMP_LABELS, " %5lu %s\n", li->ctb_typeidx, name);
288 return (0);
291 static void
292 ctfdump_labels(void)
294 ctfdump_title(CTFDUMP_LABELS, "Label Table");
295 if (ctf_label_iter(g_fp, ctfdump_labels_cb, NULL) == CTF_ERR) {
296 ctfdump_warn("failed to dump labels: %s\n",
297 ctf_errmsg(ctf_errno(g_fp)));
298 g_exit = 1;
302 static int
303 ctfdump_strings_cb(const char *s, void *arg)
305 size_t len = strlen(s) + 1;
306 ulong_t *stroff = arg;
307 ctfdump_printf(CTFDUMP_STRINGS, " [%lu] %s\n", *stroff,
308 *s == '\0' ? "\\0" : s);
309 *stroff = *stroff + len;
310 g_stats.cs_nstrings++;
311 g_stats.cs_strsz += len;
312 g_stats.cs_strmax = MAX(g_stats.cs_strmax, len);
313 return (0);
316 static void
317 ctfdump_strings(void)
319 ulong_t stroff = 0;
321 ctfdump_title(CTFDUMP_STRINGS, "String Table");
322 if (ctf_string_iter(g_fp, ctfdump_strings_cb, &stroff) == CTF_ERR) {
323 ctfdump_warn("failed to dump strings: %s\n",
324 ctf_errmsg(ctf_errno(g_fp)));
325 g_exit = 1;
329 static void
330 ctfdump_stat_int(const char *name, ulong_t value)
332 ctfdump_printf(CTFDUMP_STATS, " %-36s= %lu\n", name, value);
335 static void
336 ctfdump_stat_fp(const char *name, float value)
338 ctfdump_printf(CTFDUMP_STATS, " %-36s= %.2f\n", name, value);
341 static void
342 ctfdump_stats(void)
344 int i;
345 ulong_t sum;
347 ctfdump_title(CTFDUMP_STATS, "CTF Statistics");
349 ctfdump_stat_int("total number of data objects", g_stats.cs_ndata);
350 ctfdump_printf(CTFDUMP_STATS, "\n");
351 ctfdump_stat_int("total number of functions", g_stats.cs_nfuncs);
352 ctfdump_stat_int("total number of function arguments",
353 g_stats.cs_nfuncargs);
354 ctfdump_stat_int("maximum argument list length", g_stats.cs_nfuncmax);
355 if (g_stats.cs_nfuncs != 0)
356 ctfdump_stat_fp("average argument list length",
357 (float)g_stats.cs_nfuncargs / (float)g_stats.cs_nfuncs);
358 ctfdump_printf(CTFDUMP_STATS, "\n");
360 sum = 0;
361 for (i = 0; i < CTF_K_MAX; i++)
362 sum += g_stats.cs_ntypes[i];
363 ctfdump_stat_int("total number of types", sum);
364 ctfdump_stat_int("total number of integers",
365 g_stats.cs_ntypes[CTF_K_INTEGER]);
366 ctfdump_stat_int("total number of floats",
367 g_stats.cs_ntypes[CTF_K_FLOAT]);
368 ctfdump_stat_int("total number of pointers",
369 g_stats.cs_ntypes[CTF_K_POINTER]);
370 ctfdump_stat_int("total number of arrays",
371 g_stats.cs_ntypes[CTF_K_ARRAY]);
372 ctfdump_stat_int("total number of func types",
373 g_stats.cs_ntypes[CTF_K_FUNCTION]);
374 ctfdump_stat_int("total number of structs",
375 g_stats.cs_ntypes[CTF_K_STRUCT]);
376 ctfdump_stat_int("total number of unions",
377 g_stats.cs_ntypes[CTF_K_UNION]);
378 ctfdump_stat_int("total number of enums",
379 g_stats.cs_ntypes[CTF_K_ENUM]);
380 ctfdump_stat_int("total number of forward tags",
381 g_stats.cs_ntypes[CTF_K_FORWARD]);
382 ctfdump_stat_int("total number of typedefs",
383 g_stats.cs_ntypes[CTF_K_TYPEDEF]);
384 ctfdump_stat_int("total number of volatile types",
385 g_stats.cs_ntypes[CTF_K_VOLATILE]);
386 ctfdump_stat_int("total number of const types",
387 g_stats.cs_ntypes[CTF_K_CONST]);
388 ctfdump_stat_int("total number of restrict types",
389 g_stats.cs_ntypes[CTF_K_RESTRICT]);
390 ctfdump_stat_int("total number of unknowns (holes)",
391 g_stats.cs_ntypes[CTF_K_UNKNOWN]);
393 ctfdump_printf(CTFDUMP_STATS, "\n");
394 ctfdump_stat_int("total number of struct members", g_stats.cs_nsmembs);
395 ctfdump_stat_int("maximum number of struct members", g_stats.cs_nsmax);
396 ctfdump_stat_int("total size of all structs", g_stats.cs_structsz);
397 ctfdump_stat_int("maximum size of a struct", g_stats.cs_sszmax);
398 if (g_stats.cs_ntypes[CTF_K_STRUCT] != 0) {
399 ctfdump_stat_fp("average number of struct members",
400 (float)g_stats.cs_nsmembs /
401 (float)g_stats.cs_ntypes[CTF_K_STRUCT]);
402 ctfdump_stat_fp("average size of a struct",
403 (float)g_stats.cs_structsz /
404 (float)g_stats.cs_ntypes[CTF_K_STRUCT]);
406 ctfdump_printf(CTFDUMP_STATS, "\n");
407 ctfdump_stat_int("total number of union members", g_stats.cs_numembs);
408 ctfdump_stat_int("maximum number of union members", g_stats.cs_numax);
409 ctfdump_stat_int("total size of all unions", g_stats.cs_unionsz);
410 ctfdump_stat_int("maximum size of a union", g_stats.cs_uszmax);
411 if (g_stats.cs_ntypes[CTF_K_UNION] != 0) {
412 ctfdump_stat_fp("average number of union members",
413 (float)g_stats.cs_numembs /
414 (float)g_stats.cs_ntypes[CTF_K_UNION]);
415 ctfdump_stat_fp("average size of a union",
416 (float)g_stats.cs_unionsz /
417 (float)g_stats.cs_ntypes[CTF_K_UNION]);
419 ctfdump_printf(CTFDUMP_STATS, "\n");
421 ctfdump_stat_int("total number of enum members", g_stats.cs_nemembs);
422 ctfdump_stat_int("maximum number of enum members", g_stats.cs_nemax);
423 if (g_stats.cs_ntypes[CTF_K_ENUM] != 0) {
424 ctfdump_stat_fp("average number of enum members",
425 (float)g_stats.cs_nemembs /
426 (float)g_stats.cs_ntypes[CTF_K_ENUM]);
428 ctfdump_printf(CTFDUMP_STATS, "\n");
430 ctfdump_stat_int("total number of strings", g_stats.cs_nstrings);
431 ctfdump_stat_int("bytes of string data", g_stats.cs_strsz);
432 ctfdump_stat_int("maximum string length", g_stats.cs_strmax);
433 if (g_stats.cs_nstrings != 0)
434 ctfdump_stat_fp("average string length",
435 (float)g_stats.cs_strsz / (float)g_stats.cs_nstrings);
436 ctfdump_printf(CTFDUMP_STATS, "\n");
439 static void
440 ctfdump_intenc_name(ctf_encoding_t *cte, char *buf, int len)
442 int off = 0;
443 boolean_t space = B_FALSE;
445 if (cte->cte_format == 0 || (cte->cte_format &
446 ~(CTF_INT_SIGNED | CTF_INT_CHAR | CTF_INT_BOOL |
447 CTF_INT_VARARGS)) != 0) {
448 (void) snprintf(buf, len, "0x%x", cte->cte_format);
449 return;
452 if (cte->cte_format & CTF_INT_SIGNED) {
453 off += snprintf(buf + off, MAX(len - off, 0), "%sSIGNED",
454 space == B_TRUE ? " " : "");
455 space = B_TRUE;
458 if (cte->cte_format & CTF_INT_CHAR) {
459 off += snprintf(buf + off, MAX(len - off, 0), "%sCHAR",
460 space == B_TRUE ? " " : "");
461 space = B_TRUE;
464 if (cte->cte_format & CTF_INT_BOOL) {
465 off += snprintf(buf + off, MAX(len - off, 0), "%sBOOL",
466 space == B_TRUE ? " " : "");
467 space = B_TRUE;
470 if (cte->cte_format & CTF_INT_VARARGS) {
471 off += snprintf(buf + off, MAX(len - off, 0), "%sVARARGS",
472 space == B_TRUE ? " " : "");
473 space = B_TRUE;
477 static int
478 ctfdump_member_cb(const char *member, ctf_id_t type, ulong_t off, void *arg)
480 int *count = arg;
481 ctfdump_printf(CTFDUMP_TYPES, "\t%s type=%lu off=%lu\n", member, type,
482 off);
483 *count = *count + 1;
484 return (0);
487 static int
488 ctfdump_enum_cb(const char *name, int value, void *arg)
490 int *count = arg;
491 ctfdump_printf(CTFDUMP_TYPES, "\t%s = %d\n", name, value);
492 *count = *count + 1;
493 return (0);
496 static int
497 ctfdump_types_cb(ctf_id_t id, boolean_t root, void *arg)
499 int kind, i, count;
500 ctf_id_t ref;
501 char name[512], ienc[128];
502 const char *encn;
503 ctf_funcinfo_t ctc;
504 ctf_arinfo_t ar;
505 ctf_encoding_t cte;
506 ssize_t size;
508 if ((kind = ctf_type_kind(g_fp, id)) == CTF_ERR)
509 ctfdump_fatal("encountered malformed ctf, type %s does not "
510 "have a kind: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
512 if (ctf_type_name(g_fp, id, name, sizeof (name)) == NULL) {
513 if (ctf_errno(g_fp) != ECTF_NOPARENT)
514 ctfdump_fatal("type %lu missing name: %s\n", id,
515 ctf_errmsg(ctf_errno(g_fp)));
516 (void) snprintf(name, sizeof (name), "(unknown %s)",
517 ctf_kind_name(g_fp, kind));
520 g_stats.cs_ntypes[kind]++;
521 if (root == B_TRUE)
522 ctfdump_printf(CTFDUMP_TYPES, " <%lu> ", id);
523 else
524 ctfdump_printf(CTFDUMP_TYPES, " [%lu] ", id);
526 switch (kind) {
527 case CTF_K_UNKNOWN:
528 break;
529 case CTF_K_INTEGER:
530 if (ctf_type_encoding(g_fp, id, &cte) == CTF_ERR)
531 ctfdump_fatal("failed to get encoding information "
532 "for %s: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
533 ctfdump_intenc_name(&cte, ienc, sizeof (ienc));
534 ctfdump_printf(CTFDUMP_TYPES,
535 "%s encoding=%s offset=%u bits=%u",
536 name, ienc, cte.cte_offset, cte.cte_bits);
537 break;
538 case CTF_K_FLOAT:
539 if (ctf_type_encoding(g_fp, id, &cte) == CTF_ERR)
540 ctfdump_fatal("failed to get encoding information "
541 "for %s: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
542 if (cte.cte_format < 1 || cte.cte_format > 12)
543 encn = "unknown";
544 else
545 encn = ctfdump_fpenc[cte.cte_format];
546 ctfdump_printf(CTFDUMP_TYPES, "%s encoding=%s offset=%u "
547 "bits=%u", name, encn, cte.cte_offset, cte.cte_bits);
548 break;
549 case CTF_K_POINTER:
550 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
551 ctfdump_fatal("failed to get reference type for %s: "
552 "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
553 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %lu", name,
554 ref);
555 break;
556 case CTF_K_ARRAY:
557 if (ctf_array_info(g_fp, id, &ar) == CTF_ERR)
558 ctfdump_fatal("failed to get array information for "
559 "%s: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
560 ctfdump_printf(CTFDUMP_TYPES, "%s contents: %lu, index: %lu",
561 name, ar.ctr_contents, ar.ctr_index);
562 break;
563 case CTF_K_FUNCTION:
564 if (ctf_func_info_by_id(g_fp, id, &ctc) == CTF_ERR)
565 ctfdump_fatal("failed to get function info for %s: "
566 "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
567 if (ctc.ctc_argc > 0) {
568 ctfdump_fargs_grow(ctc.ctc_argc);
569 if (ctf_func_args_by_id(g_fp, id, g_nfargc, g_fargc) ==
570 CTF_ERR)
571 ctfdump_fatal("failed to get function "
572 "arguments for %s: %s\n", name,
573 ctf_errmsg(ctf_errno(g_fp)));
575 ctfdump_printf(CTFDUMP_TYPES,
576 "%s returns: %lu args: (", name, ctc.ctc_return);
577 for (i = 0; i < ctc.ctc_argc; i++) {
578 ctfdump_printf(CTFDUMP_TYPES, "%lu%s", g_fargc[i],
579 i + 1 == ctc.ctc_argc ? "" : ", ");
581 if (ctc.ctc_flags & CTF_FUNC_VARARG)
582 ctfdump_printf(CTFDUMP_TYPES, "%s...",
583 ctc.ctc_argc == 0 ? "" : ", ");
584 ctfdump_printf(CTFDUMP_TYPES, ")");
585 break;
586 case CTF_K_STRUCT:
587 case CTF_K_UNION:
588 size = ctf_type_size(g_fp, id);
589 if (size == CTF_ERR)
590 ctfdump_fatal("failed to get size of %s: %s\n", name,
591 ctf_errmsg(ctf_errno(g_fp)));
592 ctfdump_printf(CTFDUMP_TYPES, "%s (%zd bytes)\n", name, size);
593 count = 0;
594 if (ctf_member_iter(g_fp, id, ctfdump_member_cb, &count) != 0)
595 ctfdump_fatal("failed to iterate members of %s: %s\n",
596 name, ctf_errmsg(ctf_errno(g_fp)));
597 if (kind == CTF_K_STRUCT) {
598 g_stats.cs_nsmembs += count;
599 g_stats.cs_nsmax = MAX(count, g_stats.cs_nsmax);
600 g_stats.cs_structsz += size;
601 g_stats.cs_sszmax = MAX(size, g_stats.cs_sszmax);
602 } else {
603 g_stats.cs_numembs += count;
604 g_stats.cs_numax = MAX(count, g_stats.cs_numax);
605 g_stats.cs_unionsz += size;
606 g_stats.cs_uszmax = MAX(count, g_stats.cs_uszmax);
608 break;
609 case CTF_K_ENUM:
610 ctfdump_printf(CTFDUMP_TYPES, "%s\n", name);
611 count = 0;
612 if (ctf_enum_iter(g_fp, id, ctfdump_enum_cb, &count) != 0)
613 ctfdump_fatal("failed to iterate enumerators of %s: "
614 "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
615 g_stats.cs_nemembs += count;
616 g_stats.cs_nemax = MAX(g_stats.cs_nemax, count);
617 break;
618 case CTF_K_FORWARD:
619 ctfdump_printf(CTFDUMP_TYPES, "forward %s\n", name);
620 break;
621 case CTF_K_TYPEDEF:
622 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
623 ctfdump_fatal("failed to get reference type for %s: "
624 "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
625 ctfdump_printf(CTFDUMP_TYPES, "typedef %s refers to %lu", name,
626 ref);
627 break;
628 case CTF_K_VOLATILE:
629 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
630 ctfdump_fatal("failed to get reference type for %s: "
631 "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
632 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %lu", name,
633 ref);
634 break;
635 case CTF_K_CONST:
636 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
637 ctfdump_fatal("failed to get reference type for %s: "
638 "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
639 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %lu", name,
640 ref);
641 break;
642 case CTF_K_RESTRICT:
643 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
644 ctfdump_fatal("failed to get reference type for %s: "
645 "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
646 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %lu", name,
647 ref);
648 break;
649 default:
650 ctfdump_fatal("encountered unknown kind for type %s: %d\n",
651 name, kind);
654 ctfdump_printf(CTFDUMP_TYPES, "\n");
656 return (0);
659 static void
660 ctfdump_types(void)
662 ctfdump_title(CTFDUMP_TYPES, "Types");
664 if (ctf_type_iter(g_fp, B_TRUE, ctfdump_types_cb, NULL) == CTF_ERR) {
665 ctfdump_warn("failed to dump labels: %s\n",
666 ctf_errmsg(ctf_errno(g_fp)));
667 g_exit = 1;
671 static void
672 ctfdump_output(const char *out)
674 int fd, ret;
675 const void *data;
676 size_t len;
678 ctf_dataptr(g_fp, &data, &len);
679 if ((fd = open(out, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
680 ctfdump_fatal("failed to open output file %s: %s\n", out,
681 strerror(errno));
683 while (len > 0) {
684 ret = write(fd, data, len);
685 if (ret == -1 && errno == EINTR)
686 continue;
687 else if (ret == -1 && (errno == EFAULT || errno == EBADF))
688 abort();
689 else if (ret == -1)
690 ctfdump_fatal("failed to write to %s: %s\n", out,
691 strerror(errno));
692 data += ret;
693 len -= ret;
696 do {
697 ret = close(fd);
698 } while (ret == -1 && errno == EINTR);
699 if (ret != 0 && errno == EBADF)
700 abort();
701 if (ret != 0)
702 ctfdump_fatal("failed to close %s: %s\n", out, strerror(errno));
706 main(int argc, char *argv[])
708 int c, fd, err;
709 const char *ufile = NULL, *parent = NULL;
711 g_progname = basename(argv[0]);
712 while ((c = getopt(argc, argv, ":dfhlp:sStu:")) != -1) {
713 switch (c) {
714 case 'd':
715 g_dump |= CTFDUMP_OBJECTS;
716 break;
717 case 'f':
718 g_dump |= CTFDUMP_FUNCTIONS;
719 break;
720 case 'h':
721 g_dump |= CTFDUMP_HEADER;
722 break;
723 case 'l':
724 g_dump |= CTFDUMP_LABELS;
725 break;
726 case 'p':
727 parent = optarg;
728 break;
729 case 's':
730 g_dump |= CTFDUMP_STRINGS;
731 break;
732 case 'S':
733 g_dump |= CTFDUMP_STATS;
734 break;
735 case 't':
736 g_dump |= CTFDUMP_TYPES;
737 break;
738 case 'u':
739 g_dump |= CTFDUMP_OUTPUT;
740 ufile = optarg;
741 break;
742 case '?':
743 ctfdump_usage("Unknown option: -%c\n", optopt);
744 return (2);
745 case ':':
746 ctfdump_usage("Option -%c requires an operand\n",
747 optopt);
748 return (2);
752 argc -= optind;
753 argv += optind;
756 * Dump all information by default.
758 if (g_dump == 0)
759 g_dump = CTFDUMP_DEFAULT;
761 if (argc != 1) {
762 ctfdump_usage("no file to dump\n");
763 return (2);
766 if ((fd = open(argv[0], O_RDONLY)) < 0)
767 ctfdump_fatal("failed to open file %s: %s\n", argv[0],
768 strerror(errno));
770 g_fp = ctf_fdopen(fd, &err);
771 if (g_fp == NULL)
772 ctfdump_fatal("failed to open file %s: %s\n", argv[0],
773 ctf_errmsg(err));
775 if (parent != NULL) {
776 ctf_file_t *pfp = ctf_open(parent, &err);
778 if (pfp == NULL)
779 ctfdump_fatal("failed to open parent file %s: %s\n",
780 parent, ctf_errmsg(err));
781 if (ctf_import(g_fp, pfp) != 0)
782 ctfdump_fatal("failed to import parent %s: %s\n",
783 parent, ctf_errmsg(ctf_errno(g_fp)));
787 * If stats is set, we must run through everything exect CTFDUMP_OUTPUT.
788 * We also do CTFDUMP_STATS last as a result.
790 if (g_dump & CTFDUMP_HEADER)
791 ctfdump_header();
793 if (g_dump & (CTFDUMP_LABELS | CTFDUMP_STATS))
794 ctfdump_labels();
796 if (g_dump & (CTFDUMP_OBJECTS | CTFDUMP_STATS))
797 ctfdump_objects();
799 if (g_dump & (CTFDUMP_FUNCTIONS | CTFDUMP_STATS))
800 ctfdump_functions();
802 if (g_dump & (CTFDUMP_TYPES | CTFDUMP_STATS))
803 ctfdump_types();
805 if (g_dump & (CTFDUMP_STRINGS | CTFDUMP_STATS))
806 ctfdump_strings();
808 if (g_dump & CTFDUMP_STATS)
809 ctfdump_stats();
811 if (g_dump & CTFDUMP_OUTPUT)
812 ctfdump_output(ufile);
814 return (g_exit);