1
0
Fork 0

dump_stack: consolidate dump_stack() implementations and unify their behaviors

Both dump_stack() and show_stack() are currently implemented by each
architecture.  show_stack(NULL, NULL) dumps the backtrace for the
current task as does dump_stack().  On some archs, dump_stack() prints
extra information - pid, utsname and so on - in addition to the
backtrace while the two are identical on other archs.

The usages in arch-independent code of the two functions indicate
show_stack(NULL, NULL) should print out bare backtrace while
dump_stack() is used for debugging purposes when something went wrong,
so it does make sense to print additional information on the task which
triggered dump_stack().

There's no reason to require archs to implement two separate but mostly
identical functions.  It leads to unnecessary subtle information.

This patch expands the dummy fallback dump_stack() implementation in
lib/dump_stack.c such that it prints out debug information (taken from
x86) and invokes show_stack(NULL, NULL) and drops arch-specific
dump_stack() implementations in all archs except blackfin.  Blackfin's
dump_stack() does something wonky that I don't understand.

Debug information can be printed separately by calling
dump_stack_print_info() so that arch-specific dump_stack()
implementation can still emit the same debug information.  This is used
in blackfin.

This patch brings the following behavior changes.

* On some archs, an extra level in backtrace for show_stack() could be
  printed.  This is because the top frame was determined in
  dump_stack() on those archs while generic dump_stack() can't do that
  reliably.  It can be compensated by inlining dump_stack() but not
  sure whether that'd be necessary.

* Most archs didn't use to print debug info on dump_stack().  They do
  now.

An example WARN dump follows.

 WARNING: at kernel/workqueue.c:4841 init_workqueues+0x35/0x505()
 Hardware name: empty
 Modules linked in:
 CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.9.0-rc1-work+ #9
  0000000000000009 ffff88007c861e08 ffffffff81c614dc ffff88007c861e48
  ffffffff8108f50f ffffffff82228240 0000000000000040 ffffffff8234a03c
  0000000000000000 0000000000000000 0000000000000000 ffff88007c861e58
 Call Trace:
  [<ffffffff81c614dc>] dump_stack+0x19/0x1b
  [<ffffffff8108f50f>] warn_slowpath_common+0x7f/0xc0
  [<ffffffff8108f56a>] warn_slowpath_null+0x1a/0x20
  [<ffffffff8234a071>] init_workqueues+0x35/0x505
  ...

v2: CPU number added to the generic debug info as requested by s390
    folks and dropped the s390 specific dump_stack().  This loses %ksp
    from the debug message which the maintainers think isn't important
    enough to keep the s390-specific dump_stack() implementation.

    dump_stack_print_info() is moved to kernel/printk.c from
    lib/dump_stack.c.  Because linkage is per objecct file,
    dump_stack_print_info() living in the same lib file as generic
    dump_stack() means that archs which implement custom dump_stack()
    - at this point, only blackfin - can't use dump_stack_print_info()
    as that will bring in the generic version of dump_stack() too.  v1
    The v1 patch broke build on blackfin due to this issue.  The build
    breakage was reported by Fengguang Wu.

Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: David S. Miller <davem@davemloft.net>
Acked-by: Vineet Gupta <vgupta@synopsys.com>
Acked-by: Jesper Nilsson <jesper.nilsson@axis.com>
Acked-by: Vineet Gupta <vgupta@synopsys.com>
Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com>	[s390 bits]
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: Fengguang Wu <fengguang.wu@intel.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Sam Ravnborg <sam@ravnborg.org>
Acked-by: Richard Kuo <rkuo@codeaurora.org>		[hexagon bits]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
hifive-unleashed-5.1
Tejun Heo 2013-04-30 15:27:12 -07:00 committed by Linus Torvalds
parent 89e3f23da9
commit 196779b9b4
33 changed files with 32 additions and 262 deletions

View File

