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);
}