1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-11-17 13:47:37 +01:00
Commit graph

160 commits

Author SHA1 Message Date
Konstantin Baladurin
36b46f1921 dwarf/Gparser: fix crash during unwinding (#46)
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.
2017-10-17 11:27:43 -07:00
Dave Watson
3d9a694de8 dwarf: Fix incorrect application of restore_state
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.
2017-08-24 08:51:18 -07:00
Jonathan Byrd
1c190a8f9e aarch64: PLT entry recognition & fixes
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));
2017-08-18 09:55:49 -07:00
Bert Wesarg
57257060c9 Bring back support for UNW_CACHE_PER_THREAD.
Needs to be build with --enable-per-thread-cache. Default caching policy
is also UNW_CACHE_PER_THREAD than.
2017-08-15 10:34:28 -07:00
Dave Watson
3b3a453a65 dwarf: Fix cache size calculation
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
2017-08-15 10:33:40 -07:00
Doug Moore
55eb47d6e5 dwarf: fix single_fde
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.
2017-07-10 10:18:14 -07:00
Doug Moore
90d0d15c4e dwarf: fix synthetic eh_frame_hdr
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.
2017-07-06 09:15:08 -07:00
Doug Moore
38b2bdab33 Add a missing semicolon. 2017-07-05 09:53:46 -07:00
Doug Moore
0e74e583ae arm: Use dwarf_find_proc_info for arm dwarf processing
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.
2017-06-20 09:47:54 -07:00
Doug Moore
0b51f5892d Dwarf cache nodes are allocated in a round-robin fashion, despite the
'lru' prefix used in several data fields.  Drop the unnecessary fields,
and just use a simple counter to track the next cache entry to be recycled.
2017-06-16 08:53:36 -07:00
Doug Moore
27f5f9fa0b Leave ret_addr_column out of the data that gets copied when pushing/popping
data on/off the register state stack.
2017-05-20 14:36:25 -05:00
Doug Moore
c66661f73c Drop reference to dwarf.ret_addr_column. 2017-05-19 19:19:12 -05:00
Doug Moore
afb2491ccb Have dwarf_step return 0 or 1 for success, according to whether the
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.
2017-05-19 18:57:14 -05:00
Doug Moore
7634874591 Move the change to c->ret_addr_column to the end of dwarf_step, to make sure
that it gets set in the cache hit case.
2017-05-19 17:59:08 -05:00
Doug Moore
ec1a021243 Move the ret_addr_column field from dwarf_reg_cache_entry to dwarf_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.
2017-05-16 22:00:38 -05:00
Doug Moore
028a60f064 Change dwarf_reg_state from an array of pairs of differently-sized objects
to a pair of arrays, to reduce internal fragmentation.  Reduces storage
use by 37.5% on x86_64.
2017-05-16 17:40:58 -05:00
Doug Moore
2b692db23f In dwarf_reg_states_table_iterate, the rs stack has to persist from
one run_cfi_program call to the next, so pull the stack out of run_cfi_program
and make the caller responsible for cleanup at the end.
2017-05-16 01:04:49 -05:00
Doug Moore
bb61e0bc2b Bury the last_ip field until it can reappear in version 2.0. 2017-05-12 23:45:56 -05:00
Doug Moore
fef5de6c45 Move ret_addr_column and signal_frame from dwarf_reg_state to
dwarf_reg_cache_entry, leaving in dwarf_reg_state only what
apply_reg_state needs.
2017-05-12 22:24:00 -05:00
Doug Moore
a7c65f5c3e Remove next field from dwarf_reg_state. Create new struct
that includes next field and dwarf_reg_state, and use that
strictly for stack push/pop in run_cfi_program.
2017-05-12 22:24:00 -05:00
Doug Moore
4184bb478a Restore a dwarf-free "apply_reg_state" function. 2017-05-12 22:24:00 -05:00
Doug Moore
3888b2bbcb In dwarf_apply_reg_state change from dewarf_reg_state_t back to struct dwarf_reg_state. 2017-05-12 22:24:00 -05:00
Doug Moore
502ba27753 Add a function to capture the dwarf_reg_states that occur in processing
the dwarf code for a procedure, and a function to apply a captured
dwarf_reg_state later.
2017-05-12 22:24:00 -05:00
Doug Moore
bbdc4b12da Capture the address of the first byte after the instructionless gap
that follows the procedure.
2017-05-12 22:24:00 -05:00
Doug Moore
06d230d732 Merge dwarf_find_save_locs into dwarf_step. 2017-05-12 22:24:00 -05:00
Doug Moore
1602987b5f Extract 'find_reg_state' from dwarf_find_save_locs. 2017-05-12 22:23:59 -05:00
Doug Moore
04db2b7cea The call to put_unwind_info is what makes pi invalid, so clear the
valid bit here, and soon stop bothering to clear it in other places.
2017-05-12 22:23:59 -05:00
Doug Moore
1c76d41939 Pass in a pointer to the address where run_cfi_program will start,
or resume, its decoding, rather than always starting at the procedure
start, so that resuming a cfi_program becomes possible.
2017-05-12 22:23:59 -05:00
Doug Moore
7a962b951b Create setup_fde, and put all the one-time parts of fde processing there. 2017-05-12 22:23:59 -05:00
Doug Moore
50a457abb0 Pull cache-related fields out of reg_state, and put them into reg_cache struct. 2017-05-12 22:23:59 -05:00
Doug Moore
59ecb24ca2 dwarf:Drop dwarf_create_state_record.
In dwarf_make_proc_info, fix a leak in the case that create_state_record fails.
2017-04-28 09:59:22 -07:00
Doug Moore
3775cdd997 dwarf: Avoid a leak for a no-cache failure in create_state_record_for.
Avoid a duplicate copy for a cache miss.
2017-04-28 09:58:40 -07:00
Doug Moore
24ac32b480 run_cfi patch for libunwind
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.
2017-04-26 08:11:34 -07:00
Doug Moore
24f27f02ac dwarf: error in unmap size arguments
This patch fixes an error in the unmapping of
hash table memory when the dwarf hash table is resized.
2017-04-17 10:28:48 -07:00
Doug Moore
0f24c6dec8 dwarf: Cleanup dwarf cache hint
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.
2017-04-14 08:02:10 -07:00
Dave Watson
aee8bbe795 dwarf: fix unw_get_proc_info
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>
2017-04-04 11:15:23 -07:00
Dave Watson
54a970079d elf: Follow .gnu_debuglink when resolving function names
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.
2017-03-02 08:02:14 -08:00
Королев Сергей
b5de17183c mips[el]: fix cast from pointer to integer of different size
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
                                                           ^
