summaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/unwind_bc.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-12-21 21:17:14 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2019-12-21 21:17:14 +0100
commit60b04df6bfbf7e65954c44f7945b381e0fee5b6a (patch)
tree03f26b0e0a3ff3730cf1828a8fd1d6af6a75d1af /arch/s390/kernel/unwind_bc.c
parentMerge branch 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/k... (diff)
parents390/ftrace: save traced function caller (diff)
downloadlinux-60b04df6bfbf7e65954c44f7945b381e0fee5b6a.tar.xz
linux-60b04df6bfbf7e65954c44f7945b381e0fee5b6a.zip
Merge tag 's390-5.5-4' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 fixes from Vasily Gorbik: - Fix unwinding from irq context of interrupted user process. - Add purgatory build missing symbols check. That helped to uncover and fix missing symbols when built with kasan support enabled. - Couple of ftrace fixes. Avoid broken stack trace and fix recursion loop in function_graph tracer. * tag 's390-5.5-4' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: s390/ftrace: save traced function caller s390/unwind: stop gracefully at user mode pt_regs in irq stack s390/purgatory: do not build purgatory with kcov, kasan and friends s390/purgatory: Make sure we fail the build if purgatory has missing symbols s390/ftrace: fix endless recursion in function_graph tracer
Diffstat (limited to 'arch/s390/kernel/unwind_bc.c')
-rw-r--r--arch/s390/kernel/unwind_bc.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/arch/s390/kernel/unwind_bc.c b/arch/s390/kernel/unwind_bc.c
index da2d4d4c5b0e..707fd99f6734 100644
--- a/arch/s390/kernel/unwind_bc.c
+++ b/arch/s390/kernel/unwind_bc.c
@@ -36,10 +36,17 @@ static bool update_stack_info(struct unwind_state *state, unsigned long sp)
return true;
}
-static inline bool is_task_pt_regs(struct unwind_state *state,
- struct pt_regs *regs)
+static inline bool is_final_pt_regs(struct unwind_state *state,
+ struct pt_regs *regs)
{
- return task_pt_regs(state->task) == regs;
+ /* user mode or kernel thread pt_regs at the bottom of task stack */
+ if (task_pt_regs(state->task) == regs)
+ return true;
+
+ /* user mode pt_regs at the bottom of irq stack */
+ return state->stack_info.type == STACK_TYPE_IRQ &&
+ state->stack_info.end - sizeof(struct pt_regs) == (unsigned long)regs &&
+ READ_ONCE_NOCHECK(regs->psw.mask) & PSW_MASK_PSTATE;
}
bool unwind_next_frame(struct unwind_state *state)
@@ -80,7 +87,7 @@ bool unwind_next_frame(struct unwind_state *state)
if (!on_stack(info, sp, sizeof(struct pt_regs)))
goto out_err;
regs = (struct pt_regs *) sp;
- if (is_task_pt_regs(state, regs))
+ if (is_final_pt_regs(state, regs))
goto out_stop;
ip = READ_ONCE_NOCHECK(regs->psw.addr);
sp = READ_ONCE_NOCHECK(regs->gprs[15]);