traps.c 8.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 *  linux/arch/m68knommu/kernel/traps.c
 *
 *  Copyright (C) 1993, 1994 by Hamish Macdonald
 *
 *  68040 fixes by Michael Rausch
 *  68040 fixes by Martin Apel
 *  68060 fixes by Roman Hodek
 *  68060 fixes by Jesper Skov
 *
 * 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.
 */

/*
 * Sets up all exception vectors
 */
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/kernel.h>
#include <linux/mm.h>
23
#include <linux/module.h>
L
Linus Torvalds 已提交
24 25 26 27 28 29 30
#include <linux/types.h>
#include <linux/a.out.h>
#include <linux/user.h>
#include <linux/string.h>
#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/ptrace.h>
31
#include <linux/kallsyms.h>
L
Linus Torvalds 已提交
32 33 34 35 36 37 38 39 40 41

#include <asm/setup.h>
#include <asm/fpu.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/traps.h>
#include <asm/pgtable.h>
#include <asm/machdep.h>
#include <asm/siginfo.h>

42
static char const * const vec_names[] = {
L
Linus Torvalds 已提交
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
	"RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
	"ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
	"PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111",
	"UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION",
	"FORMAT ERROR", "UNINITIALIZED INTERRUPT",
	"UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17",
	"UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19",
	"UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21",
	"UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23",
	"SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT",
	"LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT",
	"SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3",
	"TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7",
	"TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11",
	"TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15",
	"FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW",
	"FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN",
	"FPCP UNSUPPORTED OPERATION",
	"MMU CONFIGURATION ERROR"
};

void __init trap_init(void)
{
}

void die_if_kernel(char *str, struct pt_regs *fp, int nr)
{
	if (!(fp->sr & PS_S))
		return;

	console_verbose();
	printk(KERN_EMERG "%s: %08x\n",str,nr);
	printk(KERN_EMERG "PC: [<%08lx>]\nSR: %04x  SP: %p  a2: %08lx\n",
	       fp->pc, fp->sr, fp, fp->a2);
	printk(KERN_EMERG "d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
	       fp->d0, fp->d1, fp->d2, fp->d3);
	printk(KERN_EMERG "d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
	       fp->d4, fp->d5, fp->a0, fp->a1);

	printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n",
		current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
84
	show_stack(NULL, (unsigned long *)(fp + 1));
85
	add_taint(TAINT_DIE);
L
Linus Torvalds 已提交
86 87 88 89 90 91 92 93 94
	do_exit(SIGSEGV);
}

asmlinkage void buserr_c(struct frame *fp)
{
	/* Only set esp0 if coming from user mode */
	if (user_mode(&fp->ptregs))
		current->thread.esp0 = (unsigned long) fp;

95
#if defined(DEBUG)
L
Linus Torvalds 已提交
96 97 98 99
	printk (KERN_DEBUG "*** Bus Error *** Format is %x\n", fp->ptregs.format);
#endif

	die_if_kernel("bad frame format",&fp->ptregs,0);
100
#if defined(DEBUG)
L
Linus Torvalds 已提交
101 102 103 104 105
	printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
#endif
	force_sig(SIGSEGV, current);
}

106 107 108 109 110 111 112 113 114 115 116 117 118 119
static void print_this_address(unsigned long addr, int i)
{
#ifdef CONFIG_KALLSYMS
	printk(KERN_EMERG " [%08lx] ", addr);
	print_symbol(KERN_CONT "%s\n", addr);
#else
	if (i % 5)
		printk(KERN_CONT " [%08lx] ", addr);
	else
		printk(KERN_CONT "\n" KERN_EMERG " [%08lx] ", addr);
	i++;
#endif
}

L
Linus Torvalds 已提交
120 121
int kstack_depth_to_print = 48;

