Skip to content

Commit afb2de9

Browse files
puranjaymohanpaniakin-aws
authored andcommitted
unwind: Fix unwinder for when last instruction is a call
When a function's last instruction is a BL (Branch and Link), the address of the next instruction (outside this function) is kept in the LR. The callee function then saves this LR on stack as part of the frame record. When unwinding the stack from this callee function, the unwinder recovers this LR from the frame record and uses this address to find out the caller. As this address is beyond the caller, the unwinder fails to find it in the sframe table for any function and fails. Fix this edge case by assuming 1 extra instruction after the function as part of the function when searching the sframe table. NOTE: This could have a side affect that when a frame record is malformed/corrupted, the LR can point to the end of a function + one instruction, even without that function's last instruction being a branch. But when the frame record is corrupted at runtime, there is no way to figure that out anyway so this change doesn't add to or establish a new problem. devtmpfsd() is a function that displays this behaviour in the kernel: ------------------------------------------------------------------------------------- ffff800080d9a070 <devtmpfsd>: ffff800080d9a070: d503201f nop ffff800080d9a074: d503201f nop ffff800080d9a078: d503233f paciasp ffff800080d9a07c: a9be7bfd stp x29, x30, [sp, #-32]! ffff800080d9a080: 910003fd mov x29, sp ffff800080d9a084: f9000bf3 str x19, [sp, gregkh#16] [...SNIP....] ffff800080d9a0a0: 340000d3 cbz w19, ffff800080d9a0b8 [....SNIP...] ffff800080d9a0ac: a8c27bfd ldp x29, x30, [sp], #32 ffff800080d9a0b0: d50323bf autiasp ffff800080d9a0b4: d65f03c0 ret ffff800080d9a0b8: 97f06526 bl ffff8000809b3550 <devtmpfs_work_loop> ------------------------------------------------------------------------------------- ffff800080d9a0bc: 00000000 udf #0 Here devtmpfsd() calls devtmpfs_work_loop() and the compiler know the devtmpfs_work_loop() never returns, so it adds the BL to this function as the last instruction of devtmpfsd() Signed-off-by: Puranjay Mohan <pjy@amazon.com>
1 parent c52d7f0 commit afb2de9

File tree

1 file changed

+2
-2
lines changed

1 file changed

+2
-2
lines changed

kernel/sframe_lookup.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ static struct sframe_fde *find_fde(const struct sframe_table *tbl, unsigned long
8383
if (f >= tbl->sfhdr_p->num_fdes || f < 0)
8484
return NULL;
8585
fdep = tbl->fde_p + f;
86-
if (ip < fdep->start_addr || ip >= fdep->start_addr + fdep->size)
86+
if (ip < fdep->start_addr || ip > fdep->start_addr + fdep->size)
8787
return NULL;
8888

8989
return fdep;
@@ -107,7 +107,7 @@ static int find_fre(const struct sframe_table *tbl, unsigned long pc,
107107
else
108108
ip_off = (int32_t)(pc - (unsigned long)tbl->sfhdr_p) - fdep->start_addr;
109109

110-
if (ip_off < 0 || ip_off >= fdep->size)
110+
if (ip_off < 0 || ip_off > fdep->size)
111111
return -EINVAL;
112112

113113
/*

0 commit comments

Comments
 (0)