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 | /* $Id: traps.c,v 1.15 2001/07/18 14:02:37 bjornw Exp $ * * 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,2001 Axis Communications AB * * Authors: Bjorn Wesen * Hans-Peter Nilsson * */ #include <linux/init.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/ptrace.h> #include <linux/timer.h> #include <linux/mm.h> #include <asm/uaccess.h> #include <asm/system.h> #include <asm/segment.h> #include <asm/io.h> #include <asm/pgtable.h> int kstack_depth_to_print = 24; /* * 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(unsigned long *sp) { unsigned long *stack, addr, module_start, module_end; int i; extern char _stext, _etext; /* * debugging aid: "show_stack(NULL);" prints a * back trace. */ if(sp == NULL) sp = (unsigned long*)rdsp(); stack = sp; printk("\nStack from %08lx:\n ", 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", stack); break; } stack++; printk("%08lx ", addr); } printk("\nCall Trace: "); stack = sp; 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", 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++; } } } #if 0 /* displays a short stack trace */ int show_stack() { 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 show_registers(struct pt_regs * regs) { /* We either use rdusp() - the USP register, which might not correspond to the current process for all cases we're called, or we use the current->thread.usp, which is not up to date for the current process. Experience shows we want the USP register. */ unsigned long usp = rdusp(); printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n", regs->irp, regs->srp, regs->dccr, usp, regs->mof ); printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", regs->r0, regs->r1, regs->r2, regs->r3); printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", regs->r4, regs->r5, regs->r6, regs->r7); printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", regs->r8, regs->r9, regs->r10, regs->r11); printk("r12: %08lx r13: %08lx oR10: %08lx\n", regs->r12, regs->r13, regs->orig_r10); printk("R_MMU_CAUSE: %08lx\n", *R_MMU_CAUSE); printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, (unsigned long)current); /* * When in-kernel, we also print out the stack and code at the * time of the fault.. */ if (! user_mode(regs)) { int i; show_stack((unsigned long*)usp); /* Dump kernel stack if the previous dump wasn't one. */ if (usp != 0) show_stack (NULL); printk("\nCode: "); if(regs->irp < PAGE_OFFSET) goto bad; /* Often enough the value at regs->irp does not point to the interesting instruction, which is most often the _previous_ instruction. So we dump at an offset large enough that instruction decoding should be in sync at the interesting point, but small enough to fit on a row (sort of). We point out the regs->irp location in a ksymoops-friendly way by wrapping the byte for that address in parentheses. */ for(i = -12; i < 12; i++) { unsigned char c; if(__get_user(c, &((unsigned char*)regs->irp)[i])) { bad: printk(" Bad IP value."); break; } if (i == 0) printk("(%02x) ", c); else printk("%02x ", c); } printk("\n"); } } void die_if_kernel(const char * str, struct pt_regs * regs, long err) { if(user_mode(regs)) return; stop_watchdog(); printk("%s: %04lx\n", str, err & 0xffff); show_registers(regs); reset_watchdog(); do_exit(SIGSEGV); } void __init trap_init(void) { /* Nothing needs to be done */ } |