From a6f2a7a2a871d88402dc28c02bee672f8321b7bb Mon Sep 17 00:00:00 2001 From: Tommi Rantala Date: Tue, 28 Aug 2012 09:40:08 +0300 Subject: [PATCH] Fix incorrect .debug_frame lookup with non-zero text segment vaddr Unwinding over ptrace and unwinding coredump fail to lookup the .debug_frame dwarf data when the ELF file text segment virtual address is non-zero. Looking at some binaries, the virtual address is non-zero for non-pie binaries, and zero for PIC shared libraries and PIE executables. The core dump unwinder can be used for demonstrating the bug. Without this patch, the unwinding fails badly (testing with a ARM qemu image): $ UNW_ARM_UNWIND_METHOD=1 ./test-coredump-unwind core `cat backing_files` test-coredump-unwind: unw_get_proc_info(ip=0x86d8) failed: ret=-10 After applying this patch, we can unwind all the way until running out of dwarf data: $ UNW_ARM_UNWIND_METHOD=1 ./test-coredump-unwind core `cat backing_files` ip=0x000086d8 proc=000086d4-000086dc handler=0x00000000 lsda=0x00000000 test-coredump-unwind: step test-coredump-unwind: step done:1 ip=0x000086ef proc=000086dc-000086f2 handler=0x00000000 lsda=0x00000000 test-coredump-unwind: step test-coredump-unwind: step done:1 ip=0x000086e7 proc=000086dc-000086f2 handler=0x00000000 lsda=0x00000000 test-coredump-unwind: step test-coredump-unwind: step done:1 ip=0x00008597 proc=00008584-0000859a handler=0x00000000 lsda=0x00000000 test-coredump-unwind: step test-coredump-unwind: step done:1 ip=0x76eacc3b proc=76eacba0-76eaccec handler=0x00000000 lsda=0x00000000 test-coredump-unwind: step test-coredump-unwind: step done:1 test-coredump-unwind: unw_get_proc_info(ip=0x85c3) failed: ret=-10 Note how the binary itself is mapped to address 0x8000, the virtual address for the text segment is 0x8000, and the .debug_frame program counter values are relative to 0: $ tr ' ' '\n' < backing_files 0x8000:/home/user/tests/crasher 0x76e96000:/lib/arm-linux-gnueabi/libc-2.13.so 0x76f77000:/lib/arm-linux-gnueabi/libgcc_s.so.1 0x76f88000:/lib/arm-linux-gnueabi/ld-2.13.so $ readelf -l crasher Elf file type is EXEC (Executable file) Entry point 0x859d There are 9 program headers, starting at offset 52 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align EXIDX 0x0007b0 0x000087b0 0x000087b0 0x00030 0x00030 R 0x4 PHDR 0x000034 0x00008034 0x00008034 0x00120 0x00120 R E 0x4 INTERP 0x000154 0x00008154 0x00008154 0x00013 0x00013 R 0x1 [Requesting program interpreter: /lib/ld-linux.so.3] LOAD 0x000000 0x00008000 0x00008000 0x007e4 0x007e4 R E 0x8000 LOAD 0x000efc 0x00010efc 0x00010efc 0x00148 0x00154 RW 0x8000 DYNAMIC 0x000f08 0x00010f08 0x00010f08 0x000f8 0x000f8 RW 0x4 NOTE 0x000168 0x00008168 0x00008168 0x00044 0x00044 R 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 GNU_RELRO 0x000efc 0x00010efc 0x00010efc 0x00104 0x00104 R 0x1 $ readelf --debug-dump=frames crasher | grep FDE 00000010 00000024 00000000 FDE cie=00000000 pc=00008614..000086d4 00000038 0000000c 00000000 FDE cie=00000000 pc=000086d4..000086dc 00000048 00000014 00000000 FDE cie=00000000 pc=000086dc..000086f2 00000060 00000014 00000000 FDE cie=00000000 pc=00008584..0000859a --- src/dwarf/Gfind_unwind_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dwarf/Gfind_unwind_table.c b/src/dwarf/Gfind_unwind_table.c index 800531e2..961226a5 100644 --- a/src/dwarf/Gfind_unwind_table.c +++ b/src/dwarf/Gfind_unwind_table.c @@ -220,7 +220,7 @@ dwarf_find_unwind_table (struct elf_dyn_info *edi, unw_addr_space_t as, #ifdef CONFIG_DEBUG_FRAME /* Try .debug_frame. */ - found = dwarf_find_debug_frame (found, &edi->di_debug, ip, segbase, path, + found = dwarf_find_debug_frame (found, &edi->di_debug, ip, load_base, path, start_ip, end_ip); #endif