summaryrefslogtreecommitdiffstats
path: root/src/readelf.c
diff options
context:
space:
mode:
authorMark Wielaard <[email protected]>2012-12-21 22:11:44 +0100
committerMark Wielaard <[email protected]>2012-12-22 13:17:56 +0100
commit00f758c2c1625a932456c17fd8c80fc904db3484 (patch)
treeb1e47a7f7bf30725dd903ad83996792ca7e43063 /src/readelf.c
parent5532404e1ad6dd64f87226702ab32c8f40106d55 (diff)
readelf: Adjust initial FDE address if pcrel before printing.
The FDE initial_location is printed as start address with format_dwarf_addr. Which does the right thing for .debug_frame addresses, but in .eh_frame this is encoded as DW_EH_PE_pcrel and so needs to be adjusted before formatting. Signed-off-by: Mark Wielaard <[email protected]>
Diffstat (limited to 'src/readelf.c')
-rw-r--r--src/readelf.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/src/readelf.c b/src/readelf.c
index 7f6f31c6..0a9629a7 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -4710,6 +4710,14 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
(void) elf_getshdrstrndx (ebl->elf, &shstrndx);
const char *scnname = elf_strptr (ebl->elf, shstrndx, shdr->sh_name);
+ /* Needed if we find PC-relative addresses. */
+ GElf_Addr bias;
+ if (dwfl_module_getelf (dwflmod, &bias) == NULL)
+ {
+ error (0, 0, gettext ("cannot get ELF: %s"), dwfl_errmsg (-1));
+ return;
+ }
+
Elf_Data *data = elf_rawdata (scn, NULL);
if (unlikely (data == NULL))
@@ -4956,8 +4964,21 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
Dwarf_Word address_range
= read_ubyte_unaligned_inc (ptr_size, dbg, readp);
+ /* pcrel for an FDE address is relative to the runtime
+ address of the start_address field itself. Sign extend
+ if necessary to make sure the calculation is done on the
+ full 64 bit address even when initial_location only holds
+ the lower 32 bits. */
+ Dwarf_Addr pc_start = initial_location;
+ if (ptr_size == 4)
+ pc_start = (uint64_t) (int32_t) pc_start;
+ if ((fde_encoding & 0x70) == DW_EH_PE_pcrel)
+ pc_start += ((uint64_t) shdr->sh_addr
+ + (base - (const unsigned char *) data->d_buf)
+ - bias);
+
char *a = format_dwarf_addr (dwflmod, cie->address_size,
- initial_location);
+ pc_start);
printf ("\n [%6tx] FDE length=%" PRIu64 " cie=[%6tx]\n"
" CIE_pointer: %" PRIu64 "\n"
" initial_location: %s",