binutils: CTF support for objdump and readelf
[deliverable/binutils-gdb.git] / binutils / readelf.c
index 424624e0e4d705bb494edb0123c6f3994be21fd0..5ae58574fb4cfa41479699006585b0140cd9a6b8 100644 (file)
@@ -60,6 +60,7 @@
 #include "bucomm.h"
 #include "elfcomm.h"
 #include "dwarf.h"
+#include "ctf-api.h"
 
 #include "elf/common.h"
 #include "elf/external.h"
@@ -183,6 +184,7 @@ typedef struct elf_section_list
 #define DEBUG_DUMP     (1 << 2)        /* The -w command line switch.  */
 #define STRING_DUMP     (1 << 3)       /* The -p command line switch.  */
 #define RELOC_DUMP      (1 << 4)       /* The -R command line switch.  */
+#define CTF_DUMP        (1 << 5)        /* The --ctf command line switch.  */
 
 typedef unsigned char dump_type;
 
@@ -249,12 +251,17 @@ static bfd_boolean do_dump = FALSE;
 static bfd_boolean do_version = FALSE;
 static bfd_boolean do_histogram = FALSE;
 static bfd_boolean do_debugging = FALSE;
+static bfd_boolean do_ctf = FALSE;
 static bfd_boolean do_arch = FALSE;
 static bfd_boolean do_notes = FALSE;
 static bfd_boolean do_archive_index = FALSE;
 static bfd_boolean is_32bit_elf = FALSE;
 static bfd_boolean decompress_dumps = FALSE;
 
