| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | *  linux/arch/m68knommu/kernel/traps.c | 
|  | 3 | * | 
|  | 4 | *  Copyright (C) 1993, 1994 by Hamish Macdonald | 
|  | 5 | * | 
|  | 6 | *  68040 fixes by Michael Rausch | 
|  | 7 | *  68040 fixes by Martin Apel | 
|  | 8 | *  68060 fixes by Roman Hodek | 
|  | 9 | *  68060 fixes by Jesper Skov | 
|  | 10 | * | 
|  | 11 | * This file is subject to the terms and conditions of the GNU General Public | 
|  | 12 | * License.  See the file COPYING in the main directory of this archive | 
|  | 13 | * for more details. | 
|  | 14 | */ | 
|  | 15 |  | 
|  | 16 | /* | 
|  | 17 | * Sets up all exception vectors | 
|  | 18 | */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 19 | #include <linux/sched.h> | 
|  | 20 | #include <linux/signal.h> | 
|  | 21 | #include <linux/kernel.h> | 
|  | 22 | #include <linux/mm.h> | 
| Greg Ungerer | db81fb8 | 2005-09-02 10:42:52 +1000 | [diff] [blame] | 23 | #include <linux/module.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 24 | #include <linux/types.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 25 | #include <linux/user.h> | 
|  | 26 | #include <linux/string.h> | 
|  | 27 | #include <linux/linkage.h> | 
|  | 28 | #include <linux/init.h> | 
|  | 29 | #include <linux/ptrace.h> | 
| Sebastian Siewior | f6054e2 | 2008-05-01 12:16:38 +1000 | [diff] [blame] | 30 | #include <linux/kallsyms.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 31 |  | 
|  | 32 | #include <asm/setup.h> | 
|  | 33 | #include <asm/fpu.h> | 
|  | 34 | #include <asm/system.h> | 
|  | 35 | #include <asm/uaccess.h> | 
|  | 36 | #include <asm/traps.h> | 
|  | 37 | #include <asm/pgtable.h> | 
|  | 38 | #include <asm/machdep.h> | 
|  | 39 | #include <asm/siginfo.h> | 
|  | 40 |  | 
| Greg Ungerer | db81fb8 | 2005-09-02 10:42:52 +1000 | [diff] [blame] | 41 | static char const * const vec_names[] = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 42 | "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR", | 
|  | 43 | "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc", | 
|  | 44 | "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111", | 
|  | 45 | "UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION", | 
|  | 46 | "FORMAT ERROR", "UNINITIALIZED INTERRUPT", | 
|  | 47 | "UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17", | 
|  | 48 | "UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19", | 
|  | 49 | "UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21", | 
|  | 50 | "UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23", | 
|  | 51 | "SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT", | 
|  | 52 | "LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT", | 
|  | 53 | "SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3", | 
|  | 54 | "TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7", | 
|  | 55 | "TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11", | 
|  | 56 | "TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15", | 
|  | 57 | "FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW", | 
|  | 58 | "FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN", | 
|  | 59 | "FPCP UNSUPPORTED OPERATION", | 
|  | 60 | "MMU CONFIGURATION ERROR" | 
|  | 61 | }; | 
|  | 62 |  | 
|  | 63 | void __init trap_init(void) | 
|  | 64 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 65 | } | 
|  | 66 |  | 
|  | 67 | void die_if_kernel(char *str, struct pt_regs *fp, int nr) | 
|  | 68 | { | 
|  | 69 | if (!(fp->sr & PS_S)) | 
|  | 70 | return; | 
|  | 71 |  | 
|  | 72 | console_verbose(); | 
|  | 73 | printk(KERN_EMERG "%s: %08x\n",str,nr); | 
|  | 74 | printk(KERN_EMERG "PC: [<%08lx>]\nSR: %04x  SP: %p  a2: %08lx\n", | 
|  | 75 | fp->pc, fp->sr, fp, fp->a2); | 
|  | 76 | printk(KERN_EMERG "d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n", | 
|  | 77 | fp->d0, fp->d1, fp->d2, fp->d3); | 
|  | 78 | printk(KERN_EMERG "d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n", | 
|  | 79 | fp->d4, fp->d5, fp->a0, fp->a1); | 
|  | 80 |  | 
|  | 81 | printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n", | 
|  | 82 | current->comm, current->pid, PAGE_SIZE+(unsigned long)current); | 
| Greg Ungerer | a4c8b91 | 2007-07-19 01:49:14 -0700 | [diff] [blame] | 83 | show_stack(NULL, (unsigned long *)(fp + 1)); | 
| Pavel Emelianov | bcdcd8e | 2007-07-17 04:03:42 -0700 | [diff] [blame] | 84 | add_taint(TAINT_DIE); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 85 | do_exit(SIGSEGV); | 
|  | 86 | } | 
|  | 87 |  | 
|  | 88 | asmlinkage void buserr_c(struct frame *fp) | 
|  | 89 | { | 
|  | 90 | /* Only set esp0 if coming from user mode */ | 
|  | 91 | if (user_mode(&fp->ptregs)) | 
|  | 92 | current->thread.esp0 = (unsigned long) fp; | 
|  | 93 |  | 
| Greg Ungerer | bb28632 | 2006-06-26 10:33:10 +1000 | [diff] [blame] | 94 | #if defined(DEBUG) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 95 | printk (KERN_DEBUG "*** Bus Error *** Format is %x\n", fp->ptregs.format); | 
|  | 96 | #endif | 
|  | 97 |  | 
|  | 98 | die_if_kernel("bad frame format",&fp->ptregs,0); | 
| Greg Ungerer | bb28632 | 2006-06-26 10:33:10 +1000 | [diff] [blame] | 99 | #if defined(DEBUG) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 100 | printk(KERN_DEBUG "Unknown SIGSEGV - 4\n"); | 
|  | 101 | #endif | 
|  | 102 | force_sig(SIGSEGV, current); | 
|  | 103 | } | 
|  | 104 |  | 
| Sebastian Siewior | 1fda83d | 2008-05-09 16:13:36 +0200 | [diff] [blame] | 105 | static void print_this_address(unsigned long addr, int i) | 
|  | 106 | { | 
|  | 107 | #ifdef CONFIG_KALLSYMS | 
|  | 108 | printk(KERN_EMERG " [%08lx] ", addr); | 
|  | 109 | print_symbol(KERN_CONT "%s\n", addr); | 
|  | 110 | #else | 
|  | 111 | if (i % 5) | 
|  | 112 | printk(KERN_CONT " [%08lx] ", addr); | 
|  | 113 | else | 
| Joe Perches | ad361c9 | 2009-07-06 13:05:40 -0700 | [diff] [blame] | 114 | printk(KERN_EMERG " [%08lx] ", addr); | 
| Sebastian Siewior | 1fda83d | 2008-05-09 16:13:36 +0200 | [diff] [blame] | 115 | i++; | 
|  | 116 | #endif | 
|  | 117 | } | 
|  | 118 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 119 | int kstack_depth_to_print = 48; | 
|  | 120 |  | 
| Sebastian Siewior | f6054e2 | 2008-05-01 12:16:38 +1000 | [diff] [blame] | 121 | static void __show_stack(struct task_struct *task, unsigned long *stack) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 122 | { | 
| Greg Ungerer | db81fb8 | 2005-09-02 10:42:52 +1000 | [diff] [blame] | 123 | unsigned long *endstack, addr; | 
| Sebastian Siewior | 1fda83d | 2008-05-09 16:13:36 +0200 | [diff] [blame] | 124 | #ifdef CONFIG_FRAME_POINTER | 
| Sebastian Siewior | f6054e2 | 2008-05-01 12:16:38 +1000 | [diff] [blame] | 125 | unsigned long *last_stack; | 
| Sebastian Siewior | 1fda83d | 2008-05-09 16:13:36 +0200 | [diff] [blame] | 126 | #endif | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 127 | int i; | 
|  | 128 |  | 
| Sebastian Siewior | f6054e2 | 2008-05-01 12:16:38 +1000 | [diff] [blame] | 129 | if (!stack) | 
|  | 130 | stack = (unsigned long *)task->thread.ksp; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 131 |  | 
| Greg Ungerer | db81fb8 | 2005-09-02 10:42:52 +1000 | [diff] [blame] | 132 | addr = (unsigned long) stack; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 133 | endstack = (unsigned long *) PAGE_ALIGN(addr); | 
|  | 134 |  | 
|  | 135 | printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack); | 
|  | 136 | for (i = 0; i < kstack_depth_to_print; i++) { | 
| Sebastian Siewior | f6054e2 | 2008-05-01 12:16:38 +1000 | [diff] [blame] | 137 | if (stack + 1 + i > endstack) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 138 | break; | 
|  | 139 | if (i % 8 == 0) | 
| Joe Perches | ad361c9 | 2009-07-06 13:05:40 -0700 | [diff] [blame] | 140 | printk(KERN_EMERG "       "); | 
|  | 141 | printk(KERN_CONT " %08lx", *(stack + i)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 142 | } | 
| Greg Ungerer | 329237c | 2006-12-04 17:27:09 +1000 | [diff] [blame] | 143 | printk("\n"); | 
| Sebastian Siewior | 1fda83d | 2008-05-09 16:13:36 +0200 | [diff] [blame] | 144 | i = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 145 |  | 
| Sebastian Siewior | f6054e2 | 2008-05-01 12:16:38 +1000 | [diff] [blame] | 146 | #ifdef CONFIG_FRAME_POINTER | 
|  | 147 | printk(KERN_EMERG "Call Trace:\n"); | 
|  | 148 |  | 
|  | 149 | last_stack = stack - 1; | 
|  | 150 | while (stack <= endstack && stack > last_stack) { | 
|  | 151 |  | 
|  | 152 | addr = *(stack + 1); | 
| Sebastian Siewior | 1fda83d | 2008-05-09 16:13:36 +0200 | [diff] [blame] | 153 | print_this_address(addr, i); | 
|  | 154 | i++; | 
| Sebastian Siewior | f6054e2 | 2008-05-01 12:16:38 +1000 | [diff] [blame] | 155 |  | 
|  | 156 | last_stack = stack; | 
|  | 157 | stack = (unsigned long *)*stack; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 158 | } | 
| Greg Ungerer | 329237c | 2006-12-04 17:27:09 +1000 | [diff] [blame] | 159 | printk("\n"); | 
| Sebastian Siewior | f6054e2 | 2008-05-01 12:16:38 +1000 | [diff] [blame] | 160 | #else | 
| Sebastian Siewior | 1fda83d | 2008-05-09 16:13:36 +0200 | [diff] [blame] | 161 | printk(KERN_EMERG "Call Trace with CONFIG_FRAME_POINTER disabled:\n"); | 
|  | 162 | while (stack <= endstack) { | 
|  | 163 | addr = *stack++; | 
|  | 164 | /* | 
|  | 165 | * If the address is either in the text segment of the kernel, | 
|  | 166 | * or in a region which is occupied by a module then it *may* | 
|  | 167 | * be the address of a calling routine; if so, print it so that | 
|  | 168 | * someone tracing down the cause of the crash will be able to | 
|  | 169 | * figure out the call path that was taken. | 
|  | 170 | */ | 
|  | 171 | if (__kernel_text_address(addr)) { | 
|  | 172 | print_this_address(addr, i); | 
|  | 173 | i++; | 
|  | 174 | } | 
|  | 175 | } | 
|  | 176 | printk(KERN_CONT "\n"); | 
| Sebastian Siewior | f6054e2 | 2008-05-01 12:16:38 +1000 | [diff] [blame] | 177 | #endif | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 178 | } | 
|  | 179 |  | 
|  | 180 | void bad_super_trap(struct frame *fp) | 
|  | 181 | { | 
| Greg Ungerer | 730251f | 2010-10-07 17:16:56 +1000 | [diff] [blame] | 182 | int vector = (fp->ptregs.vector >> 2) & 0xff; | 
|  | 183 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 184 | console_verbose(); | 
| Greg Ungerer | 730251f | 2010-10-07 17:16:56 +1000 | [diff] [blame] | 185 | if (vector < ARRAY_SIZE(vec_names)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 186 | printk (KERN_WARNING "*** %s ***   FORMAT=%X\n", | 
| Greg Ungerer | 730251f | 2010-10-07 17:16:56 +1000 | [diff] [blame] | 187 | vec_names[vector], | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 188 | fp->ptregs.format); | 
|  | 189 | else | 
|  | 190 | printk (KERN_WARNING "*** Exception %d ***   FORMAT=%X\n", | 
| Greg Ungerer | 730251f | 2010-10-07 17:16:56 +1000 | [diff] [blame] | 191 | vector, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 192 | fp->ptregs.format); | 
|  | 193 | printk (KERN_WARNING "Current process id is %d\n", current->pid); | 
|  | 194 | die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); | 
|  | 195 | } | 
|  | 196 |  | 
|  | 197 | asmlinkage void trap_c(struct frame *fp) | 
|  | 198 | { | 
|  | 199 | int sig; | 
| Greg Ungerer | 730251f | 2010-10-07 17:16:56 +1000 | [diff] [blame] | 200 | int vector = (fp->ptregs.vector >> 2) & 0xff; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 201 | siginfo_t info; | 
|  | 202 |  | 
|  | 203 | if (fp->ptregs.sr & PS_S) { | 
| Greg Ungerer | 730251f | 2010-10-07 17:16:56 +1000 | [diff] [blame] | 204 | if (vector == VEC_TRACE) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 205 | /* traced a trapping instruction */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 206 | } else | 
|  | 207 | bad_super_trap(fp); | 
|  | 208 | return; | 
|  | 209 | } | 
|  | 210 |  | 
|  | 211 | /* send the appropriate signal to the user program */ | 
| Greg Ungerer | 730251f | 2010-10-07 17:16:56 +1000 | [diff] [blame] | 212 | switch (vector) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 213 | case VEC_ADDRERR: | 
|  | 214 | info.si_code = BUS_ADRALN; | 
|  | 215 | sig = SIGBUS; | 
|  | 216 | break; | 
|  | 217 | case VEC_ILLEGAL: | 
|  | 218 | case VEC_LINE10: | 
|  | 219 | case VEC_LINE11: | 
|  | 220 | info.si_code = ILL_ILLOPC; | 
|  | 221 | sig = SIGILL; | 
|  | 222 | break; | 
|  | 223 | case VEC_PRIV: | 
|  | 224 | info.si_code = ILL_PRVOPC; | 
|  | 225 | sig = SIGILL; | 
|  | 226 | break; | 
|  | 227 | case VEC_COPROC: | 
|  | 228 | info.si_code = ILL_COPROC; | 
|  | 229 | sig = SIGILL; | 
|  | 230 | break; | 
|  | 231 | case VEC_TRAP1: /* gdbserver breakpoint */ | 
|  | 232 | fp->ptregs.pc -= 2; | 
|  | 233 | info.si_code = TRAP_TRACE; | 
|  | 234 | sig = SIGTRAP; | 
|  | 235 | break; | 
|  | 236 | case VEC_TRAP2: | 
|  | 237 | case VEC_TRAP3: | 
|  | 238 | case VEC_TRAP4: | 
|  | 239 | case VEC_TRAP5: | 
|  | 240 | case VEC_TRAP6: | 
|  | 241 | case VEC_TRAP7: | 
|  | 242 | case VEC_TRAP8: | 
|  | 243 | case VEC_TRAP9: | 
|  | 244 | case VEC_TRAP10: | 
|  | 245 | case VEC_TRAP11: | 
|  | 246 | case VEC_TRAP12: | 
|  | 247 | case VEC_TRAP13: | 
|  | 248 | case VEC_TRAP14: | 
|  | 249 | info.si_code = ILL_ILLTRP; | 
|  | 250 | sig = SIGILL; | 
|  | 251 | break; | 
|  | 252 | case VEC_FPBRUC: | 
|  | 253 | case VEC_FPOE: | 
|  | 254 | case VEC_FPNAN: | 
|  | 255 | info.si_code = FPE_FLTINV; | 
|  | 256 | sig = SIGFPE; | 
|  | 257 | break; | 
|  | 258 | case VEC_FPIR: | 
|  | 259 | info.si_code = FPE_FLTRES; | 
|  | 260 | sig = SIGFPE; | 
|  | 261 | break; | 
|  | 262 | case VEC_FPDIVZ: | 
|  | 263 | info.si_code = FPE_FLTDIV; | 
|  | 264 | sig = SIGFPE; | 
|  | 265 | break; | 
|  | 266 | case VEC_FPUNDER: | 
|  | 267 | info.si_code = FPE_FLTUND; | 
|  | 268 | sig = SIGFPE; | 
|  | 269 | break; | 
|  | 270 | case VEC_FPOVER: | 
|  | 271 | info.si_code = FPE_FLTOVF; | 
|  | 272 | sig = SIGFPE; | 
|  | 273 | break; | 
|  | 274 | case VEC_ZERODIV: | 
|  | 275 | info.si_code = FPE_INTDIV; | 
|  | 276 | sig = SIGFPE; | 
|  | 277 | break; | 
|  | 278 | case VEC_CHK: | 
|  | 279 | case VEC_TRAP: | 
|  | 280 | info.si_code = FPE_INTOVF; | 
|  | 281 | sig = SIGFPE; | 
|  | 282 | break; | 
|  | 283 | case VEC_TRACE:		/* ptrace single step */ | 
|  | 284 | info.si_code = TRAP_TRACE; | 
|  | 285 | sig = SIGTRAP; | 
|  | 286 | break; | 
|  | 287 | case VEC_TRAP15:		/* breakpoint */ | 
|  | 288 | info.si_code = TRAP_BRKPT; | 
|  | 289 | sig = SIGTRAP; | 
|  | 290 | break; | 
|  | 291 | default: | 
|  | 292 | info.si_code = ILL_ILLOPC; | 
|  | 293 | sig = SIGILL; | 
|  | 294 | break; | 
|  | 295 | } | 
|  | 296 | info.si_signo = sig; | 
|  | 297 | info.si_errno = 0; | 
|  | 298 | switch (fp->ptregs.format) { | 
|  | 299 | default: | 
|  | 300 | info.si_addr = (void *) fp->ptregs.pc; | 
|  | 301 | break; | 
|  | 302 | case 2: | 
|  | 303 | info.si_addr = (void *) fp->un.fmt2.iaddr; | 
|  | 304 | break; | 
|  | 305 | case 7: | 
|  | 306 | info.si_addr = (void *) fp->un.fmt7.effaddr; | 
|  | 307 | break; | 
|  | 308 | case 9: | 
|  | 309 | info.si_addr = (void *) fp->un.fmt9.iaddr; | 
|  | 310 | break; | 
|  | 311 | case 10: | 
|  | 312 | info.si_addr = (void *) fp->un.fmta.daddr; | 
|  | 313 | break; | 
|  | 314 | case 11: | 
|  | 315 | info.si_addr = (void *) fp->un.fmtb.daddr; | 
|  | 316 | break; | 
|  | 317 | } | 
|  | 318 | force_sig_info (sig, &info, current); | 
|  | 319 | } | 
|  | 320 |  | 
|  | 321 | asmlinkage void set_esp0(unsigned long ssp) | 
|  | 322 | { | 
|  | 323 | current->thread.esp0 = ssp; | 
|  | 324 | } | 
|  | 325 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 326 | /* | 
|  | 327 | * The architecture-independent backtrace generator | 
|  | 328 | */ | 
|  | 329 | void dump_stack(void) | 
|  | 330 | { | 
| Sebastian Siewior | f6054e2 | 2008-05-01 12:16:38 +1000 | [diff] [blame] | 331 | /* | 
|  | 332 | * We need frame pointers for this little trick, which works as follows: | 
|  | 333 | * | 
|  | 334 | * +------------+ 0x00 | 
|  | 335 | * | Next SP	|	-> 0x0c | 
|  | 336 | * +------------+ 0x04 | 
|  | 337 | * | Caller	| | 
|  | 338 | * +------------+ 0x08 | 
|  | 339 | * | Local vars	|	-> our stack var | 
|  | 340 | * +------------+ 0x0c | 
|  | 341 | * | Next SP	|	-> 0x18, that is what we pass to show_stack() | 
|  | 342 | * +------------+ 0x10 | 
|  | 343 | * | Caller	| | 
|  | 344 | * +------------+ 0x14 | 
|  | 345 | * | Local vars	| | 
|  | 346 | * +------------+ 0x18 | 
|  | 347 | * | ...	| | 
|  | 348 | * +------------+ | 
|  | 349 | */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 350 |  | 
| Sebastian Siewior | f6054e2 | 2008-05-01 12:16:38 +1000 | [diff] [blame] | 351 | unsigned long *stack; | 
|  | 352 |  | 
|  | 353 | stack = (unsigned long *)&stack; | 
|  | 354 | stack++; | 
|  | 355 | __show_stack(current, stack); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 356 | } | 
| Greg Ungerer | db81fb8 | 2005-09-02 10:42:52 +1000 | [diff] [blame] | 357 | EXPORT_SYMBOL(dump_stack); | 
|  | 358 |  | 
| Sebastian Siewior | f6054e2 | 2008-05-01 12:16:38 +1000 | [diff] [blame] | 359 | void show_stack(struct task_struct *task, unsigned long *stack) | 
|  | 360 | { | 
|  | 361 | if (!stack && !task) | 
|  | 362 | dump_stack(); | 
|  | 363 | else | 
|  | 364 | __show_stack(task, stack); | 
|  | 365 | } |