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 2019, 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 const char * 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 return (ctf_type_name(g_fp, ref, buf, bufsize)); 699 } 700 701 static int 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 printf("\t%s; /* offset: %lu bytes (%lu bits) */\n", 722 name, off / NBBY, off); 723 } else { 724 printf("\t%s; /* offset: %lu bytes */\n", 725 name, off / NBBY); 726 } 727 return (0); 728 } 729 730 static int 731 ctfsrc_enum_cb(const char *name, int value, void *arg) 732 { 733 _NOTE(ARGUNUSED(arg)); 734 printf("\t%s = %d,\n", name, value); 735 return (0); 736 } 737 738 static int 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 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 757 ctfsrc_type(ctf_id_t id, const char *name) 758 { 759 char refname[MAX_NAMELEN] = "unknown_t"; 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 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 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 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 printf("};\n\n"); 809 break; 810 case CTF_K_TYPEDEF: 811 /* 812 * If this fails, it's probably because the referent type is in 813 * a parent container that was not supplied via -p. 814 */ 815 if (ctfsrc_refname(id, refname, sizeof (refname)) == NULL) { 816 printf("typedef %s %s;\n\n", refname, name); 817 break; 818 } 819 820 if (!is_anon_refname(refname)) { 821 (void) ctf_type_cname(g_fp, 822 ctf_type_reference(g_fp, id), refname, 823 sizeof (refname), name); 824 825 printf("typedef %s;\n\n", refname); 826 break; 827 } 828 829 ref = ctf_type_reference(g_fp, id); 830 831 if (ctf_type_kind(g_fp, ref) == CTF_K_ENUM) { 832 printf("typedef enum {\n"); 833 834 if (ctf_enum_iter(g_fp, ref, 835 ctfsrc_enum_cb, NULL) != 0) { 836 ctfdump_fatal("failed to iterate enumerators " 837 "of %s: %s\n", refname, 838 ctf_errmsg(ctf_errno(g_fp))); 839 } 840 841 printf("} %s;\n\n", name); 842 } else { 843 if ((size = ctf_type_size(g_fp, ref)) == CTF_ERR) { 844 ctfdump_fatal("failed to get size of %s: %s\n", 845 refname, ctf_errmsg(ctf_errno(g_fp))); 846 } 847 848 printf("typedef %s{ /* 0x%zx bytes */\n", 849 refname, size); 850 851 if (ctf_member_iter(g_fp, ref, 852 ctfsrc_member_cb, NULL) != 0) { 853 ctfdump_fatal("failed to iterate members " 854 "of %s: %s\n", refname, 855 ctf_errmsg(ctf_errno(g_fp))); 856 } 857 858 printf("} %s;\n\n", name); 859 } 860 861 break; 862 case CTF_K_FORWARD: 863 printf("%s;\n\n", name); 864 break; 865 case CTF_K_UNKNOWN: 866 case CTF_K_INTEGER: 867 case CTF_K_FLOAT: 868 case CTF_K_POINTER: 869 case CTF_K_ARRAY: 870 case CTF_K_FUNCTION: 871 case CTF_K_VOLATILE: 872 case CTF_K_CONST: 873 case CTF_K_RESTRICT: 874 break; 875 default: 876 ctfdump_fatal("encountered unknown kind for type %s: %d\n", 877 name, kind); 878 break; 879 } 880 } 881 882 static int 883 ctfsrc_collect_objects_cb(const char *name, ctf_id_t id, 884 ulong_t symidx, void *arg) 885 { 886 size_t *count = arg; 887 888 /* local static vars can have an unknown ID */ 889 if (id == 0) 890 return (0); 891 892 (void) strlcpy(idnames[*count].ci_name, name, 893 sizeof (idnames[*count].ci_name)); 894 idnames[*count].ci_id = id; 895 idnames[*count].ci_symidx = symidx; 896 *count = *count + 1; 897 return (0); 898 } 899 900 static void 901 ctfsrc_object(ctf_id_t id, const char *name) 902 { 903 char tname[MAX_NAMELEN]; 904 905 if (ctf_type_cname(g_fp, id, tname, sizeof (tname), name) == NULL) { 906 if (ctf_errno(g_fp) != ECTF_NOPARENT) { 907 ctfdump_fatal("type %ld missing name: %s\n", id, 908 ctf_errmsg(ctf_errno(g_fp))); 909 } 910 (void) snprintf(tname, sizeof (tname), "unknown_t %s", name); 911 } 912 913 printf("extern %s;\n", tname); 914 } 915 916 static int 917 ctfsrc_collect_functions_cb(const char *name, ulong_t symidx, 918 ctf_funcinfo_t *ctc, void *arg) 919 { 920 size_t *count = arg; 921 922 (void) strlcpy(idnames[*count].ci_name, name, 923 sizeof (idnames[*count].ci_name)); 924 bcopy(ctc, &idnames[*count].ci_funcinfo, sizeof (*ctc)); 925 idnames[*count].ci_id = 0; 926 idnames[*count].ci_symidx = symidx; 927 *count = *count + 1; 928 return (0); 929 } 930 931 static void 932 ctfsrc_function(ctf_idname_t *idn) 933 { 934 ctf_funcinfo_t *cfi = &idn->ci_funcinfo; 935 char name[MAX_NAMELEN] = "unknown_t"; 936 937 (void) ctf_type_name(g_fp, cfi->ctc_return, name, sizeof (name)); 938 939 printf("extern %s %s(", name, idn->ci_name); 940 941 if (cfi->ctc_argc != 0) { 942 ctfdump_fargs_grow(cfi->ctc_argc); 943 if (ctf_func_args(g_fp, idn->ci_symidx, 944 g_nfargc, g_fargc) == CTF_ERR) { 945 ctfdump_fatal("failed to get arguments for function " 946 "%s: %s\n", idn->ci_name, 947 ctf_errmsg(ctf_errno(g_fp))); 948 } 949 950 for (size_t i = 0; i < cfi->ctc_argc; i++) { 951 ctf_id_t aid = g_fargc[i]; 952 953 (void) strlcpy(name, "unknown_t", sizeof (name)); 954 955 (void) ctf_type_name(g_fp, aid, name, sizeof (name)); 956 957 printf("%s%s", name, 958 i + 1 == cfi->ctc_argc ? "" : ", "); 959 } 960 } else { 961 if (!(cfi->ctc_flags & CTF_FUNC_VARARG)) 962 printf("void"); 963 } 964 965 if (cfi->ctc_flags & CTF_FUNC_VARARG) 966 printf("%s...", cfi->ctc_argc == 0 ? "" : ", "); 967 968 printf(");\n"); 969 } 970 971 static int 972 idname_compare(const void *lhs, const void *rhs) 973 { 974 return (strcmp(((ctf_idname_t *)lhs)->ci_name, 975 ((ctf_idname_t *)rhs)->ci_name)); 976 } 977 978 static void 979 ctfdump_source(void) 980 { 981 ulong_t nr_syms = ctf_nr_syms(g_fp); 982 ctf_id_t max_id = ctf_max_id(g_fp); 983 size_t count = 0; 984 985 printf("/* Types */\n\n"); 986 987 if ((idnames = calloc(max_id + 1, sizeof (idnames[0]))) == NULL) { 988 ctfdump_fatal("failed to alloc idnames: %s\n", 989 strerror(errno)); 990 } 991 992 /* 993 * Prep for any unknown types (most likely, they exist in the parent, 994 * but we weren't given the -p option). 995 */ 996 for (size_t i = 0; i <= max_id; i++) { 997 (void) strlcpy(idnames[i].ci_name, "unknown_t", 998 sizeof (idnames[i].ci_name)); 999 } 1000 1001 if (ctf_type_iter(g_fp, B_TRUE, ctfsrc_collect_types_cb, 1002 idnames) == CTF_ERR) { 1003 warnx("failed to collect types: %s", 1004 ctf_errmsg(ctf_errno(g_fp))); 1005 g_exit = 1; 1006 } 1007 1008 qsort(idnames, max_id, sizeof (ctf_idname_t), idname_compare); 1009 1010 for (size_t i = 0; i <= max_id; i++) { 1011 if (idnames[i].ci_id != 0) 1012 ctfsrc_type(idnames[i].ci_id, idnames[i].ci_name); 1013 } 1014 1015 free(idnames); 1016 1017 printf("\n\n/* Data Objects */\n\n"); 1018 1019 if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) { 1020 ctfdump_fatal("failed to alloc idnames: %s\n", 1021 strerror(errno)); 1022 } 1023 1024 if (ctf_object_iter(g_fp, ctfsrc_collect_objects_cb, 1025 &count) == CTF_ERR) { 1026 warnx("failed to collect objects: %s", 1027 ctf_errmsg(ctf_errno(g_fp))); 1028 g_exit = 1; 1029 } 1030 1031 qsort(idnames, count, sizeof (ctf_idname_t), idname_compare); 1032 1033 for (size_t i = 0; i < count; i++) 1034 ctfsrc_object(idnames[i].ci_id, idnames[i].ci_name); 1035 1036 free(idnames); 1037 1038 printf("\n\n/* Functions */\n\n"); 1039 1040 if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) { 1041 ctfdump_fatal("failed to alloc idnames: %s\n", 1042 strerror(errno)); 1043 } 1044 1045 count = 0; 1046 1047 if (ctf_function_iter(g_fp, ctfsrc_collect_functions_cb, 1048 &count) == CTF_ERR) { 1049 warnx("failed to collect functions: %s", 1050 ctf_errmsg(ctf_errno(g_fp))); 1051 g_exit = 1; 1052 } 1053 1054 qsort(idnames, count, sizeof (ctf_idname_t), idname_compare); 1055 1056 for (size_t i = 0; i < count; i++) 1057 ctfsrc_function(&idnames[i]); 1058 1059 free(idnames); 1060 } 1061 1062 static void 1063 ctfdump_output(const char *out) 1064 { 1065 int fd, ret; 1066 const void *data; 1067 size_t len; 1068 1069 ctf_dataptr(g_fp, &data, &len); 1070 if ((fd = open(out, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) 1071 ctfdump_fatal("failed to open output file %s: %s\n", out, 1072 strerror(errno)); 1073 1074 while (len > 0) { 1075 ret = write(fd, data, len); 1076 if (ret == -1 && errno == EINTR) 1077 continue; 1078 else if (ret == -1 && (errno == EFAULT || errno == EBADF)) 1079 abort(); 1080 else if (ret == -1) 1081 ctfdump_fatal("failed to write to %s: %s\n", out, 1082 strerror(errno)); 1083 data = ((char *)data) + ret; 1084 len -= ret; 1085 } 1086 1087 do { 1088 ret = close(fd); 1089 } while (ret == -1 && errno == EINTR); 1090 if (ret != 0 && errno == EBADF) 1091 abort(); 1092 if (ret != 0) 1093 ctfdump_fatal("failed to close %s: %s\n", out, strerror(errno)); 1094 } 1095 1096 int 1097 main(int argc, char *argv[]) 1098 { 1099 int c, fd, err; 1100 const char *ufile = NULL, *parent = NULL; 1101 1102 g_progname = basename(argv[0]); 1103 while ((c = getopt(argc, argv, ":cdfhlp:sStu:")) != -1) { 1104 switch (c) { 1105 case 'c': 1106 g_dump |= CTFDUMP_SOURCE; 1107 break; 1108 case 'd': 1109 g_dump |= CTFDUMP_OBJECTS; 1110 break; 1111 case 'f': 1112 g_dump |= CTFDUMP_FUNCTIONS; 1113 break; 1114 case 'h': 1115 g_dump |= CTFDUMP_HEADER; 1116 break; 1117 case 'l': 1118 g_dump |= CTFDUMP_LABELS; 1119 break; 1120 case 'p': 1121 parent = optarg; 1122 break; 1123 case 's': 1124 g_dump |= CTFDUMP_STRINGS; 1125 break; 1126 case 'S': 1127 g_dump |= CTFDUMP_STATS; 1128 break; 1129 case 't': 1130 g_dump |= CTFDUMP_TYPES; 1131 break; 1132 case 'u': 1133 g_dump |= CTFDUMP_OUTPUT; 1134 ufile = optarg; 1135 break; 1136 case '?': 1137 ctfdump_usage("Unknown option: -%c\n", optopt); 1138 return (2); 1139 case ':': 1140 ctfdump_usage("Option -%c requires an operand\n", 1141 optopt); 1142 return (2); 1143 } 1144 } 1145 1146 argc -= optind; 1147 argv += optind; 1148 1149 if ((g_dump & CTFDUMP_SOURCE) && !!(g_dump & ~CTFDUMP_SOURCE)) { 1150 ctfdump_usage("-c must be specified on its own\n"); 1151 return (2); 1152 } 1153 1154 /* 1155 * Dump all information except C source by default. 1156 */ 1157 if (g_dump == 0) 1158 g_dump = CTFDUMP_DEFAULT; 1159 1160 if (argc != 1) { 1161 ctfdump_usage("no file to dump\n"); 1162 return (2); 1163 } 1164 1165 if ((fd = open(argv[0], O_RDONLY)) < 0) 1166 ctfdump_fatal("failed to open file %s: %s\n", argv[0], 1167 strerror(errno)); 1168 1169 g_fp = ctf_fdopen(fd, &err); 1170 if (g_fp == NULL) 1171 ctfdump_fatal("failed to open file %s: %s\n", argv[0], 1172 ctf_errmsg(err)); 1173 1174 /* 1175 * Check to see if this file needs a parent. If it does not and we were 1176 * given one, that should be an error. If it does need one and the 1177 * parent is not specified, that is fine, we just won't know how to 1178 * find child types. If we are given a parent, check at least that the 1179 * labels match. 1180 */ 1181 if (ctf_parent_name(g_fp) == NULL) { 1182 if (parent != NULL) 1183 ctfdump_fatal("cannot use %s as a parent file, %s is " 1184 "not a child\n", parent, argv[0]); 1185 } else if (parent != NULL) { 1186 const char *explabel, *label; 1187 ctf_file_t *pfp = ctf_open(parent, &err); 1188 1189 if (pfp == NULL) 1190 ctfdump_fatal("failed to open parent file %s: %s\n", 1191 parent, ctf_errmsg(err)); 1192 1193 /* 1194 * Before we import the parent into the child, check that the 1195 * labels match. While there is also the notion of the parent 1196 * name, it's less straightforward to match that. Require that 1197 * labels match. 1198 */ 1199 explabel = ctf_parent_label(g_fp); 1200 label = ctf_label_topmost(pfp); 1201 if (explabel == NULL || label == NULL || 1202 strcmp(explabel, label) != 0) { 1203 if (label == NULL) 1204 label = "<missing>"; 1205 if (explabel == NULL) 1206 explabel = "<missing>"; 1207 ctfdump_fatal("label mismatch between parent %s and " 1208 "child %s, parent has %s, child expects %s\n", 1209 parent, argv[0], label, explabel); 1210 } 1211 1212 if (ctf_import(g_fp, pfp) != 0) 1213 ctfdump_fatal("failed to import parent %s: %s\n", 1214 parent, ctf_errmsg(ctf_errno(g_fp))); 1215 } else { 1216 if (g_dump & CTFDUMP_SOURCE) { 1217 printf("/* Warning: parent \"%s\" not supplied: many " 1218 "types will be unknown. */\n\n", 1219 ctf_parent_name(g_fp)); 1220 } else { 1221 fprintf(stderr, "warning: parent \"%s\" not supplied: " 1222 "many types will be unknown\n\n", 1223 ctf_parent_name(g_fp)); 1224 } 1225 } 1226 1227 if (g_dump & CTFDUMP_SOURCE) { 1228 ctfdump_source(); 1229 return (0); 1230 } 1231 1232 /* 1233 * If stats is set, we must run through everything exect CTFDUMP_OUTPUT. 1234 * We also do CTFDUMP_STATS last as a result. 1235 */ 1236 if (g_dump & CTFDUMP_HEADER) 1237 ctfdump_header(); 1238 1239 if (g_dump & (CTFDUMP_LABELS | CTFDUMP_STATS)) 1240 ctfdump_labels(); 1241 1242 if (g_dump & (CTFDUMP_OBJECTS | CTFDUMP_STATS)) 1243 ctfdump_objects(); 1244 1245 if (g_dump & (CTFDUMP_FUNCTIONS | CTFDUMP_STATS)) 1246 ctfdump_functions(); 1247 1248 if (g_dump & (CTFDUMP_TYPES | CTFDUMP_STATS)) 1249 ctfdump_types(); 1250 1251 if (g_dump & (CTFDUMP_STRINGS | CTFDUMP_STATS)) 1252 ctfdump_strings(); 1253 1254 if (g_dump & CTFDUMP_STATS) 1255 ctfdump_stats(); 1256 1257 if (g_dump & CTFDUMP_OUTPUT) 1258 ctfdump_output(ufile); 1259 1260 return (g_exit); 1261 } 1262