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

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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -145,6 +145,7 @@ config PPC
	select ARCH_MIGHT_HAVE_PC_PARPORT
	select ARCH_MIGHT_HAVE_PC_SERIO
	select ARCH_OPTIONAL_KERNEL_RWX		if ARCH_HAS_STRICT_KERNEL_RWX
	select ARCH_STACKWALK
	select ARCH_SUPPORTS_ATOMIC_RMW
	select ARCH_SUPPORTS_DEBUG_PAGEALLOC	if PPC32 || PPC_BOOK3S_64
	select ARCH_USE_BUILTIN_BSWAP
+16 −75
Original line number Diff line number Diff line
@@ -23,12 +23,18 @@

#include <asm/paca.h>

/*
 * Save stack-backtrace addresses into a stack_trace buffer.
 */
static void save_context_stack(struct stack_trace *trace, unsigned long sp,
			struct task_struct *task, int savesched)
void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
		     struct task_struct *task, struct pt_regs *regs)
{
	unsigned long sp;

	if (regs)
		sp = regs->gpr[1];
	else if (task == current)
		sp = current_stack_frame();
	else
		sp = task->thread.ksp;

	for (;;) {
		unsigned long *stack = (unsigned long *) sp;
		unsigned long newsp, ip;
@@ -39,63 +45,21 @@ static void save_context_stack(struct stack_trace *trace, unsigned long sp,
		newsp = stack[0];
		ip = stack[STACK_FRAME_LR_SAVE];

		if (savesched || !in_sched_functions(ip)) {
			if (!trace->skip)
				trace->entries[trace->nr_entries++] = ip;
			else
				trace->skip--;
		}

		if (trace->nr_entries >= trace->max_entries)
		if (!consume_entry(cookie, ip))
			return;

		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
 * stack.  Otherwise it guarantees that the stack trace is reliable.
 *
 * 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,
					   struct stack_trace *trace)
int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry,
			     void *cookie, struct task_struct *task)
{
	unsigned long sp;
	unsigned long newsp;
@@ -191,35 +155,12 @@ static int __save_stack_trace_tsk_reliable(struct task_struct *task,
			return -EINVAL;
#endif

		if (trace->nr_entries >= trace->max_entries)
			return -E2BIG;
		if (!trace->skip)
			trace->entries[trace->nr_entries++] = ip;
		else
			trace->skip--;
		if (!consume_entry(cookie, ip))
			return -EINVAL;
	}
	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)
static void handle_backtrace_ipi(struct pt_regs *regs)
{