Almost complete type dump
authorMartin Pieuchot <mpi@openbsd.org>
Tue, 15 Mar 2016 10:49:59 +0000 (11:49 +0100)
committerMartin Pieuchot <mpi@openbsd.org>
Wed, 16 Mar 2016 08:18:45 +0000 (09:18 +0100)
ctf.h
ctfdump.c

diff --git a/ctf.h b/ctf.h
index 55e1e2f3f38dff6961d1af957fd75a9c19e15e27..f07b1d49fa338f336a0075ddc0bbcb3906334e75 100644 (file)
--- a/ctf.h
+++ b/ctf.h
@@ -50,6 +50,16 @@ struct ctf_stype {
 #define cts_type _ST._type
 };
 
+struct ctf_type {
+       struct ctf_stype        _ctt_stype;
+#define ctt_name _ctt_stype.cts_name
+#define ctt_info _ctt_stype.cts_info
+#define ctt_size _ctt_stype.cts_size
+#define ctt_type _ctt_stype.cts_type
+       unsigned int            ctt_lsizehi;
+       unsigned int            ctt_lsizelo;
+};
+
 struct ctf_array {
        unsigned short          cta_contents;
        unsigned short          cta_index;
@@ -83,6 +93,7 @@ struct ctf_enum {
 
 #define CTF_MAX_NAME           0x7fffffff
 #define CTF_MAX_VLEN           0x03ff
+#define CTF_MAX_SIZE           0xfffe
 
 #define CTF_STRTAB_0           0
 #define CTF_STRTAB_1           1
@@ -114,3 +125,11 @@ struct ctf_enum {
  */
 #define CTF_NAME_STID(n)       ((n) >> 31)
 #define CTF_NAME_OFFSET(n)     ((n) & CTF_MAX_NAME)
+
+/*
+ * Type macro.
+ */
+#define CTF_SIZE_TO_LSIZE_HI(s)        ((uint32_t)((uint64_t)(s) >> 32))
+#define CTF_SIZE_TO_LSIZE_LO(s)        ((uint32_t)(s))
+#define CTF_TYPE_LSIZE(t)      \
+       (((uint64_t)(t)->ctt_lsizehi) << 32 | (t)->ctt_lsizelo)
index 99f5fc7a460780e14c555f14ca6742548773053f..9b4dff7c56e45b965a0547e116352758abf9d6ab 100644 (file)
--- a/ctfdump.c
+++ b/ctfdump.c
 
 #include "ctf.h"
 
+#ifndef nitems
+#define nitems(_a)     (sizeof((_a)) / sizeof((_a)[0]))
+#endif
+
 #define SUNW_CTF       ".SUNW_ctf"
 
 #define DUMP_OBJECT    (1 << 0)
@@ -42,6 +46,8 @@
 #define DUMP_HEADER    (1 << 2)
 #define DUMP_LABEL     (1 << 3)
 #define DUMP_STRTAB    (1 << 4)
+#define DUMP_STATISTIC (1 << 5)
+#define DUMP_TYPE      (1 << 6)
 
 int             dump(const char *, uint32_t);
 int             iself(const char *, size_t);
@@ -49,6 +55,9 @@ int            isctf(const char *, size_t);
 __dead void     usage(void);
 
 int             ctf_dump(const char *, size_t, uint32_t);
+unsigned int    ctf_dump_type(struct ctf_header *, const char *, off_t,
+                    unsigned int, unsigned int);
+const char     *ctf_kind2name(unsigned short);
 const char     *ctf_off2name(struct ctf_header *, const char *, off_t,
                     unsigned int);
 
@@ -89,6 +98,9 @@ main(int argc, char *argv[])
                case 's':
                        flags |= DUMP_STRTAB;
                        break;
+               case 't':
+                       flags |= DUMP_TYPE;
+                       break;
                default:
                        usage();
                }
@@ -483,12 +495,109 @@ ctf_dump(const char *p, size_t size, uint32_t flags)
                }
        }
 
+       if (flags & DUMP_TYPE) {
+               unsigned int             idx = 1, offset = 0;
+
+               while (offset < cth->cth_stroff)
+                       offset += ctf_dump_type(cth, data, dlen, offset, idx++);
+
+       }
+
        if (cth->cth_flags & CTF_F_COMPRESS)
                free(data);
 
        return 0;
 }
 
+unsigned int
+ctf_dump_type(struct ctf_header *cth, const char *data, off_t dlen,
+    unsigned int offset, unsigned int idx)
+{
+       const struct ctf_type   *ctt;
+       unsigned short           kind, vlen, root;
+       unsigned int             toff, tlen = 0;
+       uint64_t                 size;
+       const char              *name, *kname;
+
+       ctt = (struct ctf_type *)(data + cth->cth_typeoff + offset);
+       kind = CTF_INFO_KIND(ctt->ctt_info);
+       vlen = CTF_INFO_VLEN(ctt->ctt_info);
+       root = CTF_INFO_ISROOT(ctt->ctt_info);
+       name = ctf_off2name(cth, data, dlen, ctt->ctt_name);
+
+       if (root)
+               printf("<%u> ", idx);
+       else
+               printf("[%u] ", idx);
+
+       if ((kname = ctf_kind2name(kind)) != NULL)
+               printf("%s %s", kname, name);
+
+       if (ctt->ctt_size <= CTF_MAX_SIZE) {
+               size = ctt->ctt_size;
+               toff = sizeof(struct ctf_stype);
+       } else {
+               size = CTF_TYPE_LSIZE(ctt);
+               toff = sizeof(struct ctf_type);
+       }
+
+       switch (kind) {
+       case CTF_K_UNKNOWN:
+       case CTF_K_FORWARD:
+               break;
+       case CTF_K_INTEGER:
+               tlen = sizeof(unsigned int);
+               break;
+       case CTF_K_FLOAT:
+               break;
+       case CTF_K_ARRAY:
+               tlen = sizeof(struct ctf_array);
+               break;
+       case CTF_K_FUNCTION:
+               tlen = (vlen + (vlen & 1)) * sizeof(unsigned short);
+               break;
+       case CTF_K_STRUCT:
+       case CTF_K_UNION:
+               printf(" (%llu bytes)", size);
+               if (size < CTF_LSTRUCT_THRESH)
+                       tlen = vlen * sizeof(struct ctf_member);
+               else
+                       tlen = vlen * sizeof(struct ctf_lmember);
+               break;
+       case CTF_K_ENUM:
+               tlen = vlen * sizeof(struct ctf_enum);
+               break;
+       case CTF_K_POINTER:
+               vlen = sizeof(unsigned int);
+               /* FALLTHROUGH */
+       case CTF_K_TYPEDEF:
+       case CTF_K_VOLATILE:
+       case CTF_K_CONST:
+       case CTF_K_RESTRICT:
+               printf(" refers to %u", ctt->ctt_type);
+               break;
+       default:
+               errx(1, "incorrect type %u at offset %u", kind, offset);
+       }
+
+       printf("\n");
+
+       return toff + tlen;
+}
+
+const char *
+ctf_kind2name(unsigned short kind)
+{
+       static const char *kind_name[] = { NULL, "INTEGER", "FLOAT", "POINTER",
+          "ARRAYS", "FUNCTION", "STRUCT", "UNION", "ENUM", "FORWARD",
+          "TYPEDEF", "VOLATILE", "CONST", "RESTRICT" };
+
+       if (kind >= nitems(kind_name))
+               return NULL;
+
+       return kind_name[kind];
+}
+
 const char *
 ctf_off2name(struct ctf_header *cth, const char *data, off_t dlen,
     unsigned int offset)