Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | /* * linux/arch/cris/traps.c * * Here we handle the break vectors not used by the system call * mechanism, as well as some general stack/register dumping * things. * * Copyright (C) 2000-2007 Axis Communications AB * * Authors: Bjorn Wesen * Hans-Peter Nilsson * */ #include <linux/init.h> #include <linux/module.h> #include <asm/pgtable.h> #include <asm/uaccess.h> extern void arch_enable_nmi(void); extern void stop_watchdog(void); extern void reset_watchdog(void); extern void show_registers(struct pt_regs *regs); #ifdef CONFIG_DEBUG_BUGVERBOSE extern void handle_BUG(struct pt_regs *regs); #else #define handle_BUG(regs) #endif static int kstack_depth_to_print = 24; void (*nmi_handler)(struct pt_regs *); void show_trace(unsigned long *stack) { unsigned long addr, module_start, module_end; extern char _stext, _etext; int i; printk("\nCall Trace: "); i = 1; module_start = VMALLOC_START; module_end = VMALLOC_END; while (((long)stack & (THREAD_SIZE-1)) != 0) { if (__get_user(addr, stack)) { /* This message matches "failing address" marked s390 in ksymoops, so lines containing it will not be filtered out by ksymoops. */ printk("Failing address 0x%lx\n", (unsigned long)stack); break; } 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 (((addr >= (unsigned long)&_stext) && (addr <= (unsigned long)&_etext)) || ((addr >= module_start) && (addr <= module_end))) { if (i && ((i % 8) == 0)) printk("\n "); printk("[<%08lx>] ", addr); i++; } } } /* * These constants are 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) /* * The output (format, strings and order) is adjusted to be usable with * ksymoops-2.4.1 with some necessary CRIS-specific patches. Please don't * change it unless you're serious about adjusting ksymoops and syncing * with the ksymoops maintainer. */ void show_stack(struct task_struct *task, unsigned long *sp) { unsigned long *stack, addr; int i; /* * debugging aid: "show_stack(NULL);" prints a * back trace. */ if (sp == NULL) { if (task) sp = (unsigned long*)task->thread.ksp; else sp = (unsigned long*)rdsp(); } stack = sp; printk("\nStack from %08lx:\n ", (unsigned long)stack); for (i = 0; i < kstack_depth_to_print; i++) { if (((long)stack & (THREAD_SIZE-1)) == 0) break; if (i && ((i % 8) == 0)) printk("\n "); if (__get_user(addr, stack)) { /* This message matches "failing address" marked s390 in ksymoops, so lines containing it will not be filtered out by ksymoops. */ printk("Failing address 0x%lx\n", (unsigned long)stack); break; } stack++; printk("%08lx ", addr); } show_trace(sp); } #if 0 /* displays a short stack trace */ int show_stack(void) { unsigned long *sp = (unsigned long *)rdusp(); int i; printk("Stack dump [0x%08lx]:\n", (unsigned long)sp); for (i = 0; i < 16; i++) printk("sp + %d: 0x%08lx\n", i*4, sp[i]); return 0; } #endif void dump_stack(void) { show_stack(NULL, NULL); } EXPORT_SYMBOL(dump_stack); void set_nmi_handler(void (*handler)(struct pt_regs *)) { nmi_handler = handler; arch_enable_nmi(); } #ifdef CONFIG_DEBUG_NMI_OOPS void oops_nmi_handler(struct pt_regs *regs) { stop_watchdog(); oops_in_progress = 1; printk("NMI!\n"); show_registers(regs); oops_in_progress = 0; } static int __init oops_nmi_register(void) { set_nmi_handler(oops_nmi_handler); return 0; } __initcall(oops_nmi_register); #endif /* * This gets called from entry.S when the watchdog has bitten. Show something * similar to an Oops dump, and if the kernel is configured to be a nice * doggy, then halt instead of reboot. */ void watchdog_bite_hook(struct pt_regs *regs) { #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY local_irq_disable(); stop_watchdog(); show_registers(regs); while (1) ; /* Do nothing. */ #else show_registers(regs); #endif } /* This is normally the Oops function. */ void die_if_kernel(const char *str, struct pt_regs *regs, long err) { if (user_mode(regs)) return; #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY /* * This printout might take too long and could trigger * the watchdog normally. If NICE_DOGGY is set, simply * stop the watchdog during the printout. */ stop_watchdog(); #endif handle_BUG(regs); printk("%s: %04lx\n", str, err & 0xffff); show_registers(regs); oops_in_progress = 0; #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY reset_watchdog(); #endif do_exit(SIGSEGV); } void __init trap_init(void) { /* Nothing needs to be done */ } |