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>
This commit is contained in:
parent
859e5f45cb
commit
0ea2dc7cd6
|
@ -94,6 +94,9 @@ config MMU
|
|||
config RWSEM_GENERIC_SPINLOCK
|
||||
def_bool y
|
||||
|
||||
config STACKTRACE_SUPPORT
|
||||
def_bool y
|
||||
|
||||
config TIME_LOW_RES
|
||||
def_bool y
|
||||
|
||||
|
|
|
@ -47,6 +47,10 @@ ifeq ($(CSKYABI),abiv2)
|
|||
KBUILD_CFLAGS += -mno-stack-size
|
||||
endif
|
||||
|
||||
ifdef CONFIG_STACKTRACE
|
||||
KBUILD_CFLAGS += -mbacktrace
|
||||
endif
|
||||
|
||||
abidirs := $(patsubst %,arch/csky/%/,$(CSKYABI))
|
||||
KBUILD_CFLAGS += $(patsubst %,-I$(srctree)/%inc,$(abidirs))
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <asm/types.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/processor.h>
|
||||
#include <abi/switch_context.h>
|
||||
|
||||
struct thread_info {
|
||||
struct task_struct *task;
|
||||
|
@ -36,6 +37,9 @@ struct thread_info {
|
|||
|
||||
#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)
|
||||
{
|
||||
unsigned long sp;
|
||||
|
|
|
@ -6,3 +6,4 @@ obj-y += process.o cpu-probe.o ptrace.o dumpstack.o
|
|||
|
||||
obj-$(CONFIG_MODULES) += module.o
|
||||
obj-$(CONFIG_SMP) += smp.o
|
||||
obj-$(CONFIG_STACKTRACE) += stacktrace.o
|
||||
|
|
|
@ -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 esp, pc;
|
||||
unsigned long stack_page;
|
||||
unsigned long lr;
|
||||
unsigned long *fp, *stack_start, *stack_end;
|
||||
int count = 0;
|
||||
|
||||
if (!p || p == current || p->state == TASK_RUNNING)
|
||||
return 0;
|
||||
|
||||
stack_page = (unsigned long)p;
|
||||
esp = p->thread.esp0;
|
||||
stack_start = (unsigned long *)end_of_stack(p);
|
||||
stack_end = (unsigned long *)(task_stack_page(p) + THREAD_SIZE);
|
||||
|
||||
fp = (unsigned long *) thread_saved_fp(p);
|
||||
do {
|
||||
if (esp < stack_page+sizeof(struct task_struct) ||
|
||||
esp >= 8184+stack_page)
|
||||
if (fp < stack_start || fp > stack_end)
|
||||
return 0;
|
||||
/*FIXME: There's may be error here!*/
|
||||
pc = ((unsigned long *)esp)[1];
|
||||
/* FIXME: This depends on the order of these functions. */
|
||||
if (!in_sched_functions(pc))
|
||||
return pc;
|
||||
esp = *(unsigned long *) esp;
|
||||
#ifdef CONFIG_STACKTRACE
|
||||
lr = fp[1];
|
||||
fp = (unsigned long *)fp[0];
|
||||
#else
|
||||
lr = *fp++;
|
||||
#endif
|
||||
if (!in_sched_functions(lr) &&
|
||||
__kernel_text_address(lr))
|
||||
return lr;
|
||||
} while (count++ < 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(get_wchan);
|
||||
|
|
|
@ -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);
|
Loading…
Reference in New Issue