Commit eecac38b authored by Stafford Horne's avatar Stafford Horne
Browse files

openrisc: support framepointers and STACKTRACE_SUPPORT



For lockdep support a reliable stack trace mechanism is needed.  This
patch adds support in OpenRISC for the stacktrace framework, implemented
by a simple unwinder api.  The unwinder api supports both framepointer
and basic stack tracing.

The unwinder is now used to replace the stack_dump() implementation as
well. The new traces are inline with other architectures trace format:

 Call trace:
 [<c0004448>] show_stack+0x3c/0x58
 [<c031c940>] dump_stack+0xa8/0xe4
 [<c0008104>] __cpu_up+0x64/0x130
 [<c000d268>] bringup_cpu+0x3c/0x178
 [<c000d038>] cpuhp_invoke_callback+0xa8/0x1fc
 [<c000d680>] cpuhp_up_callbacks+0x44/0x14c
 [<c000e400>] cpu_up+0x14c/0x1bc
 [<c041da60>] smp_init+0x104/0x15c
 [<c033843c>] ? kernel_init+0x0/0x140
 [<c0415e04>] kernel_init_freeable+0xbc/0x25c
 [<c033843c>] ? kernel_init+0x0/0x140
 [<c0338458>] kernel_init+0x1c/0x140
 [<c003a174>] ? schedule_tail+0x18/0xa0
 [<c0006b80>] ret_from_fork+0x1c/0x9c

Signed-off-by: default avatarStafford Horne <shorne@gmail.com>
parent 306e5e50
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ config OPENRISC
	select ARCH_USE_QUEUED_SPINLOCKS
	select ARCH_USE_QUEUED_RWLOCKS
	select OMPIC if SMP
	select ARCH_WANT_FRAME_POINTERS

config CPU_BIG_ENDIAN
	def_bool y
@@ -60,6 +61,9 @@ config TRACE_IRQFLAGS_SUPPORT
config GENERIC_CSUM
        def_bool y

config STACKTRACE_SUPPORT
	def_bool y

source "init/Kconfig"

source "kernel/Kconfig.freezer"
+20 −0
Original line number Diff line number Diff line
/*
 * OpenRISC unwinder.h
 *
 * Architecture API for unwinding stacks.
 *
 * Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
 *
 * This file is licensed under the terms of the GNU General Public License
 * version 2.  This program is licensed "as is" without any warranty of any
 * kind, whether express or implied.
 */

#ifndef __ASM_OPENRISC_UNWINDER_H
#define __ASM_OPENRISC_UNWINDER_H

void unwind_stack(void *data, unsigned long *stack,
		  void (*trace)(void *data, unsigned long addr,
				int reliable));

#endif /* __ASM_OPENRISC_UNWINDER_H */
+2 −1
Original line number Diff line number Diff line
@@ -6,9 +6,10 @@ extra-y := head.o vmlinux.lds

obj-y	:= setup.o or32_ksyms.o process.o dma.o \
	   traps.o time.o irq.o entry.o ptrace.o signal.o \
	   sys_call_table.o
	   sys_call_table.o unwinder.o

obj-$(CONFIG_SMP)		+= smp.o
obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
obj-$(CONFIG_MODULES)		+= module.o
obj-$(CONFIG_OF)		+= prom.o

+86 −0
Original line number Diff line number Diff line
/*
 * Stack trace utility for OpenRISC
 *
 * Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
 *
 * This file is licensed under the terms of the GNU General Public License
 * version 2.  This program is licensed "as is" without any warranty of any
 * kind, whether express or implied.
 *
 * Losely based on work from sh and powerpc.
 */

#include <linux/export.h>
#include <linux/sched.h>
#include <linux/sched/debug.h>
#include <linux/stacktrace.h>

#include <asm/processor.h>
#include <asm/unwinder.h>

/*
 * Save stack-backtrace addresses into a stack_trace buffer.
 */
