1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/config.h>
16#include <linux/types.h>
17#include <linux/kernel.h>
18#include <linux/signal.h>
19#include <linux/sched.h>
20#include <linux/mm.h>
21#include <linux/spinlock.h>
22#include <linux/personality.h>
23#include <linux/ptrace.h>
24#include <linux/elf.h>
25#include <linux/interrupt.h>
26#include <linux/init.h>
27
28#include <asm/atomic.h>
29#include <asm/io.h>
30#include <asm/pgtable.h>
31#include <asm/system.h>
32#include <asm/uaccess.h>
33#include <asm/unistd.h>
34
35#include "ptrace.h"
36
37extern void c_backtrace (unsigned long fp, int pmode);
38extern void show_pte(struct mm_struct *mm, unsigned long addr);
39
40const char *processor_modes[]=
41{ "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
42 "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
43 "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" ,
44 "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32"
45};
46
47static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
48
49
50
51
52
53
54static int verify_stack(unsigned long sp)
55{
56 if (sp < PAGE_OFFSET || sp > (unsigned long)high_memory)
57 return -EFAULT;
58
59 return 0;
60}
61
62
63
64
65void dump_mem(unsigned long bottom, unsigned long top)
66{
67 unsigned long p = bottom & ~31;
68 int i;
69
70 for (p = bottom & ~31; p < top;) {
71 printk("%08lx: ", p);
72
73 for (i = 0; i < 8; i++, p += 4) {
74 unsigned int val;
75
76 if (p < bottom || p >= top)
77 printk(" ");
78 else {
79 __get_user(val, (unsigned long *)p);
80 printk("%08x ", val);
81 }
82 if (i == 3)
83 printk(" ");
84 }
85 printk ("\n");
86 }
87}
88
89
90
91
92
93
94#define VMALLOC_OFFSET (8*1024*1024)
95#define MODULE_RANGE (8*1024*1024)
96
97static void dump_instr(struct pt_regs *regs)
98{
99 unsigned long addr = instruction_pointer(regs);
100 const int thumb = thumb_mode(regs);
101 const int width = thumb ? 4 : 8;
102 int i;
103
104 printk("Code: ");
105 for (i = -2; i < 3; i++) {
106 unsigned int val, bad;
107
108 if (thumb)
109 bad = __get_user(val, &((u16 *)addr)[i]);
110 else
111 bad = __get_user(val, &((u32 *)addr)[i]);
112
113 if (!bad)
114 printk(i == 0 ? "(%0*x) " : "%0*x ", width, val);
115 else {
116 printk("bad PC value.");
117 break;
118 }
119 }
120 printk("\n");
121}
122
123static void dump_stack(struct task_struct *tsk, unsigned long sp)
124{
125 printk("Stack:\n");
126 dump_mem(sp - 16, 8192+(unsigned long)tsk);
127}
128
129static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
130{
131 unsigned int fp;
132 int ok = 1;
133
134 printk("Backtrace: ");
135 fp = regs->ARM_fp;
136 if (!fp) {
137 printk("no frame pointer");
138 ok = 0;
139 } else if (verify_stack(fp)) {
140 printk("invalid frame pointer 0x%08x", fp);
141 ok = 0;
142 } else if (fp < 4096+(unsigned long)tsk)
143 printk("frame pointer underflow");
144 printk("\n");
145
146 if (ok)
147 c_backtrace(fp, processor_mode(regs));
148}
149
150
151
152
153
154void show_trace_task(struct task_struct *tsk)
155{
156 if (tsk != current) {
157 unsigned int fp = tsk->thread.save->fp;
158 c_backtrace(fp, 0x10);
159 }
160}
161
162spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
163
164
165
166
167NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
168{
169 struct task_struct *tsk = current;
170
171 console_verbose();
172 spin_lock_irq(&die_lock);
173
174 printk("Internal error: %s: %x\n", str, err);
175 printk("CPU: %d\n", smp_processor_id());
176 show_regs(regs);
177 printk("Process %s (pid: %d, stackpage=%08lx)\n",
178 current->comm, current->pid, 4096+(unsigned long)tsk);
179
180 if (!user_mode(regs) || in_interrupt()) {
181 mm_segment_t fs;
182
183
184
185
186
187
188
189 fs = get_fs();
190 set_fs(KERNEL_DS);
191
192 dump_stack(tsk, (unsigned long)(regs + 1));
193 dump_backtrace(regs, tsk);
194 dump_instr(regs);
195
196 set_fs(fs);
197 }
198
199 spin_unlock_irq(&die_lock);
200 do_exit(SIGSEGV);
201}
202
203void die_if_kernel(const char *str, struct pt_regs *regs, int err)
204{
205 if (user_mode(regs))
206 return;
207
208 die(str, regs, err);
209}
210
211asmlinkage void do_undefinstr(int address, struct pt_regs *regs, int mode)
212{
213 unsigned long *pc;
214 siginfo_t info;
215
216
217
218
219
220 regs->ARM_pc -= thumb_mode(regs) ? 2 : 4;
221 pc = (unsigned long *)instruction_pointer(regs);
222
223#ifdef CONFIG_DEBUG_USER
224 printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n",
225 current->comm, current->pid, pc);
226 dump_instr(regs);
227#endif
228
229 current->thread.error_code = 0;
230 current->thread.trap_no = 6;
231
232 info.si_signo = SIGILL;
233 info.si_errno = 0;
234 info.si_code = ILL_ILLOPC;
235 info.si_addr = pc;
236
237 force_sig_info(SIGILL, &info, current);
238
239 die_if_kernel("Oops - undefined instruction", regs, mode);
240}
241
242#ifdef CONFIG_CPU_26
243asmlinkage void do_excpt(int address, struct pt_regs *regs, int mode)
244{
245 siginfo_t info;
246
247#ifdef CONFIG_DEBUG_USER
248 printk(KERN_INFO "%s (%d): address exception: pc=%08lx\n",
249 current->comm, current->pid, instruction_pointer(regs));
250 dump_instr(regs);
251#endif
252
253 current->thread.error_code = 0;
254 current->thread.trap_no = 11;
255
256 info.si_signo = SIGBUS;
257 info.si_errno = 0;
258 info.si_code = BUS_ADRERR;
259 info.si_addr = (void *)address;
260
261 force_sig_info(SIGBUS, &info, current);
262
263 die_if_kernel("Oops - address exception", regs, mode);
264}
265#endif
266
267asmlinkage void do_unexp_fiq (struct pt_regs *regs)
268{
269#ifndef CONFIG_IGNORE_FIQ
270 printk("Hmm. Unexpected FIQ received, but trying to continue\n");
271 printk("You may have a hardware problem...\n");
272#endif
273}
274
275
276
277
278
279
280
281asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode)
282{
283 unsigned int vectors = vectors_base();
284 mm_segment_t fs;
285
286 console_verbose();
287
288 printk(KERN_CRIT "Bad mode in %s handler detected: mode %s\n",
289 handler[reason], processor_modes[proc_mode]);
290
291
292
293
294
295
296
297 fs = get_fs();
298 set_fs(KERNEL_DS);
299
300
301
302
303
304 printk(KERN_CRIT "Vectors:\n");
305 dump_mem(vectors, 0x40);
306 printk(KERN_CRIT "Stubs:\n");
307 dump_mem(vectors + 0x200, 0x4b8);
308
309 set_fs(fs);
310
311 die("Oops", regs, 0);
312 cli();
313 panic("bad mode");
314}
315
316static int bad_syscall(int n, struct pt_regs *regs)
317{
318 siginfo_t info;
319
320
321
322
323 if (current->personality != PER_LINUX && current->exec_domain->handler) {
324
325
326
327 current->exec_domain->handler(n, regs);
328 return regs->ARM_r0;
329 }
330
331#ifdef CONFIG_DEBUG_USER
332 printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n",
333 current->pid, current->comm, n);
334 dump_instr(regs);
335#endif
336
337 info.si_signo = SIGILL;
338 info.si_errno = 0;
339 info.si_code = ILL_ILLTRP;
340 info.si_addr = (void *)instruction_pointer(regs) -
341 (thumb_mode(regs) ? 2 : 4);
342
343 force_sig_info(SIGILL, &info, current);
344 die_if_kernel("Oops", regs, n);
345 return regs->ARM_r0;
346}
347
348
349
350
351
352#define NR(x) ((__ARM_NR_##x) - __ARM_NR_BASE)
353asmlinkage int arm_syscall(int no, struct pt_regs *regs)
354{
355 siginfo_t info;
356
357 if ((no >> 16) != 0x9f)
358 return bad_syscall(no, regs);
359
360 switch (no & 0xffff) {
361 case 0:
362 info.si_signo = SIGSEGV;
363 info.si_errno = 0;
364 info.si_code = SEGV_MAPERR;
365 info.si_addr = NULL;
366
367 force_sig_info(SIGSEGV, &info, current);
368
369 die_if_kernel("branch through zero", regs, 0);
370 return 0;
371
372 case NR(breakpoint):
373
374
375
376
377 regs->ARM_pc -= 4;
378 __ptrace_cancel_bpt(current);
379
380 info.si_signo = SIGTRAP;
381 info.si_errno = 0;
382 info.si_code = TRAP_BRKPT;
383 info.si_addr = (void *)instruction_pointer(regs) -
384 (thumb_mode(regs) ? 2 : 4);
385
386 force_sig_info(SIGTRAP, &info, current);
387 return regs->ARM_r0;
388
389#ifdef CONFIG_CPU_32
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404 case NR(cacheflush):
405 cpu_cache_clean_invalidate_range(regs->ARM_r0, regs->ARM_r1, 1);
406 return 0;
407
408 case NR(usr26):
409 if (!(elf_hwcap & HWCAP_26BIT))
410 break;
411 regs->ARM_cpsr &= ~0x10;
412 return regs->ARM_r0;
413
414 case NR(usr32):
415 if (!(elf_hwcap & HWCAP_26BIT))
416 break;
417 regs->ARM_cpsr |= 0x10;
418 return regs->ARM_r0;
419#else
420 case NR(cacheflush):
421 return 0;
422
423 case NR(usr26):
424 case NR(usr32):
425 break;
426#endif
427
428 default:
429
430
431
432
433 if (no <= 0x7ff)
434 return -ENOSYS;
435 break;
436 }
437#ifdef CONFIG_DEBUG_USER
438
439
440
441
442 printk("[%d] %s: arm syscall %d\n", current->pid, current->comm, no);
443 dump_instr(regs);
444 if (user_mode(regs)) {
445 show_regs(regs);
446 c_backtrace(regs->ARM_fp, processor_mode(regs));
447 }
448#endif
449 info.si_signo = SIGILL;
450 info.si_errno = 0;
451 info.si_code = ILL_ILLTRP;
452 info.si_addr = (void *)instruction_pointer(regs) -
453 (thumb_mode(regs) ? 2 : 4);
454
455 force_sig_info(SIGILL, &info, current);
456 die_if_kernel("Oops", regs, no);
457 return 0;
458}
459
460void __bad_xchg(volatile void *ptr, int size)
461{
462 printk("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",
463 __builtin_return_address(0), ptr, size);
464 BUG();
465}
466
467
468
469
470
471asmlinkage void
472baddataabort(int code, unsigned long instr, struct pt_regs *regs)
473{
474 unsigned long addr = instruction_pointer(regs);
475 siginfo_t info;
476
477#ifdef CONFIG_DEBUG_USER
478 printk(KERN_ERR "[%d] %s: bad data abort: code %d instr 0x%08lx\n",
479 current->pid, current->comm, code, instr);
480 dump_instr(regs);
481 show_pte(current->mm, addr);
482#endif
483
484 info.si_signo = SIGILL;
485 info.si_errno = 0;
486 info.si_code = ILL_ILLOPC;
487 info.si_addr = (void *)addr;
488
489 force_sig_info(SIGILL, &info, current);
490 die_if_kernel("unknown data abort code", regs, instr);
491}
492
493void __bug(const char *file, int line, void *data)
494{
495 printk(KERN_CRIT"kernel BUG at %s:%d!", file, line);
496 if (data)
497 printk(KERN_CRIT" - extra data = %p", data);
498 printk("\n");
499 *(int *)0 = 0;
500}
501
502void __readwrite_bug(const char *fn)
503{
504 printk("%s called, but not implemented", fn);
505 BUG();
506}
507
508void __pte_error(const char *file, int line, unsigned long val)
509{
510 printk("%s:%d: bad pte %08lx.\n", file, line, val);
511}
512
513void __pmd_error(const char *file, int line, unsigned long val)
514{
515 printk("%s:%d: bad pmd %08lx.\n", file, line, val);
516}
517
518void __pgd_error(const char *file, int line, unsigned long val)
519{
520 printk("%s:%d: bad pgd %08lx.\n", file, line, val);
521}
522
523asmlinkage void __div0(void)
524{
525 printk("Division by zero in kernel.\n");
526 __backtrace();
527}
528
529void abort(void)
530{
531 void *lr = __builtin_return_address(0);
532
533 printk(KERN_CRIT "abort() called from %p! (Please "
534 "report to rmk@arm.linux.org.uk)\n", lr);
535
536 BUG();
537
538
539 panic("Oops failed to kill thread");
540}
541
542void __init trap_init(void)
543{
544 extern void __trap_init(void *);
545
546 __trap_init((void *)vectors_base());
547 if (vectors_base() != 0)
548 printk(KERN_DEBUG "Relocating machine vectors to 0x%08x\n",
549 vectors_base());
550#ifdef CONFIG_CPU_32
551 modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
552#endif
553}
554