]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
readelf: Adjust initial FDE address if pcrel before printing.
authorMark Wielaard <mjw@redhat.com>
Fri, 21 Dec 2012 21:11:44 +0000 (22:11 +0100)
committerMark Wielaard <mjw@redhat.com>
Sat, 22 Dec 2012 12:17:56 +0000 (13:17 +0100)
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 <mjw@redhat.com>
src/ChangeLog
src/readelf.c

index 547605d5d913c365ea3b1538263d40eaa5db5786..404ef0bf95b3783915c26e6ffc09fb3a3ca8d702 100644 (file)
@@ -1,6 +1,11 @@
 2012-12-21  Mark Wielaard  <mjw@redhat.com>
 
-       * addr2line (main): Call dwfl_end.
+       * readelf.c (print_debug_frame_section): Adjust FDE start address
+       if pcrel before feeding it to format_dwarf_addr.
+
+2012-12-21  Mark Wielaard  <mjw@redhat.com>
+
+       * addr2line.c (main): Call dwfl_end.
 
 2012-12-11  Roland McGrath  <roland@hack.frob.com>
 
index 7f6f31c6e32c7bb667335e30ad619bd934c4df51..0a9629a7ea354b60a0e1d0761bf7317a90145657 100644 (file)
@@ -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",