ARM: fix unwinder with panic() / vpanic()
Richard Weinberger reports that with the addition of vpanic() with
at least GCC 15.1.1, the unwinder fails to properly produce a stack
trace. panic() in this case is compiled to:
c03039d0 <panic>:
c03039d0: e92d000f push {r0, r1, r2, r3}
c03039d4: e52de004 push {lr} @ (str lr, [sp, #-4]!)
c03039d8: e24dd00c sub sp, sp, #12
c03039dc: e52de004 push {lr} @ (str lr, [sp, #-4]!)
c03039e0: eb00a82f bl c032daa4 <__gnu_mcount_nc>
...
c0303a00: ebffff16 bl c0303660 <vpanic>
and this is where the function ends. When we attempt to unwind, we
get:
vpanic from __do_trace_suspend_resume+0x0/0x50
instead of it reporting that panic() called vpanic().
The problem occurs because 'bl' sets the LR to the next instruction
to be executed, which in this case would be at 0xc0303a04, and this
happens to be __do_trace_suspend_resume().
Consequently, the next iteration of the unwinder results in it
attempting to lookup and use the unwind entry for
__do_trace_suspend_resume() instead of panic() and the backtrace
fails.
Fix this by checking whether the instruction at the unwound PC - 4
is a BL or BLX instruction, and if so, point at that instruction
instead of the next-to-be-executed instruction. This should ensure
that we only move the PC back one instruction where necessary.
This also changes the backtrace output sightly - the "from" location
changes to the BL or BLX instruction instead of the following
instruction.
Note that this will not handle ARM <-> Thumb mode transitions.
We also update the frame pointer unwinder as well so it matches the
new behaviour. This is never used in Thumb mode.
Reported-by: Richard Weinberger <richard.weinberger@gmail.com>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
2 files changed