@ -169,13 +169,6 @@ void show_stack(struct task_struct *task, unsigned long *sp)
dik_show_trace(sp); dik_show_trace(sp);
} }
void dump_stack(void)
{
show_stack(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);
void void
die_if_kernel(char * str, struct pt_regs *regs, long err, unsigned long *r9_15) die_if_kernel(char * str, struct pt_regs *regs, long err, unsigned long *r9_15)
{ {

View File

@ -220,13 +220,6 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
show_stacktrace(tsk, NULL); show_stacktrace(tsk, NULL);
} }
/* Expected by Rest of kernel code */
void dump_stack(void)
{
show_stacktrace(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);
/* Another API expected by schedular, shows up in "ps" as Wait Channel /* Another API expected by schedular, shows up in "ps" as Wait Channel
* Ofcourse just returning schedule( ) would be pointless so unwind until * Ofcourse just returning schedule( ) would be pointless so unwind until
* the function is not in schedular code * the function is not in schedular code

View File

@ -204,13 +204,6 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
} }
#endif #endif
void dump_stack(void)
{
dump_backtrace(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);
void show_stack(struct task_struct *tsk, unsigned long *sp) void show_stack(struct task_struct *tsk, unsigned long *sp)
{ {
dump_backtrace(NULL, tsk); dump_backtrace(NULL, tsk);

View File

@ -167,13 +167,6 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
} }
} }
void dump_stack(void)
{
dump_backtrace(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);
void show_stack(struct task_struct *tsk, unsigned long *sp) void show_stack(struct task_struct *tsk, unsigned long *sp)
{ {
dump_backtrace(NULL, tsk); dump_backtrace(NULL, tsk);

View File

@ -204,14 +204,6 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)
show_stack_log_lvl(tsk, (unsigned long)stack, NULL, ""); show_stack_log_lvl(tsk, (unsigned long)stack, NULL, "");
} }
void dump_stack(void)
{
unsigned long stack;
show_trace_log_lvl(current, &stack, NULL, "");
}
EXPORT_SYMBOL(dump_stack);
static const char *cpu_modes[] = { static const char *cpu_modes[] = {
"Application", "Supervisor", "Interrupt level 0", "Interrupt level 1", "Application", "Supervisor", "Interrupt level 0", "Interrupt level 1",
"Interrupt level 2", "Interrupt level 3", "Exception", "NMI" "Interrupt level 2", "Interrupt level 3", "Exception", "NMI"

View File

@ -168,6 +168,7 @@ void dump_stack(void)
#endif #endif
trace_buffer_save(tflags); trace_buffer_save(tflags);
dump_bfin_trace_buffer(); dump_bfin_trace_buffer();
dump_stack_print_info(KERN_DEFAULT);
show_stack(current, &stack); show_stack(current, &stack);
trace_buffer_restore(tflags); trace_buffer_restore(tflags);
} }

View File

@ -67,15 +67,6 @@ void show_regs(struct pt_regs *regs)
pr_err("A31: %08lx B31: %08lx\n", regs->a31, regs->b31); pr_err("A31: %08lx B31: %08lx\n", regs->a31, regs->b31);
} }
void dump_stack(void)
{
unsigned long stack;
show_stack(current, &stack);
}
EXPORT_SYMBOL(dump_stack);
void die(char *str, struct pt_regs *fp, int nr) void die(char *str, struct pt_regs *fp, int nr)
{ {
console_verbose(); console_verbose();

View File

@ -146,13 +146,6 @@ show_stack(void)
} }
#endif #endif
void
dump_stack(void)
{
show_stack(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);
void void
set_nmi_handler(void (*handler)(struct pt_regs *)) set_nmi_handler(void (*handler)(struct pt_regs *))
{ {

View File

@ -466,17 +466,6 @@ asmlinkage void compound_exception(unsigned long esfr1,
BUG(); BUG();
} /* end compound_exception() */ } /* end compound_exception() */
/*****************************************************************************/
/*
* The architecture-independent backtrace generator
*/
void dump_stack(void)
{
show_stack(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);
void show_stack(struct task_struct *task, unsigned long *sp) void show_stack(struct task_struct *task, unsigned long *sp)
{ {
} }

View File

@ -164,10 +164,3 @@ void show_trace_task(struct task_struct *tsk)
{ {
show_stack(tsk,(unsigned long *)tsk->thread.esp0); show_stack(tsk,(unsigned long *)tsk->thread.esp0);
} }
void dump_stack(void)
{
show_stack(NULL,NULL);
}
EXPORT_SYMBOL(dump_stack);

View File

@ -191,14 +191,6 @@ void show_stack(struct task_struct *task, unsigned long *fp)
do_show_stack(task, fp, 0); do_show_stack(task, fp, 0);
} }
void dump_stack(void)
{
unsigned long *fp;
asm("%0 = r30" : "=r" (fp));
show_stack(current, fp);
}
EXPORT_SYMBOL(dump_stack);
int die(const char *str, struct pt_regs *regs, long err) int die(const char *str, struct pt_regs *regs, long err)
{ {
static struct { static struct {

View File

@ -95,14 +95,6 @@ show_stack (struct task_struct *task, unsigned long *sp)
} }
} }
void
dump_stack (void)
{
show_stack(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);
void void
show_regs (struct pt_regs *regs) show_regs (struct pt_regs *regs)
{ {

View File

@ -167,15 +167,6 @@ void show_stack(struct task_struct *task, unsigned long *sp)
show_trace(task, sp); show_trace(task, sp);
} }
void dump_stack(void)
{
unsigned long stack;
show_trace(current, &stack);
}
EXPORT_SYMBOL(dump_stack);
static void show_registers(struct pt_regs *regs) static void show_registers(struct pt_regs *regs)
{ {
int i = 0; int i = 0;

View File

@ -991,18 +991,6 @@ void show_stack(struct task_struct *task, unsigned long *stack)
show_trace(stack); show_trace(stack);
} }
/*
* The architecture-independent backtrace generator
*/
void dump_stack(void)
{
unsigned long stack;
show_trace(&stack);
}
EXPORT_SYMBOL(dump_stack);
/* /*
* The vector number returned in the frame pointer may also contain * The vector number returned in the frame pointer may also contain
* the "fs" (Fault Status) bits on ColdFire. These are in the bottom * the "fs" (Fault Status) bits on ColdFire. These are in the bottom

View File

@ -987,9 +987,3 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
show_trace(tsk, sp, NULL); show_trace(tsk, sp, NULL);
} }
void dump_stack(void)
{
show_stack(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);

View File

@ -75,9 +75,3 @@ void show_stack(struct task_struct *task, unsigned long *sp)
debug_show_held_locks(task); debug_show_held_locks(task);
} }
void dump_stack(void)
{
show_stack(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);

View File

@ -206,19 +206,6 @@ void show_stack(struct task_struct *task, unsigned long *sp)
show_stacktrace(task, &regs); show_stacktrace(task, &regs);
} }
/*
* The architecture-independent dump_stack generator
*/
void dump_stack(void)
{
struct pt_regs regs;
prepare_frametrace(&regs);
show_backtrace(current, &regs);
}
EXPORT_SYMBOL(dump_stack);
static void show_code(unsigned int __user *pc) static void show_code(unsigned int __user *pc)
{ {
long i; long i;

View File

@ -293,17 +293,6 @@ void show_stack(struct task_struct *task, unsigned long *sp)
show_trace(sp); show_trace(sp);
} }
/*
* the architecture-independent dump_stack generator
*/
void dump_stack(void)
{
unsigned long stack;
show_stack(current, &stack);
}
EXPORT_SYMBOL(dump_stack);
/* /*
* dump the register file in the specified exception frame * dump the register file in the specified exception frame
*/ */

View File

@ -105,17 +105,6 @@ void show_trace_task(struct task_struct *tsk)
*/ */
} }
/*
* The architecture-independent backtrace generator
*/
void dump_stack(void)
{
unsigned long stack;
show_stack(current, &stack);
}
EXPORT_SYMBOL(dump_stack);
void show_registers(struct pt_regs *regs) void show_registers(struct pt_regs *regs)
{ {
int i; int i;

View File

@ -158,14 +158,6 @@ void show_regs(struct pt_regs *regs)
} }
} }
void dump_stack(void)
{
show_stack(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);
static void do_show_stack(struct unwind_frame_info *info) static void do_show_stack(struct unwind_frame_info *info)
{ {
int i = 1; int i = 1;

View File

@ -1362,12 +1362,6 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)
} while (count++ < kstack_depth_to_print); } while (count++ < kstack_depth_to_print);
} }
void dump_stack(void)
{
show_stack(current, NULL);
}
EXPORT_SYMBOL(dump_stack);
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
/* Called with hard IRQs off */ /* Called with hard IRQs off */
void __ppc64_runlatch_on(void) void __ppc64_runlatch_on(void)

