re PR other/82368 (with r253275 several new test cases in libbacktrace fail)
authorJakub Jelinek <jakub@redhat.com>
Wed, 14 Feb 2018 14:19:36 +0000 (15:19 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 14 Feb 2018 14:19:36 +0000 (15:19 +0100)
PR other/82368
* elf.c (EM_PPC64, EF_PPC64_ABI): Undefine and define.
(struct elf_ppc64_opd_data): New type.
(elf_initialize_syminfo): Add opd argument, handle symbols
pointing into the PowerPC64 ELFv1 .opd section.
(elf_add): Read .opd section on PowerPC64 ELFv1, pass pointer
to structure with .opd data to elf_initialize_syminfo.

From-SVN: r257658

libbacktrace/ChangeLog
libbacktrace/elf.c

index 9ebce20..60e67a7 100644 (file)
@@ -1,3 +1,13 @@
+2018-02-14  Jakub Jelinek  <jakub@redhat.com>
+
+       PR other/82368
+       * elf.c (EM_PPC64, EF_PPC64_ABI): Undefine and define.
+       (struct elf_ppc64_opd_data): New type.
+       (elf_initialize_syminfo): Add opd argument, handle symbols
+       pointing into the PowerPC64 ELFv1 .opd section.
+       (elf_add): Read .opd section on PowerPC64 ELFv1, pass pointer
+       to structure with .opd data to elf_initialize_syminfo.
+
 2018-01-31  Ian Lance Taylor  <iant@golang.org>
 
        * elf.c (elf_add): Close descriptor if we use a debugfile.
index 3ee1dbe..8ff3c47 100644 (file)
@@ -165,6 +165,8 @@ dl_iterate_phdr (int (*callback) (struct dl_phdr_info *,
 #undef ELFDATA2MSB
 #undef EV_CURRENT
 #undef ET_DYN
+#undef EM_PPC64
+#undef EF_PPC64_ABI
 #undef SHN_LORESERVE
 #undef SHN_XINDEX
 #undef SHN_UNDEF
@@ -245,6 +247,9 @@ typedef struct {
 
 #define ET_DYN 3
 
+#define EM_PPC64 21
+#define EF_PPC64_ABI 3
+
 typedef struct {
   b_elf_word   sh_name;                /* Section name, index in string tbl */
   b_elf_word   sh_type;                /* Type of section */
@@ -405,6 +410,20 @@ struct elf_syminfo_data
   size_t count;
 };
 
+/* Information about PowerPC64 ELFv1 .opd section.  */
+
+struct elf_ppc64_opd_data
+{
+  /* Address of the .opd section.  */
+  b_elf_addr addr;
+  /* Section data.  */
+  const char *data;
+  /* Size of the .opd section.  */
+  size_t size;
+  /* Corresponding section view.  */
+  struct backtrace_view view;
+};
+
 /* Compute the CRC-32 of BUF/LEN.  This uses the CRC used for
    .gnu_debuglink files.  */
 
@@ -569,7 +588,8 @@ elf_initialize_syminfo (struct backtrace_state *state,
                        const unsigned char *symtab_data, size_t symtab_size,
                        const unsigned char *strtab, size_t strtab_size,
                        backtrace_error_callback error_callback,
-                       void *data, struct elf_syminfo_data *sdata)
+                       void *data, struct elf_syminfo_data *sdata,
+                       struct elf_ppc64_opd_data *opd)
 {
   size_t sym_count;
   const b_elf_sym *sym;
@@ -620,7 +640,17 @@ elf_initialize_syminfo (struct backtrace_state *state,
          return 0;
        }
       elf_symbols[j].name = (const char *) strtab + sym->st_name;
-      elf_symbols[j].address = sym->st_value + base_address;
+      /* Special case PowerPC64 ELFv1 symbols in .opd section, if the symbol
+        is a function descriptor, read the actual code address from the
+        descriptor.  */
+      if (opd
+         && sym->st_value >= opd->addr
+         && sym->st_value < opd->addr + opd->size)
+       elf_symbols[j].address
+         = *(const b_elf_addr *) (opd->data + (sym->st_value - opd->addr));
+      else
+       elf_symbols[j].address = sym->st_value;
+      elf_symbols[j].address += base_address;
       elf_symbols[j].size = sym->st_size;
       ++j;
     }
@@ -2637,6 +2667,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
   int debug_view_valid;
   unsigned int using_debug_view;
   uint16_t *zdebug_table;
+  struct elf_ppc64_opd_data opd_data, *opd;
 
   if (!debuginfo)
     {
@@ -2655,6 +2686,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
   debuglink_name = NULL;
   debuglink_crc = 0;
   debug_view_valid = 0;
+  opd = NULL;
 
   if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback,
                           data, &ehdr_view))
@@ -2857,6 +2889,23 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
              debuglink_crc = *(const uint32_t*)(debuglink_data + crc_offset);
            }
        }
+
+      /* Read the .opd section on PowerPC64 ELFv1.  */
+      if (ehdr.e_machine == EM_PPC64
+         && (ehdr.e_flags & EF_PPC64_ABI) < 2
+         && shdr->sh_type == SHT_PROGBITS
+         && strcmp (name, ".opd") == 0)
+       {
+         if (!backtrace_get_view (state, descriptor, shdr->sh_offset,
+                                  shdr->sh_size, error_callback, data,
+                                  &opd_data.view))
+           goto fail;
+
+         opd = &opd_data;
+         opd->addr = shdr->sh_addr;
+         opd->data = (const char *) opd_data.view.data;
+         opd->size = shdr->sh_size;
+       }
     }
 
   if (symtab_shndx == 0)
@@ -2898,7 +2947,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
       if (!elf_initialize_syminfo (state, base_address,
                                   symtab_view.data, symtab_shdr->sh_size,
                                   strtab_view.data, strtab_shdr->sh_size,
-                                  error_callback, data, sdata))
+                                  error_callback, data, sdata, opd))
        {
          backtrace_free (state, sdata, sizeof *sdata, error_callback, data);
          goto fail;
@@ -2951,6 +3000,12 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
       buildid_view_valid = 0;
     }
 
+  if (opd)
+    {
+      backtrace_release_view (state, &opd->view, error_callback, data);
+      opd = NULL;
+    }
+
   if (debuglink_name != NULL)
     {
       int d;
@@ -3139,6 +3194,8 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
     backtrace_release_view (state, &buildid_view, error_callback, data);
   if (debug_view_valid)
     backtrace_release_view (state, &debug_view, error_callback, data);
+  if (opd)
+    backtrace_release_view (state, &opd->view, error_callback, data);
   if (descriptor != -1)
     backtrace_close (descriptor, error_callback, data);
   return 0;