This adds a port to Linux on the IBM Z platform (a.k.a s390x). It only
supports the 64-bit ABI. Most functionality is working and all the tests
pass with the exception of the coredump tests*.
Unwinding is only supported if DWARF unwind information is present.
libunwind can't currently make use of the backchain (if present).
The getcontext/setcontext functions only preserve/restore a subset of
registers. Currently this only consists of callee-saved registers and
some parameter registers.
Vector registers and access registers are not saved (and aren't callee-
saved) by getcontext and cannot currently be modified. They will however
be restored unmodified after resuming a context from a signal handler.
There is no special libunwind support for setjmp, the functionality is
emulated using glibc (I think all the ports do this for modern Linux
kernels).
* Unwinding on s390x requires floating point register access which the
coredump library doesn't currently support.
DW_CFA_remember_state used memcpy to overwrite state with the value
of rs_current. Unfortunately rs_current was slightly larger than state,
possibly resulting in rs_stack->next being overwritten.
Fix this by making the type of state match the type of rs_current and
using an assigment to perform the copy rather than memcpy. This should
ensure that the types match in future.
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.
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.
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.
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));
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
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.
Rather than using a copy of dwarf_find_proc_info that differs from it slightly.
By using dwarf_find_proc_info, a potential search of the di table is
allowed, where it is omitted now. Also, for ARM, avoid runtime
checks about which kind of unwind table search to use after dl_iterate_phdr.
A couple of Debug() warnings about ip lookup failure are lost here.
The dwarf callback struct defintion is moved to Gfind_proc_info-lsb.c,
which becomes the only source file that needs it.
previous stack frame was the last, just as unw_step does. For x86_64,
drop the null check for ret_addr_column, since that check is made already
in apply_reg_state.
so that it will get saved and restored with the register state. Initialize
the rs_state version of ret_addr_column at the some time the dwarf_cursor
version is initialized, and don't bother copying ret_addr_column explicitly
from cursor to cache since it's copied implicitly as part of reg_state.
Use the reg_state version in apply_reg_state, instead of the cursor version.
Which brings up the question: why do we have ret_addr_column in the dwarf_cursor?
We call find_reg_state before calling apply_reg_state, so the value of ret_addr_column
in the cursor when dwarf_step gets called gets overwritten before it is used. So
it's initial value doesn't matter. But some architectures do funky things with
cursor->ret_addr_column, even though I don't see how they matter.
So I'm not deleting dwarf_cursor->ret_addr_column, even though I suspect this
patch makes it useless.
dwarf: If the dwarf_readu8 call to set op fails, and if there are register
states pushed onto the stack, the stack is not emptied before the function
returns. This change addresses that.
Most of the rest is eliminating ‘goto fail’ from the code.
0-valued hints are used when they are just initial values with no use as
hints. And I think there were some other problems as well.
This patch cleans up and stores hint values with 1 added, so that 0-valued
hints can be ignored.
unw_get_proc_info must always load the unwind info so that unw_resume
works with GNU_args_size expressions, but must not update
use_prev_expr unless we are unw_step()ing.
blame rev: 4b63a536ee
reported-by: Doug Moore <dougm@rice.edu>
Centralize gnu_debuglink logic in elfxx. Remove previous duplicated logic
from Gfind_proc_info and os-linux.
Logic is roughly the same as previous load_debug_frame, but uses VLAs
instead of malloc.
This fixes GCC 4.9.3 warnings (Linux/mipsel):
In file included from dwarf/Lfind_unwind_table.c:4:0:
dwarf/Gfind_unwind_table.c: In function '_ULmips_dwarf_find_unwind_table':
dwarf/Gfind_unwind_table.c:140:14: warning: cast from pointer to integer of
different size [-Wpointer-to-int-cast]
addr = (unw_word_t) (hdr + 1);
^
dwarf/Gfind_unwind_table.c:196:50: warning: cast from pointer to integer of
different size [-Wpointer-to-int-cast]
+ (addr - (unw_word_t) edi->ei.image
^
dwarf/Gfind_unwind_table.c:202:40: warning: cast from pointer to integer of
different size [-Wpointer-to-int-cast]
+ ((unw_word_t) hdr - (unw_word_t)
edi->ei.image
^
dwarf/Gfind_unwind_table.c:202:59: warning: cast from pointer to integer of
different size [-Wpointer-to-int-cast]
+ ((unw_word_t) hdr - (unw_word_t)
edi->ei.image
^
```
src/dwarf/Gfind_proc_info-lsb.c:536:16: warning: 'eh_frame' may be used uninitialized in this function [-Wmaybe-uninitialized]
Elf_W (Addr) eh_frame;
^
```
Introduced-in: 25413c729a
It is possible to have multiple CFA_args_size adjustments for a single
frame. If the CFA_args_size adjustment is immediately following the
return from a function which can raise an exception, it is possible to
incorrectly adjust the stack pointer. Consider the following:
...
.cfi_escape 0x2e, 0x00
call f
.Ltmp:
.cfi_escape 0x2e, 0x10
lea label@GOTOFF(%ebx), %eax
...
Because we process the CFI program up to and *INCLUDING* IP, where the
IP is the RA, we would process the associated DW_CFA_GNU_args_size for
the post-call instruction. The result would be a DW_CFA_GNU_args_size
of 0x10 rather than 0x00, resulting in an incorrect stack adjustment.
Handle this by processing the CFI operation but not adjusting the state
record unless we are below the current IP.