Skip to content

Commit

Permalink
[PATCH] i386/x86-64: fall back to old-style call trace if no unwinding
Browse files Browse the repository at this point in the history
If no unwinding is possible at all for a certain exception instance,
fall back to the old style call trace instead of not showing any trace
at all.

Also, allow setting the stack trace mode at the command line.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Jan Beulich authored and Linus Torvalds committed Jun 26, 2006
1 parent fe7cacc commit c33bd9a
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 45 deletions.
46 changes: 33 additions & 13 deletions arch/i386/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ asmlinkage void spurious_interrupt_bug(void);
asmlinkage void machine_check(void);

static int kstack_depth_to_print = 24;
static int call_trace = 1;
ATOMIC_NOTIFIER_HEAD(i386die_chain);

int register_die_notifier(struct notifier_block *nb)
Expand Down Expand Up @@ -171,40 +172,47 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo,
return ebp;
}

static asmlinkage void show_trace_unwind(struct unwind_frame_info *info, void *log_lvl)
static asmlinkage int show_trace_unwind(struct unwind_frame_info *info, void *log_lvl)
{
int n = 0;
int printed = 0; /* nr of entries already printed on current line */

while (unwind(info) == 0 && UNW_PC(info)) {
++n;
printed = print_addr_and_symbol(UNW_PC(info), log_lvl, printed);
if (arch_unw_user_mode(info))
break;
}
if (printed)
printk("\n");
return n;
}

