Commit a1cdef04 authored by Christophe Leroy's avatar Christophe Leroy Committed by Michael Ellerman

powerpc: Convert stacktrace to generic ARCH_STACKWALK

This patch converts powerpc stacktrace to the generic ARCH_STACKWALK
implemented by commit 214d8ca6 ("stacktrace: Provide common
infrastructure")
Signed-off-by: default avatarChristophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/73b36bbb101299760b95ecd2cd3a46554bea8bf9.1615881400.git.christophe.leroy@csgroup.eu
parent 826a307b
...@@ -145,6 +145,7 @@ config PPC ...@@ -145,6 +145,7 @@ config PPC
select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_PARPORT
select ARCH_MIGHT_HAVE_PC_SERIO select ARCH_MIGHT_HAVE_PC_SERIO
select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX
select ARCH_STACKWALK
select ARCH_SUPPORTS_ATOMIC_RMW select ARCH_SUPPORTS_ATOMIC_RMW
select ARCH_SUPPORTS_DEBUG_PAGEALLOC if PPC32 || PPC_BOOK3S_64 select ARCH_SUPPORTS_DEBUG_PAGEALLOC if PPC32 || PPC_BOOK3S_64
select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_BUILTIN_BSWAP
......
...@@ -23,12 +23,18 @@ ...@@ -23,12 +23,18 @@
#include <asm/paca.h> #include <asm/paca.h>
/* void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
* Save stack-backtrace addresses into a stack_trace buffer. struct task_struct *task, struct pt_regs *regs)
*/
static void save_context_stack(struct stack_trace *trace, unsigned long sp,
struct task_struct *task, int savesched)
{ {
unsigned long sp;
if (regs)
sp = regs->gpr[1];
else if (task == current)
sp = current_stack_frame();
else
sp = task->thread.ksp;
for (;;) { for (;;) {
unsigned long *stack = (unsigned long *) sp; unsigned long *stack = (unsigned long *) sp;
unsigned long newsp, ip; unsigned long newsp, ip;
...@@ -39,63 +45,21 @@ static void save_context_stack(struct stack_trace *trace, unsigned long sp, ...@@ -39,63 +45,21 @@ static void save_context_stack(struct stack_trace *trace, unsigned long sp,
newsp = stack[0]; newsp = stack[0];
ip = stack[STACK_FRAME_LR_SAVE]; ip = stack[STACK_FRAME_LR_SAVE];
if (savesched || !in_sched_functions(ip)) { if (!consume_entry(cookie, ip))
if (!trace->skip)
trace->entries[trace->nr_entries++] = ip;
else
trace->skip--;
}
if (trace->nr_entries >= trace->max_entries)
return; return;
sp = newsp; sp = newsp;
} }
} }
void save_stack_trace(struct stack_trace *trace)
{
unsigned long sp;
sp = current_stack_frame();
save_context_stack(trace, sp, current, 1);
}
EXPORT_SYMBOL_GPL(save_stack_trace);
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
{
unsigned long sp;
if (!try_get_task_stack(tsk))
return;
if (tsk == current)
sp = current_stack_frame();
else
sp = tsk->thread.ksp;
save_context_stack(trace, sp, tsk, 0);
put_task_stack(tsk);
}
EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
void
save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
{
save_context_stack(trace, regs->gpr[1], current, 0);
}
EXPORT_SYMBOL_GPL(save_stack_trace_regs);
/* /*
* This function returns an error if it detects any unreliable features of the * This function returns an error if it detects any unreliable features of the
* stack. Otherwise it guarantees that the stack trace is reliable. * stack. Otherwise it guarantees that the stack trace is reliable.
* *
* If the task is not 'current', the caller *must* ensure the task is inactive. * If the task is not 'current', the caller *must* ensure the task is inactive.
*/ */
static int __save_stack_trace_tsk_reliable(struct task_struct *task, int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry,
struct stack_trace *trace) void *cookie, struct task_struct *task)
{ {
unsigned long sp; unsigned long sp;
unsigned long newsp; unsigned long newsp;
...@@ -191,35 +155,12 @@ static int __save_stack_trace_tsk_reliable(struct task_struct *task, ...@@ -191,35 +155,12 @@ static int __save_stack_trace_tsk_reliable(struct task_struct *task,
return -EINVAL; return -EINVAL;
#endif #endif
if (trace->nr_entries >= trace->max_entries) if (!consume_entry(cookie, ip))
return -E2BIG; return -EINVAL;
if (!trace->skip)
trace->entries[trace->nr_entries++] = ip;
else
trace->skip--;
} }
return 0; return 0;
} }
int save_stack_trace_tsk_reliable(struct task_struct *tsk,
struct stack_trace *trace)
{
int ret;
/*
* If the task doesn't have a stack (e.g., a zombie), the stack is
* "reliably" empty.
*/
if (!try_get_task_stack(tsk))
return 0;
ret = __save_stack_trace_tsk_reliable(tsk, trace);
put_task_stack(tsk);
return ret;
}
#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_NMI_IPI) #if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_NMI_IPI)
static void handle_backtrace_ipi(struct pt_regs *regs) static void handle_backtrace_ipi(struct pt_regs *regs)
{ {
......
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