summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
authorTim Moore <timoore@redhat.com>2010-01-20 18:05:26 +0100
committerTim Moore <timoore@redhat.com>2010-01-20 18:05:26 +0100
commit0f33053e1ebb5931f9dfbb6268aec57b7ce003da (patch)
treed696072b903a90b28d9d8828c7e6ac99490f50b9 /runtime
parent4e6d866ff635108634f8d0156d21c171e0d056f4 (diff)
downloadsystemtap-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.h1
-rw-r--r--runtime/unwind.c58
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 */