122
static void __show_stack(struct task_struct *task, unsigned long *stack)
L
Linus Torvalds 已提交
123
{
124
	unsigned long *endstack, addr;
125
#ifdef CONFIG_FRAME_POINTER
126
	unsigned long *last_stack;
127
#endif
L
Linus Torvalds 已提交
128 129
	int i;

130 131
	if (!stack)
		stack = (unsigned long *)task->thread.ksp;
L
Linus Torvalds 已提交
132

133
	addr = (unsigned long) stack;
L
Linus Torvalds 已提交
134 135 136 137
	endstack = (unsigned long *) PAGE_ALIGN(addr);

	printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
	for (i = 0; i < kstack_depth_to_print; i++) {
138
		if (stack + 1 + i > endstack)
L
Linus Torvalds 已提交
139 140
			break;
		if (i % 8 == 0)
141
			printk("\n" KERN_EMERG "       ");
142
		printk(" %08lx", *(stack + i));
L
Linus Torvalds 已提交
143
	}
144
	printk("\n");
145
	i = 0;
L
Linus Torvalds 已提交
146

147 148 149 150 151 152 153
#ifdef CONFIG_FRAME_POINTER
	printk(KERN_EMERG "Call Trace:\n");

	last_stack = stack - 1;
	while (stack <= endstack && stack > last_stack) {

		addr = *(stack + 1);
154 155
		print_this_address(addr, i);
		i++;
156 157 158

		last_stack = stack;
		stack = (unsigned long *)*stack;
L
Linus Torvalds 已提交
159
	}
160
	printk("\n");
161
#else
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
	printk(KERN_EMERG "Call Trace with CONFIG_FRAME_POINTER disabled:\n");
	while (stack <= endstack) {
		addr = *stack++;
		/*
		 * If the address is either in the text segment of the kernel,
		 * or in a region which is occupied by a module then 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_this_address(addr, i);
			i++;
		}
	}
	printk(KERN_CONT "\n");
178
#endif
L
Linus Torvalds 已提交
179 180 181 182 183
}

void bad_super_trap(struct frame *fp)
{
	console_verbose();
184
	if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
L
Linus Torvalds 已提交
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 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
		printk (KERN_WARNING "*** %s ***   FORMAT=%X\n",
			vec_names[(fp->ptregs.vector) >> 2],
			fp->ptregs.format);
	else
		printk (KERN_WARNING "*** Exception %d ***   FORMAT=%X\n",
			(fp->ptregs.vector) >> 2, 
			fp->ptregs.format);
	printk (KERN_WARNING "Current process id is %d\n", current->pid);
	die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
}

asmlinkage void trap_c(struct frame *fp)
{
	int sig;
	siginfo_t info;

	if (fp->ptregs.sr & PS_S) {
		if ((fp->ptregs.vector >> 2) == VEC_TRACE) {
			/* traced a trapping instruction */
			current->ptrace |= PT_DTRACE;
		} else
			bad_super_trap(fp);
		return;
	}

	/* send the appropriate signal to the user program */
	switch ((fp->ptregs.vector) >> 2) {
	    case VEC_ADDRERR:
		info.si_code = BUS_ADRALN;
		sig = SIGBUS;
		break;
	    case VEC_ILLEGAL:
	    case VEC_LINE10:
	    case VEC_LINE11:
		info.si_code = ILL_ILLOPC;
		sig = SIGILL;
		break;
	    case VEC_PRIV:
		info.si_code = ILL_PRVOPC;
		sig = SIGILL;
		break;
	    case VEC_COPROC:
		info.si_code = ILL_COPROC;
		sig = SIGILL;
		break;
	    case VEC_TRAP1: /* gdbserver breakpoint */
		fp->ptregs.pc -= 2;
		info.si_code = TRAP_TRACE;
		sig = SIGTRAP;
		break;
	    case VEC_TRAP2:
	    case VEC_TRAP3:
	    case VEC_TRAP4:
	    case VEC_TRAP5:
	    case VEC_TRAP6:
	    case VEC_TRAP7:
	    case VEC_TRAP8:
	    case VEC_TRAP9:
	    case VEC_TRAP10:
	    case VEC_TRAP11:
	    case VEC_TRAP12:
	    case VEC_TRAP13:
	    case VEC_TRAP14:
		info.si_code = ILL_ILLTRP;
		sig = SIGILL;
		break;
	    case VEC_FPBRUC:
	    case VEC_FPOE:
	    case VEC_FPNAN:
		info.si_code = FPE_FLTINV;
		sig = SIGFPE;
		break;
	    case VEC_FPIR:
		info.si_code = FPE_FLTRES;
		sig = SIGFPE;
		break;
	    case VEC_FPDIVZ:
		info.si_code = FPE_FLTDIV;
		sig = SIGFPE;
		break;
	    case VEC_FPUNDER:
		info.si_code = FPE_FLTUND;
		sig = SIGFPE;
		break;
	    case VEC_FPOVER:
		info.si_code = FPE_FLTOVF;
		sig = SIGFPE;
		break;
	    case VEC_ZERODIV:
		info.si_code = FPE_INTDIV;
		sig = SIGFPE;
		break;
	    case VEC_CHK:
	    case VEC_TRAP:
		info.si_code = FPE_INTOVF;
		sig = SIGFPE;
		break;
	    case VEC_TRACE:		/* ptrace single step */
		info.si_code = TRAP_TRACE;
		sig = SIGTRAP;
		break;
	    case VEC_TRAP15:		/* breakpoint */
		info.si_code = TRAP_BRKPT;
		sig = SIGTRAP;
		break;
	    default:
		info.si_code = ILL_ILLOPC;
		sig = SIGILL;
		break;
	}
	info.si_signo = sig;
	info.si_errno = 0;
	switch (fp->ptregs.format) {
	    default:
		info.si_addr = (void *) fp->ptregs.pc;
		break;
	    case 2:
		info.si_addr = (void *) fp->un.fmt2.iaddr;
		break;
	    case 7:
		info.si_addr = (void *) fp->un.fmt7.effaddr;
		break;
	    case 9:
		info.si_addr = (void *) fp->un.fmt9.iaddr;
		break;
	    case 10:
		info.si_addr = (void *) fp->un.fmta.daddr;
		break;
	    case 11:
		info.si_addr = (void *) fp->un.fmtb.daddr;
		break;
	}
	force_sig_info (sig, &info, current);
}

