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 */ 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 __NORETURN 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 size = ctf_type_size(g_fp, id); 617 618 /* Only the oddest enums are worth reporting on size. */ 619 if (size != CTF_ERR && size != sizeof (int)) { 620 ctfdump_printf(CTFDUMP_TYPES, "%s (%zd bytes)\n", 621 name, size); 622 } else { 623 ctfdump_printf(CTFDUMP_TYPES, "%s\n", name); 624 } 625 626 count = 0; 627 if (ctf_enum_iter(g_fp, id, ctfdump_enum_cb, &count) != 0) 628 ctfdump_fatal("failed to iterate enumerators of %s: " 629 "%s\n", name, ctf_errmsg(ctf_errno(g_fp))); 630 g_stats.cs_nemembs += count; 631 g_stats.cs_nemax = MAX(g_stats.cs_nemax, count); 632 break; 633 case CTF_K_FORWARD: 634 ctfdump_printf(CTFDUMP_TYPES, "forward %s\n", name); 635 break; 636 case CTF_K_TYPEDEF: 637 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) 638 ctfdump_fatal("failed to get reference type for %s: " 639 "%s\n", name, ctf_errmsg(ctf_errno(g_fp))); 640 ctfdump_printf(CTFDUMP_TYPES, "typedef %s refers to %ld", name, 641 ref); 642 break; 643 case CTF_K_VOLATILE: 644 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) 645 ctfdump_fatal("failed to get reference type for %s: " 646 "%s\n", name, ctf_errmsg(ctf_errno(g_fp))); 647 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name, 648 ref); 649 break; 650 case CTF_K_CONST: 651 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) 652 ctfdump_fatal("failed to get reference type for %s: " 653 "%s\n", name, ctf_errmsg(ctf_errno(g_fp))); 654 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name, 655 ref); 656 break; 657 case CTF_K_RESTRICT: 658 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) 659 ctfdump_fatal("failed to get reference type for %s: " 660 "%s\n", name, ctf_errmsg(ctf_errno(g_fp))); 661 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name, 662 ref); 663 break; 664 default: 665 ctfdump_fatal("encountered unknown kind for type %s: %d\n", 666 name, kind); 667 } 668 669 ctfdump_printf(CTFDUMP_TYPES, "\n"); 670 671 return (0); 672 } 673 674 static void 675 ctfdump_types(void) 676 { 677 ctfdump_title(CTFDUMP_TYPES, "Types"); 678 679 if (ctf_type_iter(g_fp, B_TRUE, ctfdump_types_cb, NULL) == CTF_ERR) { 680 warnx("failed to dump types: %s", 681 ctf_errmsg(ctf_errno(g_fp))); 682 g_exit = 1; 683 } 684 } 685 686 /* 687 * C-style output. This is designed mainly for comparison purposes, and doesn't 688 * produce directly valid C: 689 * 690 * - the declarations are sorted alphabetically not semantically 691 * - anonymous enums without other users are elided (e.g. IDCS_PROBE_SENT) 692 * - doubly-pointed-to functions are wrong (e.g. in kiconv_ops_t) 693 * - anon unions declared within SOUs aren't expanded 694 * - function arguments aren't expanded recursively 695 */ 696 697 static const char * 698 ctfsrc_refname(ctf_id_t id, char *buf, size_t bufsize) 699 { 700 ctf_id_t ref; 701 702 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) { 703 ctfdump_fatal("failed to get reference type for %ld: " 704 "%s\n", id, ctf_errmsg(ctf_errno(g_fp))); 705 } 706 707 return (ctf_type_name(g_fp, ref, buf, bufsize)); 708 } 709 710 static int 711 ctfsrc_member_cb(const char *member, ctf_id_t type, ulong_t off, void *arg) 712 { 713 _NOTE(ARGUNUSED(arg)); 714 char name[MAX_NAMELEN]; 715 716 if (ctf_type_cname(g_fp, type, name, sizeof (name), member) == NULL) { 717 if (ctf_errno(g_fp) != ECTF_NOPARENT) { 718 ctfdump_fatal("type %ld missing name: %s\n", type, 719 ctf_errmsg(ctf_errno(g_fp))); 720 } 721 722 (void) snprintf(name, sizeof (name), "unknown_t %s", member); 723 } 724 725 /* 726 * A byte offset is friendlier, but we'll print bits too if it's not 727 * aligned (i.e. a bitfield). 728 */ 729 if (off % NBBY != 0) { 730 printf("\t%s; /* offset: %lu bytes (%lu bits) */\n", 731 name, off / NBBY, off); 732 } else { 733 printf("\t%s; /* offset: %lu bytes */\n", 734 name, off / NBBY); 735 } 736 return (0); 737 } 738 739 static int 740 ctfsrc_enum_cb(const char *name, int value, void *arg) 741 { 742 _NOTE(ARGUNUSED(arg)); 743 printf("\t%s = %d,\n", name, value); 744 return (0); 745 } 746 747 static int 748 is_anon_refname(const char *refname) 749 { 750 return ((strcmp(refname, "struct ") == 0 || 751 strcmp(refname, "union ") == 0 || 752 strcmp(refname, "enum ") == 0)); 753 } 754 755 static int 756 ctfsrc_collect_types_cb(ctf_id_t id, boolean_t root, void *arg) 757 { 758 _NOTE(ARGUNUSED(root, arg)); 759 (void) ctf_type_name(g_fp, id, idnames[id].ci_name, 760 sizeof (idnames[id].ci_name)); 761 idnames[id].ci_id = id; 762 return (0); 763 } 764 765 static void 766 ctfsrc_type(ctf_id_t id, const char *name) 767 { 768 char refname[MAX_NAMELEN] = "unknown_t"; 769 ctf_id_t ref; 770 ssize_t size; 771 int kind; 772 773 if ((kind = ctf_type_kind(g_fp, id)) == CTF_ERR) { 774 ctfdump_fatal("encountered malformed ctf, type %s does not " 775 "have a kind: %s\n", name, ctf_errmsg(ctf_errno(g_fp))); 776 } 777 778 switch (kind) { 779 case CTF_K_STRUCT: 780 case CTF_K_UNION: 781 /* 782 * Delay printing anonymous SOUs; a later typedef will usually 783 * pick them up. 784 */ 785 if (is_anon_refname(name)) 786 break; 787 788 if ((size = ctf_type_size(g_fp, id)) == CTF_ERR) { 789 ctfdump_fatal("failed to get size of %s: %s\n", name, 790 ctf_errmsg(ctf_errno(g_fp))); 791 } 792 793 printf("%s { /* 0x%x bytes */\n", name, size); 794 795 if (ctf_member_iter(g_fp, id, ctfsrc_member_cb, NULL) != 0) { 796 ctfdump_fatal("failed to iterate members of %s: %s\n", 797 name, ctf_errmsg(ctf_errno(g_fp))); 798 } 799 800 printf("};\n\n"); 801 break; 802 case CTF_K_ENUM: 803 /* 804 * This will throw away any anon enum that isn't followed by a 805 * typedef... 806 */ 807 if (is_anon_refname(name)) 808 break; 809 810 printf("%s {\n", name); 811 812 if (ctf_enum_iter(g_fp, id, ctfsrc_enum_cb, NULL) != 0) { 813 ctfdump_fatal("failed to iterate enumerators of %s: " 814 "%s\n", name, ctf_errmsg(ctf_errno(g_fp))); 815 } 816 817 size = ctf_type_size(g_fp, id); 818 819 /* Only the oddest enums are worth reporting on size. */ 820 if (size != CTF_ERR && size != sizeof (int)) { 821 printf("} /* 0x%x bytes */;\n\n", size); 822 } else { 823 printf("};\n\n"); 824 } 825 break; 826 case CTF_K_TYPEDEF: 827 /* 828 * If this fails, it's probably because the referent type is in 829 * a parent container that was not supplied via -p. 830 */ 831 if (ctfsrc_refname(id, refname, sizeof (refname)) == NULL) { 832 printf("typedef %s %s;\n\n", refname, name); 833 break; 834 } 835 836 if (!is_anon_refname(refname)) { 837 (void) ctf_type_cname(g_fp, 838 ctf_type_reference(g_fp, id), refname, 839 sizeof (refname), name); 840 841 printf("typedef %s;\n\n", refname); 842 break; 843 } 844 845 ref = ctf_type_reference(g_fp, id); 846 847 if (ctf_type_kind(g_fp, ref) == CTF_K_ENUM) { 848 printf("typedef enum {\n"); 849 850 if (ctf_enum_iter(g_fp, ref, 851 ctfsrc_enum_cb, NULL) != 0) { 852 ctfdump_fatal("failed to iterate enumerators " 853 "of %s: %s\n", refname, 854 ctf_errmsg(ctf_errno(g_fp))); 855 } 856 857 printf("} %s;\n\n", name); 858 } else { 859 if ((size = ctf_type_size(g_fp, ref)) == CTF_ERR) { 860 ctfdump_fatal("failed to get size of %s: %s\n", 861 refname, ctf_errmsg(ctf_errno(g_fp))); 862 } 863 864 printf("typedef %s{ /* 0x%zx bytes */\n", 865 refname, size); 866 867 if (ctf_member_iter(g_fp, ref, 868 ctfsrc_member_cb, NULL) != 0) { 869 ctfdump_fatal("failed to iterate members " 870 "of %s: %s\n", refname, 871 ctf_errmsg(ctf_errno(g_fp))); 872 } 873 874 printf("} %s;\n\n", name); 875 } 876 877 break; 878 case CTF_K_FORWARD: 879 printf("%s;\n\n", name); 880 break; 881 case CTF_K_UNKNOWN: 882 case CTF_K_INTEGER: 883 case CTF_K_FLOAT: 884 case CTF_K_POINTER: 885 case CTF_K_ARRAY: 886 case CTF_K_FUNCTION: 887 case CTF_K_VOLATILE: 888 case CTF_K_CONST: 889 case CTF_K_RESTRICT: 890 break; 891 default: 892 ctfdump_fatal("encountered unknown kind for type %s: %d\n", 893 name, kind); 894 break; 895 } 896 } 897 898 static int 899 ctfsrc_collect_objects_cb(const char *name, ctf_id_t id, 900 ulong_t symidx, void *arg) 901 { 902 size_t *count = arg; 903 904 /* local static vars can have an unknown ID */ 905 if (id == 0) 906 return (0); 907 908 (void) strlcpy(idnames[*count].ci_name, name, 909 sizeof (idnames[*count].ci_name)); 910 idnames[*count].ci_id = id; 911 idnames[*count].ci_symidx = symidx; 912 *count = *count + 1; 913 return (0); 914 } 915 916 static void 917 ctfsrc_object(ctf_id_t id, const char *name) 918 { 919 char tname[MAX_NAMELEN]; 920 921 if (ctf_type_cname(g_fp, id, tname, sizeof (tname), name) == NULL) { 922 if (ctf_errno(g_fp) != ECTF_NOPARENT) { 923 ctfdump_fatal("type %ld missing name: %s\n", id, 924 ctf_errmsg(ctf_errno(g_fp))); 925 } 926 (void) snprintf(tname, sizeof (tname), "unknown_t %s", name); 927 } 928 929 printf("extern %s;\n", tname); 930 } 931 932 static int 933 ctfsrc_collect_functions_cb(const char *name, ulong_t symidx, 934 ctf_funcinfo_t *ctc, void *arg) 935 { 936 size_t *count = arg; 937 938 (void) strlcpy(idnames[*count].ci_name, name, 939 sizeof (idnames[*count].ci_name)); 940 bcopy(ctc, &idnames[*count].ci_funcinfo, sizeof (*ctc)); 941 idnames[*count].ci_id = 0; 942 idnames[*count].ci_symidx = symidx; 943 *count = *count + 1; 944 return (0); 945 } 946 947 static void 948 ctfsrc_function(ctf_idname_t *idn) 949 { 950 ctf_funcinfo_t *cfi = &idn->ci_funcinfo; 951 char name[MAX_NAMELEN] = "unknown_t"; 952 953 (void) ctf_type_name(g_fp, cfi->ctc_return, name, sizeof (name)); 954 955 printf("extern %s %s(", name, idn->ci_name); 956 957 if (cfi->ctc_argc != 0) { 958 ctfdump_fargs_grow(cfi->ctc_argc); 959 if (ctf_func_args(g_fp, idn->ci_symidx, 960 g_nfargc, g_fargc) == CTF_ERR) { 961 ctfdump_fatal("failed to get arguments for function " 962 "%s: %s\n", idn->ci_name, 963 ctf_errmsg(ctf_errno(g_fp))); 964 } 965 966 for (size_t i = 0; i < cfi->ctc_argc; i++) { 967 ctf_id_t aid = g_fargc[i]; 968 969 (void) strlcpy(name, "unknown_t", sizeof (name)); 970 971 (void) ctf_type_name(g_fp, aid, name, sizeof (name)); 972 973 printf("%s%s", name, 974 i + 1 == cfi->ctc_argc ? "" : ", "); 975 } 976 } else { 977 if (!(cfi->ctc_flags & CTF_FUNC_VARARG)) 978 printf("void"); 979 } 980 981 if (cfi->ctc_flags & CTF_FUNC_VARARG) 982 printf("%s...", cfi->ctc_argc == 0 ? "" : ", "); 983 984 printf(");\n"); 985 } 986 987 static int 988 idname_compare(const void *lhs, const void *rhs) 989 { 990 int ret; 991 char lname[MAX_NAMELEN] = {0}; 992 char rname[MAX_NAMELEN] = {0}; 993 const ctf_idname_t *l = lhs; 994 const ctf_idname_t *r = rhs; 995 uint_t arity = 0; 996 997 if ((ret = strcmp(l->ci_name, r->ci_name)) != 0) 998 return (ret); 999 1000 /* If the names match, try arity */ 1001 if (l->ci_funcinfo.ctc_argc < r->ci_funcinfo.ctc_argc) 1002 return (-1); 1003 else if (l->ci_funcinfo.ctc_argc > r->ci_funcinfo.ctc_argc) 1004 return (1); 1005 else 1006 arity = l->ci_funcinfo.ctc_argc; 1007 1008 /* If arity doesn't help, try return type */ 1009 (void) strlcpy(lname, "unknown_t", sizeof (lname)); 1010 (void) strlcpy(rname, "unknown_t", sizeof (rname)); 1011 (void) ctf_type_name(g_fp, l->ci_funcinfo.ctc_return, lname, 1012 sizeof (lname)); 1013 (void) ctf_type_name(g_fp, r->ci_funcinfo.ctc_return, rname, 1014 sizeof (rname)); 1015 1016 if ((ret = strcmp(lname, rname)) != 0) 1017 return (ret); 1018 1019 /* if return type doesn't help, try parameter types */ 1020 if (arity == 0) 1021 return (0); 1022 1023 ctf_id_t *largs = calloc(arity, sizeof (ctf_id_t)); 1024 ctf_id_t *rargs = calloc(arity, sizeof (ctf_id_t)); 1025 1026 if ((largs == NULL) || (rargs == NULL)) { 1027 free(rargs); 1028 free(largs); 1029 ctfdump_fatal("failed to alloc argument ids for sorting: " 1030 " %s\n", strerror(errno)); 1031 } 1032 1033 if (ctf_func_args(g_fp, l->ci_symidx, arity, largs) == CTF_ERR) { 1034 free(rargs); 1035 free(largs); 1036 ctfdump_fatal("failed to get arguments for function " 1037 "%s: %s\n", l->ci_name, 1038 ctf_errmsg(ctf_errno(g_fp))); 1039 } 1040 1041 if (ctf_func_args(g_fp, r->ci_symidx, arity, rargs) == CTF_ERR) { 1042 free(rargs); 1043 free(largs); 1044 ctfdump_fatal("failed to get arguments for function " 1045 "%s: %s\n", r->ci_name, 1046 ctf_errmsg(ctf_errno(g_fp))); 1047 } 1048 1049 for (uint_t i = 0; i < arity; i++) { 1050 (void) strlcpy(lname, "unknown_t", sizeof (lname)); 1051 (void) ctf_type_name(g_fp, largs[i], lname, sizeof (lname)); 1052 1053 (void) strlcpy(rname, "unknown_t", sizeof (rname)); 1054 (void) ctf_type_name(g_fp, rargs[i], rname, sizeof (rname)); 1055 1056 if ((ret = strcmp(lname, rname)) != 0) { 1057 free(rargs); 1058 free(largs); 1059 return (ret); 1060 } 1061 } 1062 1063 free(rargs); 1064 free(largs); 1065 return (0); 1066 } 1067 1068 static void 1069 ctfdump_source(void) 1070 { 1071 ulong_t nr_syms = ctf_nr_syms(g_fp); 1072 ctf_id_t max_id = ctf_max_id(g_fp); 1073 size_t count = 0; 1074 1075 printf("/* Types */\n\n"); 1076 1077 if ((idnames = calloc(max_id + 1, sizeof (idnames[0]))) == NULL) { 1078 ctfdump_fatal("failed to alloc idnames: %s\n", 1079 strerror(errno)); 1080 } 1081 1082 /* 1083 * Prep for any unknown types (most likely, they exist in the parent, 1084 * but we weren't given the -p option). 1085 */ 1086 for (size_t i = 0; i <= max_id; i++) { 1087 (void) strlcpy(idnames[i].ci_name, "unknown_t", 1088 sizeof (idnames[i].ci_name)); 1089 } 1090 1091 if (ctf_type_iter(g_fp, B_TRUE, ctfsrc_collect_types_cb, 1092 idnames) == CTF_ERR) { 1093 warnx("failed to collect types: %s", 1094 ctf_errmsg(ctf_errno(g_fp))); 1095 g_exit = 1; 1096 } 1097 1098 qsort(idnames, max_id, sizeof (ctf_idname_t), idname_compare); 1099 1100 for (size_t i = 0; i <= max_id; i++) { 1101 if (idnames[i].ci_id != 0) 1102 ctfsrc_type(idnames[i].ci_id, idnames[i].ci_name); 1103 } 1104 1105 free(idnames); 1106 1107 printf("\n\n/* Data Objects */\n\n"); 1108 1109 if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) { 1110 ctfdump_fatal("failed to alloc idnames: %s\n", 1111 strerror(errno)); 1112 } 1113 1114 if (ctf_object_iter(g_fp, ctfsrc_collect_objects_cb, 1115 &count) == CTF_ERR) { 1116 warnx("failed to collect objects: %s", 1117 ctf_errmsg(ctf_errno(g_fp))); 1118 g_exit = 1; 1119 } 1120 1121 qsort(idnames, count, sizeof (ctf_idname_t), idname_compare); 1122 1123 for (size_t i = 0; i < count; i++) 1124 ctfsrc_object(idnames[i].ci_id, idnames[i].ci_name); 1125 1126 free(idnames); 1127 1128 printf("\n\n/* Functions */\n\n"); 1129 1130 if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) { 1131 ctfdump_fatal("failed to alloc idnames: %s\n", 1132 strerror(errno)); 1133 } 1134 1135 count = 0; 1136 1137 if (ctf_function_iter(g_fp, ctfsrc_collect_functions_cb, 1138 &count) == CTF_ERR) { 1139 warnx("failed to collect functions: %s", 1140 ctf_errmsg(ctf_errno(g_fp))); 1141 g_exit = 1; 1142 } 1143 1144 qsort(idnames, count, sizeof (ctf_idname_t), idname_compare); 1145 1146 for (size_t i = 0; i < count; i++) 1147 ctfsrc_function(&idnames[i]); 1148 1149 free(idnames); 1150 } 1151 1152 static void 1153 ctfdump_output(const char *out) 1154 { 1155 int fd, ret; 1156 const void *data; 1157 size_t len; 1158 1159 ctf_dataptr(g_fp, &data, &len); 1160 if ((fd = open(out, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) 1161 ctfdump_fatal("failed to open output file %s: %s\n", out, 1162 strerror(errno)); 1163 1164 while (len > 0) { 1165 ret = write(fd, data, len); 1166 if (ret == -1 && errno == EINTR) 1167 continue; 1168 else if (ret == -1 && (errno == EFAULT || errno == EBADF)) 1169 abort(); 1170 else if (ret == -1) 1171 ctfdump_fatal("failed to write to %s: %s\n", out, 1172 strerror(errno)); 1173 data = ((char *)data) + ret; 1174 len -= ret; 1175 } 1176 1177 do { 1178 ret = close(fd); 1179 } while (ret == -1 && errno == EINTR); 1180 if (ret != 0 && errno == EBADF) 1181 abort(); 1182 if (ret != 0) 1183 ctfdump_fatal("failed to close %s: %s\n", out, strerror(errno)); 1184 } 1185 1186 int 1187 main(int argc, char *argv[]) 1188 { 1189 int c, fd, err; 1190 const char *ufile = NULL, *parent = NULL; 1191 1192 g_progname = basename(argv[0]); 1193 while ((c = getopt(argc, argv, ":cdfhlp:sStu:")) != -1) { 1194 switch (c) { 1195 case 'c': 1196 g_dump |= CTFDUMP_SOURCE; 1197 break; 1198 case 'd': 1199 g_dump |= CTFDUMP_OBJECTS; 1200 break; 1201 case 'f': 1202 g_dump |= CTFDUMP_FUNCTIONS; 1203 break; 1204 case 'h': 1205 g_dump |= CTFDUMP_HEADER; 1206 break; 1207 case 'l': 1208 g_dump |= CTFDUMP_LABELS; 1209 break; 1210 case 'p': 1211 parent = optarg; 1212 break; 1213 case 's': 1214 g_dump |= CTFDUMP_STRINGS; 1215 break; 1216 case 'S': 1217 g_dump |= CTFDUMP_STATS; 1218 break; 1219 case 't': 1220 g_dump |= CTFDUMP_TYPES; 1221 break; 1222 case 'u': 1223 g_dump |= CTFDUMP_OUTPUT; 1224 ufile = optarg; 1225 break; 1226 case '?': 1227 ctfdump_usage("Unknown option: -%c\n", optopt); 1228 return (2); 1229 case ':': 1230 ctfdump_usage("Option -%c requires an operand\n", 1231 optopt); 1232 return (2); 1233 } 1234 } 1235 1236 argc -= optind; 1237 argv += optind; 1238 1239 if ((g_dump & CTFDUMP_SOURCE) && !!(g_dump & ~CTFDUMP_SOURCE)) { 1240 ctfdump_usage("-c must be specified on its own\n"); 1241 return (2); 1242 } 1243 1244 /* 1245 * Dump all information except C source by default. 1246 */ 1247 if (g_dump == 0) 1248 g_dump = CTFDUMP_DEFAULT; 1249 1250 if (argc != 1) { 1251 ctfdump_usage("no file to dump\n"); 1252 return (2); 1253 } 1254 1255 if ((fd = open(argv[0], O_RDONLY)) < 0) 1256 ctfdump_fatal("failed to open file %s: %s\n", argv[0], 1257 strerror(errno)); 1258 1259 g_fp = ctf_fdopen(fd, &err); 1260 if (g_fp == NULL) 1261 ctfdump_fatal("failed to open file %s: %s\n", argv[0], 1262 ctf_errmsg(err)); 1263 1264 /* 1265 * Check to see if this file needs a parent. If it does not and we were 1266 * given one, that should be an error. If it does need one and the 1267 * parent is not specified, that is fine, we just won't know how to 1268 * find child types. If we are given a parent, check at least that the 1269 * labels match. 1270 */ 1271 if (ctf_parent_name(g_fp) == NULL) { 1272 if (parent != NULL) 1273 ctfdump_fatal("cannot use %s as a parent file, %s is " 1274 "not a child\n", parent, argv[0]); 1275 } else if (parent != NULL) { 1276 const char *explabel, *label; 1277 ctf_file_t *pfp = ctf_open(parent, &err); 1278 1279 if (pfp == NULL) 1280 ctfdump_fatal("failed to open parent file %s: %s\n", 1281 parent, ctf_errmsg(err)); 1282 1283 /* 1284 * Before we import the parent into the child, check that the 1285 * labels match. While there is also the notion of the parent 1286 * name, it's less straightforward to match that. Require that 1287 * labels match. 1288 */ 1289 explabel = ctf_parent_label(g_fp); 1290 label = ctf_label_topmost(pfp); 1291 if (explabel == NULL || label == NULL || 1292 strcmp(explabel, label) != 0) { 1293 if (label == NULL) 1294 label = "<missing>"; 1295 if (explabel == NULL) 1296 explabel = "<missing>"; 1297 ctfdump_fatal("label mismatch between parent %s and " 1298 "child %s, parent has %s, child expects %s\n", 1299 parent, argv[0], label, explabel); 1300 } 1301 1302 if (ctf_import(g_fp, pfp) != 0) 1303 ctfdump_fatal("failed to import parent %s: %s\n", 1304 parent, ctf_errmsg(ctf_errno(g_fp))); 1305 } else { 1306 if (g_dump & CTFDUMP_SOURCE) { 1307 printf("/* Warning: parent \"%s\" not supplied: many " 1308 "types will be unknown. */\n\n", 1309 ctf_parent_name(g_fp)); 1310 } else { 1311 fprintf(stderr, "warning: parent \"%s\" not supplied: " 1312 "many types will be unknown\n\n", 1313 ctf_parent_name(g_fp)); 1314 } 1315 } 1316 1317 if (g_dump & CTFDUMP_SOURCE) { 1318 ctfdump_source(); 1319 return (0); 1320 } 1321 1322 /* 1323 * If stats is set, we must run through everything exect CTFDUMP_OUTPUT. 1324 * We also do CTFDUMP_STATS last as a result. 1325 */ 1326 if (g_dump & CTFDUMP_HEADER) 1327 ctfdump_header(); 1328 1329 if (g_dump & (CTFDUMP_LABELS | CTFDUMP_STATS)) 1330 ctfdump_labels(); 1331 1332 if (g_dump & (CTFDUMP_OBJECTS | CTFDUMP_STATS)) 1333 ctfdump_objects(); 1334 1335 if (g_dump & (CTFDUMP_FUNCTIONS | CTFDUMP_STATS)) 1336 ctfdump_functions(); 1337 1338 if (g_dump & (CTFDUMP_TYPES | CTFDUMP_STATS)) 1339 ctfdump_types(); 1340 1341 if (g_dump & (CTFDUMP_STRINGS | CTFDUMP_STATS)) 1342 ctfdump_strings(); 1343 1344 if (g_dump & CTFDUMP_STATS) 1345 ctfdump_stats(); 1346 1347 if (g_dump & CTFDUMP_OUTPUT) 1348 ctfdump_output(ufile); 1349 1350 return (g_exit); 1351 } 1352