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