Skip to content

Commit b4d5ec9

Browse files
nhukcRussell King
authored andcommitted
ARM: 8992/1: Fix unwind_frame for clang-built kernels
Since clang does not push pc and sp in function prologues, the current implementation of unwind_frame does not work. By using the previous frame's lr/fp instead of saved pc/sp we get valid unwinds on clang-built kernels. The bounds check on next frame pointer must be changed as well since there are 8 less bytes between frames. This fixes /proc/<pid>/stack. Link: ClangBuiltLinux#912 Reported-by: Miles Chen <[email protected]> Tested-by: Miles Chen <[email protected]> Cc: [email protected] Reviewed-by: Nick Desaulniers <[email protected]> Signed-off-by: Nathan Huckleberry <[email protected]> Signed-off-by: Russell King <[email protected]>
1 parent 2cbd1cc commit b4d5ec9

File tree

1 file changed

+24
-0
lines changed

1 file changed

+24
-0
lines changed

arch/arm/kernel/stacktrace.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@
2222
* A simple function epilogue looks like this:
2323
* ldm sp, {fp, sp, pc}
2424
*
25+
* When compiled with clang, pc and sp are not pushed. A simple function
26+
* prologue looks like this when built with clang:
27+
*
28+
* stmdb {..., fp, lr}
29+
* add fp, sp, #x
30+
* sub sp, sp, #y
31+
*
32+
* A simple function epilogue looks like this when built with clang:
33+
*
34+
* sub sp, fp, #x
35+
* ldm {..., fp, pc}
36+
*
37+
*
2538
* Note that with framepointer enabled, even the leaf functions have the same
2639
* prologue and epilogue, therefore we can ignore the LR value in this case.
2740
*/
@@ -34,6 +47,16 @@ int notrace unwind_frame(struct stackframe *frame)
3447
low = frame->sp;
3548
high = ALIGN(low, THREAD_SIZE);
3649

50+
#ifdef CONFIG_CC_IS_CLANG
51+
/* check current frame pointer is within bounds */
52+
if (fp < low + 4 || fp > high - 4)
53+
return -EINVAL;
54+
55+
frame->sp = frame->fp;
56+
frame->fp = *(unsigned long *)(fp);
57+
frame->pc = frame->lr;
58+
frame->lr = *(unsigned long *)(fp + 4);
59+
#else
3760
/* check current frame pointer is within bounds */
3861
if (fp < low + 12 || fp > high - 4)
3962
return -EINVAL;
@@ -42,6 +65,7 @@ int notrace unwind_frame(struct stackframe *frame)
4265
frame->fp = *(unsigned long *)(fp - 12);
4366
frame->sp = *(unsigned long *)(fp - 8);
4467
frame->pc = *(unsigned long *)(fp - 4);
68+
#endif
4569

4670
return 0;
4771
}

0 commit comments

Comments
 (0)