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