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(-)

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,
-- 
2.39.2

Reply via email to