Print this page
10823 should ignore DW_TAG_subprogram with DW_AT_declaration tags
10824 GCC7-derived CTF can double qualifiers on arrays
10825 ctfdump -c drops last type
10826 ctfdump -c goes off the rails with a missing parent
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Jason King <jason.king@joyent.com>
Approved by: Jerry Jelinek <jerry.jelinek@joyent.com>

*** 8,18 **** * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* ! * Copyright (c) 2019, Joyent, Inc. */ /* * Dump information about CTF containers. */ --- 8,18 ---- * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* ! * Copyright 2019, Joyent, Inc. */ /* * Dump information about CTF containers. */
*** 683,703 **** * - doubly-pointed-to functions are wrong (e.g. in kiconv_ops_t) * - anon unions declared within SOUs aren't expanded * - function arguments aren't expanded recursively */ ! 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 int ctfsrc_member_cb(const char *member, ctf_id_t type, ulong_t off, void *arg) { --- 683,703 ---- * - doubly-pointed-to functions are wrong (e.g. in kiconv_ops_t) * - anon unions declared within SOUs aren't expanded * - function arguments aren't expanded recursively */ ! static const char * 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))); } ! return (ctf_type_name(g_fp, ref, buf, bufsize)); } static int ctfsrc_member_cb(const char *member, ctf_id_t type, ulong_t off, void *arg) {
*** 716,739 **** /* * 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); } static int ctfsrc_enum_cb(const char *name, int value, void *arg) { _NOTE(ARGUNUSED(arg)); ! (void) printf("\t%s = %d,\n", name, value); return (0); } static int is_anon_refname(const char *refname) --- 716,739 ---- /* * A byte offset is friendlier, but we'll print bits too if it's not * aligned (i.e. a bitfield). */ if (off % NBBY != 0) { ! printf("\t%s; /* offset: %lu bytes (%lu bits) */\n", name, off / NBBY, off); } else { ! printf("\t%s; /* offset: %lu bytes */\n", name, off / NBBY); } return (0); } static int ctfsrc_enum_cb(const char *name, int value, void *arg) { _NOTE(ARGUNUSED(arg)); ! printf("\t%s = %d,\n", name, value); return (0); } static int is_anon_refname(const char *refname)
*** 754,764 **** } 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) { --- 754,764 ---- } static void ctfsrc_type(ctf_id_t id, const char *name) { ! char refname[MAX_NAMELEN] = "unknown_t"; ctf_id_t ref; ssize_t size; int kind; if ((kind = ctf_type_kind(g_fp, id)) == CTF_ERR) {
*** 779,861 **** 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: --- 779,868 ---- 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))); } ! 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))); } ! 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; ! 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))); } ! printf("};\n\n"); break; case CTF_K_TYPEDEF: ! /* ! * If this fails, it's probably because the referent type is in ! * a parent container that was not supplied via -p. ! */ ! if (ctfsrc_refname(id, refname, sizeof (refname)) == NULL) { ! printf("typedef %s %s;\n\n", refname, name); ! break; ! } if (!is_anon_refname(refname)) { (void) ctf_type_cname(g_fp, ctf_type_reference(g_fp, id), refname, sizeof (refname), name); ! printf("typedef %s;\n\n", refname); break; } ref = ctf_type_reference(g_fp, id); if (ctf_type_kind(g_fp, ref) == CTF_K_ENUM) { ! 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))); } ! 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))); } ! 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))); } ! printf("} %s;\n\n", name); } break; case CTF_K_FORWARD: ! printf("%s;\n\n", name); break; case CTF_K_UNKNOWN: case CTF_K_INTEGER: case CTF_K_FLOAT: case CTF_K_POINTER:
*** 901,911 **** ctf_errmsg(ctf_errno(g_fp))); } (void) snprintf(tname, sizeof (tname), "unknown_t %s", name); } ! (void) printf("extern %s;\n", tname); } static int ctfsrc_collect_functions_cb(const char *name, ulong_t symidx, ctf_funcinfo_t *ctc, void *arg) --- 908,918 ---- ctf_errmsg(ctf_errno(g_fp))); } (void) snprintf(tname, sizeof (tname), "unknown_t %s", name); } ! printf("extern %s;\n", tname); } static int ctfsrc_collect_functions_cb(const char *name, ulong_t symidx, ctf_funcinfo_t *ctc, void *arg)
*** 927,937 **** 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) { --- 934,944 ---- 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)); ! 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) {
*** 941,966 **** } 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"); } static int idname_compare(const void *lhs, const void *rhs) { --- 948,973 ---- } for (size_t i = 0; i < cfi->ctc_argc; i++) { ctf_id_t aid = g_fargc[i]; ! (void) strlcpy(name, "unknown_t", sizeof (name)); (void) ctf_type_name(g_fp, aid, name, sizeof (name)); ! printf("%s%s", name, i + 1 == cfi->ctc_argc ? "" : ", "); } } else { if (!(cfi->ctc_flags & CTF_FUNC_VARARG)) ! printf("void"); } if (cfi->ctc_flags & CTF_FUNC_VARARG) ! printf("%s...", cfi->ctc_argc == 0 ? "" : ", "); ! printf(");\n"); } static int idname_compare(const void *lhs, const void *rhs) {
*** 973,1006 **** { 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_TRUE, 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)); } --- 980,1022 ---- { ulong_t nr_syms = ctf_nr_syms(g_fp); ctf_id_t max_id = ctf_max_id(g_fp); size_t count = 0; ! printf("/* Types */\n\n"); if ((idnames = calloc(max_id + 1, sizeof (idnames[0]))) == NULL) { ctfdump_fatal("failed to alloc idnames: %s\n", strerror(errno)); } + /* + * Prep for any unknown types (most likely, they exist in the parent, + * but we weren't given the -p option). + */ + for (size_t i = 0; i <= max_id; i++) { + (void) strlcpy(idnames[i].ci_name, "unknown_t", + sizeof (idnames[i].ci_name)); + } + if (ctf_type_iter(g_fp, B_TRUE, 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); ! 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)); }
*** 1017,1027 **** 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)); } --- 1033,1043 ---- for (size_t i = 0; i < count; i++) ctfsrc_object(idnames[i].ci_id, idnames[i].ci_name); free(idnames); ! 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)); }
*** 1194,1204 **** --- 1210,1230 ---- } if (ctf_import(g_fp, pfp) != 0) ctfdump_fatal("failed to import parent %s: %s\n", parent, ctf_errmsg(ctf_errno(g_fp))); + } else { + if (g_dump & CTFDUMP_SOURCE) { + printf("/* Warning: parent \"%s\" not supplied: many " + "types will be unknown. */\n\n", + ctf_parent_name(g_fp)); + } else { + fprintf(stderr, "warning: parent \"%s\" not supplied: " + "many types will be unknown\n\n", + ctf_parent_name(g_fp)); } + } if (g_dump & CTFDUMP_SOURCE) { ctfdump_source(); return (0); }