static void
save_stack_address(void *data, unsigned long addr, int reliable)
{
	struct stack_trace *trace = data;

	if (!reliable)
		return;

	if (trace->skip > 0) {
		trace->skip--;
		return;
	}

	if (trace->nr_entries < trace->max_entries)
		trace->entries[trace->nr_entries++] = addr;
}

void save_stack_trace(struct stack_trace *trace)
{
	unwind_stack(trace, (unsigned long *) &trace, save_stack_address);
}
EXPORT_SYMBOL_GPL(save_stack_trace);

static void
save_stack_address_nosched(void *data, unsigned long addr, int reliable)
{
	struct stack_trace *trace = (struct stack_trace *)data;

	if (!reliable)
		return;

	if (in_sched_functions(addr))
		return;

	if (trace->skip > 0) {
		trace->skip--;
		return;
	}

	if (trace->nr_entries < trace->max_entries)
		trace->entries[trace->nr_entries++] = addr;
}

void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
{
	unsigned long *sp = NULL;

	if (tsk == current)
		sp = (unsigned long *) &sp;
	else
		sp = (unsigned long *) KSTK_ESP(tsk);

	unwind_stack(trace, sp, save_stack_address_nosched);
}
EXPORT_SYMBOL_GPL(save_stack_trace_tsk);

void
save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
{
	unwind_stack(trace, (unsigned long *) regs->sp,
		     save_stack_address_nosched);
}
EXPORT_SYMBOL_GPL(save_stack_trace_regs);
+7 −47
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#include <asm/segment.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/unwinder.h>

extern char _etext, _stext;

@@ -45,61 +46,20 @@ int kstack_depth_to_print = 0x180;
int lwa_flag;
unsigned long __user *lwa_addr;

static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
void print_trace(void *data, unsigned long addr, int reliable)
{
	return p > (void *)tinfo && p < (void *)tinfo + THREAD_SIZE - 3;
}

void show_trace(struct task_struct *task, unsigned long *stack)
{
	struct thread_info *context;
	unsigned long addr;

	context = (struct thread_info *)
	    ((unsigned long)stack & (~(THREAD_SIZE - 1)));

	while (valid_stack_ptr(context, stack)) {
		addr = *stack++;
		if (__kernel_text_address(addr)) {
			printk(" [<%08lx>]", addr);
			print_symbol(" %s", addr);
			printk("\n");
		}
	}
	printk(" =======================\n");
	pr_emerg("[<%p>] %s%pS\n", (void *) addr, reliable ? "" : "? ",
	       (void *) addr);
}

/* displays a short stack trace */
void show_stack(struct task_struct *task, unsigned long *esp)
{
	unsigned long addr, *stack;
	int i;

	if (esp == NULL)
		esp = (unsigned long *)&esp;

	stack = esp;

	printk("Stack dump [0x%08lx]:\n", (unsigned long)esp);
	for (i = 0; i < kstack_depth_to_print; i++) {
		if (kstack_end(stack))
			break;
		if (__get_user(addr, stack)) {
			/* This message matches "failing address" marked
			   s390 in ksymoops, so lines containing it will
			   not be filtered out by ksymoops.  */
			printk("Failing address 0x%lx\n", (unsigned long)stack);
			break;
		}
		stack++;

		printk("sp + %02d: 0x%08lx\n", i * 4, addr);
	}
	printk("\n");

	show_trace(task, esp);

	return;
	pr_emerg("Call trace:\n");
	unwind_stack(NULL, esp, print_trace);
}

void show_trace_task(struct task_struct *tsk)
@@ -115,7 +75,7 @@ void show_registers(struct pt_regs *regs)
	int in_kernel = 1;
	unsigned long esp;

	esp = (unsigned long)(&regs->sp);
	esp = (unsigned long)(regs->sp);
	if (user_mode(regs))
		in_kernel = 0;

Loading