asmlinkage void set_esp0(unsigned long ssp)
{
	current->thread.esp0 = ssp;
}

/*
 * The architecture-independent backtrace generator
 */
void dump_stack(void)
{
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
	/*
	 * We need frame pointers for this little trick, which works as follows:
	 *
	 * +------------+ 0x00
	 * | Next SP	|	-> 0x0c
	 * +------------+ 0x04
	 * | Caller	|
	 * +------------+ 0x08
	 * | Local vars	|	-> our stack var
	 * +------------+ 0x0c
	 * | Next SP	|	-> 0x18, that is what we pass to show_stack()
	 * +------------+ 0x10
	 * | Caller	|
	 * +------------+ 0x14
	 * | Local vars	|
	 * +------------+ 0x18
	 * | ...	|
	 * +------------+
	 */
L
Linus Torvalds 已提交
349

350
	unsigned long *stack;
L
Linus Torvalds 已提交
351

352 353 354 355
	stack = (unsigned long *)&stack;
	stack++;
	__show_stack(current, stack);
}
356 357
EXPORT_SYMBOL(dump_stack);

358 359 360 361 362 363 364 365
void show_stack(struct task_struct *task, unsigned long *stack)
{
	if (!stack && !task)
		dump_stack();
	else
		__show_stack(task, stack);
}

L
Linus Torvalds 已提交
366 367 368 369 370 371 372 373 374 375 376 377
#ifdef CONFIG_M68KFPU_EMU
asmlinkage void fpemu_signal(int signal, int code, void *addr)
{
	siginfo_t info;

	info.si_signo = signal;
	info.si_errno = 0;
	info.si_code = code;
	info.si_addr = addr;
	force_sig_info(signal, &info, current);
}
#endif