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,11 +8,11 @@
  * source.  A copy of the CDDL is also available via the Internet at
  * http://www.illumos.org/license/CDDL.
  */
 
 /*
- * Copyright (c) 2019, Joyent, Inc.
+ * Copyright 2019, Joyent, Inc.
  */
 
 /*
  * Dump information about CTF containers.
  */

@@ -683,21 +683,21 @@
  * - 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
+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)));
         }
 
-        (void) ctf_type_name(g_fp, ref, buf, bufsize);
+        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,24 +716,24 @@
         /*
          * 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",
+                printf("\t%s; /* offset: %lu bytes (%lu bits) */\n",
                     name, off / NBBY, off);
         } else {
-                (void) printf("\t%s; /* offset: %lu bytes */\n",
+                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);
+        printf("\t%s = %d,\n", name, value);
         return (0);
 }
 
 static int
 is_anon_refname(const char *refname)

@@ -754,11 +754,11 @@
 }
 
 static void
 ctfsrc_type(ctf_id_t id, const char *name)
 {
-        char refname[MAX_NAMELEN];
+        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,83 +779,90 @@
                 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);
+                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");
+                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);
+                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");
+                printf("};\n\n");
                 break;
         case CTF_K_TYPEDEF:
-                ctfsrc_refname(id, refname, sizeof (refname));
+                /*
+                 * 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);
 
-                        (void) printf("typedef %s;\n\n", refname);
+                        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");
+                        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);
+                        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",
+                        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);
+                        printf("} %s;\n\n", name);
                 }
 
                 break;
         case CTF_K_FORWARD:
-                (void) printf("%s;\n\n", name);
+                printf("%s;\n\n", name);
                 break;
         case CTF_K_UNKNOWN:
         case CTF_K_INTEGER:
         case CTF_K_FLOAT:
         case CTF_K_POINTER:

@@ -901,11 +908,11 @@
                             ctf_errmsg(ctf_errno(g_fp)));
                 }
                 (void) snprintf(tname, sizeof (tname), "unknown_t %s", name);
         }
 
-        (void) printf("extern %s;\n", tname);
+        printf("extern %s;\n", tname);
 }
 
 static int
 ctfsrc_collect_functions_cb(const char *name, ulong_t symidx,
     ctf_funcinfo_t *ctc, void *arg)

@@ -927,11 +934,11 @@
         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);
+        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,26 +948,26 @@
                 }
 
                 for (size_t i = 0; i < cfi->ctc_argc; i++) {
                         ctf_id_t aid = g_fargc[i];
 
-                        name[0] = '\0';
+                        (void) strlcpy(name, "unknown_t", sizeof (name));
 
                         (void) ctf_type_name(g_fp, aid, name, sizeof (name));
 
-                        (void) printf("%s%s", name,
+                        printf("%s%s", name,
                             i + 1 == cfi->ctc_argc ? "" : ", ");
                 }
         } else {
                 if (!(cfi->ctc_flags & CTF_FUNC_VARARG))
-                        (void) printf("void");
+                        printf("void");
         }
 
         if (cfi->ctc_flags & CTF_FUNC_VARARG)
-                (void) printf("%s...", cfi->ctc_argc == 0 ? "" : ", ");
+                printf("%s...", cfi->ctc_argc == 0 ? "" : ", ");
 
-        (void) printf(");\n");
+        printf(");\n");
 }
 
 static int
 idname_compare(const void *lhs, const void *rhs)
 {

@@ -973,34 +980,43 @@
 {
         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");
+        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++) {
+        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");
+        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,11 +1033,11 @@
         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");
+        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,11 +1210,21 @@
                 }
 
                 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);
         }