diff options
author | Tim Moore <timoore@redhat.com> | 2010-01-20 18:05:26 +0100 |
---|---|---|
committer | Tim Moore <timoore@redhat.com> | 2010-01-20 18:05:26 +0100 |
commit | 0f33053e1ebb5931f9dfbb6268aec57b7ce003da (patch) | |
tree | d696072b903a90b28d9d8828c7e6ac99490f50b9 /runtime | |
parent | 4e6d866ff635108634f8d0156d21c171e0d056f4 (diff) | |
download | systemtap-steved-0f33053e1ebb5931f9dfbb6268aec57b7ce003da.tar.gz systemtap-steved-0f33053e1ebb5931f9dfbb6268aec57b7ce003da.tar.xz systemtap-steved-0f33053e1ebb5931f9dfbb6268aec57b7ce003da.zip |
use eh_frame_hdr table to speed up unwinding
* runtime/sym.h (_stp_module): add unwind_hdr_addr member.
* runtime/unwind.c (read_ptr_sect): Modification of read_pointer that
also handles offsets from text or "data" sections.
(read_pointer): Use it.
(_stp_search_unwind_hdr): Use read_ptr_sect to calculate values that
are relative to the .eh_frame_hdr section.
(unwind_frame): Search the frame header if this is an eh frame.
* translate.cxx (get_unwind_data): Get the eh_frame_hdr too.
(dump_unwindsyms): Write out eh_frame_hdr stuff.
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/sym.h | 1 | ||||
-rw-r--r-- | runtime/unwind.c | 58 |
2 files changed, 43 insertions, 16 deletions
diff --git a/runtime/sym.h b/runtime/sym.h index ce6ab736..e7022877 100644 --- a/runtime/sym.h +++ b/runtime/sym.h @@ -49,6 +49,7 @@ struct _stp_module { uint32_t eh_frame_len; uint32_t unwind_hdr_len; unsigned long eh_frame_addr; /* Orig load address (offset) .eh_frame */ + unsigned long unwind_hdr_addr; /* same for .eh_frame_hdr */ /* build-id information */ unsigned char *build_id_bits; unsigned long build_id_offset; diff --git a/runtime/unwind.c b/runtime/unwind.c index c8e3580d..f60ea017 100644 --- a/runtime/unwind.c +++ b/runtime/unwind.c @@ -133,8 +133,11 @@ static const u32 *cie_for_fde(const u32 *fde, void *unwind_data, return cie; } -/* read an encoded pointer */ -static unsigned long read_pointer(const u8 **pLoc, const void *end, signed ptrType) +/* read an encoded pointer and increment *pLoc past the end of the + * data read. */ +static unsigned long read_ptr_sect(const u8 **pLoc, const void *end, + signed ptrType, unsigned long textAddr, + unsigned long dataAddr) { unsigned long value = 0; union { @@ -194,6 +197,12 @@ static unsigned long read_pointer(const u8 **pLoc, const void *end, signed ptrTy case DW_EH_PE_pcrel: value += (unsigned long)*pLoc; break; + case DW_EH_PE_textrel: + value += textAddr; + break; + case DW_EH_PE_datarel: + value += dataAddr; + break; default: return 0; } @@ -205,6 +214,11 @@ static unsigned long read_pointer(const u8 **pLoc, const void *end, signed ptrTy return value; } +static unsigned long read_pointer(const u8 **pLoc, const void *end, signed ptrType) +{ + return read_ptr_sect(pLoc, end, ptrType, 0, 0); +} + static signed fde_pointer_type(const u32 *cie, void *unwind_data, uint32_t table_len) { @@ -535,7 +549,6 @@ adjustStartLoc (unsigned long startLoc, struct task_struct *tsk, /* If we previously created an unwind header, then use it now to binary search */ /* for the FDE corresponding to pc. XXX FIXME not currently supported. */ - static u32 *_stp_search_unwind_hdr(unsigned long pc, struct task_struct *tsk, struct _stp_module *m, struct _stp_section *s) @@ -544,6 +557,7 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc, struct task_struct *tsk, unsigned long startLoc; u32 *fde = NULL; unsigned num, tableSize, t2; + unsigned long eh_hdr_addr = m->unwind_hdr_addr; if (hdr == NULL || hdr[0] != 1) return NULL; @@ -570,21 +584,29 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc, struct task_struct *tsk, } ptr = hdr + 4; end = hdr + m->unwind_hdr_len; - - if (read_pointer(&ptr, end, hdr[1]) != (unsigned long)m->debug_frame) { - dbug_unwind(1, "eh_frame_ptr not valid"); + { + // XXX Can the header validity be checked just once? + unsigned long eh = read_ptr_sect(&ptr, end, hdr[1], 0, + eh_hdr_addr); + if ((hdr[1] & DW_EH_PE_ADJUST) == DW_EH_PE_pcrel) + eh = eh - (unsigned long)hdr + eh_hdr_addr; + if ((eh != (unsigned long)m->eh_frame_addr)) { + dbug_unwind(1, "eh_frame_ptr in eh_frame_hdr 0x%lx not valid; eh_frame_addr = 0x%lx", eh, (unsigned long)m->eh_frame_addr); return NULL; + } } - - num = read_pointer(&ptr, end, hdr[2]); - if (num == 0 || num != (end - ptr) / (2 * tableSize) || (end - ptr) % (2 * tableSize)) { - dbug_unwind(1, "Bad num=%d end-ptr=%ld 2*tableSize=%d", num, (long)(end - ptr), 2 * tableSize); + num = read_ptr_sect(&ptr, end, hdr[2], 0, eh_hdr_addr); + if (num == 0 || num != (end - ptr) / (2 * tableSize) + || (end - ptr) % (2 * tableSize)) { + dbug_unwind(1, "Bad num=%d end-ptr=%ld 2*tableSize=%d", + num, (long)(end - ptr), 2 * tableSize); return NULL; } do { const u8 *cur = ptr + (num / 2) * (2 * tableSize); - startLoc = read_pointer(&cur, cur + tableSize, hdr[3]); + startLoc = read_ptr_sect(&cur, cur + tableSize, hdr[3], 0, + eh_hdr_addr); startLoc = adjustStartLoc(startLoc, tsk, m, s, hdr[3], 1); if (pc < startLoc) num /= 2; @@ -594,8 +616,12 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc, struct task_struct *tsk, } } while (startLoc && num > 1); - if (num == 1 && (startLoc = adjustStartLoc(read_pointer(&ptr, ptr + tableSize, hdr[3]), tsk, m, s, hdr[3], 1)) != 0 && pc >= startLoc) - fde = (void *)read_pointer(&ptr, ptr + tableSize, hdr[3]); + if (num == 1 + && (startLoc = adjustStartLoc(read_ptr_sect(&ptr, ptr + tableSize, hdr[3], 0, eh_hdr_addr), tsk, m, s, hdr[3], 1)) != 0 && pc >= startLoc) + fde = (u32*)(read_ptr_sect(&ptr, ptr + tableSize, hdr[3], + 0, eh_hdr_addr) + - m->eh_frame_addr + +(u8*)m->eh_frame); dbug_unwind(1, "returning fde=%lx startLoc=%lx", (unsigned long) fde, startLoc); return fde; @@ -610,7 +636,7 @@ static int unwind_frame(struct unwind_frame_info *frame, void *table, uint32_t table_len, int is_ehframe) { #define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs]) - const u32 *fde, *cie = NULL; + const u32 *fde = NULL, *cie = NULL; const u8 *ptr = NULL, *end = NULL; unsigned long pc = UNW_PC(frame) - frame->call_frame; unsigned long tableSize, startLoc = 0, endLoc = 0, cfa; @@ -623,8 +649,8 @@ static int unwind_frame(struct unwind_frame_info *frame, dbug_unwind(1, "Module %s: frame_len=%d", m->name, table_len); goto err; } - - fde = _stp_search_unwind_hdr(pc, tsk, m, s); + if (is_ehframe) + fde = _stp_search_unwind_hdr(pc, tsk, m, s); dbug_unwind(1, "%s: fde=%lx\n", m->name, (unsigned long) fde); /* found the fde, now set startLoc and endLoc */ |