1
0
Fork 0

csky: stacktrace supported.

The gcc option "-mbacktrace" will push fp(r8),lr into stack and we could
unwind the stack with:
	fp = *fp
	lr = (unsigned int *)fp[1]

Signed-off-by: Guo Ren <ren_guo@c-sky.com>
hifive-unleashed-5.1
Guo Ren 2018-12-09 14:18:05 +08:00
parent 859e5f45cb
commit 0ea2dc7cd6
6 changed files with 86 additions and 12 deletions

View File

@ -94,6 +94,9 @@ config MMU
config RWSEM_GENERIC_SPINLOCK config RWSEM_GENERIC_SPINLOCK
def_bool y def_bool y
config STACKTRACE_SUPPORT
def_bool y
config TIME_LOW_RES config TIME_LOW_RES
def_bool y def_bool y

View File

@ -47,6 +47,10 @@ ifeq ($(CSKYABI),abiv2)
KBUILD_CFLAGS += -mno-stack-size KBUILD_CFLAGS += -mno-stack-size
endif endif
ifdef CONFIG_STACKTRACE
KBUILD_CFLAGS += -mbacktrace
endif
abidirs := $(patsubst %,arch/csky/%/,$(CSKYABI)) abidirs := $(patsubst %,arch/csky/%/,$(CSKYABI))
KBUILD_CFLAGS += $(patsubst %,-I$(srctree)/%inc,$(abidirs)) KBUILD_CFLAGS += $(patsubst %,-I$(srctree)/%inc,$(abidirs))

View File

@ -10,6 +10,7 @@
#include <asm/types.h> #include <asm/types.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <abi/switch_context.h>
struct thread_info { struct thread_info {
struct task_struct *task; struct task_struct *task;
@ -36,6 +37,9 @@ struct thread_info {
#define THREAD_SIZE_ORDER (THREAD_SHIFT - PAGE_SHIFT) #define THREAD_SIZE_ORDER (THREAD_SHIFT - PAGE_SHIFT)
#define thread_saved_fp(tsk) \
((unsigned long)(((struct switch_stack *)(tsk->thread.ksp))->r8))
static inline struct thread_info *current_thread_info(void) static inline struct thread_info *current_thread_info(void)
{ {
unsigned long sp; unsigned long sp;

View File

@ -6,3 +6,4 @@ obj-y += process.o cpu-probe.o ptrace.o dumpstack.o
obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o

View File

@ -93,26 +93,31 @@ int dump_task_regs(struct task_struct *tsk, elf_gregset_t *pr_regs)
unsigned long get_wchan(struct task_struct *p) unsigned long get_wchan(struct task_struct *p)
{ {
unsigned long esp, pc; unsigned long lr;
unsigned long stack_page; unsigned long *fp, *stack_start, *stack_end;
int count = 0; int count = 0;
if (!p || p == current || p->state == TASK_RUNNING) if (!p || p == current || p->state == TASK_RUNNING)
return 0; return 0;
stack_page = (unsigned long)p; stack_start = (unsigned long *)end_of_stack(p);
esp = p->thread.esp0; stack_end = (unsigned long *)(task_stack_page(p) + THREAD_SIZE);
fp = (unsigned long *) thread_saved_fp(p);
do { do {
if (esp < stack_page+sizeof(struct task_struct) || if (fp < stack_start || fp > stack_end)
esp >= 8184+stack_page)
return 0; return 0;
/*FIXME: There's may be error here!*/ #ifdef CONFIG_STACKTRACE
pc = ((unsigned long *)esp)[1]; lr = fp[1];
/* FIXME: This depends on the order of these functions. */ fp = (unsigned long *)fp[0];
if (!in_sched_functions(pc)) #else
return pc; lr = *fp++;
esp = *(unsigned long *) esp; #endif
if (!in_sched_functions(lr) &&
__kernel_text_address(lr))
return lr;
} while (count++ < 16); } while (count++ < 16);
return 0; return 0;
} }
EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(get_wchan);

View File

@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. */
#include <linux/sched/debug.h>
#include <linux/sched/task_stack.h>
#include <linux/stacktrace.h>
#include <linux/ftrace.h>
void save_stack_trace(struct stack_trace *trace)
{
save_stack_trace_tsk(current, trace);
}
EXPORT_SYMBOL_GPL(save_stack_trace);
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
{
unsigned long *fp, *stack_start, *stack_end;
unsigned long addr;
int skip = trace->skip;
int savesched;
int graph_idx = 0;
if (tsk == current) {
asm volatile("mov %0, r8\n":"=r"(fp));
savesched = 1;
} else {
fp = (unsigned long *)thread_saved_fp(tsk);
savesched = 0;
}
addr = (unsigned long) fp & THREAD_MASK;
stack_start = (unsigned long *) addr;
stack_end = (unsigned long *) (addr + THREAD_SIZE);
while (fp > stack_start && fp < stack_end) {
unsigned long lpp, fpp;
fpp = fp[0];
lpp = fp[1];
if (!__kernel_text_address(lpp))
break;
else
lpp = ftrace_graph_ret_addr(tsk, &graph_idx, lpp, NULL);
if (savesched || !in_sched_functions(lpp)) {
if (skip) {
skip--;
} else {
trace->entries[trace->nr_entries++] = lpp;
if (trace->nr_entries >= trace->max_entries)
break;
}
}
fp = (unsigned long *)fpp;
}
}
EXPORT_SYMBOL_GPL(save_stack_trace_tsk);