提交 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 {
struct user_fpsimd_state fpstate;
/* Callee-saved registers */
unsigned long ra;
unsigned long sp;
unsigned long s[7]; /* s0 ~ s6 */
};
#define INIT_THREAD { }
......
......@@ -32,8 +32,8 @@ struct stack_frame {
};
extern int unwind_frame(struct task_struct *tsk, struct stackframe *frame);
extern void walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
int (*fn)(struct stackframe *, void *), void *data);
extern void walk_stackframe(struct task_struct *tsk, struct pt_regs *regs,
int (*fn)(unsigned long, void *), void *data);
static inline bool on_task_stack(struct task_struct *tsk, unsigned long sp,
struct stack_info *info)
......
......@@ -213,6 +213,7 @@ void foo(void)
OFFSET(TASK_THREAD_FPCR, task_struct, thread.fpstate.fpcr);
BLANK();
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_S1, task_struct, thread.s[1]);
OFFSET(TASK_THREAD_S2, task_struct, thread.s[2]);
......
......@@ -398,6 +398,7 @@ __switch_to:
.prologue 0
/* Save context into prev->thread */
stl $26, TASK_THREAD_RA($17)
stl $30, TASK_THREAD_SP($17)
stl $9, TASK_THREAD_S0($17)
stl $10, TASK_THREAD_S1($17)
stl $11, TASK_THREAD_S2($17)
......@@ -415,6 +416,11 @@ __switch_to:
ldl $14, TASK_THREAD_S5($18)
ldl $15, TASK_THREAD_S6($18)
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
bic $sp, $8, $8
mov $17, $0
......
......@@ -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
* 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;
perf_callchain_store(entry, frame->pc);
perf_callchain_store(entry, pc);
return 0;
}
void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
struct pt_regs *regs)
{
struct stackframe frame;
frame.fp = regs->r15;
frame.pc = regs->pc;
walk_stackframe(current, &frame, callchain_trace, entry);
walk_stackframe(NULL, regs, callchain_trace, entry);
}
/*
......
......@@ -169,6 +169,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
childti->pcb.ksp = (unsigned long) childregs;
childti->pcb.flags = 7; /* set FEN, clear everything else */
p->thread.sp = (unsigned long) childregs;
if (unlikely(p->flags & PF_KTHREAD)) {
/* kernel thread */
......
......@@ -10,6 +10,8 @@
#include <linux/sched/debug.h>
#include <linux/ftrace.h>
#include <linux/perf_event.h>
#include <linux/kallsyms.h>
#include <asm/stacktrace.h>
/*
......@@ -59,40 +61,84 @@ int unwind_frame(struct task_struct *tsk, struct stackframe *frame)
}
EXPORT_SYMBOL_GPL(unwind_frame);
void walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
int (*fn)(struct stackframe *, void *), void *data)
void walk_stackframe(struct task_struct *tsk, struct pt_regs *regs,
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) {
int ret;
if (fn(frame, data))
break;
ret = unwind_frame(tsk, frame);
ret = unwind_frame(tsk, &frame);
if (ret < 0)
break;
if (fn(frame.pc, data))
break;
}
}
EXPORT_SYMBOL_GPL(walk_stackframe);
#else /* !CONFIG_FRAME_POINTER */
void walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
int (*fn)(struct stackframe *, void *), void *data)
void walk_stackframe(struct task_struct *tsk, struct pt_regs *regs,
int (*fn)(unsigned long, void *), void *data)
{
unsigned long *sp = (unsigned long *)current_thread_info()->pcb.ksp;
unsigned long addr;
struct perf_callchain_entry_ctx *entry = data;
unsigned long *ksp;
unsigned long sp, pc;
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);
while (!kstack_end(sp) && entry->nr < entry->max_stack) {
addr = *sp++;
if (__kernel_text_address(addr))
perf_callchain_store(entry, addr);
ksp = (unsigned long *)sp;
while (!kstack_end(ksp)) {
if (__kernel_text_address(pc) && fn(pc, data))
break;
pc = (*ksp++) - 0x4;
}
}
EXPORT_SYMBOL_GPL(walk_stackframe);
#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.
*/
......
......@@ -12,13 +12,20 @@
#include <linux/extable.h>
#include <linux/perf_event.h>
#include <linux/kdebug.h>
#include <linux/sched.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/mmu_context.h>
#include <asm/fpu.h>
#include <asm/kprobes.h>
#include <asm/uprobes.h>
#include <asm/stacktrace.h>
#include <asm/processor.h>
#include <asm/ptrace.h>
#include "proto.h"
......@@ -68,53 +75,6 @@ dik_show_code(unsigned int *pc)
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)
{
if (regs->ps & 8)
......@@ -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);
dik_show_regs(regs);
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);
if (test_and_set_thread_flag(TIF_DIE_IF_KERNEL)) {
......@@ -535,7 +495,7 @@ do_entUna(void *va, unsigned long opcode, unsigned long reg,
dik_show_regs(regs);
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)) {
printk("die_if_kernel recursion detected.\n");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册