aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/arch/arm/kernel/unwind_arm32.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/core/arch/arm/kernel/unwind_arm32.c b/core/arch/arm/kernel/unwind_arm32.c
index 17cc48c2..0d35d003 100644
--- a/core/arch/arm/kernel/unwind_arm32.c
+++ b/core/arch/arm/kernel/unwind_arm32.c
@@ -369,8 +369,13 @@ bool unwind_stack_arm32(struct unwind_state_arm32 *state, vaddr_t exidx,
/* The pc value is correct and will be overwritten, save it */
state->start_pc = state->registers[PC];
- /* Find the item to run */
- index = find_index(state->start_pc, exidx, exidx_sz);
+ /*
+ * Find the item to run. Subtract 2 from PC to make sure that we're
+ * still inside the calling function in case a __no_return function
+ * (typically panic()) is called unconditionally and may cause LR and
+ * thus this PC to point into the next and entirely unrelated function.
+ */
+ index = find_index(state->start_pc - 2, exidx, exidx_sz);
finished = false;
if (index->insn != EXIDX_CANTUNWIND) {
@@ -462,7 +467,13 @@ void print_kernel_stack(int level)
state.registers[FP] = read_fp();
state.registers[SP] = read_sp();
state.registers[LR] = read_lr();
- state.registers[PC] = (uint32_t)print_kernel_stack;
+
+ /*
+ * Add 4 to make sure that we have an address well inside this function.
+ * This is needed because we're subtracting 2 from PC when calling
+ * find_index() above. See a comment there for more details.
+ */
+ state.registers[PC] = (uint32_t)print_kernel_stack + 4;
get_stack_limits(&stack_start, &stack_end);
print_stack_arm32(level, &state, exidx, exidx_sz, stack_start,
@@ -494,7 +505,13 @@ vaddr_t *unw_get_kernel_stack(void)
state.registers[FP] = read_fp();
state.registers[SP] = read_sp();
state.registers[LR] = read_lr();
- state.registers[PC] = (uint32_t)unw_get_kernel_stack;
+
+ /*
+ * Add 4 to make sure that we have an address well inside this function.
+ * This is needed because we're subtracting 2 from PC when calling
+ * find_index() above. See a comment there for more details.
+ */
+ state.registers[PC] = (uint32_t)unw_get_kernel_stack + 4;
while (unwind_stack_arm32(&state, exidx, exidx_sz, stack, stack_size)) {
tmp = unw_grow(addr, &size, (n + 1) * sizeof(vaddr_t));