If loading debug link is not successful, the initial NULL pointer for
ei->image will eventually be restored, causing segfault during a later
call to valid_object.
Move populating the prev_image and prev_size to after elf_map_image() to
fix this.
Signed-off-by: Hans-Christian Noren Egtvedt <hegtvedt@cisco.com>
During unwinding/resuming execution of a normal call frame,
it is not only necessary to use the previous instruction to lookup the unwind info
but also when executing the cfi program. Although the call usually don't modify
any unwinding state, it can happen for noreturn call or when the callee cleanup the stack.
In these cases, the next instruction after the call may have a cfi adjusting the state
(e.g. stack pointer) and such instruction should be executed.
3d9a694de8 worked around this issue by treating `cfi_restore_state`
specially. It works when the compiler use that instruction to restore the state, i.e.
```
.cfi_remember_state
je .L0
push ...
.cfi_def_cfi_offset <new_value>
call noreturn
.L0
.cfi_restore_state
```
which is what GCC ususally does. However, it is not necessarily the case and clang/LLVM doesn't
do that. Instead LLVM emits the following unwind info which is also perfectly valid but is not
handled by the special case.
```
je .L0
push ...
.cfi_def_cfi_offset <new_value>
call noreturn
.L0
.cfi_def_cfi_offset <old_value>
```
e9e8ed73e3 also worked around this issue for another special case.
This patch fix this issue for all cfi types by adjusting the `end_ip` based on the type of the
current frame instead, similar to what's done in `fetch_proc_info`.
Since this requires using the same `use_prev_instr` value after `fetch_proc_info` returns,
the patch also remove the `need_unwind_info` parameter to the function and move the code updating
`use_prev_instr` after all use of the old value are done.
(At least on x86(_32),) `unw_resume` will call `setcontext` which will modify the signal masks
based on the value in the context. Since the signal mask is not being initialized by
`unw_getcontext`, this cause the signal mask to be set to a random (uninitialized) value after
`unw_resume` which cause the test to fail since it relies on the signal mask for SIGUSR2 being
cleared.
The proper fix is likely to either make `unw_resume` not touch the signal mask if the context
wasn't initialized with a signal ucontext, or to make `unw_getcontext` record the signal mask too.
It's unclear to me which approach should be taken...
In the mean time, the intermittent failure can be fixed simply by zero initialing the context first
which would clear all the signal masks.
When siginfo is available, a more reliable way is to use the `ucontext` passed in
to the signal handler directly and rely on `sigreturn` to reset it.
Unfortunately, this is currently not implemented on all archs either.
* Add `SA_SIGINFO` flag
This is needed to guarantee the availability of the `ucontext` argument
* Mark the `NULL` pointer load as `volatile`
Further prevent any compiler optimization on the load.
We should update locations of the registers after all of them will
be restored. Otherwise some locations will be incorrect.
For example if function stores ebp, edi, esi and ebx registers on
stack in its prologue, compiler can generate following unwind info:
DW_CFA_expression: r5 (ebp) (DW_OP_breg5 (ebp): 0)
DW_CFA_expression: r7 (edi) (DW_OP_breg5 (ebp): -4)
DW_CFA_expression: r6 (esi) (DW_OP_breg5 (ebp): -8)
DW_CFA_expression: r3 (ebx) (DW_OP_breg5 (ebp): -12)
In this case locations of the ebx and ebp will be calculated using
current ebp but locations of the esi and edi will be calculated using
previous (restored) one. Due to it their locations will be incorrect
and it could lead to crash if we will try to get esi or edi value.
This patch fixes this problem.
glibc no longer defines sigreturn, but we want to use it
when unwinding through signal stacks to resture the signal mask,
without forcing all uses of getcontext/setcontext to save and
restore the signal mask
Repro for a multilib binary on host x86_64:
CFLAGS="-m32" LDFLAGS="-m32" ./configure --enable-debug -- host=i686-pc-linux-gnu --target=i686-pc-linux-gnu --libdur=/usr/lib32 --prefix=/usr --disable-documentation
make check
Gtest-init function fails trying to step through libc_start_main. The CFA function is:
DW_CFA_def_cfa_offset: 112
DW_CFA_advance_loc: 5 to ...643
DW_CFA_restore state
Where the return address is 643.
Generally, it appears we apply all ip <= end_ip, which is incorrect in some circumstances.
libgcc only applies ip < end_ip + is_signal_frame, but that seems to break async signal handling
tests in libunwind for unknown reasons.
This is somewhat simlar to the fix in e9e8ed73e for GNU_args_size,
where the same ip check was added.
The calls to mincore() or msync() are not checking for actual accessibility
this could lead to SIGSEGV if the address from a mapped page with the
PROT_NONE property occurs on the stack.
Hence an attempt to write one byte from the checked address to a pipe will
fail if the address is not readable.
I tried to build libunwind for arm target and got a build error. Type
for "uc" argument is inconsistent between unw_init_local2 and
unw_init_local_common.
From 54fb6483e47916836c314a38715e8e0ce8c3da44 Mon Sep 17 00:00:00 2001
From: Guillaume Blanc <guillaume.blanc@parrot.com>
Date: Tue, 22 Aug 2017 16:46:20 +0200
Subject: [PATCH] arm: Fix unw_init_local2 argument type
Attached is a corrected version of my previous patch for aarch64 PLT
entry recognition. The comparison in the is_plt_entry function should
have been:
ret = (((w0 & 0xff0000009f000000) == 0xf900000090000000)
&& ((w1 & 0xffffffffff000000) == 0xd61f022091000000));
We were testing libunwind-coredump and got some warnings about
uninitialized eh_valid_mask.
The code was working fine because the default value of the mask was 0, but
it could potentially take a wrong branch if there's garbage in memory.
If I configure with ./configure --prefix= --enable-shared --disable-static, a
broken symlink lib/libunwind-generic.a is installed that points to a missing
architecture-specific version of that library (e.g. lib/libunwind-x86_64.a). I
suppose that not installing that library is the intended behavior with these
configuration settings, so the symlink should not be there in the first place.
Reported-by: MarcoKoch
Some binaries contain a gnu_debuglink, even though the actual
file it points to doesn't exist. In those cases, continue
to use the existing binary instead of trying to load the debuglink file.
The ARM Thumb implementation of unw_tdep_getcontext switches to ARM
mode (".code 32"), but doesn't switch back to Thumb mode.
In gcc, this is fine (it automatically switches back to Thumb mode
at the end of an asm block), but in clang, this causes bad assembly
output (thumb instructions generated by C/C++ code later on are
interpreted as ARM mode assembly, which can't work).
Switching back to Thumb mode manually fixes clang, and is a no-op for gcc.
If Thumb is used, the least bit of the retrived IP value is set,
which makes the retrived opcode based on the IP invalid.
This patch fixes such behavior and adds a missed condition
found with glibc built for recent ARMv7l with Thumb2.
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
CC: Yvan Roux
CC: Arun Sharma
CC: David Mosberger
Let's not drop error code or zero-return unconditionally.
This has been incurring occasional indefinite loop in
dotnet core when it already had hit the bottom by
continously returning 1 from unw_step();
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
The and mask trick only works for power-of-two sized things,
but must be computed using the full size. This incorrectly
resulted in a very small cache size.
Found using bisect and 'make perf' in tests directory.
blame rev: 0b51f5892d
In remote ptrace mode, we currently use PTRACE_PEEKUSER to read the registers.
PTRACE_PEEKUSER only works on x86 or arm 32 bit compatibility mode on linux. On aarch64 system,
it always return -EIO. https://github.com/torvalds/linux/blob/master/kernel/ptrace.c#L885-L1102
PTRACE_GETREGSET is the newer and more supported way of reading registers. Use that if it's available.
We've tried to run slightly modified test-coredump-unwind.c built with
tcmalloc, and it promptly crashed. Attached patch fixes the heap buffer
overflow bug which caused it.
Add register state and state iterate functions to ppc32 and ppc64
directories. They were added to other arch directories in change
502ba27753... but not these, for some reason.
Commit dbce594d33
added unconditional dwarf usage into unw_get_proc_name.
Unfortunately ia64 is the only architecture that
does not support it in libunwind (configure.ac):
```
if test x$target_arch != xia64; then
use_dwarf=yes
else
use_dwarf=no
fi
```
As a result build fails on ia64 as:
```
ia64-unknown-linux-gnu-gcc ... -c mi/Lget_proc_name.c ...
In file included from mi/Lget_proc_name.c:4:0:
mi/Gget_proc_name.c: In function '_ULia64_get_proc_name':
mi/Gget_proc_name.c:107:8: error: 'struct cursor' has no member named 'dwarf'
if (c->dwarf.use_prev_instr)
^~
mi/Gget_proc_name.c:111:8: error: 'struct cursor' has no member named 'dwarf'
if (c->dwarf.use_prev_instr && offp != NULL && error == 0)
^~
```
Signed-off-by: Sergei Trofimovich <slyfox@gentoo.org>
Usage of the single_fde field in cb_data suggests that it should be
set only when dwarf_extract_proc_info_from_fde has completed successfully,
but instead it is set before the linear search for the matching ip has
begun. Set it only when that search has completed successfully, and
has thus extracted the proc_info.
Ben Avison (bavison@riscopen.org) has observed that when a synthetic
eh_frame_hdr is generated, there is no space in it for the eh_frame,
so the eh_frame value is written to, and later read from, memory that
is not assigned to this purpose, with unpredictable results.
This change adds a new field to the dwarf_eh_frame_hdr type, to
make room for that value, and adds the (packed) attribute to the
struct defintion to avoid a problem with unused space in the struct.
This allows libunwind to work in situations with limited stack size (ie. fibers). 512 is still more than enough for storing the cursor with some slack. (#25)