2017-02-14 08:21:49 -08:00
Rene Nielsen
cfd4306cc7 mips: fix compiler warnings
This fixes a number of compiler warnings I got when compiling for mips32el with
gcc 5.3.0.
2017-02-14 08:18:49 -08:00
Bert Wesarg
b15e74a884 dwarf: Utilize ELFs find_section to find the eh_frame.
Makes it thread-safe.
2017-02-02 08:29:17 -08:00
Bert Wesarg
2e60ca34d2 dwarf: Fix warning about -Wmaybe-uninitialized.
```
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
2017-01-24 11:09:25 -08:00
Saleem Abdulrasool
e9e8ed73e3 dwarf: Account for multiple CFA for args_size
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.
2017-01-19 10:07:53 -08:00
Konstantin Belousov
9e97c9b17a dwarf: Make binary path calculation os-specific.
/proc/self/exe only works on Linux, move path computation to os-* files
2017-01-19 10:07:13 -08:00
Konstantin Belousov
09a598a3da Make the code compile on FreeBSD. 2017-01-18 09:18:29 -08:00
Dave Watson
a51cf49031 dwarf: Configurable cache size
Add interface for configurable dwarf cache size

* Use item size and round up to nearest power of 2.
* Initial cache still exists in BSS.  Without this, it means we would fail
  backtrace when out of memory.  The test-mem test fails without this
2017-01-13 08:36:33 -08:00
Dave Watson
4b63a536ee dwarf: Correct handling of DW_CFA_GNU_args_size
When resuming execution, DW_CFA_GNU_args_size from the current frame
must be added back to the stack pointer.  Clang now generates these frequently
at -O3.  A simple repro for x86_64, that will crash with clang ~3.9 or newer:

void f(int, int,int,int,int,int,int,int,int);

int main() {
  try {
    f(0,1,2,3,4,5,6,7,8);
  } catch (int) {
    return 0;
  }
  return 1;
}

Where f is something that throws an int, but in a different translation unit to
prevent optimization.

This results in cfi instructions before the call:
 .cfi_escape 0x2e, 0x20

Grabbing the args_size means fully parsing the cfi in the current frame, which
is unfortunate because it means nearly twice the work at each step.  The logic
to grab args_size can be in unw_step or get_proc_info (since this is always
called before resuming in stack unwinding).  Putting it in get_proc_info allows
the more common unw_step code to remain fast.

It would potentially fit in nicely with a proc info cache (as mentioned in the
if0 comment block)
2017-01-13 08:28:21 -08:00
Dave Watson
f7fe1c9a7e x86_64: Add stack alignment prologue tdep_trace fastpath
GCC versions 4.9~current will often generate stack alignment prologues like:

lea 0x8(%rsp),%r10
and $0xfffffffffffffff0,%rsp
...
push %rbp
mov %rsp, %rbp
push %r10

resulting in dwarf expressions:
DW_CFA_def_cfa_expression (DW_OP_breg6: -8; DW_OP_deref)
DW_CFA_expression: r6 (rbp) (DW_OP_breg6: 0)

These prologues seem to be generated for SSE/AVX code, but sometimes
other times as well.

tdep_trace fastpath currently falls back to the slow dwarf parsing path
if it encounters any cfa_expressions. Unfortunately this is happening
often enough in our codebase to cause perf issues.  We could also fix the
fallback path (make the rs cache bigger, lock-free instead of locking, etc),
but that seems like a separate issue, and it will ever be as fast as the tracing
code.   Our binaries each have at least ~100 functions in them like this.

This patch teaches the tdep_trace about the two specific cfa_expressions,
which really just result in a single extra memory dereference of the stack
at a fixed offset from rbp.
2017-01-13 08:28:21 -08:00
Jonathan Byrd
25413c729a dwarf: Improve support for binaries missing the GNU_EH_FRAME segment
Improves support for binaries missing the GNU_EH_FRAME segment
(.eh_frame_hdr section) by adding a function
'dwarf_find_eh_frame_section' that can create a synthetic one.
2017-01-13 08:28:21 -08:00
Королев Сергей
ad0d7633bc dwarf: check maps_init result
This fixes GCC 4.9.3 warnings (Linux/mipsel):

dwarf/Gfind_proc_info-lsb.c: In function 'locate_debug_info':
dwarf/Gfind_proc_info-lsb.c:244:23: warning: 'mi.buf_end' may be used
uninitialized in this function [-Wmaybe-uninitialized]
   struct map_iterator mi;
                       ^
dwarf/Gfind_proc_info-lsb.c:244:23: warning: 'mi.buf' may be used
uninitialized in this function [-Wmaybe-uninitialized]
In file included from dwarf/Gfind_proc_info-lsb.c:46:0:
./os-linux.h:292:27: warning: 'mi.buf_size' may be used uninitialized in
this function [-Wmaybe-uninitialized]
       munmap (mi->buf_end - mi->buf_size, mi->buf_size);
                           ^
dwarf/Gfind_proc_info-lsb.c:244:23: note: 'mi.buf_size' was declared here
   struct map_iterator mi;
                       ^
2017-01-13 08:27:39 -08:00
Keno Fischer
8afc33ce9f Add an option to have start_ip_offset be relative to start_ip
By default, the start_ip_offset in libunwind's table_entry struct is
relative to the unw_dyn_info_t's segbase. This presents a problem
for us in conjunction with using LLVM's MCJIT because it likes to
spread text sections and the corresponding eh_frame sections quite
far apart. This represents my attempt to support this use case in the
simplest manner that is backwards compatible, by adding a new format
kind (UNW_INFO_FORMAT_REMOTE_TABLE2) that indicates that the
`start_ip_offset` should be interpreted as relative to `start_ip`
rather than segbase.
2015-09-15 12:18:30 -07:00