https://gcc.gnu.org/g:c6803cdaba7a7bf933e52cd36f901430253cc2b0

commit r15-2051-gc6803cdaba7a7bf933e52cd36f901430253cc2b0
Author: Ian Lance Taylor <i...@golang.org>
Date:   Mon Jul 15 17:27:18 2024 -0700

    libbacktrace: support FDPIC
    
    Based on patch by Max Filippov.
    
            * internal.h: If FDPIC, #include <link.h> and/or <sys/link.h>.
            (libbacktrace_using_fdpic): Define.
            (struct libbacktrace_base_address): Define.
            (libbacktrace_add_base): Define.
            (backtrace_dwarf_add): Change base_address to struct
            libbacktrace_base_address.
            * dwarf.c (struct dwarf_data): Change base_address to struct
            libbacktrace_base_address.
            (add_ranges, find_address_ranges, build_ddress_map): Likewise.
            (build_dwarf_data, build_dwarf_add): Likewise.
            (add_low_high_range): Change base_address to struct
            libbacktrace_base_address.  Use libbacktrace_add_base.
            (add_ranges_from_ranges, add_ranges_from_rnglists): Likewise.
            (add_line): Use libbacktrace_add_base.
            * elf.c (elf_initialize_syminfo): Change base_address to struct
            libbacktrace_base_address.  Use libbacktrace_add_base.
            (elf_add): Change base_address to struct
            libbacktrace_base_address.
            (phdr_callback): Likewise.  Initialize base_address.m.
            (backtrace_initialize): If using FDPIC, don't call elf_add with
            main executable; always use dl_iterate_phdr.
            * macho.c (macho_add_symtab): Change base_address to struct
            libbacktrace_base_address.  Use libbacktrace_add_base.
            (macho_syminfo): Change base_address to struct
            libbacktrace_base_address.
            (macho_add_fat, macho_add_dsym, macho_add): Likewise.
            (backtrace_initialize): Likewise.  Initialize base_address.m.
            * pecoff.c (coff_initialize_syminfo): Change base_address to
            struct libbacktrace_base_address.  Use libbacktrace_add_base.
            (coff_add): Change base_address to struct
            libbacktrace_base_address.  Initialize base_address.m.

Diff:
---
 libbacktrace/dwarf.c    | 63 +++++++++++++++++++++++++++----------------------
 libbacktrace/elf.c      | 31 +++++++++++++++++-------
 libbacktrace/internal.h | 36 +++++++++++++++++++++++++++-
 libbacktrace/macho.c    | 25 ++++++++++++--------
 libbacktrace/pecoff.c   | 30 ++++++++++++-----------
 5 files changed, 123 insertions(+), 62 deletions(-)

diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c
index cc36a0a2990d..96ffc4cc481b 100644
--- a/libbacktrace/dwarf.c
+++ b/libbacktrace/dwarf.c
@@ -388,8 +388,8 @@ struct dwarf_data
   struct dwarf_data *next;
   /* The data for .gnu_debugaltlink.  */
   struct dwarf_data *altlink;
-  /* The base address for this file.  */
-  uintptr_t base_address;
+  /* The base address mapping for this file.  */
+  struct libbacktrace_base_address base_address;
   /* A sorted list of address ranges.  */
   struct unit_addrs *addrs;
   /* Number of address ranges in list.  */
@@ -1610,8 +1610,9 @@ 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,
-                   struct unit *u, const struct pcrange *pcrange,
+                   struct libbacktrace_base_address base_address,
+                   int is_bigendian, struct unit *u,
+                   const struct pcrange *pcrange,
                    int (*add_range) (struct backtrace_state *state,
                                      void *rdata, uintptr_t lowpc,
                                      uintptr_t highpc,
@@ -1646,8 +1647,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 = libbacktrace_add_base (lowpc, base_address);
+  highpc = libbacktrace_add_base (highpc, base_address);
 
   return add_range (state, rdata, lowpc, highpc, error_callback, data, vec);
 }
@@ -1659,7 +1660,7 @@ static int
 add_ranges_from_ranges (
     struct backtrace_state *state,
     const struct dwarf_sections *dwarf_sections,
-    uintptr_t base_address, int is_bigendian,
+    struct libbacktrace_base_address base_address, int is_bigendian,
     struct unit *u, uintptr_t base,
     const struct pcrange *pcrange,
     int (*add_range) (struct backtrace_state *state, void *rdata,
@@ -1705,10 +1706,11 @@ add_ranges_from_ranges (
        base = (uintptr_t) high;
       else
        {
-         if (!add_range (state, rdata,
-                         (uintptr_t) low + base + base_address,
-                         (uintptr_t) high + base + base_address,
-                         error_callback, data, vec))
+         uintptr_t rl, rh;
+
+         rl = libbacktrace_add_base ((uintptr_t) low + base, base_address);
+         rh = libbacktrace_add_base ((uintptr_t) high + base, base_address);
+         if (!add_range (state, rdata, rl, rh, error_callback, data, vec))
            return 0;
        }
     }
@@ -1726,7 +1728,7 @@ static int
 add_ranges_from_rnglists (
     struct backtrace_state *state,
     const struct dwarf_sections *dwarf_sections,
-    uintptr_t base_address, int is_bigendian,
+    struct libbacktrace_base_address 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 +1811,10 @@ 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,
+                           libbacktrace_add_base (low, base_address),
+                           libbacktrace_add_base (high, base_address),
+                           error_callback, data, vec))
              return 0;
          }
          break;
