From d68b6d8155082bfb427cb794fbcb7c4a55f5f315 Mon Sep 17 00:00:00 2001 From: chao an Date: Thu, 14 Sep 2023 16:37:06 +0800 Subject: [PATCH] unwinder: fix unwind abort for uleb128 case When unwind instruction is 0xb2,the subsequent instructions are uleb128 bytes. For now,it uses only the first uleb128 byte in code. For vsp increments of 0x204~0x400,use one uleb128 byte like below: 0xc06a00e4 : 0x80b27fac Compact model index: 0 0xb2 0x7f vsp = vsp + 1024 0xac pop {r4, r5, r6, r7, r8, r14} For vsp increments larger than 0x400,use two uleb128 bytes like below: 0xc06a00e4 : @0xc0cc9e0c Compact model index: 1 0xb2 0x81 0x01 vsp = vsp + 1032 0xac pop {r4, r5, r6, r7, r8, r14} The unwind works well since the decoded uleb128 byte is also 0x81. For vsp increments larger than 0x600,use two uleb128 bytes like below: 0xc06a00e4 : @0xc0cc9e0c Compact model index: 1 0xb2 0x81 0x02 vsp = vsp + 1544 0xac pop {r4, r5, r6, r7, r8, r14} In this case,the decoded uleb128 result is 0x101(vsp=0x204+(0x101<<2)). While the uleb128 used in code is 0x81(vsp=0x204+(0x81<<2)). The unwind aborts at this frame since it gets incorrect vsp. To fix this, add uleb128 decode to cover all the above case. Signed-off-by: chao an --- arch/arm/src/common/arm_backtrace_unwind.c | 27 +++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/arch/arm/src/common/arm_backtrace_unwind.c b/arch/arm/src/common/arm_backtrace_unwind.c index 0a96b59a55421..599df384db812 100644 --- a/arch/arm/src/common/arm_backtrace_unwind.c +++ b/arch/arm/src/common/arm_backtrace_unwind.c @@ -338,6 +338,31 @@ static int unwind_exec_pop_subset_r0_to_r3(struct unwind_ctrl_s *ctrl, return 0; } +static unsigned long unwind_decode_uleb128(struct unwind_ctrl_s *ctrl) +{ + unsigned long bytes = 0; + unsigned long insn; + unsigned long result = 0; + + /* unwind_get_byte() will advance `ctrl` one instruction at a time, so + * loop until we get an instruction byte where bit 7 is not set. + * + * Note: This decodes a maximum of 4 bytes to output 28 bits data where + * max is 0xfffffff: that will cover a vsp increment of 1073742336, hence + * it is sufficient for unwinding the stack. + */ + + do + { + insn = unwind_get_byte(ctrl); + result |= (insn & 0x7f) << (bytes * 7); + bytes++; + } + while (!!(insn & 0x80) && (bytes != sizeof(result))); + + return result; +} + /**************************************************************************** * Name: unwind_pop_register * @@ -403,7 +428,7 @@ static int unwind_exec_content(struct unwind_ctrl_s *ctrl) } else if (content == 0xb2) { - unsigned long uleb128 = unwind_get_byte(ctrl); + unsigned long uleb128 = unwind_decode_uleb128(ctrl); ctrl->vrs[SP] += 0x204 + (uleb128 << 2); }