diff mbox series

[RFC,1/2] libbacktrace: add FDPIC support

Message ID 20240527065026.855607-2-jcmvbkbc@gmail.com
State New
Headers show
Series libbacktrace: add FDPIC support | expand

Commit Message

Max Filippov May 27, 2024, 6:50 a.m. UTC
Instead of a single base address FDPIC ELF files use load map: a
structure with an array of mappings for individual segments.  Change
libbacktrace functions and structures to support that.

libbacktrace/

	PR libbacktrace/114941
	* dwarf.c: Include <link.h> or <sys/link.h> if available.
	(struct dwarf_data): Change base_address type to base_address_type.
	(add_low_high_range): Change base_address argument type to
	base_address_type.  Use __RELOC_UINTPTR for lowpc and highpc
	calculation.
	(add_ranges_from_ranges): Change base_address argument type to
	base_address_type.  Use __RELOC_UINTPTR to calculate arguments
	for add_range().
	(add_ranges_from_rnglists): Change base_address argument type to
	base_address_type.  Use __RELOC_UINTPTR to calculate arguments
	for add_range().  Use __RELOC_UINTPTR for low calculation.
	(add_ranges, find_address_ranges, build_address_map): Change
	base_address argument type to base_address_type.
	(add_line): Use __RELOC_UINTPTR for ln->pc calculation.
	(build_dwarf_data, backtrace_dwarf_add): Change base_address
	argument type to base_address_type.
	* elf.c (elf_initialize_syminfo): Change base_address argument
	type to base_address_type.  Use __RELOC_UINTPTR for
	elf_symbols[j].address calculation.
	(elf_add): Change base_address argument type to
	base_address_type.  Do early return -1 in case of FDPIC
	executable, update corresponding comment.
	(backtrace_initialize): Change NULL base address parameter in
	the add_elf() call to no_base_address.
	* internal.h (base_address_type, __RELOC_POINTER)
	(__RELOC_UINTPTR, no_base_address): New definitions.
	(backtrace_dwarf_add): Change base_address argument type to
	base_address_type.
---
 libbacktrace/dwarf.c    | 60 ++++++++++++++++++++++++-----------------
 libbacktrace/elf.c      | 20 +++++++++-----
 libbacktrace/internal.h | 14 +++++++++-
 3 files changed, 62 insertions(+), 32 deletions(-)

Comments

Max Filippov June 11, 2024, 4:54 p.m. UTC | #1
On Sun, May 26, 2024 at 11:50 PM Max Filippov <jcmvbkbc@gmail.com> wrote:
>
> Instead of a single base address FDPIC ELF files use load map: a
> structure with an array of mappings for individual segments.  Change
> libbacktrace functions and structures to support that.

Ping?

> libbacktrace/
>
>         PR libbacktrace/114941
>         * dwarf.c: Include <link.h> or <sys/link.h> if available.
>         (struct dwarf_data): Change base_address type to base_address_type.
>         (add_low_high_range): Change base_address argument type to
>         base_address_type.  Use __RELOC_UINTPTR for lowpc and highpc
>         calculation.
>         (add_ranges_from_ranges): Change base_address argument type to
>         base_address_type.  Use __RELOC_UINTPTR to calculate arguments
>         for add_range().
>         (add_ranges_from_rnglists): Change base_address argument type to
>         base_address_type.  Use __RELOC_UINTPTR to calculate arguments
>         for add_range().  Use __RELOC_UINTPTR for low calculation.
>         (add_ranges, find_address_ranges, build_address_map): Change
>         base_address argument type to base_address_type.
>         (add_line): Use __RELOC_UINTPTR for ln->pc calculation.
>         (build_dwarf_data, backtrace_dwarf_add): Change base_address
>         argument type to base_address_type.
>         * elf.c (elf_initialize_syminfo): Change base_address argument
>         type to base_address_type.  Use __RELOC_UINTPTR for
>         elf_symbols[j].address calculation.
>         (elf_add): Change base_address argument type to
>         base_address_type.  Do early return -1 in case of FDPIC
>         executable, update corresponding comment.
>         (backtrace_initialize): Change NULL base address parameter in
>         the add_elf() call to no_base_address.
>         * internal.h (base_address_type, __RELOC_POINTER)
>         (__RELOC_UINTPTR, no_base_address): New definitions.
>         (backtrace_dwarf_add): Change base_address argument type to
>         base_address_type.
> ---
>  libbacktrace/dwarf.c    | 60 ++++++++++++++++++++++++-----------------
>  libbacktrace/elf.c      | 20 +++++++++-----
>  libbacktrace/internal.h | 14 +++++++++-
>  3 files changed, 62 insertions(+), 32 deletions(-)
diff mbox series

