summaryrefslogtreecommitdiffstats
path: root/runtime/unwind.c
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/unwind.c')
-rw-r--r--runtime/unwind.c32
1 files changed, 28 insertions, 4 deletions
diff --git a/runtime/unwind.c b/runtime/unwind.c
index 21ea4559..bc8a93dc 100644
--- a/runtime/unwind.c
+++ b/runtime/unwind.c
@@ -550,10 +550,29 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc, s
return result && ptr.p8 == end && (targetLoc == 0 || state->label == NULL);
}
+// If this is an address inside a module, adjust for section relocation
+// and the elfutils base relocation done during loading of the .dwarf_frame
+// in translate.cxx.
+static unsigned long
+adjustStartLoc (unsigned long startLoc,
+ struct _stp_module *m,
+ struct _stp_section *s)
+{
+ if (startLoc && (strcmp (m->name, "kernel") != 0))
+ {
+ startLoc = _stp_module_relocate (m->name, s->name,
+ startLoc);
+ startLoc -= m->dwarf_module_base;
+ }
+ return startLoc;
+}
+
/* If we previously created an unwind header, then use it now to binary search */
/* for the FDE corresponding to pc. */
-static u32 *_stp_search_unwind_hdr(unsigned long pc, struct _stp_module *m)
+static u32 *_stp_search_unwind_hdr(unsigned long pc,
+ struct _stp_module *m,
+ struct _stp_section *s)
{
const u8 *ptr, *end, *hdr = m->unwind_hdr;
unsigned long startLoc;
@@ -600,6 +619,7 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc, struct _stp_module *m)
do {
const u8 *cur = ptr + (num / 2) * (2 * tableSize);
startLoc = read_pointer(&cur, cur + tableSize, hdr[3]);
+ startLoc = adjustStartLoc(startLoc, m, s);
if (pc < startLoc)
num /= 2;
else {
@@ -608,7 +628,7 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc, struct _stp_module *m)
}
} while (startLoc && num > 1);
- if (num == 1 && (startLoc = read_pointer(&ptr, ptr + tableSize, hdr[3])) != 0 && pc >= startLoc)
+ if (num == 1 && (startLoc = adjustStartLoc(read_pointer(&ptr, ptr + tableSize, hdr[3]), m, s)) != 0 && pc >= startLoc)
fde = (void *)read_pointer(&ptr, ptr + tableSize, hdr[3]);
dbug_unwind(1, "returning fde=%lx startLoc=%lx", fde, startLoc);
@@ -676,6 +696,7 @@ int unwind(struct unwind_frame_info *frame)
signed ptrType = -1;
uleb128_t retAddrReg = 0;
struct _stp_module *m;
+ struct _stp_section *s = NULL;
struct unwind_state state;
dbug_unwind(1, "pc=%lx, %lx", pc, UNW_PC(frame));
@@ -683,7 +704,7 @@ int unwind(struct unwind_frame_info *frame)
if (UNW_PC(frame) == 0)
return -EINVAL;
- m = NULL /*_stp_get_unwind_info(pc) */;
+ m = _stp_mod_sec_lookup (pc, &s);
if (unlikely(m == NULL)) {
dbug_unwind(1, "No module found for pc=%lx", pc);
return -EINVAL;
@@ -694,7 +715,7 @@ int unwind(struct unwind_frame_info *frame)
goto err;
}
- fde = _stp_search_unwind_hdr(pc, m);
+ fde = _stp_search_unwind_hdr(pc, m, s);
dbug_unwind(1, "%s: fde=%lx\n", m->name, fde);
/* found the fde, now set startLoc and endLoc */
@@ -704,6 +725,8 @@ int unwind(struct unwind_frame_info *frame)
ptr = (const u8 *)(fde + 2);
ptrType = fde_pointer_type(cie);
startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
+ startLoc = adjustStartLoc(startLoc, m, s);
+
dbug_unwind(2, "startLoc=%lx, ptrType=%s", startLoc, _stp_eh_enc_name(ptrType));
if (!(ptrType & DW_EH_PE_indirect))
ptrType &= DW_EH_PE_FORM | DW_EH_PE_signed;
@@ -733,6 +756,7 @@ int unwind(struct unwind_frame_info *frame)
ptr = (const u8 *)(fde + 2);
startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
+ startLoc = adjustStartLoc(startLoc, m, s);
dbug_unwind(2, "startLoc=%lx, ptrType=%s", startLoc, _stp_eh_enc_name(ptrType));
if (!startLoc)
continue;