View File

@ -129,23 +129,6 @@ static void show_last_breaking_event(struct pt_regs *regs)
#endif #endif
} }
/*
* The architecture-independent dump_stack generator
*/
void dump_stack(void)
{
printk("CPU: %d %s %s %.*s\n",
task_thread_info(current)->cpu, print_tainted(),
init_utsname()->release,
(int)strcspn(init_utsname()->version, " "),
init_utsname()->version);
printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
current->comm, current->pid, current,
(void *) current->thread.ksp);
show_stack(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);
static inline int mask_bits(struct pt_regs *regs, unsigned long bits) static inline int mask_bits(struct pt_regs *regs, unsigned long bits)
{ {
return (regs->psw.mask & bits) / ((~bits + 1) & bits); return (regs->psw.mask & bits) / ((~bits + 1) & bits);

View File

@ -149,16 +149,6 @@ static void show_registers(struct pt_regs *regs)
printk(KERN_NOTICE "\n"); printk(KERN_NOTICE "\n");
} }
/*
* The architecture-independent dump_stack generator
*/
void dump_stack(void)
{
show_stack(current_thread_info()->task,
(long *) get_irq_regs()->regs[0]);
}
EXPORT_SYMBOL(dump_stack);
void __die(const char *str, struct pt_regs *regs, const char *file, void __die(const char *str, struct pt_regs *regs, const char *file,
const char *func, unsigned long line) const char *func, unsigned long line)
{ {

View File

@ -158,9 +158,3 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
(unsigned long)task_stack_page(tsk)); (unsigned long)task_stack_page(tsk));
show_trace(tsk, sp, NULL); show_trace(tsk, sp, NULL);
} }
void dump_stack(void)
{
show_stack(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);

View File

@ -164,13 +164,6 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp)
printk("\n"); printk("\n");
} }
void dump_stack(void)
{
show_stack(current, NULL);
}
EXPORT_SYMBOL(dump_stack);
/* /*
* Note: sparc64 has a pretty intricated thread_saved_pc, check it out. * Note: sparc64 has a pretty intricated thread_saved_pc, check it out.
*/ */

