| /* |
| * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> |
| * Copyright (C) 2007-2009 PetaLogix |
| * Copyright (C) 2006 Atmark Techno, Inc. |
| * |
| * This file is subject to the terms and conditions of the GNU General Public |
| * License. See the file "COPYING" in the main directory of this archive |
| * for more details. |
| */ |
| |
| #include <linux/kernel.h> |
| #include <linux/kallsyms.h> |
| #include <linux/module.h> |
| #include <linux/sched.h> |
| #include <linux/debug_locks.h> |
| |
| #include <asm/exceptions.h> |
| #include <asm/system.h> |
| |
| void trap_init(void) |
| { |
| __enable_hw_exceptions(); |
| } |
| |
| void __bad_xchg(volatile void *ptr, int size) |
| { |
| printk(KERN_INFO "xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n", |
| __builtin_return_address(0), ptr, size); |
| BUG(); |
| } |
| EXPORT_SYMBOL(__bad_xchg); |
| |
| static int kstack_depth_to_print = 24; |
| |
| static int __init kstack_setup(char *s) |
| { |
| kstack_depth_to_print = strict_strtoul(s, 0, NULL); |
| |
| return 1; |
| } |
| __setup("kstack=", kstack_setup); |
| |
| void show_trace(struct task_struct *task, unsigned long *stack) |
| { |
| unsigned long addr; |
| |
| if (!stack) |
| stack = (unsigned long *)&stack; |
| |
| printk(KERN_NOTICE "Call Trace: "); |
| #ifdef CONFIG_KALLSYMS |
| printk(KERN_NOTICE "\n"); |
| #endif |
| while (!kstack_end(stack)) { |
| addr = *stack++; |
| /* |
| * If the address is either in the text segment of the |
| * kernel, or in the region which contains vmalloc'ed |
| * memory, it *may* be the address of a calling |
| * routine; if so, print it so that someone tracing |
| * down the cause of the crash will be able to figure |
| * out the call path that was taken. |
| */ |
| if (kernel_text_address(addr)) |
| print_ip_sym(addr); |
| } |
| printk(KERN_NOTICE "\n"); |
| |
| if (!task) |
| task = current; |
| |
| debug_show_held_locks(task); |
| } |
| |
| void show_stack(struct task_struct *task, unsigned long *sp) |
| { |
| unsigned long *stack; |
| int i; |
| |
| if (sp == NULL) { |
| if (task) |
| sp = (unsigned long *) ((struct thread_info *) |
| (task->stack))->cpu_context.r1; |
| else |
| sp = (unsigned long *)&sp; |
| } |
| |
| stack = sp; |
| |
| printk(KERN_INFO "\nStack:\n "); |
| |
| for (i = 0; i < kstack_depth_to_print; i++) { |
| if (kstack_end(sp)) |
| break; |
| if (i && ((i % 8) == 0)) |
| printk("\n "); |
| printk("%08lx ", *sp++); |
| } |
| printk("\n"); |
| show_trace(task, stack); |
| } |
| |
| void dump_stack(void) |
| { |
| show_stack(NULL, NULL); |
| } |
| EXPORT_SYMBOL(dump_stack); |