Patch

diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c
index ed0672964c24..bcab23562e2a 100644
--- a/libbacktrace/dwarf.c
+++ b/libbacktrace/dwarf.c
@@ -43,6 +43,15 @@  POSSIBILITY OF SUCH DAMAGE.  */
 #include "backtrace.h"
 #include "internal.h"
 
+#ifdef __FDPIC__
+ #ifdef HAVE_LINK_H
+  #include <link.h>
+ #endif
+ #ifdef HAVE_SYS_LINK_H
+  #include <sys/link.h>
+ #endif
+#endif
+
 #if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN
 
 /* If strnlen is not declared, provide our own version.  */
@@ -389,7 +398,7 @@  struct dwarf_data
   /* The data for .gnu_debugaltlink.  */
   struct dwarf_data *altlink;
   /* The base address for this file.  */
-  uintptr_t base_address;
+  base_address_type base_address;
   /* A sorted list of address ranges.  */
   struct unit_addrs *addrs;
   /* Number of address ranges in list.  */
@@ -1610,7 +1619,7 @@  update_pcrange (const struct attr* attr, const struct attr_val* val,
 static int
 add_low_high_range (struct backtrace_state *state,
 		    const struct dwarf_sections *dwarf_sections,
-		    uintptr_t base_address, int is_bigendian,
+		    base_address_type base_address, int is_bigendian,
 		    struct unit *u, const struct pcrange *pcrange,
 		    int (*add_range) (struct backtrace_state *state,
 				      void *rdata, uintptr_t lowpc,
@@ -1646,8 +1655,8 @@  add_low_high_range (struct backtrace_state *state,
 
   /* Add in the base address of the module when recording PC values,
      so that we can look up the PC directly.  */
-  lowpc += base_address;
-  highpc += base_address;
+  lowpc = __RELOC_UINTPTR (lowpc, base_address);
+  highpc = __RELOC_UINTPTR (highpc, base_address);
 
   return add_range (state, rdata, lowpc, highpc, error_callback, data, vec);
 }
@@ -1659,7 +1668,7 @@  static int
 add_ranges_from_ranges (
     struct backtrace_state *state,
     const struct dwarf_sections *dwarf_sections,
-    uintptr_t base_address, int is_bigendian,
+    base_address_type base_address, int is_bigendian,
     struct unit *u, uintptr_t base,
     const struct pcrange *pcrange,
     int (*add_range) (struct backtrace_state *state, void *rdata,
@@ -1706,8 +1715,8 @@  add_ranges_from_ranges (
       else
 	{
 	  if (!add_range (state, rdata, 
-			  (uintptr_t) low + base + base_address,
-			  (uintptr_t) high + base + base_address,
+			  __RELOC_UINTPTR (low + base, base_address),
+			  __RELOC_UINTPTR (high + base, base_address),
 			  error_callback, data, vec))
 	    return 0;
 	}
@@ -1726,7 +1735,7 @@  static int
 add_ranges_from_rnglists (
     struct backtrace_state *state,
     const struct dwarf_sections *dwarf_sections,
-    uintptr_t base_address, int is_bigendian,
+    base_address_type base_address, int is_bigendian,
     struct unit *u, uintptr_t base,
     const struct pcrange *pcrange,
     int (*add_range) (struct backtrace_state *state, void *rdata,
@@ -1809,9 +1818,9 @@  add_ranges_from_rnglists (
 				     u->addrsize, is_bigendian, index,
 				     error_callback, data, &high))
 	      return 0;
-	    if (!add_range (state, rdata, low + base_address,
-			    high + base_address, error_callback, data,
-			    vec))
+	    if (!add_range (state, rdata, __RELOC_UINTPTR (low, base_address),
+			    __RELOC_UINTPTR (high, base_address),
+			    error_callback, data, vec))
 	      return 0;
 	  }
 	  break;
@@ -1828,7 +1837,7 @@  add_ranges_from_rnglists (
 				     error_callback, data, &low))
 	      return 0;
 	    length = read_uleb128 (&rnglists_buf);
-	    low += base_address;
+	    low = __RELOC_UINTPTR (low, base_address);
 	    if (!add_range (state, rdata, low, low + length,
 			    error_callback, data, vec))
 	      return 0;
@@ -1842,8 +1851,9 @@  add_ranges_from_rnglists (
 
 	    low = read_uleb128 (&rnglists_buf);
 	    high = read_uleb128 (&rnglists_buf);
-	    if (!add_range (state, rdata, low + base + base_address,
-			    high + base + base_address,
+	    if (!add_range (state, rdata,
+			    __RELOC_UINTPTR (low + base, base_address),
+			    __RELOC_UINTPTR (high + base, base_address),
 			    error_callback, data, vec))
 	      return 0;
 	  }
@@ -1860,9 +1870,9 @@  add_ranges_from_rnglists (
 
 	    low = (uintptr_t) read_address (&rnglists_buf, u->addrsize);
 	    high = (uintptr_t) read_address (&rnglists_buf, u->addrsize);
-	    if (!add_range (state, rdata, low + base_address,
-			    high + base_address, error_callback, data,
-			    vec))
+	    if (!add_range (state, rdata, __RELOC_UINTPTR (low, base_address),
+			    __RELOC_UINTPTR (high, base_address),
+			    error_callback, data, vec))
 	      return 0;
 	  }
 	  break;
@@ -1874,7 +1884,7 @@  add_ranges_from_rnglists (
 
 	    low = (uintptr_t) read_address (&rnglists_buf, u->addrsize);
 	    length = (uintptr_t) read_uleb128 (&rnglists_buf);
-	    low += base_address;
+	    low = __RELOC_UINTPTR (low, base_address);
 	    if (!add_range (state, rdata, low, low + length,
 			    error_callback, data, vec))
 	      return 0;
@@ -1902,7 +1912,7 @@  add_ranges_from_rnglists (
 static int
 add_ranges (struct backtrace_state *state,
 	    const struct dwarf_sections *dwarf_sections,
-	    uintptr_t base_address, int is_bigendian,
+	    base_address_type base_address, int is_bigendian,
 	    struct unit *u, uintptr_t base, const struct pcrange *pcrange,
 	    int (*add_range) (struct backtrace_state *state, void *rdata, 
 			      uintptr_t lowpc, uintptr_t highpc,
@@ -1938,7 +1948,8 @@  add_ranges (struct backtrace_state *state,
    read, 0 if there is some error.  */
 
 static int
-find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
+find_address_ranges (struct backtrace_state *state,
+		     base_address_type base_address,
 		     struct dwarf_buf *unit_buf,
 		     const struct dwarf_sections *dwarf_sections,
 		     int is_bigendian, struct dwarf_data *altlink,
@@ -2093,7 +2104,8 @@  find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
    on success, 0 on failure.  */
 
 static int
-build_address_map (struct backtrace_state *state, uintptr_t base_address,
+build_address_map (struct backtrace_state *state,
+		   base_address_type base_address,
 		   const struct dwarf_sections *dwarf_sections,
 		   int is_bigendian, struct dwarf_data *altlink,
 		   backtrace_error_callback error_callback, void *data,
@@ -2312,7 +2324,7 @@  add_line (struct backtrace_state *state, struct dwarf_data *ddata,
 
   /* Add in the base address here, so that we can look up the PC
      directly.  */
-  ln->pc = pc + ddata->base_address;
+  ln->pc = __RELOC_UINTPTR (pc, ddata->base_address);
 
   ln->filename = filename;
   ln->lineno = lineno;
@@ -3951,7 +3963,7 @@  dwarf_fileline (struct backtrace_state *state, uintptr_t pc,
 
 static struct dwarf_data *
 build_dwarf_data (struct backtrace_state *state,
-		  uintptr_t base_address,
+		  base_address_type base_address,
 		  const struct dwarf_sections *dwarf_sections,
 		  int is_bigendian,
 		  struct dwarf_data *altlink,
@@ -4009,7 +4021,7 @@  build_dwarf_data (struct backtrace_state *state,
 
 int
 backtrace_dwarf_add (struct backtrace_state *state,
-		     uintptr_t base_address,
+		     base_address_type base_address,
 		     const struct dwarf_sections *dwarf_sections,
 		     int is_bigendian,
 		     struct dwarf_data *fileline_altlink,
diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index 3cd87020b031..c2d18b4a398e 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -633,7 +633,7 @@  elf_symbol_search (const void *vkey, const void *ventry)
 
 static int
 elf_initialize_syminfo (struct backtrace_state *state,
-			uintptr_t base_address,
+			base_address_type base_address,
 			const unsigned char *symtab_data, size_t symtab_size,
 			const unsigned char *strtab, size_t strtab_size,
 			backtrace_error_callback error_callback,
@@ -699,7 +699,7 @@  elf_initialize_syminfo (struct backtrace_state *state,
 	  = *(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].address = __RELOC_UINTPTR (elf_symbols[j].address, base_address);
       elf_symbols[j].size = sym->st_size;
       ++j;
     }
@@ -6506,7 +6506,7 @@  backtrace_uncompress_lzma (struct backtrace_state *state,
 static int
 elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 	 const unsigned char *memory, size_t memory_size,
-	 uintptr_t base_address, struct elf_ppc64_opd_data *caller_opd,
+	 base_address_type base_address, struct elf_ppc64_opd_data *caller_opd,
 	 backtrace_error_callback error_callback, void *data,
 	 fileline *fileline_fn, int *found_sym, int *found_dwarf,
 	 struct dwarf_data **fileline_entry, int exe, int debuginfo,
@@ -6636,9 +6636,15 @@  elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 
   /* If the executable is ET_DYN, it is either a PIE, or we are running
      directly a shared library with .interp.  We need to wait for
-     dl_iterate_phdr in that case to determine the actual base_address.  */
+     dl_iterate_phdr in that case to determine the actual base_address.
+     In case of FDPIC we always need the actual base_address.  */
+#ifndef __FDPIC__
   if (exe && ehdr.e_type == ET_DYN)
     return -1;
+#else
+  if (exe)
+    return -1;
+#endif
 
   shoff = ehdr.e_shoff;
   shnum = ehdr.e_shnum;
@@ -7413,9 +7419,9 @@  backtrace_initialize (struct backtrace_state *state, const char *filename,
   fileline elf_fileline_fn = elf_nodebug;
   struct phdr_data pd;
 
-  ret = elf_add (state, filename, descriptor, NULL, 0, 0, NULL, error_callback,
-		 data, &elf_fileline_fn, &found_sym, &found_dwarf, NULL, 1, 0,
-		 NULL, 0);
+  ret = elf_add (state, filename, descriptor, NULL, 0, no_base_address, NULL,
+		 error_callback, data, &elf_fileline_fn, &found_sym,
+		 &found_dwarf, NULL, 1, 0, NULL, 0);
   if (!ret)
     return 0;
 
diff --git a/libbacktrace/internal.h b/libbacktrace/internal.h
index 4fa0af8cb6c9..456911166026 100644
--- a/libbacktrace/internal.h
+++ b/libbacktrace/internal.h
@@ -323,10 +323,22 @@  struct dwarf_sections
 
 struct dwarf_data;
 
+#if defined (HAVE_DL_ITERATE_PHDR) && defined (__FDPIC__)
+typedef struct elf32_fdpic_loadaddr base_address_type;
+#define __RELOC_UINTPTR(ptr, base) ((uintptr_t)__RELOC_POINTER (ptr, base))
+#define no_base_address ((struct elf32_fdpic_loadaddr){0})
+#else
+typedef uintptr_t base_address_type;
+#define __RELOC_POINTER(ptr, base) ((ptr) + (base))
+#define __RELOC_UINTPTR(ptr, base) ((uintptr_t)__RELOC_POINTER (ptr, base))
+#define no_base_address ((uintptr_t)0)
+#endif
+
+
 /* Add file/line information for a DWARF module.  */
 
 extern int backtrace_dwarf_add (struct backtrace_state *state,
-				uintptr_t base_address,
+				base_address_type base_address,
 				const struct dwarf_sections *dwarf_sections,
 				int is_bigendian,
 				struct dwarf_data *fileline_altlink,