View File

@ -2350,13 +2350,6 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp)
} while (++count < 16); } while (++count < 16);
} }
void dump_stack(void)
{
show_stack(current, NULL);
}
EXPORT_SYMBOL(dump_stack);
static inline struct reg_window *kernel_stack_up(struct reg_window *rw) static inline struct reg_window *kernel_stack_up(struct reg_window *rw)
{ {
unsigned long fp = rw->ins[6]; unsigned long fp = rw->ins[6];

View File

@ -35,18 +35,6 @@ void show_trace(struct task_struct *task, unsigned long * stack)
} }
#endif #endif
/*
* stack dumps generator - this is used by arch-independent code.
* And this is identical to i386 currently.
*/
void dump_stack(void)
{
unsigned long stack;
show_trace(current, &stack);
}
EXPORT_SYMBOL(dump_stack);
/*Stolen from arch/i386/kernel/traps.c */ /*Stolen from arch/i386/kernel/traps.c */
static const int kstack_depth_to_print = 24; static const int kstack_depth_to_print = 24;

View File

@ -170,12 +170,6 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
c_backtrace(fp, mode); c_backtrace(fp, mode);
} }
void dump_stack(void)
{
dump_backtrace(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);
void show_stack(struct task_struct *tsk, unsigned long *sp) void show_stack(struct task_struct *tsk, unsigned long *sp)
{ {
dump_backtrace(NULL, tsk); dump_backtrace(NULL, tsk);

View File

@ -191,24 +191,6 @@ void show_stack(struct task_struct *task, unsigned long *sp)
show_stack_log_lvl(task, NULL, sp, bp, ""); show_stack_log_lvl(task, NULL, sp, bp, "");
} }
/*
* The architecture-independent dump_stack generator
*/
void dump_stack(void)
{
unsigned long bp;
unsigned long stack;
bp = stack_frame(current, NULL);
printk("Pid: %d, comm: %.20s %s %s %.*s\n",
current->pid, current->comm, print_tainted(),
init_utsname()->release,
(int)strcspn(init_utsname()->version, " "),
init_utsname()->version);
show_trace(NULL, NULL, &stack, bp);
}
EXPORT_SYMBOL(dump_stack);
static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED; static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED;
static int die_owner = -1; static int die_owner = -1;
static unsigned int die_nest_count; static unsigned int die_nest_count;

View File

@ -481,14 +481,6 @@ void show_stack(struct task_struct *task, unsigned long *sp)
show_trace(task, stack); show_trace(task, stack);
} }
void dump_stack(void)
{
show_stack(current, NULL);
}
EXPORT_SYMBOL(dump_stack);
void show_code(unsigned int *pc) void show_code(unsigned int *pc)
{ {
long i; long i;

View File

@ -145,6 +145,7 @@ extern void wake_up_klogd(void);
void log_buf_kexec_setup(void); void log_buf_kexec_setup(void);
void __init setup_log_buf(int early); void __init setup_log_buf(int early);
void dump_stack_print_info(const char *log_lvl);
#else #else
static inline __printf(1, 0) static inline __printf(1, 0)
int vprintk(const char *s, va_list args) int vprintk(const char *s, va_list args)
@ -182,6 +183,10 @@ static inline void log_buf_kexec_setup(void)
static inline void setup_log_buf(int early) static inline void setup_log_buf(int early)
{ {
} }
static inline void dump_stack_print_info(const char *log_lvl)
{
}
#endif #endif
extern void dump_stack(void) __cold; extern void dump_stack(void) __cold;

View File

@ -43,6 +43,7 @@
#include <linux/rculist.h> #include <linux/rculist.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/irq_work.h> #include <linux/irq_work.h>
#include <linux/utsname.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
@ -2849,4 +2850,21 @@ void kmsg_dump_rewind(struct kmsg_dumper *dumper)
raw_spin_unlock_irqrestore(&logbuf_lock, flags); raw_spin_unlock_irqrestore(&logbuf_lock, flags);
} }
EXPORT_SYMBOL_GPL(kmsg_dump_rewind); EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
/**
* dump_stack_print_info - print generic debug info for dump_stack()
* @log_lvl: log level
*
* Arch-specific dump_stack() implementations can use this function to
* print out the same debug information as the generic dump_stack().
*/
void dump_stack_print_info(const char *log_lvl)
{
printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s\n",
log_lvl, raw_smp_processor_id(), current->pid, current->comm,
print_tainted(), init_utsname()->release,
(int)strcspn(init_utsname()->version, " "),
init_utsname()->version);
}
#endif #endif

View File

@ -5,11 +5,16 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/sched.h>
/**
* dump_stack - dump the current task information and its stack trace
*
* Architectures can override this implementation by implementing its own.
*/
void dump_stack(void) void dump_stack(void)
{ {
printk(KERN_NOTICE dump_stack_print_info(KERN_DEFAULT);
"This architecture does not implement dump_stack()\n"); show_stack(NULL, NULL);
} }
EXPORT_SYMBOL(dump_stack); EXPORT_SYMBOL(dump_stack);