]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
libctf: dump: dump the header; dump enum64s; adapt to API changes
authorNick Alcock <nick.alcock@oracle.com>
Fri, 25 Apr 2025 20:18:29 +0000 (21:18 +0100)
committerNick Alcock <nick.alcock@oracle.com>
Fri, 25 Apr 2025 20:23:08 +0000 (21:23 +0100)
A bunch of dumper changes.  Most importantly, adapt to the changes in the _f
iteration function prototypes by no longer carrying around our own cds_fp
dict pointer everywhere but just using the one we are given by the iteration
function.

But also, dump the v3 and v4/BTF headers separately, using the stored
original v3-pre-upgrade header copy if present.  The v3 dumper is not tested
yet, of course, but is more or less unchanged from the old code, so probably
nearly works.  The v4 dumper is tested.

Add enum64 support (basically just a bit of extra code to print the
signedness of enums).

libctf/ctf-dump.c

index 64c6a09f65f5bc30746b447481719e0174c9c531..6d770224fe344a71e0b6d2f225697f12b685bcce 100644 (file)
@@ -36,7 +36,6 @@ typedef struct ctf_dump_item
 struct ctf_dump_state
 {
   ctf_sect_names_t cds_sect;
-  ctf_dict_t *cds_fp;
   ctf_dump_item_t *cds_current;
   ctf_list_t cds_items;
 };
@@ -46,17 +45,16 @@ struct ctf_dump_state
 typedef struct ctf_dump_membstate
 {
   char **cdm_str;
-  ctf_dict_t *cdm_fp;
   const char *cdm_toplevel_indent;
 } ctf_dump_membstate_t;
 
 static int
