libctf: fix a number of build problems found on Solaris and NetBSD
[deliverable/binutils-gdb.git] / binutils / readelf.c
index 20ebacc9cbd029bb68364668a96a66ebafd26fd1..8e2902fdcac41201edd37c2351df3b465a533851 100644 (file)
@@ -60,6 +60,9 @@
 #include "bucomm.h"
 #include "elfcomm.h"
 #include "dwarf.h"
+#ifdef HAVE_LIBCTF
+#include "ctf-api.h"
+#endif
 
 #include "elf/common.h"
 #include "elf/external.h"
 #include "elf/d10v.h"
 #include "elf/d30v.h"
 #include "elf/dlx.h"
+#include "elf/bpf.h"
 #include "elf/epiphany.h"
 #include "elf/fr30.h"
 #include "elf/frv.h"
@@ -182,6 +186,9 @@ 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.  */
+#ifdef HAVE_LIBCTF
+#define CTF_DUMP        (1 << 5)        /* The --ctf command line switch.  */
+#endif
 
 typedef unsigned char dump_type;
 
@@ -248,12 +255,21 @@ static bfd_boolean do_dump = FALSE;
 static bfd_boolean do_version = FALSE;
 static bfd_boolean do_histogram = FALSE;
 static bfd_boolean do_debugging = FALSE;
+#ifdef HAVE_LIBCTF
+static bfd_boolean do_ctf = FALSE;
+#endif
 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;
 
