Instead of maintaining a pointer to the `sos_memory' array, maintain an
index that tells the next free position. When atomic operations are
available, the allocation boils down to a single fetch-and-add
operation.
To ensure that we return properly aligned pointers from sos_alloc(),
MAX_ALIGN must be a power-of-two. On i386 the power-of-two assumption
fails as sizeof(long double) = 12. Fix this by rounding up to 16.
Use the __BIGGEST_ALIGNMENT__ macro provided by GCC for sos_alloc()
allocation alignment. The macro gives ``the largest alignment ever used
for any data type on the target machine you are compiling for.''
__BIGGEST_ALIGNMENT__ also has some other nice properties, e.g. it is
power-of-two on all architectures (note that on i386, sizeof(long
double) = 12), and on some architectures (e.g. SuperH) the alignment
requirement can be lower than sizeof(long double).
tdep_get_func_addr in ppc64 passes NULL for the last argument of
as->access_mem. tdep_get_func_addr is called by elf_w(lookup_symbol),
which in turn is called by elf_w(get_proc_name_in_image).
elf_w(get_proc_name_in_image) is part of the API, and is only passed an
unw_addr_space_t, not a unw_cursor_t, meaning that we cannot recover the
UPT_info on the PPC64 platform.
This could be fixed by giving libunwind the knowledge to perform
relocations itself, thus not needing to look at the running image to
determine function addresses.
Disable the building of libunwind-coredump except on x86_64 and x86
(where implimentations exsist).
Allow overriding of this autodetection via --enable-coredump and
--disable-coredump.
Rename the `ALIGN' macro to `UNW_ALIGN', and move it from
`_UCD_internal.h' to `libunwind_i.h' so that we can share it with the
mempool code. `ALIGN' was clashing with system headers on FreeBSD:
In file included from src/coredump/_UCD_access_reg_freebsd.c:26:
src/coredump/_UCD_internal.h:102:1: warning: "ALIGN" redefined
In file included from /usr/include/sys/param.h:115,
from src/coredump/_UCD_lib.h:52,
from src/coredump/_UCD_access_reg_freebsd.c:24:
/usr/include/machine/param.h:79:1: warning: this is the location of the previous definition
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
After successfully stepping the cursor on ARM, the proc info is
invalidated only in dwarf_step(). Invalidate the proc info also when
stepping with the non-dwarf based methods. This fixes
unw_get_proc_info() returning stale data.
The core dump unwinder can be used for demonstrating the bug. When
unwinding based only on DWARF data, the proc info is correct:
$ UNW_ARM_UNWIND_METHOD=1 ./test-coredump-unwind core `cat backing_files` 2>/dev/null
ip=0x000086d8 proc=000086d4-000086dc handler=0x00000000 lsda=0x00000000
ip=0x000086ef proc=000086dc-000086f2 handler=0x00000000 lsda=0x00000000
ip=0x000086e7 proc=000086dc-000086f2 handler=0x00000000 lsda=0x00000000
ip=0x00008597 proc=00008584-0000859a handler=0x00000000 lsda=0x00000000
ip=0x76e3ac3b proc=76e3aba0-76e3acec handler=0x00000000 lsda=0x00000000
When unwinding based only on the exidx method, we see the proc info
lagging behind:
$ UNW_ARM_UNWIND_METHOD=4 ./test-coredump-unwind core `cat backing_files` 2>/dev/null
ip=0x000086d8 proc=000086d4-000086db handler=0x00000000 lsda=0x00000000
ip=0x000086ef proc=000086d4-000086db handler=0x00000000 lsda=0x00000000
ip=0x000086e7 proc=000086dc-000086f3 handler=0x00000000 lsda=0x00000000
ip=0x00008597 proc=000086dc-000086f3 handler=0x00000000 lsda=0x00000000
ip=0x76e3ac3b proc=00008584-0000859b handler=0x00000000 lsda=0x00000000
ip=0x000085c3 proc=76e3aba0-76e3ae4b handler=0x00000000 lsda=0x00000000
Finally, with this patch applied, we get the desired proc info also with
the exidx unwinder:
$ UNW_ARM_UNWIND_METHOD=4 ./test-coredump-unwind core `cat backing_files` 2>/dev/null
ip=0x000086d8 proc=000086d4-000086db handler=0x00000000 lsda=0x00000000
ip=0x000086ef proc=000086dc-000086f3 handler=0x00000000 lsda=0x00000000
ip=0x000086e7 proc=000086dc-000086f3 handler=0x00000000 lsda=0x00000000
ip=0x00008597 proc=00008584-0000859b handler=0x00000000 lsda=0x00000000
ip=0x76e3ac3b proc=76e3aba0-76e3ae4b handler=0x00000000 lsda=0x00000000
ip=0x000085c3 proc=0000859c-00008613 handler=0x00000000 lsda=0x00000000
Implement the Linux version of _UCD_access_reg() for ARM. We can
sidestep the register number remapping, as the libunwind register
numbers match one-to-one to the ELF core file register numbers.
Just pass potentially NULL pointers to free() in the error path in
load_debug_frame(). Saved 40 bytes of code in libunwind.so on ARM -O2
thumb build at the expense of slightly slower execution.
Stop pretending that unw_get_proc_info() works on PPC, and instead give
an error back to the caller. As far as I can tell, none of the libunwind
tests clear out the `unw_proc_info_t' before passing it to
unw_get_proc_info(), so they would end up working on garbage data.
ppc32/Gstep.c:116: warning: comparison between pointer and integer
ppc32/Gstep.c:116: warning: comparison with string literal results in unspecified behavior
ppc32/Gstep.c:116: warning: initialization makes integer from pointer without a cast
ppc32/Gstep.c:116: warning: passing argument 2 of 'fprintf' makes pointer from integer without a cast
/usr/powerpc-linux-gnu/include/stdio.h:333: note: expected 'const char *__restrict__' but argument is of type 'int'
Fix bitrot in HPPA common_init(). This has only been compile tested.
hppa/init.h: In function 'common_init':
hppa/init.h:33: error: 'struct cursor' has no member named 'ip_loc'
hppa/init.h:33: warning: implicit declaration of function 'HPPA_REG_LOC'
hppa/init.h:34: error: 'struct cursor' has no member named 'sp_loc'
hppa/init.h:36: warning: implicit declaration of function 'hppa_get'
hppa/init.h:36: error: 'struct cursor' has no member named 'ip_loc'
hppa/init.h:36: error: 'struct cursor' has no member named 'ip'
hppa/init.h:40: error: 'struct cursor' has no member named 'sp'
When cross-compiling libunwind with optimizations (-O1 or higher),
gcc-4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) optimizes away the memory
writes prior to the inline asm() statement in arm_local_resume() in the
non-signal-frame path, causing the `regs' array to be only allocated on
the stack, but not populated. This means that we are restoring garbage
to the registers.
As suggested in the GCC docs, add a fixed size input memory constraint
for the array content. This is enough to get the desired code to be
generated.
Adding __builtin_unreachable() to the point that we should never reach
was also in itself enough to inhibit the optimization. It also reduces
the function size by a few instructions.
Check the endianness earlier in unw_create_addr_space() on all
architectures to avoid leaking the dynamically allocated address space
struct.
This was already fixed for ARM in commit cf6a998796 ("Fix memory leak
in ARM unw_create_addr_space()"). Move the endianness check also on ARM
to avoid malloc() & free() in the error case.
Properly export the symbol names also on MIPS. `make check' was
complaining:
src/.libs/libunwind.a(Linit.o): In function `mips_local_addr_space_init':
src/mips/Ginit.c:183: multiple definition of `mips_local_addr_space_init'
../src/.libs/libunwind-mips.a(Ginit.o):src/mips/Ginit.c:183: first defined here
src/.libs/libunwind.a(Lglobal.o): In function `_ULmips_init':
src/mips/Gglobal.c:42: multiple definition of `mips_lock'
../src/.libs/libunwind-mips.a(Gglobal.o):src/mips/Gglobal.c:42: first defined here
collect2: ld returned 1 exit status
After searching the normal symbol table, look if the binary contains
.gnu_debugdata section. If it does, run LZMA decompression on it, load
the resulting ELF image into memory and call lookup_symbol() on it
again.
lookup_symbol() is modified so that it takes min_dist as a parameter and
only returns a symbol when it finds one that is closer than indicated by
the parameter.
Signed-off-by: Martin Milata <mmilata@redhat.com>
The code for symbol lookup (elfxx.c:lookup_symbol) works by iterating
over symbol tables while maintaing the symbol closest to the supplied
instruction pointer. Whenever this search encountered symbol that was
longer than result buffer, the function returned -UNW_ENOMEM even though
the final symbol wasn't too long.
Signed-off-by: Martin Milata <mmilata@redhat.com>
dwarf/Gfind_unwind_table.c: In function '_Ux86_dwarf_find_unwind_table':
dwarf/Gfind_unwind_table.c:223:46: error: 'struct elf_dyn_info' has no member named 'edi'
Fixup commit d93d96ad83 ("Fix compilation
on IA64"), and replace the dwarf_find_unwind_table() call with
tdep_find_unwind_table().
Fixes linkage error on IA64:
../src/.libs/libunwind-coredump.so: undefined reference to `dwarf_find_unwind_table'
Change the way we generate the cursor header files, so that we do not
need to invoke IA64 binaries, which would fail when cross-compiling
libunwind.
Adopt the strategy used in the Linux kernel build system, and parse our
annotated offset information from the assembler file produced by the
compiler.
- Add tdep macro for {dwarf,ia64}_find_unwind_table so that ia64
doesn't try to use dwarf code.
- Fix extraneous #if.
- Fix mistyped filename in Makefile.am.
- Link ia64-specific tests with correct libraries.
Signed-off-by: Martin Milata <mmilata@redhat.com>
This reverts commit c9c5a40be1.
dwarf_get() returns 0 on success. We should continue unwinding
in that case.
TBD: investigate test-ptrace failure on some platforms.
If dwarf_get returns 0 (indicating the end of call chain), we should
not override the return value to 1. This may result in the caller
continuing to unwind and getting spurious errors.
In the commit d04dc94cc2, the check for
dwarf.ip == 0 was removed from non-dwarf walker in x86_64 version of
unw_step(). Apparently this broke the detection of the end of frame
chain when NULL %rbp is specified, because the case just marked
dwarf.ip as 0. Explicitly set ret to 0 to indicate the end of
iteration.
Older kernels interpret the pid argument of the process information
sysctls as pid only. If libunwind UPT consumer passed tid to _UPT_create,
tdep_get_elf_image() returns error due to sysctls failure. Provide a
slow workaround by searching for a process owning the supplied tid if
sysctl returned ESRCH.
Currently the expression evaluation always succeeds,
and possible error is not propagated to the caller.
The ',' operator makes the condition always return 0.
Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Tested-by: Paul Pluzhnikov <ppluzhnikov@google.com>
ALIGN lets you align pointers and STRUCT_MEMBER lets you get
structure members at a specific offset.
These are useful in general, and will be needed for the coredump notes
cleanup work.
These let you get the pid and the current signal from the coredump.
This isn't strictly unwind related, but these are trivial to implement
as we have the info, and you almost always want these when you're
printing a backtrace from a core file.
Move ptrace-independent code from src/ptrace/_UPT_find_proc_info.c
to src/dwarf/{G,L}find_unwind_table.c. Name this moved function
dwarf_find_unwind_table().
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
This is a common part of struct UPT_info
and struct UCD_info (to be introduced later).
Make _UPTi_find_unwind_table function operate only on this part
of struct UPT_info.
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Commit 7d43108f9c ("No
libunwind-generic.so if configured with --disable-shared") introduced a
check to avoid creating a broken libunwind-generic.so link, but the
result of the commit is that libunwind-generic.so is never created (at
least when installing to a clean directory).
We need to check for the installed libunwind-$(arch).so file,
libunwind-generic.so will be the symbolic link name.
There is a window of time between the munmap and the tls_cache being
marked as destroyed, where there could be a bad access to memory that
has been unmapped/freed. Reorder the code a bit to close the window.
Signed-off-by: Paul Pluzhnikov <ppluzhnikov@google.com>
Commit 297d9cd07d (Fix for failing test-setjmp)
breaks non glibc systems, since __GLIBC_PREREQ is not defined there.
As a consequence, preprocessor aborts with an error.
Trying to hide __GLIBC_PREREQ under #ifdef __GLIBC would require
either code duplication, or moving the longjmp implementation into
the separate file, which is included twice. In fact, I am not sure
in any use of the __GLIBC_PREREQ at the compile time, because the
compiled code can be run on the later version of glibc.
Below is the patch, tested on FreeBSD x86/x86_64 and Scientific Linux 6.1
x86_64. I compile the code always, but keep it in under unused static
symbol. In principle, the code could be optimized out by linker.
[ Minor formatting edits: asharma@fb.com ]
The crashes were tracked down to f->rpb_cfa_offset being incorrect.
The problem is that {rsp,rbp}_cfa_offset only have 15 bits, but for
SIGRETURN frame they are filled with:
// src/x86_64/Gstash_frame.c
f->cfa_reg_offset = d->cfa - c->sigcontext_addr;
f->rbp_cfa_offset = DWARF_GET_LOC(d->loc[RBP]) - d->cfa;
f->rsp_cfa_offset = DWARF_GET_LOC(d->loc[RSP]) - d->cfa;
The problem is that the delta here can be arbitrarily large when
sigaltstack is used, and can easily overflow the 15 and 30-bit fields.
When signal handler starts running, the stack layout is:
... higher addresses ...
ucontext
CFA->
__restore_rt (== pretcode in rt_sigframe from
linux-2.6/arch/x86/include/asm/sigframe.h)
SP ->
... sighandler runs on this stack.
... lower addresses ...
This makes it very convenient to find ucontext from the CFA.
Attached patch re-tested on Linux/x86_64, no new failures.
Signed-off-by: Paul Pluzhnikov <ppluzhnikov@google.com>
Reviwed-by: Lassi Tuura <lat@cern.ch>
On Mon, Nov 14, 2011 at 5:02 PM, Paul Pluzhnikov <ppluzhnikov@google.com> wrote:
> P.S. test-setjmp is failing for me (before or after the patch).
> When I enable assertions (to confirm my new assertions are correct), I see:
>
> lt-test-setjmp: ../../src/dwarf/Gparser.c:754: apply_reg_state: \
> Assertion `rs->reg[17].where == DWARF_WHERE_EXPR' failed.
>
> which likely explains that failure.
The problem is actually two-fold:
First, the loops in {sig,}longjmp.c are "do { ... } while (unw_step() >= 0);"
But unw_step() returns 0 on reaching the end of the chain (_start),
and the loop should stop there.
The second problem is that with this commit:
c67da0b50e
glibc obfuscates value of SP in jmp_buf, so we might as well just give up.
Patch attached.
Thanks,
--
Paul Pluzhnikov
The ARM EABI does not use the .eh_frame and .eh_frame_hdr sections for unwinding. Therefore it doesn't make sense to call dwarf_step if CONFIG_DEBUG_FRAME is not defined.