-ctf_dump_append (ctf_dump_state_t *state, char *str)
+ctf_dump_append (ctf_dict_t *fp, ctf_dump_state_t *state, char *str)
 {
   ctf_dump_item_t *cdi;
 
   if ((cdi = malloc (sizeof (struct ctf_dump_item))) == NULL)
-    return (ctf_set_errno (state->cds_fp, ENOMEM));
+    return (ctf_set_errno (fp, ENOMEM));
 
   cdi->cdi_item = str;
   ctf_list_append (&state->cds_items, cdi);
@@ -146,7 +144,8 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
       /* Report encodings of everything with an encoding other than enums:
         base-type enums cannot have a nonzero cte_offset or cte_bits value.
         (Slices of them can, but they are of kind CTF_K_SLICE.)  */
-      if (unsliced_kind != CTF_K_ENUM && ctf_type_encoding (fp, id, &ep) == 0)
+      if (unsliced_kind != CTF_K_ENUM && unsliced_kind != CTF_K_ENUM64
+         && ctf_type_encoding (fp, id, &ep) == 0)
        {
          if ((ssize_t) ep.cte_bits != ctf_type_size (fp, id) * CHAR_BIT
              && flag & CTF_FT_BITFIELD)
@@ -257,7 +256,7 @@ ctf_dump_header_strfield (ctf_dict_t *fp, ctf_dump_state_t *state,
     {
       if (asprintf (&str, "%s: %s\n", name, ctf_strptr (fp, value)) < 0)
        goto err;
-      ctf_dump_append (state, str);
+      ctf_dump_append (fp, state, str);
     }
   return 0;
 
@@ -275,7 +274,7 @@ ctf_dump_header_sizefield (ctf_dict_t *fp, ctf_dump_state_t *state,
     {
       if (asprintf (&str, "%s: %x\n", name, value) < 0)
        goto err;
-      ctf_dump_append (state, str);
+      ctf_dump_append (fp, state, str);
     }
   return 0;
 
@@ -295,7 +294,7 @@ ctf_dump_header_sectfield (ctf_dict_t *fp, ctf_dump_state_t *state,
                    (unsigned long) off, (unsigned long) (nextoff - 1),
                    (unsigned long) (nextoff - off)) < 0)
        goto err;
-      ctf_dump_append (state, str);
+      ctf_dump_append (fp, state, str);
     }
   return 0;
 
@@ -303,74 +302,91 @@ ctf_dump_header_sectfield (ctf_dict_t *fp, ctf_dump_state_t *state,
   return (ctf_set_errno (fp, errno));
 }
 
-/* Dump the file header into the cds_items.  */
+/* Dump one section-offset+len field from the file header into the cds_items.  */
 static int
-ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
+ctf_dump_header_sectlenfield (ctf_dict_t *fp, ctf_dump_state_t *state,
+                          const char *sect, uint32_t off, uint32_t len)
+{
+  char *str;
+  if (len - off)
+    {
+      if (asprintf (&str, "%s:\t0x%lx -- 0x%lx (0x%lx bytes)\n", sect,
+                   (unsigned long) off, (unsigned long) (off + len),
+                   (unsigned long) len) < 0)
+       goto err;
+      ctf_dump_append (fp, state, str);
+    }
+  return 0;
+
+ err:
+  return (ctf_set_errno (fp, errno));
+}
+
+/* Dump the CTFv3-or-below file header into the cds_items.  */
+
+static int
+ctf_dump_v3_header (ctf_dict_t *fp, ctf_dump_state_t *state)
 {
   char *str;
   char *flagstr = NULL;
-  const ctf_header_t *hp = fp->ctf_header;
+  const ctf_header_v3_t *hp = fp->ctf_v3_header;
   const char *vertab[] =
     {
      NULL, "CTF_VERSION_1",
      "CTF_VERSION_1_UPGRADED_3 (latest format, version 1 type "
      "boundaries)",
      "CTF_VERSION_2",
-     "CTF_VERSION_3",
-     "CTF_VERSION_4",
-     NULL
+     "CTF_VERSION_3"
     };
   const char *verstr = NULL;
 
-  if (asprintf (&str, "Magic number: 0x%x\n", hp->cth_magic) < 0)
+  if (asprintf (&str, "Magic number: 0x%x\n", hp->cth_preamble.ctp_magic) < 0)
       goto err;
-  ctf_dump_append (state, str);
+  ctf_dump_append (fp, state, str);
 
-  if (hp->cth_version <= CTF_VERSION)
-    verstr = vertab[hp->cth_version];
+  if (hp->cth_preamble.ctp_version < CTF_VERSION_4)
+    verstr = vertab[hp->cth_preamble.ctp_version];
 
   if (verstr == NULL)
     verstr = "(not a valid version)";
 
-  if (asprintf (&str, "Version: %i (%s)\n", hp->cth_version,
+  if (asprintf (&str, "Version: %i (%s)\n", hp->cth_preamble.ctp_version,
                verstr) < 0)
     goto err;
-  ctf_dump_append (state, str);
+  ctf_dump_append (fp, state, str);
 
   /* Everything else is only printed if present.  */
 
-  /* The flags are unusual in that they represent the ctf_dict_t *in memory*:
-     flags representing compression, etc, are turned off as the file is
-     decompressed.  So we store a copy of the flags before they are changed, for
-     the dumper.  */
+  /* We store the original version of the header, to let us dump un-upgraded
+     info that is lost or radically changed on upgrade.  */
 
-  if (fp->ctf_openflags > 0)
+  if (hp->cth_flags > 0)
     {
       if (asprintf (&flagstr, "%s%s%s%s%s%s%s",
-                   fp->ctf_openflags & CTF_F_COMPRESS
+                   hp->cth_flags & CTF_F_COMPRESS
                    ? "CTF_F_COMPRESS": "",
-                   (fp->ctf_openflags & CTF_F_COMPRESS)
-                   && (fp->ctf_openflags & ~CTF_F_COMPRESS)
+                   (hp->cth_flags & CTF_F_COMPRESS)
+                   && (hp->cth_flags & ~CTF_F_COMPRESS)
                    ? ", " : "",
-                   fp->ctf_openflags & CTF_F_NEWFUNCINFO
+                   hp->cth_flags & CTF_F_NEWFUNCINFO
                    ? "CTF_F_NEWFUNCINFO" : "",
-                   (fp->ctf_openflags & (CTF_F_NEWFUNCINFO))
-                   && (fp->ctf_openflags & ~(CTF_F_COMPRESS | CTF_F_NEWFUNCINFO))
+                   (hp->cth_flags & (CTF_F_NEWFUNCINFO))
+                   && (hp->cth_flags & ~(CTF_F_COMPRESS | CTF_F_NEWFUNCINFO))
                    ? ", " : "",
-                   fp->ctf_openflags & CTF_F_IDXSORTED
+                   hp->cth_flags & CTF_F_IDXSORTED
                    ? "CTF_F_IDXSORTED" : "",
-                   fp->ctf_openflags & (CTF_F_IDXSORTED)
-                   && (fp->ctf_openflags & ~(CTF_F_COMPRESS | CTF_F_NEWFUNCINFO
-                                             | CTF_F_IDXSORTED))
+                   hp->cth_flags & (CTF_F_IDXSORTED)
+                   && (hp->cth_flags & ~(CTF_F_COMPRESS | CTF_F_NEWFUNCINFO
+                                         | CTF_F_IDXSORTED))
                    ? ", " : "",
-                   fp->ctf_openflags & CTF_F_DYNSTR
+                   hp->cth_flags & CTF_F_DYNSTR
                    ? "CTF_F_DYNSTR" : "") < 0)
        goto err;
 
-      if (asprintf (&str, "Flags: 0x%x (%s)", fp->ctf_openflags, flagstr) < 0)
+      if (asprintf (&str, "Flags: 0x%x (%s)", hp->cth_flags, flagstr) < 0)
        goto err;
       free (flagstr);
-      ctf_dump_append (state, str);
+      ctf_dump_append (fp, state, str);
     }
 
   if (ctf_dump_header_strfield (fp, state, "Parent label",
@@ -384,12 +400,6 @@ ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
                                hp->cth_cuname) < 0)
     goto err;
 
-  if (ctf_dump_header_sizefield (fp, state, "Parent strlen", hp->cth_parent_strlen) < 0)
-    goto err;
-
-  if (ctf_dump_header_sizefield (fp, state, "Parent max type", hp->cth_parent_typemax) < 0)
-    goto err;
-
   if (ctf_dump_header_sectfield (fp, state, "Label section", hp->cth_lbloff,
                                 hp->cth_objtoff) < 0)
     goto err;
@@ -428,31 +438,110 @@ ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
   return (ctf_set_errno (fp, errno));
 }
 
-/* Dump a single label into the cds_items.  */
-
+/* Dump the file header into the cds_items.  */
 static int
-ctf_dump_label (const char *name, const ctf_lblinfo_t *info,
-               void *arg)
+ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
 {
   char *str;
-  char *typestr;
-  ctf_dump_state_t *state = arg;
+  char *flagstr = NULL;
+  const ctf_header_t *hp = fp->ctf_header;
+  const char *vertab[] =
+    {
+     "CTF_VERSION_4"
+    };
+  const char *verstr = NULL;
 
-  if (asprintf (&str, "%s -> ", name) < 0)
-    return (ctf_set_errno (state->cds_fp, errno));
+  /* Figure out what we're dumping, first.  */
 
-  if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type,
-                                      CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
+  if (fp->ctf_v3_header)
     {
-      free (str);
-      return 0;                                /* Swallow the error.  */
+      ctf_dump_v3_header (fp, state);
+      return 0;
     }
 
-  str = str_append (str, typestr);
-  free (typestr);
+  if (asprintf (&str, "Magic number: 0x%lx\n", CTH_MAGIC (hp)) < 0)
+      goto err;
+  ctf_dump_append (fp, state, str);
+
+  if (CTH_VERSION (hp) != CTF_VERSION_4)
+    verstr = "(not a valid version)";
+  else
+    verstr = vertab[CTH_VERSION (hp) - CTF_VERSION_4];
+
+  if (asprintf (&str, "Version: %li (%s)\n", CTH_VERSION (hp),
+               verstr) < 0)
+    goto err;
+  ctf_dump_append (fp, state, str);
+
+  /* Everything else is only printed if present.  */
+
+  /* The flags are unusual in that they represent the ctf_dict_t *in memory*:
+     flags representing compression, etc, are turned off as the file is
+     decompressed.  So we store a copy of the flags before they are changed, for
+     the dumper.  We also store the original version of the header, to let us
+     dump un-upgraded info that is lost or radically changed on upgrade.  */
+
+  if (fp->ctf_openflags > 0)
+    {
+      if (asprintf (&flagstr, "%s%s%s%s",
+                   fp->ctf_openflags & CTF_F_COMPRESS
+                   ? "CTF_F_COMPRESS": "",
+                   (fp->ctf_openflags & CTF_F_COMPRESS)
+                   && (fp->ctf_openflags & ~CTF_F_COMPRESS)
+                   ? ", " : "",
+                   fp->ctf_openflags & CTF_F_IDXSORTED
+                   ? "CTF_F_IDXSORTED" : "",
+                   (fp->ctf_openflags & ~(CTF_F_COMPRESS | CTF_F_IDXSORTED))
+                   ? "; unknown flags present" : "") < 0)
+       goto err;
+
+      if (asprintf (&str, "Flags: 0x%x (%s)", fp->ctf_openflags, flagstr) < 0)
+       goto err;
+      free (flagstr);
+      ctf_dump_append (fp, state, str);
+    }
+
+  if (ctf_dump_header_strfield (fp, state, "Parent name", hp->cth_parent_name) < 0)
+    goto err;
+
+  if (ctf_dump_header_strfield (fp, state, "Compilation unit name",
+                               hp->cth_cu_name) < 0)
+    goto err;
+
+  if (ctf_dump_header_sizefield (fp, state, "Parent strlen", hp->cth_parent_strlen) < 0)
+    goto err;
+
+  if (ctf_dump_header_sizefield (fp, state, "Parent types", hp->cth_parent_ntypes) < 0)
+    goto err;
+
+  if (ctf_dump_header_sectlenfield (fp, state, "Data object section",
+                                   hp->cth_objt_off, hp->cth_objt_len) < 0)
+    goto err;
+
+  if (ctf_dump_header_sectlenfield (fp, state, "Function info section",
+                                   hp->cth_func_off, hp->cth_func_len) < 0)
+    goto err;
+
+  if (ctf_dump_header_sectlenfield (fp, state, "Object index section",
+                                   hp->cth_objtidx_off, hp->cth_objtidx_len) < 0)
+    goto err;
+
+  if (ctf_dump_header_sectlenfield (fp, state, "Function index section",
+                                   hp->cth_funcidx_off, hp->cth_funcidx_len) < 0)
+    goto err;
+
+  if (ctf_dump_header_sectlenfield (fp, state, "Type section",
+                                   hp->btf.bth_type_off, hp->btf.bth_type_len) < 0)
+    goto err;
+
+  if (ctf_dump_header_sectlenfield (fp, state, "String section", hp->btf.bth_str_off,
+                                   hp->btf.bth_str_off + hp->btf.bth_str_len + 1) < 0)
+    goto err;
 
-  ctf_dump_append (state, str);
   return 0;
+ err:
+  free (flagstr);
+  return (ctf_set_errno (fp, errno));
 }
 
 /* Dump all the object or function entries into the cds_items.  */
@@ -485,16 +574,16 @@ ctf_dump_objts (ctf_dict_t *fp, ctf_dump_state_t *state, int functions)
       else
        str = xstrdup ("");
 
-      if ((typestr = ctf_dump_format_type (state->cds_fp, id,
-                                          CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
+      if ((typestr = ctf_dump_format_type (fp, id, CTF_ADD_ROOT
+                                          | CTF_FT_REFS)) == NULL)
        {
-         ctf_dump_append (state, str);
+         ctf_dump_append (fp, state, str);
          continue;                             /* Swallow the error.  */
        }
 
       str = str_append (str, typestr);
       free (typestr);
-      ctf_dump_append (state, str);
+      ctf_dump_append (fp, state, str);
       continue;
 
     oom:
@@ -507,7 +596,9 @@ ctf_dump_objts (ctf_dict_t *fp, ctf_dump_state_t *state, int functions)
 
 /* Dump a single variable into the cds_items.  */
 static int
-ctf_dump_var (const char *name, ctf_id_t type, void *arg)
+ctf_dump_var (ctf_dict_t *fp, ctf_id_t type,
+             unsigned long offset,
+             size_t size, void *arg)
 {
   char *str;
   char *typestr;
@@ -526,14 +617,14 @@ ctf_dump_var (const char *name, ctf_id_t type, void *arg)
   str = str_append (str, typestr);
   free (typestr);
 
-  ctf_dump_append (state, str);
+  ctf_dump_append (fp, state, str);
   return 0;
 }
 
 /* Dump a single struct/union member into the string in the membstate.  */
 static int
-ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
-                int depth, void *arg)
+ctf_dump_member (ctf_dict_t *fp, const char *name, ctf_id_t id,
+                unsigned long offset, int bit_width, int depth, void *arg)
 {
   ctf_dump_membstate_t *state = arg;
   char *typestr = NULL;
@@ -548,8 +639,7 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
   *state->cdm_str = str_append (*state->cdm_str, bit);
   free (bit);
 
-  if ((typestr = ctf_dump_format_type (state->cdm_fp, id,
-                                      CTF_ADD_ROOT | CTF_FT_BITFIELD
+  if ((typestr = ctf_dump_format_type (fp, id, CTF_ADD_ROOT | CTF_FT_BITFIELD
                                       | CTF_FT_ID)) == NULL)
     return -1;                         /* errno is set for us.  */
 
@@ -567,7 +657,7 @@ ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
  oom:
   free (typestr);
   free (bit);
-  return (ctf_set_errno (state->cdm_fp, errno));
+  return (ctf_set_errno (fp, errno));
 }
 
 /* Report the number of digits in the hexadecimal representation of a type
@@ -587,37 +677,36 @@ type_hex_digits (ctf_id_t id)
 
 /* Dump a single type into the cds_items.  */
 static int
-ctf_dump_type (ctf_id_t id, int flag, void *arg)
+ctf_dump_type (ctf_dict_t *fp, ctf_id_t id, int flag, void *arg)
 {
   char *str;
   char *indent;
   ctf_dump_state_t *state = arg;
-  ctf_dump_membstate_t membstate = { &str, state->cds_fp, NULL };
+  ctf_dump_membstate_t membstate = { &str, NULL };
 
   /* Indent neatly.  */
   if (asprintf (&indent, "    %*s", type_hex_digits (id), "") < 0)
-    return (ctf_set_errno (state->cds_fp, ENOMEM));
+    return (ctf_set_errno (fp, ENOMEM));
 
   /* Dump the type itself.  */
-  if ((str = ctf_dump_format_type (state->cds_fp, id,
-                                  flag | CTF_FT_REFS)) == NULL)
+  if ((str = ctf_dump_format_type (fp, id, flag | CTF_FT_REFS)) == NULL)
     goto err;
   str = str_append (str, "\n");
 
   membstate.cdm_toplevel_indent = indent;
 
   /* Member dumping for structs, unions...  */
-  if (ctf_type_kind (state->cds_fp, id) == CTF_K_STRUCT
-      || ctf_type_kind (state->cds_fp, id) == CTF_K_UNION)
+  if (ctf_type_kind (fp, id) == CTF_K_STRUCT
+      || ctf_type_kind (fp, id) == CTF_K_UNION)
     {
-      if ((ctf_type_visit (state->cds_fp, id, ctf_dump_member, &membstate)) < 0)
+      if ((ctf_type_visit (fp, id, ctf_dump_member, &membstate)) < 0)
        {
-         if (id == 0 || ctf_errno (state->cds_fp) == ECTF_NONREPRESENTABLE)
+         if (id == 0 || ctf_errno (fp) == ECTF_NONREPRESENTABLE)
            {
-             ctf_dump_append (state, str);
+             ctf_dump_append (fp, state, str);
              return 0;
            }
-         ctf_err_warn (state->cds_fp, 1, ctf_errno (state->cds_fp),
+         ctf_err_warn (fp, 1, ctf_errno (fp),
                        _("cannot visit members dumping type 0x%lx"), id);
          goto err;
        }
@@ -625,29 +714,38 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
 
   /* ... and enums, for which we dump the first and last few members and skip
      the ones in the middle.  */
-  if (ctf_type_kind (state->cds_fp, id) == CTF_K_ENUM)
+  if (ctf_type_kind (fp, id) == CTF_K_ENUM ||
+      ctf_type_kind (fp, id) == CTF_K_ENUM64)
     {
-      int enum_count = ctf_member_count (state->cds_fp, id);
+      int enum_count = ctf_member_count (fp, id);
       ctf_next_t *it = NULL;
       int i = 0;
       const char *enumerand;
       char *bit;
-      int value;
+      int64_t value;
 
-      while ((enumerand = ctf_enum_next (state->cds_fp, id,
+      while ((enumerand = ctf_enum_next (fp, id,
                                         &it, &value)) != NULL)
        {
+         int ret;
+
          i++;
          if ((i > 5) && (i < enum_count - 4))
            continue;
 
          str = str_append (str, indent);
 
-         if (asprintf (&bit, "%s: %i\n", enumerand, value) < 0)
+         if (!ctf_enum_unsigned (fp, id))
+           ret = asprintf (&bit, "%s: %" PRIi64 "\n", enumerand, value);
+         else
+           ret = asprintf (&bit, "%s: %" PRIu64 "\n", enumerand, (uint64_t) value);
+
+         if (ret < 0)
            {
              ctf_next_destroy (it);
              goto oom;
            }
+
          str = str_append (str, bit);
          free (bit);
 
@@ -657,15 +755,15 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
              str = str_append (str, "...\n");
            }
        }
-      if (ctf_errno (state->cds_fp) != ECTF_NEXT_END)
+      if (ctf_errno (fp) != ECTF_NEXT_END)
        {
-         ctf_err_warn (state->cds_fp, 1, ctf_errno (state->cds_fp),
+         ctf_err_warn (fp, 1, ctf_errno (fp),
                        _("cannot visit enumerands dumping type 0x%lx"), id);
          goto err;
        }
     }
 
-  ctf_dump_append (state, str);
+  ctf_dump_append (fp, state, str);
   free (indent);
 
   return 0;
@@ -681,7 +779,7 @@ ctf_dump_type (ctf_id_t id, int flag, void *arg)
  oom:
   free (indent);
   free (str);
-  return ctf_set_errno (state->cds_fp, ENOMEM);
+  return ctf_set_errno (fp, ENOMEM);
 }
 
 /* Dump the string table into the cds_items.  */
@@ -699,7 +797,7 @@ ctf_dump_str (ctf_dict_t *fp, ctf_dump_state_t *state)
                    (unsigned long) (s - fp->ctf_str[CTF_STRTAB_0].cts_strs),
                    s) < 0)
        return (ctf_set_errno (fp, errno));
-      ctf_dump_append (state, str);
+      ctf_dump_append (fp, state, str);
       s += strlen (s) + 1;
     }
 
@@ -746,7 +844,6 @@ ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
       state = *statep;
 
       memset (state, 0, sizeof (struct ctf_dump_state));
-      state->cds_fp = fp;
       state->cds_sect = sect;
 
       switch (sect)
@@ -763,7 +860,7 @@ ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
            goto end;                   /* errno is set for us.  */
          break;
        case CTF_SECT_VAR:
-         if (ctf_variable_iter (fp, ctf_dump_var, state) < 0)
+         if (ctf_dump_datasecs (fp, state) < 0)
            goto end;                   /* errno is set for us.  */
          break;
        case CTF_SECT_TYPE: