diff options
Diffstat (limited to 'runtime/unwind.c')
-rw-r--r-- | runtime/unwind.c | 32 |
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; |