提交 0115f679 编写于 作者: W Wu Liliu 提交者: guzitao

sw64: reimplement show_stack() method

Sunway inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I5GFQ0

--------------------------------

It used to show stack information by SP, that means it has nothing to
do with task, which is unexpected. In order to show stack of task, we
improve the implementation of show_stack().

However, the original task struct does not have sp, so we add it into
thread_struct and do something necessary in __switch_to.

Meanwhile, walk_stackframe() can be reused, so refactor related codes
for better support.
Signed-off-by: NWu Liliu <wuliliu@wxiat.com>
Signed-off-by: NGu Zitao <guzitao@wxiat.com>
上级 9e0b719c
...@@ -45,6 +45,7 @@ struct thread_struct { ...@@ -45,6 +45,7 @@ struct thread_struct {
struct user_fpsimd_state fpstate; struct user_fpsimd_state fpstate;
/* Callee-saved registers */ /* Callee-saved registers */
unsigned long ra; unsigned long ra;
unsigned long sp;
unsigned long s[7]; /* s0 ~ s6 */ unsigned long s[7]; /* s0 ~ s6 */
}; };
#define INIT_THREAD { } #define INIT_THREAD { }
......
...@@ -32,8 +32,8 @@ struct stack_frame { ...@@ -32,8 +32,8 @@ struct stack_frame {
}; };
extern int unwind_frame(struct task_struct *tsk, struct stackframe *frame); extern int unwind_frame(struct task_struct *tsk, struct stackframe *frame);
extern void walk_stackframe(struct task_struct *tsk, struct stackframe *frame, extern void walk_stackframe(struct task_struct *tsk, struct pt_regs *regs,
int (*fn)(struct stackframe *, void *), void *data); int (*fn)(unsigned long, void *), void *data);
static inline bool on_task_stack(struct task_struct *tsk, unsigned long sp, static inline bool on_task_stack(struct task_struct *tsk, unsigned long sp,
struct stack_info *info) struct stack_info *info)
......
...@@ -213,6 +213,7 @@ void foo(void) ...@@ -213,6 +213,7 @@ void foo(void)
OFFSET(TASK_THREAD_FPCR, task_struct, thread.fpstate.fpcr); OFFSET(TASK_THREAD_FPCR, task_struct, thread.fpstate.fpcr);
BLANK(); BLANK();
OFFSET(TASK_THREAD_RA, task_struct, thread.ra); OFFSET(TASK_THREAD_RA, task_struct, thread.ra);
OFFSET(TASK_THREAD_SP, task_struct, thread.sp);
OFFSET(TASK_THREAD_S0, task_struct, thread.s[0]); OFFSET(TASK_THREAD_S0, task_struct, thread.s[0]);
OFFSET(TASK_THREAD_S1, task_struct, thread.s[1]); OFFSET(TASK_THREAD_S1, task_struct, thread.s[1]);
OFFSET(TASK_THREAD_S2, task_struct, thread.s[2]); OFFSET(TASK_THREAD_S2, task_struct, thread.s[2]);
......
...@@ -398,6 +398,7 @@ __switch_to: ...@@ -398,6 +398,7 @@ __switch_to:
.prologue 0 .prologue 0
/* Save context into prev->thread */ /* Save context into prev->thread */
stl $26, TASK_THREAD_RA($17) stl $26, TASK_THREAD_RA($17)
stl $30, TASK_THREAD_SP($17)
stl $9, TASK_THREAD_S0($17) stl $9, TASK_THREAD_S0($17)
stl $10, TASK_THREAD_S1($17) stl $10, TASK_THREAD_S1($17)
stl $11, TASK_THREAD_S2($17) stl $11, TASK_THREAD_S2($17)
...@@ -415,6 +416,11 @@ __switch_to: ...@@ -415,6 +416,11 @@ __switch_to:
ldl $14, TASK_THREAD_S5($18) ldl $14, TASK_THREAD_S5($18)
ldl $15, TASK_THREAD_S6($18) ldl $15, TASK_THREAD_S6($18)
sys_call HMC_swpctx sys_call HMC_swpctx
/*
* SP has been saved and restored by HMC_swpctx,
* and restore it again here for future expansion.
*/
ldl $30, TASK_THREAD_SP($18)
ldi $8, 0x3fff ldi $8, 0x3fff
bic $sp, $8, $8 bic $sp, $8, $8
mov $17, $0 mov $17, $0
......
...@@ -761,24 +761,18 @@ void perf_callchain_user(struct perf_callchain_entry_ctx *entry, ...@@ -761,24 +761,18 @@ void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
* whist unwinding the stackframe and is like a subroutine return so we use * whist unwinding the stackframe and is like a subroutine return so we use
* the PC. * the PC.
*/ */
static int callchain_trace(struct stackframe *frame, void *data) static int callchain_trace(unsigned long pc, void *data)
{ {
struct perf_callchain_entry_ctx *entry = data; struct perf_callchain_entry_ctx *entry = data;
perf_callchain_store(entry, frame->pc); perf_callchain_store(entry, pc);
return 0; return 0;
} }
void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
struct pt_regs *regs) struct pt_regs *regs)
{ {
struct stackframe frame; walk_stackframe(NULL, regs, callchain_trace, entry);
frame.fp = regs->r15;
frame.pc = regs->pc;
walk_stackframe(current, &frame, callchain_trace, entry);
} }
/* /*
......
...@@ -169,6 +169,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp, ...@@ -169,6 +169,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
childti->pcb.ksp = (unsigned long) childregs; childti->pcb.ksp = (unsigned long) childregs;
childti->pcb.flags = 7; /* set FEN, clear everything else */ childti->pcb.flags = 7; /* set FEN, clear everything else */
p->thread.sp = (unsigned long) childregs;
if (unlikely(p->flags & PF_KTHREAD)) { if (unlikely(p->flags & PF_KTHREAD)) {
/* kernel thread */ /* kernel thread */
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include <linux/sched/debug.h> #include <linux/sched/debug.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <linux/perf_event.h> #include <linux/perf_event.h>
#include <linux/kallsyms.h>
#include <asm/stacktrace.h> #include <asm/stacktrace.h>
/* /*
...@@ -59,40 +61,84 @@ int unwind_frame(struct task_struct *tsk, struct stackframe *frame) ...@@ -59,40 +61,84 @@ int unwind_frame(struct task_struct *tsk, struct stackframe *frame)
} }
EXPORT_SYMBOL_GPL(unwind_frame); EXPORT_SYMBOL_GPL(unwind_frame);
void walk_stackframe(struct task_struct *tsk, struct stackframe *frame, void walk_stackframe(struct task_struct *tsk, struct pt_regs *regs,
int (*fn)(struct stackframe *, void *), void *data) int (*fn)(unsigned long, void *), void *data)
{ {
unsigned long pc, fp;
struct stackframe frame;
if (regs) {
pc = regs->pc;
fp = regs->r15;
} else if (tsk == current || tsk == NULL) {
fp = (unsigned long)__builtin_frame_address(0);
pc = (unsigned long)walk_stackframe;
} else {
fp = tsk->thread.s[6];
pc = tsk->thread.ra;
}
if (!__kernel_text_address(pc) || fn(pc, data))
return;
frame.pc = pc;
frame.fp = fp;
while (1) { while (1) {
int ret; int ret;
ret = unwind_frame(tsk, &frame);
if (fn(frame, data))
break;
ret = unwind_frame(tsk, frame);
if (ret < 0) if (ret < 0)
break; break;
if (fn(frame.pc, data))
break;
} }
} }
EXPORT_SYMBOL_GPL(walk_stackframe); EXPORT_SYMBOL_GPL(walk_stackframe);
#else /* !CONFIG_FRAME_POINTER */ #else /* !CONFIG_FRAME_POINTER */
void walk_stackframe(struct task_struct *tsk, struct stackframe *frame, void walk_stackframe(struct task_struct *tsk, struct pt_regs *regs,
int (*fn)(struct stackframe *, void *), void *data) int (*fn)(unsigned long, void *), void *data)
{ {
unsigned long *sp = (unsigned long *)current_thread_info()->pcb.ksp; unsigned long *ksp;
unsigned long addr; unsigned long sp, pc;
struct perf_callchain_entry_ctx *entry = data;
if (regs) {
sp = (unsigned long)(regs+1);
pc = regs->pc;
} else if (tsk == current || tsk == NULL) {
register unsigned long current_sp __asm__ ("$30");
sp = current_sp;
pc = (unsigned long)walk_stackframe;
} else {
sp = tsk->thread.sp;
pc = tsk->thread.ra;
}
perf_callchain_store(entry, frame->pc); ksp = (unsigned long *)sp;
while (!kstack_end(sp) && entry->nr < entry->max_stack) {
addr = *sp++; while (!kstack_end(ksp)) {
if (__kernel_text_address(addr)) if (__kernel_text_address(pc) && fn(pc, data))
perf_callchain_store(entry, addr); break;
pc = (*ksp++) - 0x4;
} }
} }
EXPORT_SYMBOL_GPL(walk_stackframe); EXPORT_SYMBOL_GPL(walk_stackframe);
#endif/* CONFIG_FRAME_POINTER */ #endif/* CONFIG_FRAME_POINTER */
static int print_address_trace(unsigned long pc, void *data)
{
print_ip_sym((const char *)data, pc);
return 0;
}
void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl)
{
pr_info("Trace:\n");
walk_stackframe(task, NULL, print_address_trace, (void *)loglvl);
}
/* /*
* Save stack-backtrace addresses into a stack_trace buffer. * Save stack-backtrace addresses into a stack_trace buffer.
*/ */
......
...@@ -12,13 +12,20 @@ ...@@ -12,13 +12,20 @@
#include <linux/extable.h> #include <linux/extable.h>
#include <linux/perf_event.h> #include <linux/perf_event.h>
#include <linux/kdebug.h> #include <linux/kdebug.h>
#include <linux/sched.h>
#include <linux/kexec.h> #include <linux/kexec.h>
#include <linux/kallsyms.h>
#include <linux/sched/task_stack.h>
#include <linux/sched/debug.h>
#include <asm/gentrap.h> #include <asm/gentrap.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/fpu.h> #include <asm/fpu.h>
#include <asm/kprobes.h> #include <asm/kprobes.h>
#include <asm/uprobes.h> #include <asm/uprobes.h>
#include <asm/stacktrace.h>
#include <asm/processor.h>
#include <asm/ptrace.h>
#include "proto.h" #include "proto.h"
...@@ -68,53 +75,6 @@ dik_show_code(unsigned int *pc) ...@@ -68,53 +75,6 @@ dik_show_code(unsigned int *pc)
printk("\n"); printk("\n");
} }
static void
dik_show_trace(unsigned long *sp, const char *loglvl)
{
long i = 0;
unsigned long tmp;
printk("%sTrace:\n", loglvl);
while (0x1ff8 & (unsigned long)sp) {
tmp = *sp;
sp++;
if (!__kernel_text_address(tmp))
continue;
printk("%s[<%lx>] %pSR\n", loglvl, tmp, (void *)tmp);
if (i > 40) {
printk("%s ...", loglvl);
break;
}
}
printk("\n");
}
static int kstack_depth_to_print = 24;
void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl)
{
unsigned long *stack;
int i;
/*
* debugging aid: "show_stack(NULL, NULL, KERN_EMERG);" prints the
* back trace for this cpu.
*/
if (sp == NULL)
sp = (unsigned long *)&sp;
stack = sp;
for (i = 0; i < kstack_depth_to_print; i++) {
if (((long) stack & (THREAD_SIZE-1)) == 0)
break;
if (i && ((i % 4) == 0))
printk("%s ", loglvl);
printk("%016lx ", *stack++);
}
printk("\n");
dik_show_trace(sp, loglvl);
}
void die_if_kernel(char *str, struct pt_regs *regs, long err) void die_if_kernel(char *str, struct pt_regs *regs, long err)
{ {
if (regs->ps & 8) if (regs->ps & 8)
...@@ -125,7 +85,7 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) ...@@ -125,7 +85,7 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
printk("%s(%d): %s %ld\n", current->comm, task_pid_nr(current), str, err); printk("%s(%d): %s %ld\n", current->comm, task_pid_nr(current), str, err);
dik_show_regs(regs); dik_show_regs(regs);
add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
dik_show_trace((unsigned long *)(regs+1), KERN_DEFAULT); show_stack(current, NULL, KERN_EMERG);
dik_show_code((unsigned int *)regs->pc); dik_show_code((unsigned int *)regs->pc);
if (test_and_set_thread_flag(TIF_DIE_IF_KERNEL)) { if (test_and_set_thread_flag(TIF_DIE_IF_KERNEL)) {
...@@ -535,7 +495,7 @@ do_entUna(void *va, unsigned long opcode, unsigned long reg, ...@@ -535,7 +495,7 @@ do_entUna(void *va, unsigned long opcode, unsigned long reg,
dik_show_regs(regs); dik_show_regs(regs);
dik_show_code((unsigned int *)pc); dik_show_code((unsigned int *)pc);
dik_show_trace((unsigned long *)(regs+1), KERN_DEFAULT); show_stack(current, NULL, KERN_EMERG);
if (test_and_set_thread_flag(TIF_DIE_IF_KERNEL)) { if (test_and_set_thread_flag(TIF_DIE_IF_KERNEL)) {
printk("die_if_kernel recursion detected.\n"); printk("die_if_kernel recursion detected.\n");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册