+#ifdef HAVE_LIBCTF
+static char *dump_ctf_parent_name;
+static char *dump_ctf_symtab_name;
+static char *dump_ctf_strtab_name;
+#endif
+
 struct group_list
 {
   struct group_list *  next;
@@ -781,6 +797,7 @@ guess_is_rela (unsigned int e_machine)
     case EM_SCORE:
     case EM_XGATE:
     case EM_NFP:
+    case EM_BPF:
       return FALSE;
 
       /* Targets that use RELA relocations.  */
@@ -1482,6 +1499,10 @@ dump_relocations (Filedata *          filedata,
          rtype = elf_visium_reloc_type (type);
          break;
 
+        case EM_BPF:
+          rtype = elf_bpf_reloc_type (type);
+          break;
+
        case EM_ADAPTEVA_EPIPHANY:
          rtype = elf_epiphany_reloc_type (type);
          break;
@@ -1797,6 +1818,19 @@ dump_relocations (Filedata *          filedata,
   return res;
 }
 
+static const char *
+get_aarch64_dynamic_type (unsigned long type)
+{
+  switch (type)
+    {
+    case DT_AARCH64_BTI_PLT:  return "AARCH64_BTI_PLT";
+    case DT_AARCH64_PAC_PLT:  return "AARCH64_PAC_PLT";
+    case DT_AARCH64_VARIANT_PCS:  return "AARCH64_VARIANT_PCS";
+    default:
+      return NULL;
+    }
+}
+
 static const char *
 get_mips_dynamic_type (unsigned long type)
 {
@@ -2170,6 +2204,9 @@ get_dynamic_type (Filedata * filedata, unsigned long type)
 
          switch (filedata->file_header.e_machine)
            {
+           case EM_AARCH64:
+             result = get_aarch64_dynamic_type (type);
+             break;
            case EM_MIPS:
            case EM_MIPS_RS3_LE:
              result = get_mips_dynamic_type (type);
@@ -4372,6 +4409,12 @@ 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
+#ifdef HAVE_LIBCTF
+#define OPTION_CTF_DUMP                517
+#define OPTION_CTF_PARENT      518
+#define OPTION_CTF_SYMBOLS     519
+#define OPTION_CTF_STRINGS     520
+#endif
 
 static struct option options[] =
 {
@@ -4410,6 +4453,14 @@ static struct option options[] =
   {"dwarf-start",      required_argument, 0, OPTION_DWARF_START},
   {"dwarf-check",      no_argument, 0, OPTION_DWARF_CHECK},
 
+#ifdef HAVE_LIBCTF
+  {"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},
+#endif
+
   {"version",         no_argument, 0, 'v'},
   {"wide",            no_argument, 0, 'W'},
   {"help",            no_argument, 0, 'H'},
@@ -4459,6 +4510,17 @@ 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"));
+#ifdef HAVE_LIBCTF
+  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"));
+#endif
+
 #ifdef SUPPORT_DISASSEMBLY
   fprintf (stream, _("\
   -i --instruction-dump=<number|name>\n\
@@ -4686,6 +4748,21 @@ parse_args (Filedata * filedata, int argc, char ** argv)
        case OPTION_DWARF_CHECK:
          dwarf_check = TRUE;
          break;
+#ifdef HAVE_LIBCTF
+       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;
+#endif
        case OPTION_DYN_SYMS:
          do_dyn_syms = TRUE;
          break;
@@ -6853,7 +6930,7 @@ process_section_groups (Filedata * filedata)
                     printable_section_name (filedata, section),
                     (unsigned long) section->sh_entsize,
                     (unsigned long) section->sh_size);
-             break;
+             continue;
            }
 
          start = (unsigned char *) get_data (NULL, filedata, section->sh_offset,
@@ -9344,6 +9421,21 @@ process_unwind (Filedata * filedata)
   return TRUE;
 }
 
+static void
+dynamic_section_aarch64_val (Elf_Internal_Dyn * entry)
+{
+  switch (entry->d_tag)
+    {
+    case DT_AARCH64_BTI_PLT:
+    case DT_AARCH64_PAC_PLT:
+      break;
+    default:
+      print_vma (entry->d_un.d_ptr, PREFIX_HEX);
+      break;
+    }
+  putchar ('\n');
+}
+
 static void
 dynamic_section_mips_val (Elf_Internal_Dyn * entry)
 {
@@ -10358,6 +10450,9 @@ process_dynamic_section (Filedata * filedata)
            {
              switch (filedata->file_header.e_machine)
                {
+               case EM_AARCH64:
+                 dynamic_section_aarch64_val (entry);
+                 break;
                case EM_MIPS:
                case EM_MIPS_RS3_LE:
                  dynamic_section_mips_val (entry);
@@ -10455,7 +10550,7 @@ process_version_sections (Filedata * filedata)
                    printable_section_name (filedata, section),
                    section->sh_info);
 
-           printf (_("  Addr: 0x"));
+           printf (_(" Addr: 0x"));
            printf_vma (section->sh_addr);
            printf (_("  Offset: %#08lx  Link: %u (%s)\n"),
                    (unsigned long) section->sh_offset, section->sh_link,
@@ -10747,7 +10842,7 @@ process_version_sections (Filedata * filedata)
                              total),
                    printable_section_name (filedata, section), (unsigned long) total);
 
-           printf (_(" Addr: "));
+           printf (_(" Addr: 0x"));
            printf_vma (section->sh_addr);
            printf (_("  Offset: %#08lx  Link: %u (%s)\n"),
                    (unsigned long) section->sh_offset, section->sh_link,
@@ -11062,6 +11157,22 @@ get_solaris_symbol_visibility (unsigned int visibility)
     }
 }
 
+static const char *
+get_aarch64_symbol_other (unsigned int other)
+{
+  static char buf[32];
+
+  if (other & STO_AARCH64_VARIANT_PCS)
+    {
+      other &= ~STO_AARCH64_VARIANT_PCS;
+      if (other == 0)
+       return "VARIANT_PCS";
+      snprintf (buf, sizeof buf, "VARIANT_PCS | %x", other);
+      return buf;
+    }
+  return NULL;
+}
+
 static const char *
 get_mips_symbol_other (unsigned int other)
 {
@@ -11173,6 +11284,9 @@ get_symbol_other (Filedata * filedata, unsigned int other)
 
   switch (filedata->file_header.e_machine)
     {
+    case EM_AARCH64:
+      result = get_aarch64_symbol_other (other);
+      break;
     case EM_MIPS:
       result = get_mips_symbol_other (other);
       break;
@@ -12377,6 +12491,8 @@ is_32bit_abs_reloc (Filedata * filedata, unsigned int reloc_type)
     case EM_AARCH64:
       return (reloc_type == 258
              || reloc_type == 1); /* R_AARCH64_ABS32 || R_AARCH64_P32_ABS32 */
+    case EM_BPF:
+      return reloc_type == 11; /* R_BPF_DATA_32 */
     case EM_ADAPTEVA_EPIPHANY:
       return reloc_type == 3;
     case EM_ALPHA:
@@ -13708,6 +13824,162 @@ dump_section_as_bytes (Elf_Internal_Shdr *  section,
   return TRUE;
 }
 
+#ifdef HAVE_LIBCTF
+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_size = shdr->sh_size;
+  buf->cts_entsize = shdr->sh_entsize;
+
+  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;
+}
+#endif /* HAVE_LIBCTF */
+
 static bfd_boolean
 load_specific_debug_section (enum dwarf_section_display_enum  debug,
                             const Elf_Internal_Shdr *        sec,
@@ -14045,6 +14317,14 @@ process_section_contents (Filedata * filedata)
          if (! display_debug_section (i, section, filedata))
            res = FALSE;
        }
+
+#ifdef HAVE_LIBCTF
+      if (dump & CTF_DUMP)
+       {
+         if (! dump_section_as_ctf (section, filedata))
+           res = FALSE;
+       }
+#endif
     }
 
   /* Check to see if the user requested a
@@ -14337,7 +14617,7 @@ typedef struct
 static const char * arm_attr_tag_CPU_arch[] =
   {"Pre-v4", "v4", "v4T", "v5T", "v5TE", "v5TEJ", "v6", "v6KZ", "v6T2",
    "v6K", "v7", "v6-M", "v6S-M", "v7E-M", "v8", "v8-R", "v8-M.baseline",
-   "v8-M.mainline"};
+   "v8-M.mainline", "", "", "", "v8.1-M.mainline"};
 static const char * arm_attr_tag_ARM_ISA_use[] = {"No", "Yes"};
 static const char * arm_attr_tag_THUMB_ISA_use[] =
   {"No", "Thumb-1", "Thumb-2", "Yes"};
@@ -14401,6 +14681,9 @@ static const char * arm_attr_tag_Virtualization_use[] =
 static const char * arm_attr_tag_MPextension_use_legacy[] =
   {"Not Allowed", "Allowed"};
 
+static const char * arm_attr_tag_MVE_arch[] =
+  {"No MVE", "MVE Integer only", "MVE Integer and FP"};
+
 #define LOOKUP(id, name) \
   {id, #name, 0x80 | ARRAY_SIZE(arm_attr_tag_##name), arm_attr_tag_##name}
 static arm_attr_public_tag arm_attr_public_tags[] =
@@ -14440,6 +14723,7 @@ static arm_attr_public_tag arm_attr_public_tags[] =
   LOOKUP(42, MPextension_use),
   LOOKUP(44, DIV_use),
   LOOKUP(46, DSP_extension),
+  LOOKUP(48, MVE_arch),
   {64, "nodefaults", 0, NULL},
   {65, "also_compatible_with", 0, NULL},
   LOOKUP(66, T2EE_use),
@@ -17246,6 +17530,9 @@ decode_x86_isa (unsigned int bitmask)
        case GNU_PROPERTY_X86_ISA_1_AVX512_VNNI:
          printf ("AVX512_VNNI");
          break;
+       case GNU_PROPERTY_X86_ISA_1_AVX512_BF16:
+         printf ("AVX512_BF16");
+         break;
        default:
          printf (_("<unknown: %x>"), bit);
          break;
@@ -17341,6 +17628,33 @@ decode_x86_feature_2 (unsigned int bitmask)
     }
 }
 
+static void
+decode_aarch64_feature_1_and (unsigned int bitmask)
+{
+  while (bitmask)
+    {
+      unsigned int bit = bitmask & (- bitmask);
+
+      bitmask &= ~ bit;
+      switch (bit)
+       {
+       case GNU_PROPERTY_AARCH64_FEATURE_1_BTI:
+         printf ("BTI");
+         break;
+
+       case GNU_PROPERTY_AARCH64_FEATURE_1_PAC:
+         printf ("PAC");
+         break;
+
+       default:
+         printf (_("<unknown: %x>"), bit);
+         break;
+       }
+      if (bitmask)
+       printf (", ");
+    }
+}
+
 static void
 print_gnu_property_note (Filedata * filedata, Elf_Internal_Note * pnote)
 {
@@ -17475,6 +17789,18 @@ print_gnu_property_note (Filedata * filedata, Elf_Internal_Note * pnote)
                  break;
                }
            }
+         else if (filedata->file_header.e_machine == EM_AARCH64)
+           {
+             if (type == GNU_PROPERTY_AARCH64_FEATURE_1_AND)
+               {
+                 printf ("AArch64 feature: ");
+                 if (datasz != 4)
+                   printf (_("<corrupt length: %#x> "), datasz);
+                 else
+                   decode_aarch64_feature_1_and (byte_get (ptr, 4));
+                 goto next;
+               }
+           }
        }
       else
        {
@@ -17868,25 +18194,60 @@ get_stapsdt_note_type (unsigned e_type)
 static bfd_boolean
 print_stapsdt_note (Elf_Internal_Note *pnote)
 {
-  int addr_size = is_32bit_elf ? 4 : 8;
+  size_t len, maxlen;
+  unsigned long addr_size = is_32bit_elf ? 4 : 8;
   char *data = pnote->descdata;
   char *data_end = pnote->descdata + pnote->descsz;
   bfd_vma pc, base_addr, semaphore;
   char *provider, *probe, *arg_fmt;
 
+  if (pnote->descsz < (addr_size * 3))
+    goto stapdt_note_too_small;
+
   pc = byte_get ((unsigned char *) data, addr_size);
   data += addr_size;
+
   base_addr = byte_get ((unsigned char *) data, addr_size);
   data += addr_size;
+
   semaphore = byte_get ((unsigned char *) data, addr_size);
   data += addr_size;
 
-  provider = data;
-  data += strlen (data) + 1;
-  probe = data;
-  data += strlen (data) + 1;
-  arg_fmt = data;
-  data += strlen (data) + 1;
+  if (data >= data_end)
+    goto stapdt_note_too_small;
+  maxlen = data_end - data;
+  len = strnlen (data, maxlen);
+  if (len < maxlen)
+    {
+      provider = data;
+      data += len + 1;
+    }
+  else
+    goto stapdt_note_too_small;
+
+  if (data >= data_end)
+    goto stapdt_note_too_small;
+  maxlen = data_end - data;
+  len = strnlen (data, maxlen);
+  if (len < maxlen)
+    {
+      probe = data;
+      data += len + 1;
+    }
+  else
+    goto stapdt_note_too_small;
+  
+  if (data >= data_end)
+    goto stapdt_note_too_small;
+  maxlen = data_end - data;
+  len = strnlen (data, maxlen);
+  if (len < maxlen)
+    {
+      arg_fmt = data;
+      data += len + 1;
+    }
+  else
+    goto stapdt_note_too_small;
 
   printf (_("    Provider: %s\n"), provider);
   printf (_("    Name: %s\n"), probe);
@@ -17900,6 +18261,11 @@ print_stapsdt_note (Elf_Internal_Note *pnote)
   printf (_("    Arguments: %s\n"), arg_fmt);
 
   return data == data_end;
+
+ stapdt_note_too_small:
+  printf (_("  <corrupt - note is too small>\n"));
+  error (_("corrupt stapdt note - the data size is too small\n"));
+  return FALSE;
 }
 
 static const char *
@@ -19262,7 +19628,7 @@ open_debug_file (const char * pathname)
 static bfd_boolean
 process_object (Filedata * filedata)
 {
-  Filedata * separates;
+  bfd_boolean  have_separate_files;
   unsigned int i;
   bfd_boolean res = TRUE;
 
@@ -19339,19 +19705,26 @@ process_object (Filedata * filedata)
     res = FALSE;
 
   if (filedata->file_header.e_shstrndx != SHN_UNDEF)
-    separates = load_separate_debug_file (filedata, filedata->file_name);
+    have_separate_files = load_separate_debug_files (filedata, filedata->file_name);
   else
-    separates = NULL;
+    have_separate_files = FALSE;
 
   if (! process_section_contents (filedata))
     res = FALSE;
 
-  if (separates)
+  if (have_separate_files)
     {
-      if (! process_section_headers (separates))
-       res = FALSE;
-      else if (! process_section_contents (separates))
-       res = FALSE;
+      separate_info * d;
+
+      for (d = first_separate_info; d != NULL; d = d->next)
+       {
+         if (! process_section_headers (d->handle))
+           res = FALSE;
+         else if (! process_section_contents (d->handle))
+           res = FALSE;
+       }
+
+      /* The file handles are closed by the call to free_debug_memory() below.  */
     }
 
   if (! process_notes (filedata))
@@ -19831,5 +20204,11 @@ main (int argc, char ** argv)
   if (cmdline.dump_sects != NULL)
     free (cmdline.dump_sects);
 
+#ifdef HAVE_LIBCTF
+  free (dump_ctf_symtab_name);
+  free (dump_ctf_strtab_name);
+  free (dump_ctf_parent_name);
+#endif
+
   return err ? EXIT_FAILURE : EXIT_SUCCESS;
 }
This page took 0.034537 seconds and 4 git commands to generate.