static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
unsigned long *stack, char *log_lvl)
{
unsigned long ebp;
struct unwind_frame_info info;

if (!task)
task = current;

if (regs) {
if (unwind_init_frame_info(&info, task, regs) == 0) {
show_trace_unwind(&info, log_lvl);
return;
if (call_trace >= 0) {
int unw_ret = 0;
struct unwind_frame_info info;

if (regs) {
if (unwind_init_frame_info(&info, task, regs) == 0)
unw_ret = show_trace_unwind(&info, log_lvl);
} else if (task == current)
unw_ret = unwind_init_running(&info, show_trace_unwind, log_lvl);
else {
if (unwind_init_blocked(&info, task) == 0)
unw_ret = show_trace_unwind(&info, log_lvl);
}
} else if (task == current) {
if (unwind_init_running(&info, show_trace_unwind, log_lvl) == 0)
return;
} else {
if (unwind_init_blocked(&info, task) == 0) {
show_trace_unwind(&info, log_lvl);
return;
if (unw_ret > 0) {
if (call_trace > 0)
return;
printk("%sLegacy call trace:\n", log_lvl);
}
}

Expand Down Expand Up @@ -1245,3 +1253,15 @@ static int __init kstack_setup(char *s)
return 1;
}
__setup("kstack=", kstack_setup);

static int __init call_trace_setup(char *s)
{
if (strcmp(s, "old") == 0)
call_trace = -1;
else if (strcmp(s, "both") == 0)
call_trace = 0;
else if (strcmp(s, "new") == 0)
call_trace = 1;
return 1;
}
__setup("call_trace=", call_trace_setup);
51 changes: 35 additions & 16 deletions arch/x86_64/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ static inline void preempt_conditional_cli(struct pt_regs *regs)
}

static int kstack_depth_to_print = 10;
static int call_trace = 1;

#ifdef CONFIG_KALLSYMS
#include <linux/kallsyms.h>
Expand Down Expand Up @@ -190,11 +191,12 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
return NULL;
}

static void show_trace_unwind(struct unwind_frame_info *info, void *context)
static int show_trace_unwind(struct unwind_frame_info *info, void *context)
{
int i = 11;
int i = 11, n = 0;

while (unwind(info) == 0 && UNW_PC(info)) {
++n;
if (i > 50) {
printk("\n ");
i = 7;
Expand All @@ -205,6 +207,7 @@ static void show_trace_unwind(struct unwind_frame_info *info, void *context)
break;
}
printk("\n");
return n;
}

/*
Expand All @@ -218,27 +221,32 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s
{
const unsigned cpu = safe_smp_processor_id();
unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr;
int i;
int i = 11;
unsigned used = 0;
struct unwind_frame_info info;

printk("\nCall Trace:");

if (!tsk)
tsk = current;

if (regs) {
if (unwind_init_frame_info(&info, tsk, regs) == 0) {
show_trace_unwind(&info, NULL);
return;
if (call_trace >= 0) {
int unw_ret = 0;
struct unwind_frame_info info;

if (regs) {
if (unwind_init_frame_info(&info, tsk, regs) == 0)
unw_ret = show_trace_unwind(&info, NULL);
} else if (tsk == current)
unw_ret = unwind_init_running(&info, show_trace_unwind, NULL);
else {
if (unwind_init_blocked(&info, tsk) == 0)
unw_ret = show_trace_unwind(&info, NULL);
}
} else if (tsk == current) {
if (unwind_init_running(&info, show_trace_unwind, NULL) == 0)
return;
} else {
if (unwind_init_blocked(&info, tsk) == 0) {
show_trace_unwind(&info, NULL);
return;
if (unw_ret > 0) {
if (call_trace > 0)
return;
printk("Legacy call trace:");
i = 18;
}
}

Expand All @@ -264,7 +272,7 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s
} \
} while (0)

for(i = 11; ; ) {
for(; ; ) {
const char *id;
unsigned long *estack_end;
estack_end = in_exception_stack(cpu, (unsigned long)stack,
Expand Down Expand Up @@ -1052,3 +1060,14 @@ static int __init kstack_setup(char *s)
}
__setup("kstack=", kstack_setup);

static int __init call_trace_setup(char *s)
{
if (strcmp(s, "old") == 0)
call_trace = -1;
else if (strcmp(s, "both") == 0)
call_trace = 0;
else if (strcmp(s, "new") == 0)
call_trace = 1;
return 1;
}
__setup("call_trace=", call_trace_setup);
8 changes: 4 additions & 4 deletions include/asm-i386/unwind.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ static inline void arch_unw_init_blocked(struct unwind_frame_info *info)
info->regs.xes = __USER_DS;
}

extern asmlinkage void arch_unwind_init_running(struct unwind_frame_info *,
asmlinkage void (*callback)(struct unwind_frame_info *,
void *arg),
void *arg);
extern asmlinkage int arch_unwind_init_running(struct unwind_frame_info *,
asmlinkage int (*callback)(struct unwind_frame_info *,
void *arg),
void *arg);

static inline int arch_unw_user_mode(const struct unwind_frame_info *info)
{
Expand Down
8 changes: 4 additions & 4 deletions include/asm-x86_64/unwind.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ static inline void arch_unw_init_blocked(struct unwind_frame_info *info)
info->regs.ss = __KERNEL_DS;
}

extern void arch_unwind_init_running(struct unwind_frame_info *,
void (*callback)(struct unwind_frame_info *,
void *arg),
void *arg);
extern int arch_unwind_init_running(struct unwind_frame_info *,
int (*callback)(struct unwind_frame_info *,
void *arg),
void *arg);

static inline int arch_unw_user_mode(const struct unwind_frame_info *info)
{
Expand Down
8 changes: 4 additions & 4 deletions include/linux/unwind.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ extern int unwind_init_blocked(struct unwind_frame_info *,
* Prepare to unwind the currently running thread.
*/
extern int unwind_init_running(struct unwind_frame_info *,
asmlinkage void (*callback)(struct unwind_frame_info *,
void *arg),
asmlinkage int (*callback)(struct unwind_frame_info *,
void *arg),
void *arg);

/*
Expand Down Expand Up @@ -97,8 +97,8 @@ static inline int unwind_init_blocked(struct unwind_frame_info *info,
}

static inline int unwind_init_running(struct unwind_frame_info *info,
asmlinkage void (*cb)(struct unwind_frame_info *,
void *arg),
asmlinkage int (*cb)(struct unwind_frame_info *,
void *arg),
void *arg)
{
return -ENOSYS;
Expand Down
7 changes: 3 additions & 4 deletions kernel/unwind.c
Original file line number Diff line number Diff line change
Expand Up @@ -885,14 +885,13 @@ EXPORT_SYMBOL(unwind_init_blocked);
* Prepare to unwind the currently running thread.
*/
int unwind_init_running(struct unwind_frame_info *info,
asmlinkage void (*callback)(struct unwind_frame_info *,
void *arg),
asmlinkage int (*callback)(struct unwind_frame_info *,
void *arg),
void *arg)
{
info->task = current;
arch_unwind_init_running(info, callback, arg);

return 0;
return arch_unwind_init_running(info, callback, arg);
}
EXPORT_SYMBOL(unwind_init_running);

Expand Down

0 comments on commit c33bd9a

Please sign in to comment.