diff mbox series

Handle PowerPC64 ELFv1 function descriptors in libbacktrace (PR other/82368)

Message ID 20180214114138.GX5867@tucnak
State New
Headers show
Series Handle PowerPC64 ELFv1 function descriptors in libbacktrace (PR other/82368) | expand

Commit Message

Jakub Jelinek Feb. 14, 2018, 11:41 a.m. UTC
Hi!

As mentioned in detail in the PR, PowerPC64 ELFv1 function symbols
point to function descriptors in .opd section rather than actual
code, and one needs to read the code address from the .opd section
in order to associate symbols with .text addresses.

Fixed thusly, bootstrapped/regtested on powerpc64-linux (-m32/-m64
testing) and powerpc64le-linux, ok for trunk?

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.


	Jakub

Comments

Segher Boessenkool Feb. 14, 2018, 12:10 p.m. UTC | #1
Hi Jakub,

On Wed, Feb 14, 2018 at 12:41:38PM +0100, Jakub Jelinek wrote:
> As mentioned in detail in the PR, PowerPC64 ELFv1 function symbols
> point to function descriptors in .opd section rather than actual
> code, and one needs to read the code address from the .opd section
> in order to associate symbols with .text addresses.
> 
> Fixed thusly, bootstrapped/regtested on powerpc64-linux (-m32/-m64
> testing) and powerpc64le-linux, ok for trunk?
> 
> 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.

Looks good to me; you may want a libbacktrace maintainer though.


Segher
Ian Lance Taylor Feb. 14, 2018, 1:49 p.m. UTC | #2
On Wed, Feb 14, 2018 at 3:41 AM, Jakub Jelinek <jakub@redhat.com> wrote:
>
> As mentioned in detail in the PR, PowerPC64 ELFv1 function symbols
> point to function descriptors in .opd section rather than actual
> code, and one needs to read the code address from the .opd section
> in order to associate symbols with .text addresses.
>
> Fixed thusly, bootstrapped/regtested on powerpc64-linux (-m32/-m64
> testing) and powerpc64le-linux, ok for trunk?
>
> 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.

This is OK.

Thanks for taking this on.

Ian
Szabolcs Nagy Feb. 15, 2018, 11:08 a.m. UTC | #3
On 14/02/18 11:41, Jakub Jelinek wrote:
> Hi!
> 
> As mentioned in detail in the PR, PowerPC64 ELFv1 function symbols
> point to function descriptors in .opd section rather than actual
> code, and one needs to read the code address from the .opd section
> in order to associate symbols with .text addresses.
> 
> Fixed thusly, bootstrapped/regtested on powerpc64-linux (-m32/-m64
> testing) and powerpc64le-linux, ok for trunk?
> 
> 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.
> 
> --- libbacktrace/elf.c.jj	2018-02-08 20:46:10.671242369 +0000
> +++ libbacktrace/elf.c	2018-02-14 08:39:06.674088951 +0000
...
> @@ -2857,6 +2889,23 @@ elf_add (struct backtrace_state *state,
>   	      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

this broke baremetal arm targets (e.g. aarch64-none-elf with newlib)

...src/gcc/libbacktrace/elf.c: In function 'elf_add':
...src/gcc/libbacktrace/elf.c:2896:24: error: 'SHT_PROGBITS' undeclared (first use in this function)

     && 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)
Jakub Jelinek Feb. 15, 2018, 11:33 a.m. UTC | #4
On Thu, Feb 15, 2018 at 11:08:20AM +0000, Szabolcs Nagy wrote:
> > --- libbacktrace/elf.c.jj	2018-02-08 20:46:10.671242369 +0000
> > +++ libbacktrace/elf.c	2018-02-14 08:39:06.674088951 +0000
> ...
> > @@ -2857,6 +2889,23 @@ elf_add (struct backtrace_state *state,
> >   	      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
> 
> this broke baremetal arm targets (e.g. aarch64-none-elf with newlib)
> 
> ...src/gcc/libbacktrace/elf.c: In function 'elf_add':
> ...src/gcc/libbacktrace/elf.c:2896:24: error: 'SHT_PROGBITS' undeclared (first use in this function)
> 
>     && shdr->sh_type == SHT_PROGBITS
>                         ^~~~~~~~~~~~

Oops, sorry, fixed thusly, committed as obvious to trunk.

2018-02-15  Jakub Jelinek  <jakub@redhat.com>

	PR other/82368
	* elf.c (SHT_PROGBITS): Undefine and define.

--- libbacktrace/elf.c.jj	2018-02-14 15:19:13.849333101 +0100
+++ libbacktrace/elf.c	2018-02-15 12:30:53.948579969 +0100
@@ -170,6 +170,7 @@ dl_iterate_phdr (int (*callback) (struct
 #undef SHN_LORESERVE
 #undef SHN_XINDEX
 #undef SHN_UNDEF
+#undef SHT_PROGBITS
 #undef SHT_SYMTAB
 #undef SHT_STRTAB
 #undef SHT_DYNSYM
@@ -267,6 +268,7 @@ typedef struct {
 #define SHN_LORESERVE	0xFF00		/* Begin range of reserved indices */
 #define SHN_XINDEX	0xFFFF		/* Section index is held elsewhere */
 
+#define SHT_PROGBITS 1
 #define SHT_SYMTAB 2
 #define SHT_STRTAB 3
 #define SHT_DYNSYM 11


	Jakub
diff mbox series

Patch

--- libbacktrace/elf.c.jj	2018-02-08 20:46:10.671242369 +0000
+++ libbacktrace/elf.c	2018-02-14 08:39:06.674088951 +0000
@@ -165,6 +165,8 @@  dl_iterate_phdr (int (*callback) (struct
 #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
 			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
 	  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,
   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,
   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,
 	      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,
       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,
       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,
     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;