+static char *dump_ctf_parent_name;
+static char *dump_ctf_symtab_name;
+static char *dump_ctf_strtab_name;
+
 struct group_list
 {
   struct group_list *  next;
@@ -4394,6 +4401,10 @@ get_section_type_name (Filedata * filedata, unsigned int sh_type)
 #define OPTION_DWARF_DEPTH     514
 #define OPTION_DWARF_START     515
 #define OPTION_DWARF_CHECK     516
+#define OPTION_CTF_DUMP                517
+#define OPTION_CTF_PARENT      518
+#define OPTION_CTF_SYMBOLS     519
+#define OPTION_CTF_STRINGS     520
 
 static struct option options[] =
 {
@@ -4432,6 +4443,12 @@ static struct option options[] =
   {"dwarf-start",      required_argument, 0, OPTION_DWARF_START},
   {"dwarf-check",      no_argument, 0, OPTION_DWARF_CHECK},
 
+  {"ctf",              required_argument, 0, OPTION_CTF_DUMP},
+
+  {"ctf-symbols",      required_argument, 0, OPTION_CTF_SYMBOLS},
+  {"ctf-strings",      required_argument, 0, OPTION_CTF_STRINGS},
+  {"ctf-parent",       required_argument, 0, OPTION_CTF_PARENT},
+
   {"version",         no_argument, 0, 'v'},
   {"wide",            no_argument, 0, 'W'},
   {"help",            no_argument, 0, 'H'},
@@ -4481,6 +4498,15 @@ usage (FILE * stream)
   --dwarf-depth=N        Do not display DIEs at depth N or greater\n\
   --dwarf-start=N        Display DIEs starting with N, at the same depth\n\
                          or deeper\n"));
+  fprintf (stream, _("\
+  --ctf=<number|name>    Display CTF info from section <number|name>\n\
+  --ctf-parent=<number|name>\n\
+                         Use section <number|name> as the CTF parent\n\n\
+  --ctf-symbols=<number|name>\n\
+                         Use section <number|name> as the CTF external symtab\n\n\
+  --ctf-strings=<number|name>\n\
+                         Use section <number|name> as the CTF external strtab\n\n"));
+
 #ifdef SUPPORT_DISASSEMBLY
   fprintf (stream, _("\
   -i --instruction-dump=<number|name>\n\
@@ -4708,6 +4734,19 @@ parse_args (Filedata * filedata, int argc, char ** argv)
        case OPTION_DWARF_CHECK:
          dwarf_check = TRUE;
          break;
+       case OPTION_CTF_DUMP:
+         do_ctf = TRUE;
+         request_dump (filedata, CTF_DUMP);
+         break;
+       case OPTION_CTF_SYMBOLS:
+         dump_ctf_symtab_name = strdup (optarg);
+         break;
+       case OPTION_CTF_STRINGS:
+         dump_ctf_strtab_name = strdup (optarg);
+         break;
+       case OPTION_CTF_PARENT:
+         dump_ctf_parent_name = strdup (optarg);
+         break;
        case OPTION_DYN_SYMS:
          do_dyn_syms = TRUE;
          break;
@@ -13769,6 +13808,163 @@ dump_section_as_bytes (Elf_Internal_Shdr *  section,
   return TRUE;
 }
 
+static ctf_sect_t *
+shdr_to_ctf_sect (ctf_sect_t *buf, Elf_Internal_Shdr *shdr, Filedata *filedata)
+{
+  buf->cts_name = SECTION_NAME(shdr);
+  buf->cts_type = shdr->sh_type;
+  buf->cts_flags = shdr->sh_flags;
+  buf->cts_size = shdr->sh_size;
+  buf->cts_entsize = shdr->sh_entsize;
+  buf->cts_offset = (off64_t) shdr->sh_offset;
+
+  return buf;
+}
+
+/* Formatting callback function passed to ctf_dump.  Returns either the pointer
+   it is passed, or a pointer to newly-allocated storage, in which case
+   dump_ctf() will free it when it no longer needs it.  */
+
+static char *dump_ctf_indent_lines (ctf_sect_names_t sect ATTRIBUTE_UNUSED,
+                                   char *s, void *arg)
+{
+  char *spaces = arg;
+  char *new_s;
+
+  if (asprintf (&new_s, "%s%s", spaces, s) < 0)
+    return s;
+  return new_s;
+}
+
+static bfd_boolean
+dump_section_as_ctf (Elf_Internal_Shdr * section, Filedata * filedata)
+{
+  Elf_Internal_Shdr *  parent_sec = NULL;
+  Elf_Internal_Shdr *  symtab_sec = NULL;
+  Elf_Internal_Shdr *  strtab_sec = NULL;
+  void *              data = NULL;
+  void *              symdata = NULL;
+  void *              strdata = NULL;
+  void *              parentdata = NULL;
+  ctf_sect_t           ctfsect, symsect, strsect, parentsect;
+  ctf_sect_t *         symsectp = NULL;
+  ctf_sect_t *         strsectp = NULL;
+  ctf_file_t *         ctf = NULL;
+  ctf_file_t *         parent = NULL;
+
+  const char *things[] = {"Labels", "Data objects", "Function objects",
+                         "Variables", "Types", "Strings", ""};
+  const char **thing;
+  int err;
+  bfd_boolean ret = FALSE;
+  size_t i;
+
+  shdr_to_ctf_sect (&ctfsect, section, filedata);
+  data = get_section_contents (section, filedata);
+  ctfsect.cts_data = data;
+
+  if (dump_ctf_symtab_name)
+    {
+      if ((symtab_sec = find_section (filedata, dump_ctf_symtab_name)) == NULL)
+       {
+         error (_("No symbol section named %s\n"), dump_ctf_symtab_name);
+         goto fail;
+       }
+      if ((symdata = (void *) get_data (NULL, filedata,
+                                       symtab_sec->sh_offset, 1,
+                                       symtab_sec->sh_size,
+                                       _("symbols"))) == NULL)
+       goto fail;
+      symsectp = shdr_to_ctf_sect (&symsect, symtab_sec, filedata);
+      symsect.cts_data = symdata;
+    }
+  if (dump_ctf_strtab_name)
+    {
+      if ((strtab_sec = find_section (filedata, dump_ctf_strtab_name)) == NULL)
+       {
+         error (_("No string table section named %s\n"),
+                dump_ctf_strtab_name);
+         goto fail;
+       }
+      if ((strdata = (void *) get_data (NULL, filedata,
+                                       strtab_sec->sh_offset, 1,
+                                       strtab_sec->sh_size,
+                                       _("strings"))) == NULL)
+       goto fail;
+      strsectp = shdr_to_ctf_sect (&strsect, strtab_sec, filedata);
+      strsect.cts_data = strdata;
+    }
+  if (dump_ctf_parent_name)
+    {
+      if ((parent_sec = find_section (filedata, dump_ctf_parent_name)) == NULL)
+       {
+         error (_("No CTF parent section named %s\n"), dump_ctf_parent_name);
+         goto fail;
+       }
+      if ((parentdata = (void *) get_data (NULL, filedata,
+                                          parent_sec->sh_offset, 1,
+                                          parent_sec->sh_size,
+                                          _("CTF parent"))) == NULL)
+       goto fail;
+      shdr_to_ctf_sect (&parentsect, parent_sec, filedata);
+      parentsect.cts_data = parentdata;
+    }
+
+  /* Load the CTF file and dump it.  */
+
+  if ((ctf = ctf_bufopen (&ctfsect, symsectp, strsectp, &err)) == NULL)
+    {
+      error (_("CTF open failure: %s\n"), ctf_errmsg (err));
+      goto fail;
+    }
+
+  if (parentdata)
+    {
+      if ((parent = ctf_bufopen (&parentsect, symsectp, strsectp, &err)) == NULL)
+       {
+         error (_("CTF open failure: %s\n"), ctf_errmsg (err));
+         goto fail;
+       }
+
+      ctf_import (ctf, parent);
+    }
+
+  ret = TRUE;
+
+  printf (_("\nDump of CTF section '%s':\n"),
+         printable_section_name (filedata, section));
+
+  for (i = 1, thing = things; *thing[0]; thing++, i++)
+    {
+      ctf_dump_state_t *s = NULL;
+      char *item;
+
+      printf ("\n  %s:\n", *thing);
+      while ((item = ctf_dump (ctf, &s, i, dump_ctf_indent_lines,
+                              (void *) "    ")) != NULL)
+       {
+         printf ("%s\n", item);
+         free (item);
+       }
+
+      if (ctf_errno (ctf))
+       {
+         error (_("Iteration failed: %s, %s\n"), *thing,
+                  ctf_errmsg (ctf_errno (ctf)));
+         ret = FALSE;
+       }
+    }
+
+ fail:
+  ctf_file_close (ctf);
+  ctf_file_close (parent);
+  free (parentdata);
+  free (data);
+  free (symdata);
+  free (strdata);
+  return ret;
+}
+
 static bfd_boolean
 load_specific_debug_section (enum dwarf_section_display_enum  debug,
                             const Elf_Internal_Shdr *        sec,
@@ -14106,6 +14302,12 @@ process_section_contents (Filedata * filedata)
          if (! display_debug_section (i, section, filedata))
            res = FALSE;
        }
+
+      if (dump & CTF_DUMP)
+       {
+         if (! dump_section_as_ctf (section, filedata))
+           res = FALSE;
+       }
     }
 
   /* Check to see if the user requested a
@@ -19985,5 +20187,9 @@ main (int argc, char ** argv)
   if (cmdline.dump_sects != NULL)
     free (cmdline.dump_sects);
 
+  free (dump_ctf_symtab_name);
+  free (dump_ctf_strtab_name);
+  free (dump_ctf_parent_name);
+
   return err ? EXIT_FAILURE : EXIT_SUCCESS;
 }
This page took 0.032634 seconds and 4 git commands to generate.