@@ -1828,7 +1831,7 @@ add_ranges_from_rnglists (
                                     error_callback, data, &low))
              return 0;
            length = read_uleb128 (&rnglists_buf);
-           low += base_address;
+           low = libbacktrace_add_base (low, base_address);
            if (!add_range (state, rdata, low, low + length,
                            error_callback, data, vec))
              return 0;
@@ -1842,8 +1845,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,
+                           libbacktrace_add_base (low + base, base_address),
+                           libbacktrace_add_base (high + base, base_address),
                            error_callback, data, vec))
              return 0;
          }
@@ -1860,9 +1864,10 @@ 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,
+                           libbacktrace_add_base (low, base_address),
+                           libbacktrace_add_base (high, base_address),
+                           error_callback, data, vec))
              return 0;
          }
          break;
@@ -1874,7 +1879,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 = libbacktrace_add_base (low, base_address);
            if (!add_range (state, rdata, low, low + length,
                            error_callback, data, vec))
              return 0;
@@ -1902,7 +1907,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,
+           struct libbacktrace_base_address 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 +1943,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,
+                    struct libbacktrace_base_address base_address,
                     struct dwarf_buf *unit_buf,
                     const struct dwarf_sections *dwarf_sections,
                     int is_bigendian, struct dwarf_data *altlink,
@@ -2093,7 +2099,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,
+                  struct libbacktrace_base_address base_address,
                   const struct dwarf_sections *dwarf_sections,
                   int is_bigendian, struct dwarf_data *altlink,
                   backtrace_error_callback error_callback, void *data,
@@ -2312,7 +2319,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 = libbacktrace_add_base (pc, ddata->base_address);
 
   ln->filename = filename;
   ln->lineno = lineno;
@@ -3951,7 +3958,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,
+                 struct libbacktrace_base_address base_address,
                  const struct dwarf_sections *dwarf_sections,
                  int is_bigendian,
                  struct dwarf_data *altlink,
