Commit c0cfb9eb authored by Nathan Huckleberry's avatar Nathan Huckleberry Committed by Greg Kroah-Hartman

ARM: 8992/1: Fix unwind_frame for clang-built kernels

commit b4d5ec9b upstream.

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: https://github.com/ClangBuiltLinux/linux/issues/912Reported-by: default avatarMiles Chen <miles.chen@mediatek.com>
Tested-by: default avatarMiles Chen <miles.chen@mediatek.com>
Cc: stable@vger.kernel.org
Reviewed-by: default avatarNick Desaulniers <ndesaulniers@google.com>
Signed-off-by: default avatarNathan Huckleberry <nhuck@google.com>
Signed-off-by: default avatarRussell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2310f713
......@@ -21,6 +21,19 @@
* A simple function epilogue looks like this:
* ldm sp, {fp, sp, pc}
*
* When compiled with clang, pc and sp are not pushed. A simple function
* prologue looks like this when built with clang:
*
* stmdb {..., fp, lr}
* add fp, sp, #x
* sub sp, sp, #y
*
* A simple function epilogue looks like this when built with clang:
*
* sub sp, fp, #x
* ldm {..., fp, pc}
*
*
* Note that with framepointer enabled, even the leaf functions have the same
* prologue and epilogue, therefore we can ignore the LR value in this case.
*/
......@@ -33,6 +46,16 @@ int notrace unwind_frame(struct stackframe *frame)
low = frame->sp;
high = ALIGN(low, THREAD_SIZE);
#ifdef CONFIG_CC_IS_CLANG
/* check current frame pointer is within bounds */
if (fp < low + 4 || fp > high - 4)
return -EINVAL;
frame->sp = frame->fp;
frame->fp = *(unsigned long *)(fp);
frame->pc = frame->lr;
frame->lr = *(unsigned long *)(fp + 4);
#else
/* check current frame pointer is within bounds */
if (fp < low + 12 || fp > high - 4)
return -EINVAL;
......@@ -41,6 +64,7 @@ int notrace unwind_frame(struct stackframe *frame)
frame->fp = *(unsigned long *)(fp - 12);
frame->sp = *(unsigned long *)(fp - 8);
frame->pc = *(unsigned long *)(fp - 4);
#endif
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment