| From e306dfd06fcb44d21c80acb8e5a88d55f3d1cf63 Mon Sep 17 00:00:00 2001 |
| From: Olof Johansson <olof@lixom.net> |
| Date: Fri, 14 Feb 2014 19:35:15 +0000 |
| Subject: ARM64: unwind: Fix PC calculation |
| |
| From: Olof Johansson <olof@lixom.net> |
| |
| commit e306dfd06fcb44d21c80acb8e5a88d55f3d1cf63 upstream. |
| |
| The frame PC value in the unwind code used to just take the saved LR |
| value and use that. That's incorrect as a stack trace, since it shows |
| the return path stack, not the call path stack. |
| |
| In particular, it shows faulty information in case the bl is done as |
| the very last instruction of one label, since the return point will be |
| in the next label. That can easily be seen with tail calls to panic(), |
| which is marked __noreturn and thus doesn't have anything useful after it. |
| |
| Easiest here is to just correct the unwind code and do a -4, to get the |
| actual call site for the backtrace instead of the return site. |
| |
| Signed-off-by: Olof Johansson <olof@lixom.net> |
| Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/arm64/kernel/stacktrace.c | 6 +++++- |
| 1 file changed, 5 insertions(+), 1 deletion(-) |
| |
| --- a/arch/arm64/kernel/stacktrace.c |
| +++ b/arch/arm64/kernel/stacktrace.c |
| @@ -48,7 +48,11 @@ int unwind_frame(struct stackframe *fram |
| |
| frame->sp = fp + 0x10; |
| frame->fp = *(unsigned long *)(fp); |
| - frame->pc = *(unsigned long *)(fp + 8); |
| + /* |
| + * -4 here because we care about the PC at time of bl, |
| + * not where the return will go. |
| + */ |
| + frame->pc = *(unsigned long *)(fp + 8) - 4; |
| |
| return 0; |
| } |