Ubuntu's libc-bin (2.15-0ubuntu20.2) on x86_64 uses DW_CFA_val_expression
in describing the pthread spinlock operations __lll_unlock_wake() and
__lll_lock_wait(). libunwind 1.1 doesn't understand that opcode and
so backtraces from those operations are truncated.
This changeset adds basic support for it, by adding a new type to
dwarf_loc_t that describes the register's actual contents rather than
its location. I've only implemented the new type for x86_64, and
stubbed it out for all other architectures -- it looks like a lot
of that code is duplicated so oughtn't to be that hard, but I don't
have test cases for them.
Tested that DW_CFA_val_expression works on x86_64 (by using
https://code.google.com/p/gperftools/ on a lock-heavy program).
Build-tested on x86, x86_64 and arm. The unit tests don't pass for me
on any of those archs, but this cset doesn't break anything that was
passing before.
Signed-off-by: Tim Deegan <tjd@phlegethon.org>
The dwarf_eval_expr routine uses macros push, pop, and pick to
manipulate the DWARF expression stack. When these macros are
nested, e.g. in the implementation of DW_OP_dup:
push (pick (0));
the combination can lead to unfortunate results.
In particular, when substituting into:
do {
if (tos >= MAX_EXPR_STACK_SIZE)
{
Debug (1, "Stack overflow\n");
return -UNW_EINVAL;
}
stack[tos++] = (x);
} while (0)
a value of "x" that makes use of "tos" (as instances of the
pick or pop macros do), the resulting expression will both
use and modify tos without an intervening sequence point,
which is undefined behavior according to the C standard.
And in fact with current GCC on PowerPC, this leads to a
miscompilation of the DW_OP_dup implementation.
This patch fixes the problem by assigning "x" to a
temporary variable before modifying tos.
Signed-off-by: Ulrich Weigand <uweigand@de.ibm.com>
The DWARF code allocates its unwind_info objects out of a
memory pool. The code which frees the object therefore calls
the mempool freeing code. However, there are cases where the
free code will be run with an unwind_info that was allocated
through a different mechanism (e.g. an ARM exidx table entry).
In these cases, the object should not be freed through the
mempool code.
To correct this, a check was added to ensure that the unwind_info
is of the appropriate type before passing the object along to the
mempool to be freed.
This change adds some special cases to allow libunwind to compile
for QNX.
* QNX's copy of <elf.h> and <link.h> reside in sys/ instead. To deal
with this, an AC_CHECK_HEADERS() was added to check for the files
in both locations.
* Similarly, QNX does not have <endian.h>. In cases where the file is
not found, logic was added to refer to QNX-specific macros to determine
endianness.
* The QCC compiler, which is a wrapper around GCC, cannot handle some
standard GCC options. Therefore, logic was added to check for QCC,
and when it is found, to suppress the use of -lgcc, and to express the
option -nostartfiles as -Wc,-nostartfiles instead, which is correctly
passed on to the underlying GCC.
* Finally, the support file os-qnx.c was added, patterned after the existing
os-*.c files. Only local image lookup is currently supported (see the
comments for more information), but this is sufficient for QNX, since
ptrace is not supported there anyway, and that is the only case where the
function is required to do remote image lookup.
Change-Id: Ie7934f94a7317bdde59335f2acd4c3a97c0384c1
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
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.
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'
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>
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>
Since the dl_iterate_phdr is required for local unwinding only the use of
struct dl_phdr_info can be eliminated in case libunwind gets compiled for
remote unwinding. This enhances libunwinds portability to targets that
don't provide any dl_iterate_phdr functionality.
Signed-off-by: Ken Werner <ken.werner@linaro.org>
Exclude <link.h> because it is only required for local unwinding when
iterating over the program headers.
Have the following DWARF related functions available in case of
UNW_REMOTE_ONLY because they are used by libunwind-ptrace:
dwarf_find_debug_frame
locate_debug_info
find_binary_for_address
load_debug_frame
debug_frame_tab_new
debug_frame_tab_append
debug_frame_tab_shrink
debug_frame_tab_compare
Signed-off-by: Ken Werner <ken.werner@linaro.org>
Rename the dwarf dl_iterate_phdr callback routine and the callback_data
structure to dwarf_callback and dwarf_callback_data. Make it available
within libunwind by declaring the two at the dwarf.h header file.
Signed-off-by: Ken Werner <ken.werner@linaro.org>
Adds new function to perform a pure stack walk without unwinding,
functionally similar to backtrace() but accelerated by an address
attribute cache the caller maintains across calls.
Current implementation fails to find separate debug symbols when
.gnu_debuglink is set to the same name of the target ELF basename
(e.g. "libc.so.6" for /lib/libc.so.6). This patch fixes this by ignoring
separate debug files that contain a .gnu_debuglink section.
It also fixes a small typo in a related Debug() line.
Signed-off-by: Andris Zeila <andris.zeila@accenture.com>
the instruction after the call for a normal frame. libunwind uses
IP-1 to lookup unwind information. However, this is not necessary for
interrupted frames such as signal frames (or interrupt frames) in
the kernel context.
This patch handles both cases correctly.
Based on work by Mark Wielaard <mwielaard@redhat.com>
Original code was accessing rs_cache memory without holding a lock
in some cases. If there was sufficient cache pressure, entry being
accessed may be overwritten by another thread, resulting in a data
race.
We now make a thread local copy of the data, before releasing the
lock. If we end up supporting UNW_CACHE_PER_THREAD properly
in the future, this memcpy should be unnecessary.
Greetings,
Attached patch gets rid of additional unnecessary branch (rs_get_cache
can not return NULL unless caching_policy is UNW_CACHE_NONE), gets rid of
goto's, and makes apply_reg_state (major CPU consumer) execute with cache
lock not held (before the patch, apply_reg_state was called with lock held
for newly-inserted entries, but not for found-in-cache entries).
Tested on Linux/x86_64 with no regressions.
Thanks,
--
Paul Pluzhnikov
Greetings,
Attached patch is rather on the obvious side:
- rs1 can't be NULL since it's assigned on previous line
- rs_new never returns NULL, and if it ever did, we'd crash on memcpy that
preceeds the NULL check.
Tested on Linux/x86_64 with no regressions.
Thanks,
--
Paul Pluzhnikov
Currently, libunwind allocates several PATH_MAX entries on stack, while
trying to find a binary via /proc/.../maps.
However stack space may be at premium (especially when sigaltstack is used),
and PATH_MAX on Linux is 4096, while SIGSTKSZ is only 8192 on x86.
Attached patch eliminates multiple PATH_MAX stack allocations, and simplifies
code in maps_next, at the cost of being unable to do anything if we can't
mmap one page. It appears to me that under such low-memory conditions,
libunwind will fail shortly elsewhere anyway.
This patch also disables more of debug_frame-handling code when
CONFIG_DEBUG_FRAME is undefined.
Tested on Linux/x86_64 with and without CONFIG_DEBUG_FRAME, no regressions.
The behavior on wait vs abort unwind depends on the locking primitive
chosen by the user. This makes the API consistent and independent of
the locking primitive.
Greetings,
We use libunwind just for stack traces (I suspect many others do as well).
The use pattern is:
GetStackTrace(void** result, int max_depth)
{
...
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
while (n < max_depth) {
if (unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *) &ip) < 0) {
break;
}
result[n++] = ip;
if (unw_step(&cursor) <= 0) {
break;
}
}
Given this usage, it is quite convenient for us to block signals (or
prevent signal handlers from re-entering libunwind by other means) at the
"top level", which makes most of the sigprocmask calls performed by
libunwind itself unneccessary.
The second patch in this series adds a configure option which removes most
of the sigprocmask calls.
Attached patch is a preliminary for it -- consolidating all of the
"sigprocmask; mutex_lock;" sequences into lock_acquire and "mutex_unlock;
sigprocmask;" sequences into lock_release.
Thanks,
--
Paul Pluzhnikov
commit 402d15b123d54a7669db7cf17a76dd315094e472
Author: Paul Pluzhnikov <ppluzhnikov@google.com>
Date: Mon Sep 21 10:18:28 2009 -0700
Replace "sigprocmask + mutext_lock" with a single lock_acquire.
Likewise, replace "mutext_unlock + sigprocmask" with lock_release.