From d4fd1989ea142be620978dcac2e1b86929f3237a Mon Sep 17 00:00:00 2001 From: Maxime Bizon Date: Thu, 20 Jul 2006 18:52:02 +0200 Subject: [MIPS] Honour "panic_on_oops" sysctl. Signed-off-by: Maxime Bizon Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 954a198494e..368fdb77917 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -292,6 +293,16 @@ NORET_TYPE void ATTRIB_NORET die(const char * str, struct pt_regs * regs) printk("%s[#%d]:\n", str, ++die_counter); show_registers(regs); spin_unlock_irq(&die_lock); + + if (in_interrupt()) + panic("Fatal exception in interrupt"); + + if (panic_on_oops) { + printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n"); + ssleep(5); + panic("Fatal exception"); + } + do_exit(SIGSEGV); } -- cgit v1.2.3-70-g09d2 From e889d78fd5775d0b466f570928f5b0f0c9f05355 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Tue, 25 Jul 2006 23:51:36 +0900 Subject: [MIPS] Rearrange show_stack, show_trace Print call-trace in show_stack() (like on other archs). Also make show_trace() static and simplify its argument list. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 51 ++++++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 28 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 368fdb77917..c6f70467e75 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -79,6 +79,25 @@ void (*board_bind_eic_interrupt)(int irq, int regset); */ #define MODULE_RANGE (8*1024*1024) +static void show_trace(unsigned long *stack) +{ + const int field = 2 * sizeof(unsigned long); + unsigned long addr; + + printk("Call Trace:"); +#ifdef CONFIG_KALLSYMS + printk("\n"); +#endif + while (!kstack_end(stack)) { + addr = *stack++; + if (__kernel_text_address(addr)) { + printk(" [<%0*lx>] ", field, addr); + print_symbol("%s\n", addr); + } + } + printk("\n"); +} + /* * This routine abuses get_user()/put_user() to reference pointers * with at least a bit of error checking ... @@ -88,6 +107,7 @@ void show_stack(struct task_struct *task, unsigned long *sp) const int field = 2 * sizeof(unsigned long); long stackdata; int i; + unsigned long *stack; if (!sp) { if (task && task != current) @@ -95,6 +115,7 @@ void show_stack(struct task_struct *task, unsigned long *sp) else sp = (unsigned long *) &sp; } + stack = sp; printk("Stack :"); i = 0; @@ -115,32 +136,7 @@ void show_stack(struct task_struct *task, unsigned long *sp) i++; } printk("\n"); -} - -void show_trace(struct task_struct *task, unsigned long *stack) -{ - const int field = 2 * sizeof(unsigned long); - unsigned long addr; - - if (!stack) { - if (task && task != current) - stack = (unsigned long *) task->thread.reg29; - else - stack = (unsigned long *) &stack; - } - - printk("Call Trace:"); -#ifdef CONFIG_KALLSYMS - printk("\n"); -#endif - while (!kstack_end(stack)) { - addr = *stack++; - if (__kernel_text_address(addr)) { - printk(" [<%0*lx>] ", field, addr); - print_symbol("%s\n", addr); - } - } - printk("\n"); + show_trace(stack); } /* @@ -150,7 +146,7 @@ void dump_stack(void) { unsigned long stack; - show_trace(current, &stack); + show_trace(&stack); } EXPORT_SYMBOL(dump_stack); @@ -270,7 +266,6 @@ void show_registers(struct pt_regs *regs) printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n", current->comm, current->pid, current_thread_info(), current); show_stack(current, (long *) regs->regs[29]); - show_trace(current, (long *) regs->regs[29]); show_code((unsigned int *) regs->cp0_epc); printk("\n"); } -- cgit v1.2.3-70-g09d2 From f66686f70a2a61e53ee8c2284f75ca342e4c0dc8 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Sat, 29 Jul 2006 23:27:20 +0900 Subject: [MIPS] dump_stack() based on prologue code analysis Instead of dump all possible address in the stack, unwind the stack frame based on prologue code analysis, as like as get_wchan() does. While the code analysis might fail for some reason, there is a new kernel option "raw_show_trace" to disable this feature. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 66 +++++++++++++++++++++++++------ arch/mips/kernel/traps.c | 98 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 141 insertions(+), 23 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 7ab67f786bf..8709a46a45c 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -281,7 +281,7 @@ static struct mips_frame_info { } *schedule_frame, mfinfo[64]; static int mfinfo_num; -static int __init get_frame_info(struct mips_frame_info *info) +static int get_frame_info(struct mips_frame_info *info) { int i; void *func = info->func; @@ -329,14 +329,12 @@ static int __init get_frame_info(struct mips_frame_info *info) ip->i_format.simmediate / sizeof(long); } } - if (info->pc_offset == -1 || info->frame_size == 0) { - if (func == schedule) - printk("Can't analyze prologue code at %p\n", func); - info->pc_offset = -1; - info->frame_size = 0; - } - - return 0; + if (info->frame_size && info->pc_offset >= 0) /* nested */ + return 0; + if (info->pc_offset < 0) /* leaf */ + return 1; + /* prologue seems boggus... */ + return -1; } static int __init frame_info_init(void) @@ -367,8 +365,15 @@ static int __init frame_info_init(void) mfinfo[0].func = schedule; schedule_frame = &mfinfo[0]; #endif - for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++) - get_frame_info(&mfinfo[i]); + for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++) { + struct mips_frame_info *info = &mfinfo[i]; + if (get_frame_info(info)) { + /* leaf or unknown */ + if (info->func == schedule) + printk("Can't analyze prologue code at %p\n", + info->func); + } + } mfinfo_num = i; return 0; @@ -427,6 +432,8 @@ unsigned long get_wchan(struct task_struct *p) if (i < 0) break; + if (mfinfo[i].pc_offset < 0) + break; pc = ((unsigned long *)frame)[mfinfo[i].pc_offset]; if (!mfinfo[i].frame_size) break; @@ -437,3 +444,40 @@ unsigned long get_wchan(struct task_struct *p) return pc; } +#ifdef CONFIG_KALLSYMS +/* used by show_frametrace() */ +unsigned long unwind_stack(struct task_struct *task, + unsigned long **sp, unsigned long pc) +{ + unsigned long stack_page; + struct mips_frame_info info; + char *modname; + char namebuf[KSYM_NAME_LEN + 1]; + unsigned long size, ofs; + + stack_page = (unsigned long)task_stack_page(task); + if (!stack_page) + return 0; + + if (!kallsyms_lookup(pc, &size, &ofs, &modname, namebuf)) + return 0; + if (ofs == 0) + return 0; + + info.func = (void *)(pc - ofs); + info.func_size = ofs; /* analyze from start to ofs */ + if (get_frame_info(&info)) { + /* leaf or unknown */ + *sp += info.frame_size / sizeof(long); + return 0; + } + if ((unsigned long)*sp < stack_page || + (unsigned long)*sp + info.frame_size / sizeof(long) > + stack_page + THREAD_SIZE - 32) + return 0; + + pc = (*sp)[info.pc_offset]; + *sp += info.frame_size / sizeof(long); + return pc; +} +#endif diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index c6f70467e75..7aa9dfc57b8 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -98,24 +98,53 @@ static void show_trace(unsigned long *stack) printk("\n"); } +#ifdef CONFIG_KALLSYMS +static int raw_show_trace; +static int __init set_raw_show_trace(char *str) +{ + raw_show_trace = 1; + return 1; +} +__setup("raw_show_trace", set_raw_show_trace); + +extern unsigned long unwind_stack(struct task_struct *task, + unsigned long **sp, unsigned long pc); +static void show_frametrace(struct task_struct *task, struct pt_regs *regs) +{ + const int field = 2 * sizeof(unsigned long); + unsigned long *stack = (long *)regs->regs[29]; + unsigned long pc = regs->cp0_epc; + int top = 1; + + if (raw_show_trace || !__kernel_text_address(pc)) { + show_trace(stack); + return; + } + printk("Call Trace:\n"); + while (__kernel_text_address(pc)) { + printk(" [<%0*lx>] ", field, pc); + print_symbol("%s\n", pc); + pc = unwind_stack(task, &stack, pc); + if (top && pc == 0) + pc = regs->regs[31]; /* leaf? */ + top = 0; + } + printk("\n"); +} +#else +#define show_frametrace(task, r) show_trace((long *)(r)->regs[29]); +#endif + /* * This routine abuses get_user()/put_user() to reference pointers * with at least a bit of error checking ... */ -void show_stack(struct task_struct *task, unsigned long *sp) +static void show_stacktrace(struct task_struct *task, struct pt_regs *regs) { const int field = 2 * sizeof(unsigned long); long stackdata; int i; - unsigned long *stack; - - if (!sp) { - if (task && task != current) - sp = (unsigned long *) task->thread.reg29; - else - sp = (unsigned long *) &sp; - } - stack = sp; + unsigned long *sp = (unsigned long *)regs->regs[29]; printk("Stack :"); i = 0; @@ -136,7 +165,44 @@ void show_stack(struct task_struct *task, unsigned long *sp) i++; } printk("\n"); - show_trace(stack); + show_frametrace(task, regs); +} + +static noinline void prepare_frametrace(struct pt_regs *regs) +{ + __asm__ __volatile__( + "1: la $2, 1b\n\t" +#ifdef CONFIG_64BIT + "sd $2, %0\n\t" + "sd $29, %1\n\t" + "sd $31, %2\n\t" +#else + "sw $2, %0\n\t" + "sw $29, %1\n\t" + "sw $31, %2\n\t" +#endif + : "=m" (regs->cp0_epc), + "=m" (regs->regs[29]), "=m" (regs->regs[31]) + : : "memory"); +} + +void show_stack(struct task_struct *task, unsigned long *sp) +{ + struct pt_regs regs; + if (sp) { + regs.regs[29] = (unsigned long)sp; + regs.regs[31] = 0; + regs.cp0_epc = 0; + } else { + if (task && task != current) { + regs.regs[29] = task->thread.reg29; + regs.regs[31] = 0; + regs.cp0_epc = task->thread.reg31; + } else { + prepare_frametrace(®s); + } + } + show_stacktrace(task, ®s); } /* @@ -146,6 +212,14 @@ void dump_stack(void) { unsigned long stack; +#ifdef CONFIG_KALLSYMS + if (!raw_show_trace) { + struct pt_regs regs; + prepare_frametrace(®s); + show_frametrace(current, ®s); + return; + } +#endif show_trace(&stack); } @@ -265,7 +339,7 @@ void show_registers(struct pt_regs *regs) print_modules(); printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n", current->comm, current->pid, current_thread_info(), current); - show_stack(current, (long *) regs->regs[29]); + show_stacktrace(current, regs); show_code((unsigned int *) regs->cp0_epc); printk("\n"); } -- cgit v1.2.3-70-g09d2 From cf495a333093a1c0eca90c7d8d98313a3b7f01a1 Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Thu, 3 Aug 2006 09:29:16 +0200 Subject: [MIPS] Remove unused MODULE_RANGE macro. Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 7aa9dfc57b8..4a11a3d8447 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -73,11 +73,6 @@ void (*board_nmi_handler_setup)(void); void (*board_ejtag_handler_setup)(void); void (*board_bind_eic_interrupt)(int irq, int regset); -/* - * These constant is for searching for possible module text segments. - * MODULE_RANGE is a guess of how much space is likely to be vmalloced. - */ -#define MODULE_RANGE (8*1024*1024) static void show_trace(unsigned long *stack) { -- cgit v1.2.3-70-g09d2 From 87151ae39bf5556abe83d69af0be9580c32c501b Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Thu, 3 Aug 2006 09:29:17 +0200 Subject: [MIPS] Miscellaneous cleanup in prologue analysis code We usually use backtrace term for dumping a call tree during debug. Therefore this patch renames show_frametrace() into show_backtrace() and show_trace() into show_raw_backtrace(). It also uses the new function print_ip_sym(). Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 4a11a3d8447..549cbb8209a 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -74,21 +74,18 @@ void (*board_ejtag_handler_setup)(void); void (*board_bind_eic_interrupt)(int irq, int regset); -static void show_trace(unsigned long *stack) +static void show_raw_backtrace(unsigned long *sp) { - const int field = 2 * sizeof(unsigned long); unsigned long addr; printk("Call Trace:"); #ifdef CONFIG_KALLSYMS printk("\n"); #endif - while (!kstack_end(stack)) { - addr = *stack++; - if (__kernel_text_address(addr)) { - printk(" [<%0*lx>] ", field, addr); - print_symbol("%s\n", addr); - } + while (!kstack_end(sp)) { + addr = *sp++; + if (__kernel_text_address(addr)) + print_ip_sym(addr); } printk("\n"); } @@ -104,22 +101,20 @@ __setup("raw_show_trace", set_raw_show_trace); extern unsigned long unwind_stack(struct task_struct *task, unsigned long **sp, unsigned long pc); -static void show_frametrace(struct task_struct *task, struct pt_regs *regs) +static void show_backtrace(struct task_struct *task, struct pt_regs *regs) { - const int field = 2 * sizeof(unsigned long); - unsigned long *stack = (long *)regs->regs[29]; + unsigned long *sp = (long *)regs->regs[29]; unsigned long pc = regs->cp0_epc; int top = 1; if (raw_show_trace || !__kernel_text_address(pc)) { - show_trace(stack); + show_raw_backtrace(sp); return; } printk("Call Trace:\n"); while (__kernel_text_address(pc)) { - printk(" [<%0*lx>] ", field, pc); - print_symbol("%s\n", pc); - pc = unwind_stack(task, &stack, pc); + print_ip_sym(pc); + pc = unwind_stack(task, &sp, pc); if (top && pc == 0) pc = regs->regs[31]; /* leaf? */ top = 0; @@ -127,7 +122,7 @@ static void show_frametrace(struct task_struct *task, struct pt_regs *regs) printk("\n"); } #else -#define show_frametrace(task, r) show_trace((long *)(r)->regs[29]); +#define show_backtrace(task, r) show_raw_backtrace((long *)(r)->regs[29]); #endif /* @@ -160,7 +155,7 @@ static void show_stacktrace(struct task_struct *task, struct pt_regs *regs) i++; } printk("\n"); - show_frametrace(task, regs); + show_backtrace(task, regs); } static noinline void prepare_frametrace(struct pt_regs *regs) @@ -211,11 +206,11 @@ void dump_stack(void) if (!raw_show_trace) { struct pt_regs regs; prepare_frametrace(®s); - show_frametrace(current, ®s); + show_backtrace(current, ®s); return; } #endif - show_trace(&stack); + show_raw_backtrace(&stack); } EXPORT_SYMBOL(dump_stack); -- cgit v1.2.3-70-g09d2 From 1666a6fc73f724cdc6bd7d699f9ada4b04953efe Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Thu, 3 Aug 2006 09:29:19 +0200 Subject: [MIPS] Simplify dump_stack() Make dump_stack() code not depend on CONFIG_KALLSYMS. It also make prepare_frametrace() always inlined to get less false entries reported by show_raw_backtrace(). Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 549cbb8209a..303f0084302 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -158,7 +158,7 @@ static void show_stacktrace(struct task_struct *task, struct pt_regs *regs) show_backtrace(task, regs); } -static noinline void prepare_frametrace(struct pt_regs *regs) +static __always_inline void prepare_frametrace(struct pt_regs *regs) { __asm__ __volatile__( "1: la $2, 1b\n\t" @@ -200,17 +200,15 @@ void show_stack(struct task_struct *task, unsigned long *sp) */ void dump_stack(void) { - unsigned long stack; + struct pt_regs regs; -#ifdef CONFIG_KALLSYMS - if (!raw_show_trace) { - struct pt_regs regs; - prepare_frametrace(®s); - show_backtrace(current, ®s); - return; - } -#endif - show_raw_backtrace(&stack); + /* + * Remove any garbage that may be in regs (specially func + * addresses) to avoid show_raw_backtrace() to report them + */ + memset(®s, 0, sizeof(regs)); + prepare_frametrace(®s); + show_backtrace(current, ®s); } EXPORT_SYMBOL(dump_stack); -- cgit v1.2.3-70-g09d2 From 4d157d5eac29d7d5559fdcabf20f3961bc5cb3e7 Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Thu, 3 Aug 2006 09:29:21 +0200 Subject: [MIPS] Improve unwind_stack() This patch allows unwind_stack() to return ra for leaf function. But it tries to detects cases where get_frame_info() wrongly consider nested function as a leaf one. It also pass 'unsinged long *sp' instead of 'unsigned long **sp' as second parameter. The code looks cleaner. Signed-off-by: Franck Bui-Huu Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 35 ++++++++++++++++++++++------------- arch/mips/kernel/traps.c | 24 ++++++++++++------------ 2 files changed, 34 insertions(+), 25 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 309bfa4a152..951bf9ca3ce 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -448,15 +448,16 @@ unsigned long get_wchan(struct task_struct *p) } #ifdef CONFIG_KALLSYMS -/* used by show_frametrace() */ -unsigned long unwind_stack(struct task_struct *task, - unsigned long **sp, unsigned long pc) +/* used by show_backtrace() */ +unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, + unsigned long pc, unsigned long ra) { unsigned long stack_page; struct mips_frame_info info; char *modname; char namebuf[KSYM_NAME_LEN + 1]; unsigned long size, ofs; + int leaf; stack_page = (unsigned long)task_stack_page(task); if (!stack_page) @@ -469,18 +470,26 @@ unsigned long unwind_stack(struct task_struct *task, info.func = (void *)(pc - ofs); info.func_size = ofs; /* analyze from start to ofs */ - if (get_frame_info(&info)) { - /* leaf or unknown */ - *sp += info.frame_size / sizeof(long); + leaf = get_frame_info(&info); + if (leaf < 0) return 0; - } - if ((unsigned long)*sp < stack_page || - (unsigned long)*sp + info.frame_size / sizeof(long) > - stack_page + THREAD_SIZE - 32) + + if (*sp < stack_page || + *sp + info.frame_size > stack_page + THREAD_SIZE - 32) return 0; - pc = (*sp)[info.pc_offset]; - *sp += info.frame_size / sizeof(long); - return pc; + if (leaf) + /* + * For some extreme cases, get_frame_info() can + * consider wrongly a nested function as a leaf + * one. In that cases avoid to return always the + * same value. + */ + pc = pc != ra ? ra : 0; + else + pc = ((unsigned long *)(*sp))[info.pc_offset]; + + *sp += info.frame_size; + return __kernel_text_address(pc) ? pc : 0; } #endif diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 303f0084302..ab77034921c 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -74,8 +74,9 @@ void (*board_ejtag_handler_setup)(void); void (*board_bind_eic_interrupt)(int irq, int regset); -static void show_raw_backtrace(unsigned long *sp) +static void show_raw_backtrace(unsigned long reg29) { + unsigned long *sp = (unsigned long *)reg29; unsigned long addr; printk("Call Trace:"); @@ -99,30 +100,29 @@ static int __init set_raw_show_trace(char *str) } __setup("raw_show_trace", set_raw_show_trace); -extern unsigned long unwind_stack(struct task_struct *task, - unsigned long **sp, unsigned long pc); +extern unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, + unsigned long pc, unsigned long ra); + static void show_backtrace(struct task_struct *task, struct pt_regs *regs) { - unsigned long *sp = (long *)regs->regs[29]; + unsigned long sp = regs->regs[29]; + unsigned long ra = regs->regs[31]; unsigned long pc = regs->cp0_epc; - int top = 1; if (raw_show_trace || !__kernel_text_address(pc)) { show_raw_backtrace(sp); return; } printk("Call Trace:\n"); - while (__kernel_text_address(pc)) { + do { print_ip_sym(pc); - pc = unwind_stack(task, &sp, pc); - if (top && pc == 0) - pc = regs->regs[31]; /* leaf? */ - top = 0; - } + pc = unwind_stack(task, &sp, pc, ra); + ra = 0; + } while (pc); printk("\n"); } #else -#define show_backtrace(task, r) show_raw_backtrace((long *)(r)->regs[29]); +#define show_backtrace(task, r) show_raw_backtrace((r)->regs[29]); #endif /* -- cgit v1.2.3-70-g09d2 From 898d229107f7aa8ea45685c11e2930783755f9ba Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Tue, 29 Aug 2006 12:10:22 +0900 Subject: [MIPS] Make prepare_frametrace() not clobber v0 Since lmo commit 323a380bf9e1a1679a774a2b053e3c1f2aa3f179 ("Simplify dump_stack()") made prepare_frametrace() always inlined, using $2 (v0) in __asm__ is not safe anymore. We can use $1 (at) instead. Also we should use "dla" instead of "la" for 64-bit kernel. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'arch/mips/kernel/traps.c') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index ab77034921c..e51d8fd9a15 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -161,16 +161,20 @@ static void show_stacktrace(struct task_struct *task, struct pt_regs *regs) static __always_inline void prepare_frametrace(struct pt_regs *regs) { __asm__ __volatile__( - "1: la $2, 1b\n\t" + ".set push\n\t" + ".set noat\n\t" #ifdef CONFIG_64BIT - "sd $2, %0\n\t" + "1: dla $1, 1b\n\t" + "sd $1, %0\n\t" "sd $29, %1\n\t" "sd $31, %2\n\t" #else - "sw $2, %0\n\t" + "1: la $1, 1b\n\t" + "sw $1, %0\n\t" "sw $29, %1\n\t" "sw $31, %2\n\t" #endif + ".set pop\n\t" : "=m" (regs->cp0_epc), "=m" (regs->regs[29]), "=m" (regs->regs[31]) : : "memory"); -- cgit v1.2.3-70-g09d2