Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  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 */
 19#include <linux/sched.h>
 20#include <linux/signal.h>
 21#include <linux/kernel.h>
 22#include <linux/mm.h>
 23#include <linux/module.h>
 24#include <linux/types.h>
 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>
 30#include <linux/kallsyms.h>
 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
 41static char const * const vec_names[] = {
 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
 63void die_if_kernel(char *str, struct pt_regs *fp, int nr)
 64{
 65	if (!(fp->sr & PS_S))
 66		return;
 67
 68	console_verbose();
 69	printk(KERN_EMERG "%s: %08x\n",str,nr);
 70	printk(KERN_EMERG "PC: [<%08lx>]\nSR: %04x  SP: %p  a2: %08lx\n",
 71	       fp->pc, fp->sr, fp, fp->a2);
 72	printk(KERN_EMERG "d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
 73	       fp->d0, fp->d1, fp->d2, fp->d3);
 74	printk(KERN_EMERG "d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
 75	       fp->d4, fp->d5, fp->a0, fp->a1);
 76
 77	printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n",
 78		current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
 79	show_stack(NULL, (unsigned long *)(fp + 1));
 80	add_taint(TAINT_DIE);
 81	do_exit(SIGSEGV);
 82}
 83
 84asmlinkage void buserr_c(struct frame *fp)
 85{
 86	/* Only set esp0 if coming from user mode */
 87	if (user_mode(&fp->ptregs))
 88		current->thread.esp0 = (unsigned long) fp;
 89
 90#if defined(DEBUG)
 91	printk (KERN_DEBUG "*** Bus Error *** Format is %x\n", fp->ptregs.format);
 92#endif
 93
 94	die_if_kernel("bad frame format",&fp->ptregs,0);
 95#if defined(DEBUG)
 96	printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
 97#endif
 98	force_sig(SIGSEGV, current);
 99}
100
101static void print_this_address(unsigned long addr, int i)
102{
103#ifdef CONFIG_KALLSYMS
104	printk(KERN_EMERG " [%08lx] ", addr);
105	print_symbol(KERN_CONT "%s\n", addr);
106#else
107	if (i % 5)
108		printk(KERN_CONT " [%08lx] ", addr);
109	else
110		printk(KERN_EMERG " [%08lx] ", addr);
111	i++;
112#endif
113}
114
115int kstack_depth_to_print = 48;
116
117static void __show_stack(struct task_struct *task, unsigned long *stack)
118{
119	unsigned long *endstack, addr;
120#ifdef CONFIG_FRAME_POINTER
121	unsigned long *last_stack;
122#endif
123	int i;
124
125	if (!stack)
126		stack = (unsigned long *)task->thread.ksp;
127
128	addr = (unsigned long) stack;
129	endstack = (unsigned long *) PAGE_ALIGN(addr);
130
131	printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
132	for (i = 0; i < kstack_depth_to_print; i++) {
133		if (stack + 1 + i > endstack)
134			break;
135		if (i % 8 == 0)
136			printk(KERN_EMERG "       ");
137		printk(KERN_CONT " %08lx", *(stack + i));
138	}
139	printk("\n");
140	i = 0;
141
142#ifdef CONFIG_FRAME_POINTER
143	printk(KERN_EMERG "Call Trace:\n");
144
145	last_stack = stack - 1;
146	while (stack <= endstack && stack > last_stack) {
147
148		addr = *(stack + 1);
149		print_this_address(addr, i);
150		i++;
151
152		last_stack = stack;
153		stack = (unsigned long *)*stack;
154	}
155	printk("\n");
156#else
157	printk(KERN_EMERG "Call Trace with CONFIG_FRAME_POINTER disabled:\n");
158	while (stack <= endstack) {
159		addr = *stack++;
160		/*
161		 * If the address is either in the text segment of the kernel,
162		 * or in a region which is occupied by a module then it *may*
163		 * be the address of a calling routine; if so, print it so that
164		 * someone tracing down the cause of the crash will be able to
165		 * figure out the call path that was taken.
166		 */
167		if (__kernel_text_address(addr)) {
168			print_this_address(addr, i);
169			i++;
170		}
171	}
172	printk(KERN_CONT "\n");
173#endif
174}
175
176void bad_super_trap(struct frame *fp)
177{
178	int vector = (fp->ptregs.vector >> 2) & 0xff;
179
180	console_verbose();
181	if (vector < ARRAY_SIZE(vec_names))
182		printk (KERN_WARNING "*** %s ***   FORMAT=%X\n",
183			vec_names[vector],
184			fp->ptregs.format);
185	else
186		printk (KERN_WARNING "*** Exception %d ***   FORMAT=%X\n",
187			vector,
188			fp->ptregs.format);
189	printk (KERN_WARNING "Current process id is %d\n", current->pid);
190	die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
191}
192
193asmlinkage void trap_c(struct frame *fp)
194{
195	int sig;
196	int vector = (fp->ptregs.vector >> 2) & 0xff;
197	siginfo_t info;
198
199	if (fp->ptregs.sr & PS_S) {
200		if (vector == VEC_TRACE) {
201			/* traced a trapping instruction */
202		} else
203			bad_super_trap(fp);
204		return;
205	}
206
207	/* send the appropriate signal to the user program */
208	switch (vector) {
209	    case VEC_ADDRERR:
210		info.si_code = BUS_ADRALN;
211		sig = SIGBUS;
212		break;
213	    case VEC_ILLEGAL:
214	    case VEC_LINE10:
215	    case VEC_LINE11:
216		info.si_code = ILL_ILLOPC;
217		sig = SIGILL;
218		break;
219	    case VEC_PRIV:
220		info.si_code = ILL_PRVOPC;
221		sig = SIGILL;
222		break;
223	    case VEC_COPROC:
224		info.si_code = ILL_COPROC;
225		sig = SIGILL;
226		break;
227	    case VEC_TRAP1: /* gdbserver breakpoint */
228		fp->ptregs.pc -= 2;
229		info.si_code = TRAP_TRACE;
230		sig = SIGTRAP;
231		break;
232	    case VEC_TRAP2:
233	    case VEC_TRAP3:
234	    case VEC_TRAP4:
235	    case VEC_TRAP5:
236	    case VEC_TRAP6:
237	    case VEC_TRAP7:
238	    case VEC_TRAP8:
239	    case VEC_TRAP9:
240	    case VEC_TRAP10:
241	    case VEC_TRAP11:
242	    case VEC_TRAP12:
243	    case VEC_TRAP13:
244	    case VEC_TRAP14:
245		info.si_code = ILL_ILLTRP;
246		sig = SIGILL;
247		break;
248	    case VEC_FPBRUC:
249	    case VEC_FPOE:
250	    case VEC_FPNAN:
251		info.si_code = FPE_FLTINV;
252		sig = SIGFPE;
253		break;
254	    case VEC_FPIR:
255		info.si_code = FPE_FLTRES;
256		sig = SIGFPE;
257		break;
258	    case VEC_FPDIVZ:
259		info.si_code = FPE_FLTDIV;
260		sig = SIGFPE;
261		break;
262	    case VEC_FPUNDER:
263		info.si_code = FPE_FLTUND;
264		sig = SIGFPE;
265		break;
266	    case VEC_FPOVER:
267		info.si_code = FPE_FLTOVF;
268		sig = SIGFPE;
269		break;
270	    case VEC_ZERODIV:
271		info.si_code = FPE_INTDIV;
272		sig = SIGFPE;
273		break;
274	    case VEC_CHK:
275	    case VEC_TRAP:
276		info.si_code = FPE_INTOVF;
277		sig = SIGFPE;
278		break;
279	    case VEC_TRACE:		/* ptrace single step */
280		info.si_code = TRAP_TRACE;
281		sig = SIGTRAP;
282		break;
283	    case VEC_TRAP15:		/* breakpoint */
284		info.si_code = TRAP_BRKPT;
285		sig = SIGTRAP;
286		break;
287	    default:
288		info.si_code = ILL_ILLOPC;
289		sig = SIGILL;
290		break;
291	}
292	info.si_signo = sig;
293	info.si_errno = 0;
294	switch (fp->ptregs.format) {
295	    default:
296		info.si_addr = (void *) fp->ptregs.pc;
297		break;
298	    case 2:
299		info.si_addr = (void *) fp->un.fmt2.iaddr;
300		break;
301	    case 7:
302		info.si_addr = (void *) fp->un.fmt7.effaddr;
303		break;
304	    case 9:
305		info.si_addr = (void *) fp->un.fmt9.iaddr;
306		break;
307	    case 10:
308		info.si_addr = (void *) fp->un.fmta.daddr;
309		break;
310	    case 11:
311		info.si_addr = (void *) fp->un.fmtb.daddr;
312		break;
313	}
314	force_sig_info (sig, &info, current);
315}
316
317asmlinkage void set_esp0(unsigned long ssp)
318{
319	current->thread.esp0 = ssp;
320}
321
322/*
323 * The architecture-independent backtrace generator
324 */
325void dump_stack(void)
326{
327	/*
328	 * We need frame pointers for this little trick, which works as follows:
329	 *
330	 * +------------+ 0x00
331	 * | Next SP	|	-> 0x0c
332	 * +------------+ 0x04
333	 * | Caller	|
334	 * +------------+ 0x08
335	 * | Local vars	|	-> our stack var
336	 * +------------+ 0x0c
337	 * | Next SP	|	-> 0x18, that is what we pass to show_stack()
338	 * +------------+ 0x10
339	 * | Caller	|
340	 * +------------+ 0x14
341	 * | Local vars	|
342	 * +------------+ 0x18
343	 * | ...	|
344	 * +------------+
345	 */
346
347	unsigned long *stack;
348
349	stack = (unsigned long *)&stack;
350	stack++;
351	__show_stack(current, stack);
352}
353EXPORT_SYMBOL(dump_stack);
354
355void show_stack(struct task_struct *task, unsigned long *stack)
356{
357	if (!stack && !task)
358		dump_stack();
359	else
360		__show_stack(task, stack);
361}