@@ -4009,7 +4016,7 @@ build_dwarf_data (struct backtrace_state *state,
 
 int
 backtrace_dwarf_add (struct backtrace_state *state,
-                    uintptr_t base_address,
+                    struct libbacktrace_base_address 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 107c96892a03..e8d67feab6d3 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,
+                       struct libbacktrace_base_address 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,8 @@ 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 =
+       libbacktrace_add_base (elf_symbols[j].address, base_address);
       elf_symbols[j].size = sym->st_size;
       ++j;
     }
@@ -6499,7 +6500,8 @@ 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,
+        struct libbacktrace_base_address 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,
@@ -7349,6 +7351,7 @@ phdr_callback (struct dl_phdr_info *info, size_t size 
ATTRIBUTE_UNUSED,
   const char *filename;
   int descriptor;
   int does_not_exist;
+  struct libbacktrace_base_address base_address;
   fileline elf_fileline_fn;
   int found_dwarf;
 
@@ -7378,7 +7381,8 @@ phdr_callback (struct dl_phdr_info *info, size_t size 
ATTRIBUTE_UNUSED,
        return 0;
     }
 
-  if (elf_add (pd->state, filename, descriptor, NULL, 0, info->dlpi_addr, NULL,
+  base_address.m = info->dlpi_addr;
+  if (elf_add (pd->state, filename, descriptor, NULL, 0, base_address, NULL,
               pd->error_callback, pd->data, &elf_fileline_fn, pd->found_sym,
               &found_dwarf, NULL, 0, 0, NULL, 0))
     {
@@ -7407,11 +7411,20 @@ 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);
-  if (!ret)
-    return 0;
+  /* When using fdpic we must use dl_iterate_phdr for all modules, including
+     the main executable, so that we can get the right base address
+     mapping.  */
+  if (!libbacktrace_using_fdpic ())
+    {
+      struct libbacktrace_base_address zero_base_address;
+
+      memset (&zero_base_address, 0, sizeof zero_base_address);
+      ret = elf_add (state, filename, descriptor, NULL, 0, zero_base_address,
+                    NULL, error_callback, data, &elf_fileline_fn, &found_sym,
+                    &found_dwarf, NULL, 1, 0, NULL, 0);
+      if (!ret)
+       return 0;
+    }
 
   pd.state = state;
   pd.error_callback = error_callback;
diff --git a/libbacktrace/internal.h b/libbacktrace/internal.h
index 4fa0af8cb6c9..a119cda692fd 100644
--- a/libbacktrace/internal.h
+++ b/libbacktrace/internal.h
@@ -323,10 +323,44 @@ struct dwarf_sections
 
 struct dwarf_data;
 
+/* The load address mapping.  */
+
+#if defined(__FDPIC__) && defined(HAVE_DL_ITERATE_PHDR) && 
(defined(HAVE_LINK_H) || defined(HAVE_SYS_LINK_H))
+
+#ifdef HAVE_LINK_H
+ #include <link.h>
+#endif
+#ifdef HAVE_SYS_LINK_H
+ #include <sys/link.h>
+#endif
+
+#define libbacktrace_using_fdpic() (1)
+
+struct libbacktrace_base_address
+{
+  struct elf32_fdpic_loadaddr m;
+};
+
+#define libbacktrace_add_base(pc, base) \
+  ((uintptr_t) (__RELOC_POINTER ((pc), (base).m)))
+
+#else /* not _FDPIC__ */
+
+#define libbacktrace_using_fdpic() (0)
+
+struct libbacktrace_base_address
+{
+  uintptr_t m;
+};
+
+#define libbacktrace_add_base(pc, base) ((pc) + (base).m)
+
+#endif /* not _FDPIC__ */
+
 /* Add file/line information for a DWARF module.  */
 
 extern int backtrace_dwarf_add (struct backtrace_state *state,
-                               uintptr_t base_address,
+                               struct libbacktrace_base_address base_address,
                                const struct dwarf_sections *dwarf_sections,
                                int is_bigendian,
                                struct dwarf_data *fileline_altlink,
diff --git a/libbacktrace/macho.c b/libbacktrace/macho.c
index 8f768f14a579..fc4c9591dfa3 100644
--- a/libbacktrace/macho.c
+++ b/libbacktrace/macho.c
@@ -315,8 +315,9 @@ static const char * const dwarf_section_names[DEBUG_MAX] =
 /* Forward declaration.  */
 
 static int macho_add (struct backtrace_state *, const char *, int, off_t,
-                     const unsigned char *, uintptr_t, int,
-                     backtrace_error_callback, void *, fileline *, int *);
+                     const unsigned char *, struct libbacktrace_base_address,
+                     int, backtrace_error_callback, void *, fileline *,
+                     int *);
 
 /* A dummy callback function used when we can't find any debug info.  */
 
@@ -511,7 +512,7 @@ macho_defined_symbol (uint8_t type)
 
 static int
 macho_add_symtab (struct backtrace_state *state, int descriptor,
-                 uintptr_t base_address, int is_64,
+                 struct libbacktrace_base_address base_address, int is_64,
                  off_t symoff, unsigned int nsyms, off_t stroff,
                  unsigned int strsize,
                  backtrace_error_callback error_callback, void *data)
@@ -626,7 +627,7 @@ macho_add_symtab (struct backtrace_state *state, int 
descriptor,
       if (name[0] == '_')
        ++name;
       macho_symbols[j].name = name;
-      macho_symbols[j].address = value + base_address;
+      macho_symbols[j].address = libbacktrace_add_base (value, base_address);
       ++j;
     }
 
@@ -758,7 +759,8 @@ macho_syminfo (struct backtrace_state *state, uintptr_t 
addr,
 static int
 macho_add_fat (struct backtrace_state *state, const char *filename,
               int descriptor, int swapped, off_t offset,
-              const unsigned char *match_uuid, uintptr_t base_address,
+              const unsigned char *match_uuid,
+              struct libbacktrace_base_address base_address,
               int skip_symtab, uint32_t nfat_arch, int is_64,
               backtrace_error_callback error_callback, void *data,
               fileline *fileline_fn, int *found_sym)
@@ -860,7 +862,8 @@ macho_add_fat (struct backtrace_state *state, const char 
*filename,
 
 static int
 macho_add_dsym (struct backtrace_state *state, const char *filename,
-               uintptr_t base_address, const unsigned char *uuid,
+               struct libbacktrace_base_address base_address,
+               const unsigned char *uuid,
                backtrace_error_callback error_callback, void *data,
                fileline* fileline_fn)
 {
@@ -978,7 +981,7 @@ macho_add_dsym (struct backtrace_state *state, const char 
*filename,
 static int
 macho_add (struct backtrace_state *state, const char *filename, int descriptor,
           off_t offset, const unsigned char *match_uuid,
-          uintptr_t base_address, int skip_symtab,
+          struct libbacktrace_base_address base_address, int skip_symtab,
           backtrace_error_callback error_callback, void *data,
           fileline *fileline_fn, int *found_sym)
 {
@@ -1240,7 +1243,7 @@ backtrace_initialize (struct backtrace_state *state, 
const char *filename,
   c = _dyld_image_count ();
   for (i = 0; i < c; ++i)
     {
-      uintptr_t base_address;
+      struct libbacktrace_base_address base_address;
       const char *name;
       int d;
       fileline mff;
@@ -1264,7 +1267,7 @@ backtrace_initialize (struct backtrace_state *state, 
const char *filename,
            continue;
        }
 
-      base_address = _dyld_get_image_vmaddr_slide (i);
+      base_address.m = _dyld_get_image_vmaddr_slide (i);
 
       mff = macho_nodebug;
       if (!macho_add (state, name, d, 0, NULL, base_address, 0,
@@ -1319,10 +1322,12 @@ backtrace_initialize (struct backtrace_state *state, 
const char *filename,
                      void *data, fileline *fileline_fn)
 {
   fileline macho_fileline_fn;
+  struct libbacktrace_base_address zero_base_address;
   int found_sym;
 
   macho_fileline_fn = macho_nodebug;
-  if (!macho_add (state, filename, descriptor, 0, NULL, 0, 0,
+  memset (&zero_base_address, 0, sizeof zero_base_address);
+  if (!macho_add (state, filename, descriptor, 0, NULL, zero_base_address, 0,
                  error_callback, data, &macho_fileline_fn, &found_sym))
     return 0;
 
diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c
index e88e4d2b0383..636e1b11296b 100644
--- a/libbacktrace/pecoff.c
+++ b/libbacktrace/pecoff.c
@@ -382,10 +382,11 @@ coff_is_function_symbol (const b_coff_internal_symbol 
*isym)
 
 static int
 coff_initialize_syminfo (struct backtrace_state *state,
-                        uintptr_t base_address, int is_64,
-                        const b_coff_section_header *sects, size_t sects_num,
-                        const b_coff_external_symbol *syms, size_t syms_size,
-                        const unsigned char *strtab, size_t strtab_size,
+                        struct libbacktrace_base_address base_address,
+                        int is_64, const b_coff_section_header *sects,
+                        size_t sects_num, const b_coff_external_symbol *syms,
+                        size_t syms_size, const unsigned char *strtab,
+                        size_t strtab_size,
                         backtrace_error_callback error_callback,
                         void *data, struct coff_syminfo_data *sdata)
 {
@@ -490,9 +491,10 @@ coff_initialize_syminfo (struct backtrace_state *state,
          secnum = coff_read2 (asym->section_number);
 
          coff_sym->name = name;
-         coff_sym->address = (coff_read4 (asym->value)
-                              + sects[secnum - 1].virtual_address
-                              + base_address);
+         coff_sym->address =
+           libbacktrace_add_base ((coff_read4 (asym->value)
+                                   + sects[secnum - 1].virtual_address),
+                                  base_address);
          coff_sym++;
        }
 
@@ -662,8 +664,8 @@ coff_add (struct backtrace_state *state, int descriptor,
   struct backtrace_view debug_view;
   int debug_view_valid;
   int is_64;
-  uintptr_t image_base;
-  uintptr_t base_address = 0;
+  struct libbacktrace_base_address image_base;
+  struct libbacktrace_base_address base_address;
   struct dwarf_sections dwarf_sections;
 
   *found_sym = 0;
@@ -739,13 +741,14 @@ coff_add (struct backtrace_state *state, int descriptor,
     (sects_view.data + fhdr.size_of_optional_header);
 
   is_64 = 0;
+  memset (&image_base, 0, sizeof image_base);
   if (fhdr.size_of_optional_header > sizeof (*opt_hdr))
     {
       if (opt_hdr->magic == PE_MAGIC)
-       image_base = opt_hdr->u.pe.image_base;
+       image_base.m = opt_hdr->u.pe.image_base;
       else if (opt_hdr->magic == PEP_MAGIC)
        {
-         image_base = opt_hdr->u.pep.image_base;
+         image_base.m = opt_hdr->u.pep.image_base;
          is_64 = 1;
        }
       else
@@ -754,8 +757,6 @@ coff_add (struct backtrace_state *state, int descriptor,
          goto fail;
        }
     }
-  else
-    image_base = 0;
 
   /* Read the symbol table and the string table.  */
 
@@ -910,8 +911,9 @@ coff_add (struct backtrace_state *state, int descriptor,
                                  + (sections[i].offset - min_offset));
     }
 
+  memset (&base_address, 0, sizeof base_address);
 #ifdef HAVE_WINDOWS_H
-  base_address = module_handle - image_base;
+  base_address.m = module_handle - image_base.m;
 #endif
 
   if (!backtrace_dwarf_add (state, base_address, &dwarf_sections,

Reply via email to