const char * mdb_strerror(int err) { static char buf[256]; const char *str; if (err >= EMDB_BASE && (err - EMDB_BASE) < _mdb_nerr) str = _mdb_errlist[err - EMDB_BASE]; else str = strerror(err); switch (err) { case EMDB_PARTIAL: (void) mdb_iob_snprintf(buf, sizeof (buf), str, errno_rbytes, errno_nbytes); str = buf; break; #ifndef _KMDB case EMDB_RTLD_DB: if (rd_errstr(errno_rtld_db) != NULL) str = rd_errstr(errno_rtld_db); break; #endif case EMDB_CTF: if (ctf_errmsg(errno_libctf) != NULL) str = ctf_errmsg(errno_libctf); break; } return (str ? str : "unknown error"); }
static int ctfdump_functions_cb(const char *name, ulong_t symidx, ctf_funcinfo_t *ctc, void *arg) { int i; if (ctc->ctc_argc != 0) { ctfdump_fargs_grow(ctc->ctc_argc); if (ctf_func_args(g_fp, symidx, g_nfargc, g_fargc) == CTF_ERR) ctfdump_fatal("failed to get arguments for function " "%s: %s\n", name, ctf_errmsg(ctf_errno(g_fp))); } ctfdump_printf(CTFDUMP_FUNCTIONS, " [%lu] %s (%lu) returns: %u args: (", g_stats.cs_nfuncs, name, symidx, ctc->ctc_return); for (i = 0; i < ctc->ctc_argc; i++) ctfdump_printf(CTFDUMP_FUNCTIONS, "%lu%s", g_fargc[i], i + 1 == ctc->ctc_argc ? "" : ", "); if (ctc->ctc_flags & CTF_FUNC_VARARG) ctfdump_printf(CTFDUMP_FUNCTIONS, "%s...", ctc->ctc_argc == 0 ? "" : ", "); ctfdump_printf(CTFDUMP_FUNCTIONS, ")\n"); g_stats.cs_nfuncs++; g_stats.cs_nfuncargs += ctc->ctc_argc; g_stats.cs_nfuncmax = MAX(ctc->ctc_argc, g_stats.cs_nfuncmax); return (0); }
static int ctfsrc_member_cb(const char *member, ctf_id_t type, ulong_t off, void *arg) { _NOTE(ARGUNUSED(arg)); char name[MAX_NAMELEN]; if (ctf_type_cname(g_fp, type, name, sizeof (name), member) == NULL) { if (ctf_errno(g_fp) != ECTF_NOPARENT) { ctfdump_fatal("type %ld missing name: %s\n", type, ctf_errmsg(ctf_errno(g_fp))); } (void) snprintf(name, sizeof (name), "unknown_t %s", member); } /* * A byte offset is friendlier, but we'll print bits too if it's not * aligned (i.e. a bitfield). */ if (off % NBBY != 0) { (void) printf("\t%s; /* offset: %lu bytes (%lu bits) */\n", name, off / NBBY, off); } else { (void) printf("\t%s; /* offset: %lu bytes */\n", name, off / NBBY); } return (0); }
int main(int argc, char **argv) { Elf *elf; ctf_file_t *ctfp; int errp, fd; if (ctf_version(CTF_VERSION) == -1) errx(1, "mismatched libctf versions\n"); if (elf_version(EV_CURRENT) == EV_NONE) errx(1, "mismatched libelf versions\n"); if (argc != 2) errx(2, "usage: %s <file>\n", __progname); if ((ctfp = ctf_open(argv[1], &errp)) == NULL) errx(1, "failed to ctf_open file: %s: %s\n", argv[1], ctf_errmsg(errp)); if ((fd = open(argv[1], O_RDONLY)) == -1) errx(1, "could not open %s\n", argv[1]); if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) errx(1, "could not interpret ELF from %s\n", argv[1]); walk_symtab(elf, argv[1], ctfp, check_sym); (void) elf_end(elf); (void) close(fd); return (0); }
static void ctfdump_labels(void) { ctfdump_title(CTFDUMP_LABELS, "Label Table"); if (ctf_label_iter(g_fp, ctfdump_labels_cb, NULL) == CTF_ERR) { ctfdump_warn("failed to dump labels: %s\n", ctf_errmsg(ctf_errno(g_fp))); g_exit = 1; } }
static void ctfdump_objects(void) { ctfdump_title(CTFDUMP_OBJECTS, "Data Objects"); if (ctf_object_iter(g_fp, ctfdump_objects_cb, NULL) == CTF_ERR) { ctfdump_warn("failed to dump objects: %s\n", ctf_errmsg(ctf_errno(g_fp))); g_exit = 1; } }
static void ctfdump_functions(void) { ctfdump_title(CTFDUMP_FUNCTIONS, "Functions"); if (ctf_function_iter(g_fp, ctfdump_functions_cb, NULL) == CTF_ERR) { ctfdump_warn("failed to dump functions: %s\n", ctf_errmsg(ctf_errno(g_fp))); g_exit = 1; } }
static void ctfdump_types(void) { ctfdump_title(CTFDUMP_TYPES, "Types"); if (ctf_type_iter(g_fp, B_TRUE, ctfdump_types_cb, NULL) == CTF_ERR) { ctfdump_warn("failed to dump labels: %s\n", ctf_errmsg(ctf_errno(g_fp))); g_exit = 1; } }
static void ctfsrc_refname(ctf_id_t id, char *buf, size_t bufsize) { ctf_id_t ref; if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) { ctfdump_fatal("failed to get reference type for %ld: " "%s\n", id, ctf_errmsg(ctf_errno(g_fp))); } (void) ctf_type_name(g_fp, ref, buf, bufsize); }
static void ctfdump_strings(void) { ulong_t stroff = 0; ctfdump_title(CTFDUMP_STRINGS, "String Table"); if (ctf_string_iter(g_fp, ctfdump_strings_cb, &stroff) == CTF_ERR) { ctfdump_warn("failed to dump strings: %s\n", ctf_errmsg(ctf_errno(g_fp))); g_exit = 1; } }
static void ctfsrc_object(ctf_id_t id, const char *name) { char tname[MAX_NAMELEN]; if (ctf_type_cname(g_fp, id, tname, sizeof (tname), name) == NULL) { if (ctf_errno(g_fp) != ECTF_NOPARENT) { ctfdump_fatal("type %ld missing name: %s\n", id, ctf_errmsg(ctf_errno(g_fp))); } (void) snprintf(tname, sizeof (tname), "unknown_t %s", name); } (void) printf("extern %s;\n", tname); }
void kctl_mod_loaded(struct modctl *modp) { int rc; mutex_enter(&mod_lock); if (modp->mod_mp == NULL) { mutex_exit(&mod_lock); return; } if ((rc = kctl_mod_decompress(modp)) != 0) { cmn_err(CE_WARN, "failed to decompress CTF data for %s: %s\n", modp->mod_modname, ctf_errmsg(rc)); } mutex_exit(&mod_lock); if (!(kmdb_kdi_get_flags() & KMDB_KDI_FL_NOMODS)) kctl_dmod_autoload(modp->mod_modname); }
const char * dtrace_errmsg(dtrace_hdl_t *dtp, int error) { const char *str; int i; if (error == EDT_COMPILER && dtp != NULL && dtp->dt_errmsg[0] != '\0') str = dtp->dt_errmsg; else if (error == EDT_CTF && dtp != NULL && dtp->dt_ctferr != 0) str = ctf_errmsg(dtp->dt_ctferr); else if (error >= EDT_BASE && (error - EDT_BASE) < _dt_nerr) { for (i = 0; i < _dt_nerr; i++) { if (_dt_errlist[i].err == error) return (_dt_errlist[i].msg); } str = NULL; } else str = strerror(error); return (str ? str : "Unknown error"); }
static void ctfsrc_function(ctf_idname_t *idn) { ctf_funcinfo_t *cfi = &idn->ci_funcinfo; char name[MAX_NAMELEN] = "unknown_t"; (void) ctf_type_name(g_fp, cfi->ctc_return, name, sizeof (name)); (void) printf("extern %s %s(", name, idn->ci_name); if (cfi->ctc_argc != 0) { ctfdump_fargs_grow(cfi->ctc_argc); if (ctf_func_args(g_fp, idn->ci_symidx, g_nfargc, g_fargc) == CTF_ERR) { ctfdump_fatal("failed to get arguments for function " "%s: %s\n", idn->ci_name, ctf_errmsg(ctf_errno(g_fp))); } for (size_t i = 0; i < cfi->ctc_argc; i++) { ctf_id_t aid = g_fargc[i]; name[0] = '\0'; (void) ctf_type_name(g_fp, aid, name, sizeof (name)); (void) printf("%s%s", name, i + 1 == cfi->ctc_argc ? "" : ", "); } } else { if (!(cfi->ctc_flags & CTF_FUNC_VARARG)) (void) printf("void"); } if (cfi->ctc_flags & CTF_FUNC_VARARG) (void) printf("%s...", cfi->ctc_argc == 0 ? "" : ", "); (void) printf(");\n"); }
/* * Lookup the dynamic translator type tag for the specified probe argument and * assign the type to the specified node. If the type is not yet defined, add * it to the "D" module's type container as a typedef for an unknown type. */ dt_node_t * dt_probe_tag(dt_probe_t *prp, uint_t argn, dt_node_t *dnp) { dtrace_hdl_t *dtp = prp->pr_pvp->pv_hdl; dtrace_typeinfo_t dtt; size_t len; char *tag; len = snprintf(NULL, 0, "__dtrace_%s___%s_arg%u", prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn); tag = alloca(len + 1); (void) snprintf(tag, len + 1, "__dtrace_%s___%s_arg%u", prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn); if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_DDEFS, tag, &dtt) != 0) { dtt.dtt_object = DTRACE_OBJ_DDEFS; dtt.dtt_ctfp = DT_DYN_CTFP(dtp); dtt.dtt_type = ctf_add_typedef(DT_DYN_CTFP(dtp), CTF_ADD_ROOT, tag, DT_DYN_TYPE(dtp)); if (dtt.dtt_type == CTF_ERR || ctf_update(dtt.dtt_ctfp) == CTF_ERR) { xyerror(D_UNKNOWN, "cannot define type %s: %s\n", tag, ctf_errmsg(ctf_errno(dtt.dtt_ctfp))); } } bzero(dnp, sizeof (dt_node_t)); dnp->dn_kind = DT_NODE_TYPE; dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE); dt_node_attr_assign(dnp, _dtrace_defattr); return (dnp); }
int main(int argc, char *argv[]) { int c, fd, err; const char *ufile = NULL, *parent = NULL; g_progname = basename(argv[0]); while ((c = getopt(argc, argv, ":cdfhlp:sStu:")) != -1) { switch (c) { case 'c': g_dump |= CTFDUMP_SOURCE; break; case 'd': g_dump |= CTFDUMP_OBJECTS; break; case 'f': g_dump |= CTFDUMP_FUNCTIONS; break; case 'h': g_dump |= CTFDUMP_HEADER; break; case 'l': g_dump |= CTFDUMP_LABELS; break; case 'p': parent = optarg; break; case 's': g_dump |= CTFDUMP_STRINGS; break; case 'S': g_dump |= CTFDUMP_STATS; break; case 't': g_dump |= CTFDUMP_TYPES; break; case 'u': g_dump |= CTFDUMP_OUTPUT; ufile = optarg; break; case '?': ctfdump_usage("Unknown option: -%c\n", optopt); return (2); case ':': ctfdump_usage("Option -%c requires an operand\n", optopt); return (2); } } argc -= optind; argv += optind; if ((g_dump & CTFDUMP_SOURCE) && !!(g_dump & ~CTFDUMP_SOURCE)) { ctfdump_usage("-c must be specified on its own\n"); return (2); } /* * Dump all information except C source by default. */ if (g_dump == 0) g_dump = CTFDUMP_DEFAULT; if (argc != 1) { ctfdump_usage("no file to dump\n"); return (2); } if ((fd = open(argv[0], O_RDONLY)) < 0) ctfdump_fatal("failed to open file %s: %s\n", argv[0], strerror(errno)); g_fp = ctf_fdopen(fd, &err); if (g_fp == NULL) ctfdump_fatal("failed to open file %s: %s\n", argv[0], ctf_errmsg(err)); /* * Check to see if this file needs a parent. If it does not and we were * given one, that should be an error. If it does need one and the * parent is not specified, that is fine, we just won't know how to * find child types. If we are given a parent, check at least that the * labels match. */ if (ctf_parent_name(g_fp) == NULL) { if (parent != NULL) ctfdump_fatal("cannot use %s as a parent file, %s is " "not a child\n", parent, argv[0]); } else if (parent != NULL) { const char *explabel, *label; ctf_file_t *pfp = ctf_open(parent, &err); if (pfp == NULL) ctfdump_fatal("failed to open parent file %s: %s\n", parent, ctf_errmsg(err)); /* * Before we import the parent into the child, check that the * labels match. While there is also the notion of the parent * name, it's less straightforward to match that. Require that * labels match. */ explabel = ctf_parent_label(g_fp); label = ctf_label_topmost(pfp); if (explabel == NULL || label == NULL || strcmp(explabel, label) != 0) { if (label == NULL) label = "<missing>"; if (explabel == NULL) explabel = "<missing>"; ctfdump_fatal("label mismatch between parent %s and " "child %s, parent has %s, child expects %s\n", parent, argv[0], label, explabel); } if (ctf_import(g_fp, pfp) != 0) ctfdump_fatal("failed to import parent %s: %s\n", parent, ctf_errmsg(ctf_errno(g_fp))); } if (g_dump & CTFDUMP_SOURCE) { ctfdump_source(); return (0); } /* * If stats is set, we must run through everything exect CTFDUMP_OUTPUT. * We also do CTFDUMP_STATS last as a result. */ if (g_dump & CTFDUMP_HEADER) ctfdump_header(); if (g_dump & (CTFDUMP_LABELS | CTFDUMP_STATS)) ctfdump_labels(); if (g_dump & (CTFDUMP_OBJECTS | CTFDUMP_STATS)) ctfdump_objects(); if (g_dump & (CTFDUMP_FUNCTIONS | CTFDUMP_STATS)) ctfdump_functions(); if (g_dump & (CTFDUMP_TYPES | CTFDUMP_STATS)) ctfdump_types(); if (g_dump & (CTFDUMP_STRINGS | CTFDUMP_STATS)) ctfdump_strings(); if (g_dump & CTFDUMP_STATS) ctfdump_stats(); if (g_dump & CTFDUMP_OUTPUT) ctfdump_output(ufile); return (g_exit); }
int main(int argc, char *argv[]) { int c, fd, err; const char *ufile = NULL, *parent = NULL; g_progname = basename(argv[0]); while ((c = getopt(argc, argv, ":dfhlp:sStu:")) != -1) { switch (c) { case 'd': g_dump |= CTFDUMP_OBJECTS; break; case 'f': g_dump |= CTFDUMP_FUNCTIONS; break; case 'h': g_dump |= CTFDUMP_HEADER; break; case 'l': g_dump |= CTFDUMP_LABELS; break; case 'p': parent = optarg; break; case 's': g_dump |= CTFDUMP_STRINGS; break; case 'S': g_dump |= CTFDUMP_STATS; break; case 't': g_dump |= CTFDUMP_TYPES; break; case 'u': g_dump |= CTFDUMP_OUTPUT; ufile = optarg; break; case '?': ctfdump_usage("Unknown option: -%c\n", optopt); return (2); case ':': ctfdump_usage("Option -%c requires an operand\n", optopt); return (2); } } argc -= optind; argv += optind; /* * Dump all information by default. */ if (g_dump == 0) g_dump = CTFDUMP_DEFAULT; if (argc != 1) { ctfdump_usage("no file to dump\n"); return (2); } if ((fd = open(argv[0], O_RDONLY)) < 0) ctfdump_fatal("failed to open file %s: %s\n", argv[0], strerror(errno)); g_fp = ctf_fdopen(fd, &err); if (g_fp == NULL) ctfdump_fatal("failed to open file %s: %s\n", argv[0], ctf_errmsg(err)); if (parent != NULL) { ctf_file_t *pfp = ctf_open(parent, &err); if (pfp == NULL) ctfdump_fatal("failed to open parent file %s: %s\n", parent, ctf_errmsg(err)); if (ctf_import(g_fp, pfp) != 0) ctfdump_fatal("failed to import parent %s: %s\n", parent, ctf_errmsg(ctf_errno(g_fp))); } /* * If stats is set, we must run through everything exect CTFDUMP_OUTPUT. * We also do CTFDUMP_STATS last as a result. */ if (g_dump & CTFDUMP_HEADER) ctfdump_header(); if (g_dump & (CTFDUMP_LABELS | CTFDUMP_STATS)) ctfdump_labels(); if (g_dump & (CTFDUMP_OBJECTS | CTFDUMP_STATS)) ctfdump_objects(); if (g_dump & (CTFDUMP_FUNCTIONS | CTFDUMP_STATS)) ctfdump_functions(); if (g_dump & (CTFDUMP_TYPES | CTFDUMP_STATS)) ctfdump_types(); if (g_dump & (CTFDUMP_STRINGS | CTFDUMP_STATS)) ctfdump_strings(); if (g_dump & CTFDUMP_STATS) ctfdump_stats(); if (g_dump & CTFDUMP_OUTPUT) ctfdump_output(ufile); return (g_exit); }
static void ctfsrc_type(ctf_id_t id, const char *name) { char refname[MAX_NAMELEN]; ctf_id_t ref; ssize_t size; int kind; if ((kind = ctf_type_kind(g_fp, id)) == CTF_ERR) { ctfdump_fatal("encountered malformed ctf, type %s does not " "have a kind: %s\n", name, ctf_errmsg(ctf_errno(g_fp))); } switch (kind) { case CTF_K_STRUCT: case CTF_K_UNION: /* * Delay printing anonymous SOUs; a later typedef will usually * pick them up. */ if (is_anon_refname(name)) break; if ((size = ctf_type_size(g_fp, id)) == CTF_ERR) { ctfdump_fatal("failed to get size of %s: %s\n", name, ctf_errmsg(ctf_errno(g_fp))); } (void) printf("%s { /* 0x%x bytes */\n", name, size); if (ctf_member_iter(g_fp, id, ctfsrc_member_cb, NULL) != 0) { ctfdump_fatal("failed to iterate members of %s: %s\n", name, ctf_errmsg(ctf_errno(g_fp))); } (void) printf("};\n\n"); break; case CTF_K_ENUM: /* * This will throw away any anon enum that isn't followed by a * typedef... */ if (is_anon_refname(name)) break; (void) printf("%s {\n", name); if (ctf_enum_iter(g_fp, id, ctfsrc_enum_cb, NULL) != 0) { ctfdump_fatal("failed to iterate enumerators of %s: " "%s\n", name, ctf_errmsg(ctf_errno(g_fp))); } (void) printf("};\n\n"); break; case CTF_K_TYPEDEF: ctfsrc_refname(id, refname, sizeof (refname)); if (!is_anon_refname(refname)) { (void) ctf_type_cname(g_fp, ctf_type_reference(g_fp, id), refname, sizeof (refname), name); (void) printf("typedef %s;\n\n", refname); break; } ref = ctf_type_reference(g_fp, id); if (ctf_type_kind(g_fp, ref) == CTF_K_ENUM) { (void) printf("typedef enum {\n"); if (ctf_enum_iter(g_fp, ref, ctfsrc_enum_cb, NULL) != 0) { ctfdump_fatal("failed to iterate enumerators " "of %s: %s\n", refname, ctf_errmsg(ctf_errno(g_fp))); } (void) printf("} %s;\n\n", name); } else { if ((size = ctf_type_size(g_fp, ref)) == CTF_ERR) { ctfdump_fatal("failed to get size of %s: %s\n", refname, ctf_errmsg(ctf_errno(g_fp))); } (void) printf("typedef %s{ /* 0x%zx bytes */\n", refname, size); if (ctf_member_iter(g_fp, ref, ctfsrc_member_cb, NULL) != 0) { ctfdump_fatal("failed to iterate members " "of %s: %s\n", refname, ctf_errmsg(ctf_errno(g_fp))); } (void) printf("} %s;\n\n", name); } break; case CTF_K_FORWARD: (void) printf("%s;\n\n", name); break; case CTF_K_UNKNOWN: case CTF_K_INTEGER: case CTF_K_FLOAT: case CTF_K_POINTER: case CTF_K_ARRAY: case CTF_K_FUNCTION: case CTF_K_VOLATILE: case CTF_K_CONST: case CTF_K_RESTRICT: break; default: ctfdump_fatal("encountered unknown kind for type %s: %d\n", name, kind); break; } }
static int ctfdump_types_cb(ctf_id_t id, boolean_t root, void *arg) { int kind, i, count; ctf_id_t ref; char name[512], ienc[128]; const char *encn; ctf_funcinfo_t ctc; ctf_arinfo_t ar; ctf_encoding_t cte; ssize_t size; if ((kind = ctf_type_kind(g_fp, id)) == CTF_ERR) ctfdump_fatal("encountered malformed ctf, type %s does not " "have a kind: %s\n", name, ctf_errmsg(ctf_errno(g_fp))); if (ctf_type_name(g_fp, id, name, sizeof (name)) == NULL) { if (ctf_errno(g_fp) != ECTF_NOPARENT) ctfdump_fatal("type %lu missing name: %s\n", id, ctf_errmsg(ctf_errno(g_fp))); (void) snprintf(name, sizeof (name), "(unknown %s)", ctf_kind_name(g_fp, kind)); } g_stats.cs_ntypes[kind]++; if (root == B_TRUE) ctfdump_printf(CTFDUMP_TYPES, " <%lu> ", id); else ctfdump_printf(CTFDUMP_TYPES, " [%lu] ", id); switch (kind) { case CTF_K_UNKNOWN: break; case CTF_K_INTEGER: if (ctf_type_encoding(g_fp, id, &cte) == CTF_ERR) ctfdump_fatal("failed to get encoding information " "for %s: %s\n", name, ctf_errmsg(ctf_errno(g_fp))); ctfdump_intenc_name(&cte, ienc, sizeof (ienc)); ctfdump_printf(CTFDUMP_TYPES, "%s encoding=%s offset=%u bits=%u", name, ienc, cte.cte_offset, cte.cte_bits); break; case CTF_K_FLOAT: if (ctf_type_encoding(g_fp, id, &cte) == CTF_ERR) ctfdump_fatal("failed to get encoding information " "for %s: %s\n", name, ctf_errmsg(ctf_errno(g_fp))); if (cte.cte_format < 1 || cte.cte_format > 12) encn = "unknown"; else encn = ctfdump_fpenc[cte.cte_format]; ctfdump_printf(CTFDUMP_TYPES, "%s encoding=%s offset=%u " "bits=%u", name, encn, cte.cte_offset, cte.cte_bits); break; case CTF_K_POINTER: if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) ctfdump_fatal("failed to get reference type for %s: " "%s\n", name, ctf_errmsg(ctf_errno(g_fp))); ctfdump_printf(CTFDUMP_TYPES, "%s refers to %lu", name, ref); break; case CTF_K_ARRAY: if (ctf_array_info(g_fp, id, &ar) == CTF_ERR) ctfdump_fatal("failed to get array information for " "%s: %s\n", name, ctf_errmsg(ctf_errno(g_fp))); ctfdump_printf(CTFDUMP_TYPES, "%s contents: %lu, index: %lu", name, ar.ctr_contents, ar.ctr_index); break; case CTF_K_FUNCTION: if (ctf_func_info_by_id(g_fp, id, &ctc) == CTF_ERR) ctfdump_fatal("failed to get function info for %s: " "%s\n", name, ctf_errmsg(ctf_errno(g_fp))); if (ctc.ctc_argc > 0) { ctfdump_fargs_grow(ctc.ctc_argc); if (ctf_func_args_by_id(g_fp, id, g_nfargc, g_fargc) == CTF_ERR) ctfdump_fatal("failed to get function " "arguments for %s: %s\n", name, ctf_errmsg(ctf_errno(g_fp))); } ctfdump_printf(CTFDUMP_TYPES, "%s returns: %lu args: (", name, ctc.ctc_return); for (i = 0; i < ctc.ctc_argc; i++) { ctfdump_printf(CTFDUMP_TYPES, "%lu%s", g_fargc[i], i + 1 == ctc.ctc_argc ? "" : ", "); } if (ctc.ctc_flags & CTF_FUNC_VARARG) ctfdump_printf(CTFDUMP_TYPES, "%s...", ctc.ctc_argc == 0 ? "" : ", "); ctfdump_printf(CTFDUMP_TYPES, ")"); break; case CTF_K_STRUCT: case CTF_K_UNION: size = ctf_type_size(g_fp, id); if (size == CTF_ERR) ctfdump_fatal("failed to get size of %s: %s\n", name, ctf_errmsg(ctf_errno(g_fp))); ctfdump_printf(CTFDUMP_TYPES, "%s (%d bytes)\n", name, size); count = 0; if (ctf_member_iter(g_fp, id, ctfdump_member_cb, &count) != 0) ctfdump_fatal("failed to iterate members of %s: %s\n", name, ctf_errmsg(ctf_errno(g_fp))); if (kind == CTF_K_STRUCT) { g_stats.cs_nsmembs += count; g_stats.cs_nsmax = MAX(count, g_stats.cs_nsmax); g_stats.cs_structsz += size; g_stats.cs_sszmax = MAX(size, g_stats.cs_sszmax); } else { g_stats.cs_numembs += count; g_stats.cs_numax = MAX(count, g_stats.cs_numax); g_stats.cs_unionsz += size; g_stats.cs_uszmax = MAX(count, g_stats.cs_uszmax); } break; case CTF_K_ENUM: ctfdump_printf(CTFDUMP_TYPES, "%s\n", name); count = 0; if (ctf_enum_iter(g_fp, id, ctfdump_enum_cb, &count) != 0) ctfdump_fatal("failed to iterate enumerators of %s: " "%s\n", name, ctf_errmsg(ctf_errno(g_fp))); g_stats.cs_nemembs += count; g_stats.cs_nemax = MAX(g_stats.cs_nemax, count); break; case CTF_K_FORWARD: ctfdump_printf(CTFDUMP_TYPES, "forward %s\n", name); break; case CTF_K_TYPEDEF: if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) ctfdump_fatal("failed to get reference type for %s: " "%s\n", name, ctf_errmsg(ctf_errno(g_fp))); ctfdump_printf(CTFDUMP_TYPES, "typedef %s refers to %lu", name, ref); break; case CTF_K_VOLATILE: if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) ctfdump_fatal("failed to get reference type for %s: " "%s\n", name, ctf_errmsg(ctf_errno(g_fp))); ctfdump_printf(CTFDUMP_TYPES, "%s refers to %lu", name, ref); break; case CTF_K_CONST: if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) ctfdump_fatal("failed to get reference type for %s: " "%s\n", name, ctf_errmsg(ctf_errno(g_fp))); ctfdump_printf(CTFDUMP_TYPES, "%s refers to %lu", name, ref); break; case CTF_K_RESTRICT: if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) ctfdump_fatal("failed to get reference type for %s: " "%s\n", name, ctf_errmsg(ctf_errno(g_fp))); ctfdump_printf(CTFDUMP_TYPES, "%s refers to %lu", name, ref); break; default: ctfdump_fatal("encountered unknown kind for type %s: %d\n", name, kind); } ctfdump_printf(CTFDUMP_TYPES, "\n"); return (0); }
static void ctfdump_source(void) { ulong_t nr_syms = ctf_nr_syms(g_fp); ctf_id_t max_id = ctf_max_id(g_fp); size_t count = 0; (void) printf("/* Types */\n\n"); if ((idnames = calloc(max_id + 1, sizeof (idnames[0]))) == NULL) { ctfdump_fatal("failed to alloc idnames: %s\n", strerror(errno)); } if (ctf_type_iter(g_fp, B_FALSE, ctfsrc_collect_types_cb, idnames) == CTF_ERR) { warnx("failed to collect types: %s", ctf_errmsg(ctf_errno(g_fp))); g_exit = 1; } qsort(idnames, max_id, sizeof (ctf_idname_t), idname_compare); for (size_t i = 0; i < max_id; i++) { if (idnames[i].ci_id != 0) ctfsrc_type(idnames[i].ci_id, idnames[i].ci_name); } free(idnames); (void) printf("\n\n/* Data Objects */\n\n"); if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) { ctfdump_fatal("failed to alloc idnames: %s\n", strerror(errno)); } if (ctf_object_iter(g_fp, ctfsrc_collect_objects_cb, &count) == CTF_ERR) { warnx("failed to collect objects: %s", ctf_errmsg(ctf_errno(g_fp))); g_exit = 1; } qsort(idnames, count, sizeof (ctf_idname_t), idname_compare); for (size_t i = 0; i < count; i++) ctfsrc_object(idnames[i].ci_id, idnames[i].ci_name); free(idnames); (void) printf("\n\n/* Functions */\n\n"); if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) { ctfdump_fatal("failed to alloc idnames: %s\n", strerror(errno)); } count = 0; if (ctf_function_iter(g_fp, ctfsrc_collect_functions_cb, &count) == CTF_ERR) { warnx("failed to collect functions: %s", ctf_errmsg(ctf_errno(g_fp))); g_exit = 1; } qsort(idnames, count, sizeof (ctf_idname_t), idname_compare); for (size_t i = 0; i < count; i++) ctfsrc_function(&idnames[i]); free(idnames); }
/* * Begin a macro. * * Once we figure out the type of the thing that we're supposed to dump (struct, * union, or enum), we select the proper type-specific ops-vector for dumping. */ static int fth_section_init(char *fullname) { ctf_id_t ltid = 0, tid; char *curtype, *lpart, *part, *npart; int lkind = 0, kind; curtype = xstrdup(fullname); lpart = NULL; part = strtok(fullname, "."); /* * First figure out what sort of type we're looking at. Life would be * simple if we were only going to get type names, but it's not - we * could also get `type.member'. In that case, we need to figure out * (and dump) the type of `member' instead. */ for (;;) { if (lpart == NULL) { /* First part - the struct name */ if ((tid = find_type(part)) == CTF_ERR || (tid = ctf_type_resolve(ctf, tid)) == CTF_ERR || (kind = ctf_type_kind(ctf, tid)) == CTF_ERR) { free(curtype); return (parse_warn("Couldn't find %s: %s", part, ctf_errmsg(ctf_errno(ctf)))); } } else { /* Second (or more) part - the member name */ if (lkind != CTF_K_STRUCT && lkind != CTF_K_UNION) { free(curtype); return (parse_warn("%s isn't a struct/union", lpart)); } if ((tid = find_member(ltid, part)) <= 0) { free(curtype); return (parse_warn("%s isn't a member of %s", part, lpart)); } if ((kind = ctf_type_kind(ctf, tid)) == CTF_ERR) { free(curtype); return (parse_warn("Can't get kind for %s", part)); } } /* * Stop if there aren't any more parts. We use `npart' here * because we don't want to clobber part - we need it later. */ if ((npart = strtok(NULL, ".")) == NULL) break; lpart = part; ltid = tid; lkind = kind; part = npart; } /* * Pick the right ops vector for dumping. */ switch (kind) { case CTF_K_STRUCT: case CTF_K_UNION: fth_type_ops = &fth_struct_ops; break; case CTF_K_ENUM: fth_type_ops = &fth_enum_ops; break; default: fth_type_ops = &fth_null_ops; free(curtype); return (parse_warn("%s isn't a struct, union, or enum", part)); } fth_curtype = curtype; return (fth_type_ops->fto_header(tid)); }