|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Copyright (c) 1992 NeXT Computer, Inc.
27: *
28: * Intel386 Family: Trap handlers.
29: *
30: * HISTORY
31: *
32: * 13 April 1992 ? at NeXT
33: * Created.
34: */
35:
36: #import <gdb.h>
37:
38: #import <mach/mach_types.h>
39: #import <mach/exception.h>
40:
41: #import <kern/syscall_sw.h>
42: #import <kern/kdp.h>
43:
44: #import <vm/vm_kern.h>
45:
46: #import <machdep/i386/trap.h>
47: #import <machdep/i386/machdep_call.h>
48: #import <machdep/i386/cpu_inline.h>
49: #import <machdep/i386/fp_exported.h>
50: #import <machdep/i386/sel_inline.h>
51: #import <machdep/i386/err_inline.h>
52:
53: #import <sys/kernel.h>
54: #import <sys/systm.h>
55: #import <sys/proc.h>
56: #import <sys/user.h>
57: #import <sys/syslog.h>
58:
59: #define N_BACKTRACE 4 // number of backtrace frames to print
60:
61: static
62: void
63: kernel_debug_trap(
64: thread_saved_state_t *saved_state
65: );
66: static
67: kern_return_t
68: kernel_pagefault(
69: vm_offset_t address,
70: except_frame_t *frame
71: );
72: static
73: boolean_t
74: kernel_try_recover(
75: except_frame_t *frame
76: );
77: static
78: void
79: kernel_recover_thread(
80: thread_saved_state_t *saved_state
81: );
82:
83: void
84: _i386_backtrace(
85: void *frame,
86: int nframes
87: );
88:
89: void
90: user_trap(
91: thread_saved_state_t *state
92: )
93: {
94: except_frame_t *frame = &state->frame;
95: int trapno;
96: thread_t thread;
97: int _exception, code = 0, subcode = 0;
98: vm_offset_t va;
99: kern_return_t result;
100: int uerror;
101: struct proc *p;
102: struct timeval syst;
103:
104: thread = current_thread();
105: trapno = state->trapno;
106:
107: if (p = current_proc())
108: syst = p->p_stats->p_ru.ru_stime;
109:
110: switch (trapno) {
111:
112: case T_ZERO_DIVIDE:
113: _exception = EXC_ARITHMETIC;
114: code = EXC_I386_ZERO_DIVIDE;
115: break;
116:
117: case T_DEBUG:
118: _exception = EXC_BREAKPOINT;
119: code = EXC_I386_DEBUG;
120: break;
121:
122: case T_BREAKPOINT:
123: _exception = EXC_BREAKPOINT;
124: code = EXC_I386_BREAKPOINT;
125: break;
126:
127: case T_OVERFLOW:
128: _exception = EXC_SOFTWARE;
129: code = EXC_I386_OVERFLOW;
130: break;
131:
132: case T_BOUNDS_CHECK:
133: _exception = EXC_SOFTWARE;
134: code = EXC_I386_BOUNDS_CHECK;
135: break;
136:
137: case T_INVALID_OPCODE:
138: _exception = EXC_BAD_INSTRUCTION;
139: code = EXC_I386_INVALID_OPCODE;
140: break;
141:
142: case T_NOEXTENSION:
143: fp_noextension(state);
144: goto out;
145:
146: case T_SEGMENT_NOTPRESENT:
147: _exception = EXC_BAD_INSTRUCTION;
148: code = EXC_I386_SEGMENT_NOTPRESENT;
149: subcode = err_to_error_code(frame->err);
150: break;
151:
152: case T_STACK_EXCEPTION:
153: _exception = EXC_BAD_INSTRUCTION;
154: code = EXC_I386_STACK_EXCEPTION;
155: subcode = err_to_error_code(frame->err);
156: break;
157:
158: case T_GENERAL_PROTECTION:
159: _exception = EXC_BAD_INSTRUCTION;
160: code = EXC_I386_GENERAL_PROTECTION;
161: subcode = err_to_error_code(frame->err);
162: break;
163:
164: case T_PAGE_FAULT:
165: va = cr2();
166: result = vm_fault(thread->task->map, trunc_page(va),
167: frame->err.pgfault.wrtflt?
168: VM_PROT_READ | VM_PROT_WRITE:
169: VM_PROT_READ,
170: FALSE, 0);
171: if (result == KERN_SUCCESS)
172: goto out;
173:
174: _exception = EXC_BAD_ACCESS;
175: code = result;
176: subcode = va;
177: break;
178:
179: case T_EXTENSION_FAULT:
180: fp_extension_fault(state);
181: goto out;
182:
183: case T_ALIGNMENT_CHECK:
184: _exception = EXC_SOFTWARE;
185: code = EXC_I386_ALIGNMENT_CHECK;
186: break;
187:
188: default:
189: _exception = EXC_BAD_INSTRUCTION;
190: code = trapno;
191: break;
192: }
193:
194: exception(_exception, code, subcode);
195: /* NOTREACHED */
196:
197: out:
198: if (p && (p->p_flag & P_PROFIL)) {
199: int ticks;
200: struct timeval *tv = &p->p_stats->p_ru.ru_stime;
201:
202: ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
203: (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
204: if (ticks)
205: addupc_task(p, frame->eip, ticks);
206: }
207:
208: thread_exception_return();
209: /* NOTREACHED */
210: }
211:
212: void
213: kernel_trap(
214: thread_saved_state_t *state
215: )
216: {
217: except_frame_t *frame = &state->frame;
218: int trapno;
219: vm_offset_t va;
220: int _exception, code = 0, subcode = 0;
221: kern_return_t result;
222: int uerror;
223:
224: trapno = state->trapno;
225:
226: switch (trapno) {
227:
228: case T_NOEXTENSION:
229: /* ignore exception */;
230: return;
231:
232: case T_EXTENSION_FAULT:
233: fp_kernel_extension_fault(state);
234: return;
235:
236: case T_DEBUG:
237: case T_BREAKPOINT:
238: kernel_debug_trap(state);
239: return;
240:
241: case T_PAGE_FAULT:
242: va = cr2();
243:
244: if (va >= KERNEL_LINEAR_BASE)
245: result = kernel_pagefault(va, frame);
246: else
247: result = vm_fault(current_task()->map, trunc_page(va),
248: frame->err.pgfault.wrtflt?
249: VM_PROT_READ | VM_PROT_WRITE:
250: VM_PROT_READ,
251: FALSE, 0);
252:
253: if (result == KERN_SUCCESS)
254: return;
255:
256: if (kernel_try_recover(frame))
257: return;
258:
259: if (va < KERNEL_LINEAR_BASE) {
260: /*
261: * This can happen on return to user mode
262: * when a private thread LDT contains
263: * unallocated virtual memory. Send an
264: * exception RPC, after carefully piecing
265: * the thread state back together.
266: */
267: kernel_recover_thread(state);
268:
269: _exception = EXC_BAD_ACCESS;
270: code = result;
271: subcode = va;
272: exception_from_kernel(_exception, code, subcode);
273: thread_exception_return();
274: /* NOTREACHED */
275: }
276: break;
277:
278: case T_GENERAL_PROTECTION:
279: case T_SEGMENT_NOTPRESENT:
280: case T_STACK_EXCEPTION:
281: if (frame->err.normal.tbl == ERR_LDT) {
282: /*
283: * This can happen on return to user mode
284: * when one of the segment registers refers
285: * to a descriptor that is invalid for some
286: * reason or another. Send an exception RPC,
287: * after carefully piecing the thread state
288: * back together.
289: */
290: kernel_recover_thread(state);
291:
292: _exception = EXC_BAD_INSTRUCTION;
293: code = trapno;
294: subcode = err_to_error_code(frame->err);
295: exception_from_kernel(_exception, code, subcode);
296: thread_exception_return();
297: /* NOTREACHED */
298: }
299: break;
300:
301: case T_INVALID_TSS:
302: if ((frame->eflags & EFL_NT) != 0) {
303: /*
304: * This can happen on return to user mode
305: * when a thread managed to set the NT flag
306: * and then entered the kernel through a call
307: * gate. The fix is to redo the IRET, since
308: * the NT flag cannot be set at this point (we
309: * just came through a trap gate to get here).
310: */
311: kernel_recover_thread(state);
312: thread_exception_return();
313: /* NOTREACHED */
314: }
315: break;
316: }
317:
318: if (kernel_try_recover(frame))
319: return;
320:
321: #if GDB
322: DoSafeAlert("Kernel Trap", "", FALSE);
323: printf("unexpected kernel trap %x eip %x\n", trapno, frame->eip);
324: switch (trapno) {
325:
326: case T_ZERO_DIVIDE:
327: _exception = EXC_ARITHMETIC;
328: code = EXC_I386_ZERO_DIVIDE;
329: break;
330:
331: case T_OVERFLOW:
332: _exception = EXC_SOFTWARE;
333: code = EXC_I386_OVERFLOW;
334: break;
335:
336: case T_BOUNDS_CHECK:
337: _exception = EXC_ARITHMETIC;
338: code = EXC_I386_BOUNDS_CHECK;
339: break;
340:
341: case T_INVALID_OPCODE:
342: _exception = EXC_BAD_INSTRUCTION;
343: code = EXC_I386_INVALID_OPCODE;
344: break;
345:
346: case T_SEGMENT_NOTPRESENT:
347: _exception = EXC_BAD_INSTRUCTION;
348: code = EXC_I386_SEGMENT_NOTPRESENT;
349: subcode = err_to_error_code(frame->err);
350: break;
351:
352: case T_STACK_EXCEPTION:
353: _exception = EXC_BAD_INSTRUCTION;
354: code = EXC_I386_STACK_EXCEPTION;
355: subcode = err_to_error_code(frame->err);
356: break;
357:
358: case T_GENERAL_PROTECTION:
359: _exception = EXC_BAD_INSTRUCTION;
360: code = EXC_I386_GENERAL_PROTECTION;
361: subcode = err_to_error_code(frame->err);
362: break;
363:
364: case T_PAGE_FAULT:
365: _exception = EXC_BAD_ACCESS;
366: code = result;
367: subcode = va;
368: break;
369:
370: case T_ALIGNMENT_CHECK:
371: _exception = EXC_SOFTWARE;
372: code = EXC_I386_ALIGNMENT_CHECK;
373: break;
374:
375: default:
376: _exception = EXC_BAD_INSTRUCTION;
377: code = trapno;
378: break;
379: }
380:
381: _i386_backtrace(state->regs.ebp, N_BACKTRACE);
382:
383: kdp_raise_exception(_exception, code, subcode, state);
384: DoRestore();
385: panic("continued after kernel trap");
386: #else
387: printf("unexpected kernel trap %x eip %x\n", trapno, frame->eip);
388: panic("kernel trap");
389: #endif
390: }
391:
392: static
393: kern_return_t
394: kernel_pagefault(
395: vm_offset_t va,
396: except_frame_t *frame
397: )
398: {
399: thread_t thread = current_thread();
400: vm_map_t map;
401: kern_return_t result;
402:
403: if (thread == THREAD_NULL)
404: map = kernel_map;
405: else {
406: map = thread->task->map;
407: if (vm_map_pmap(map) != kernel_pmap)
408: map = kernel_map;
409: }
410:
411: result = vm_fault(map, trunc_page(va - KERNEL_LINEAR_BASE),
412: frame->err.pgfault.wrtflt?
413: VM_PROT_READ | VM_PROT_WRITE:
414: VM_PROT_READ,
415: FALSE, 0);
416:
417: return (result);
418: }
419:
420: static
421: void
422: kernel_debug_trap(
423: thread_saved_state_t *state
424: )
425: {
426: except_frame_t *frame = &state->frame;
427: int code;
428: dr6_t debug = (dr6_t) { 0 };
429: extern void unix_syscall_(void),
430: mach_kernel_trap_(void),
431: machdep_call_(void);
432:
433: // Clear debug status
434: set_dr6(debug);
435:
436: if (state->trapno == T_DEBUG) {
437: if ( frame->eip == (unsigned int)unix_syscall_ ||
438: frame->eip == (unsigned int)mach_kernel_trap_ ||
439: frame->eip == (unsigned int)machdep_call_ ) {
440: current_thread()->pcb->trace = TRUE;
441: frame->eflags &= ~EFL_TF;
442: return;
443: }
444: code = EXC_I386_DEBUG;
445: }
446: else
447: code = EXC_I386_BREAKPOINT;
448:
449: #if GDB
450: kdp_raise_exception(EXC_BREAKPOINT, code, 0, state);
451: #else
452: panic("kernel debug trap");
453: #endif
454: }
455:
456: static
457: boolean_t
458: kernel_try_recover(
459: except_frame_t *frame
460: )
461: {
462: vm_offset_t recover = current_thread()->recover;
463:
464: if (recover != 0) {
465: frame->eip = recover;
466: frame->cs = KCS_SEL;
467: frame->eflags &= ~EFL_DF;
468: }
469: else
470: return (FALSE);
471:
472: current_thread()->recover = 0;
473:
474: return (TRUE);
475: }
476:
477: static
478: void
479: kernel_recover_thread(
480: thread_saved_state_t *state
481: )
482: {
483: thread_saved_state_t *user_regs = USER_REGS(current_thread());
484: vm_offset_t stack_ptr = (vm_offset_t)&state->frame.esp;
485:
486: user_regs->frame.err = state->frame.err;
487:
488: if (stack_ptr > (vm_offset_t)&user_regs->regs.ds) {
489:
490: user_regs->regs.eax = state->regs.eax;
491: user_regs->regs.ecx = state->regs.ecx;
492: user_regs->regs.edx = state->regs.edx;
493: user_regs->regs.ebx = state->regs.ebx;
494: user_regs->regs.ebp = state->regs.ebp;
495: user_regs->regs.esi = state->regs.esi;
496: user_regs->regs.edi = state->regs.edi;
497:
498: user_regs->regs.ds = state->regs.ds;
499: user_regs->regs.es = state->regs.es;
500: user_regs->regs.fs = state->regs.fs;
501: user_regs->regs.gs = state->regs.gs;
502: }
503: else if (stack_ptr > (vm_offset_t)&user_regs->regs.es) {
504: user_regs->regs.es = state->regs.es;
505: user_regs->regs.fs = state->regs.fs;
506: user_regs->regs.gs = state->regs.gs;
507: }
508: else if (stack_ptr > (vm_offset_t)&user_regs->regs.fs) {
509: user_regs->regs.fs = state->regs.fs;
510: user_regs->regs.gs = state->regs.gs;
511: }
512: else if (stack_ptr > (vm_offset_t)&user_regs->regs.gs)
513: user_regs->regs.gs = state->regs.gs;
514: }
515:
516: static inline
517: void
518: check_for_trace(
519: thread_saved_state_t *state
520: )
521: {
522: thread_t thread = current_thread();
523:
524: if (thread->pcb->trace) {
525: thread->pcb->trace = FALSE;
526: state->frame.eflags |= EFL_TF;
527: }
528: }
529:
530: void
531: machdep_call(
532: thread_saved_state_t *state
533: )
534: {
535: except_frame_t *frame = &state->frame;
536: regs_t *regs = &state->regs;
537: int trapno, nargs;
538: machdep_call_t *entry;
539:
540: check_for_trace(state);
541:
542: trapno = regs->eax;
543: if (trapno < 0 || trapno >= machdep_call_count) {
544: regs->eax = (unsigned int)kern_invalid();
545:
546: thread_exception_return();
547: /* NOTREACHED */
548: }
549:
550: entry = &machdep_call_table[trapno];
551: nargs = entry->nargs;
552:
553: if (nargs > 0) {
554: int args[nargs];
555:
556: if (copyin(frame->esp + sizeof (int),
557: args,
558: nargs * sizeof (int))) {
559:
560: regs->eax = KERN_INVALID_ADDRESS;
561:
562: thread_exception_return();
563: /* NOTREACHED */
564: }
565:
566: asm volatile("
567: 1:
568: mov (%2),%%eax;
569: pushl %%eax;
570: sub $4,%2;
571: dec %1;
572: jne 1b;
573: mov %3,%%eax;
574: call *%%eax;
575: mov %%eax,%0"
576:
577: : "=r" (regs->eax)
578: : "r" (nargs),
579: "r" (&args[nargs - 1]),
580: "g" (entry->routine)
581: : "ax", "cx", "dx", "sp");
582: }
583: else
584: regs->eax = (unsigned int)(*entry->routine)();
585:
586: thread_exception_return();
587: /* NOTREACHED */
588: }
589:
590: void
591: mach_kernel_trap(
592: thread_saved_state_t *state
593: )
594: {
595: except_frame_t *frame = &state->frame;
596: regs_t *regs = &state->regs;
597: int trapno, nargs;
598: mach_trap_t *entry;
599:
600: check_for_trace(state);
601:
602: trapno = -(int)regs->eax;
603: if (trapno < 0 || trapno >= mach_trap_count) {
604: regs->eax = (unsigned int)kern_invalid();
605:
606: thread_exception_return();
607: /* NOTREACHED */
608: }
609:
610: entry = &mach_trap_table[trapno];
611: nargs = entry->mach_trap_arg_count;
612:
613: if (nargs > 0) {
614: int args[nargs];
615:
616: if (copyin(frame->esp + sizeof (int),
617: args,
618: nargs * sizeof (int))) {
619:
620: exception(EXC_BAD_ACCESS,
621: KERN_INVALID_ADDRESS,
622: frame->esp + sizeof (int));
623: /* NOTREACHED */
624: }
625:
626: asm volatile("
627: 1:
628: mov (%2),%%eax;
629: pushl %%eax;
630: sub $4,%2;
631: dec %1;
632: jne 1b;
633: mov %3,%%eax;
634: call *%%eax;
635: mov %%eax,%0"
636:
637: : "=r" (regs->eax)
638: : "r" (nargs),
639: "r" (&args[nargs - 1]),
640: "g" (entry->mach_trap_function)
641: : "ax", "cx", "dx", "sp");
642: }
643: else
644: regs->eax = (unsigned int)(*entry->mach_trap_function)();
645:
646: thread_exception_return();
647: /* NOTREACHED */
648: }
649:
650: void
651: unix_syscall(
652: thread_saved_state_t *state
653: )
654: {
655: except_frame_t *frame = &state->frame;
656: regs_t *regs = &state->regs;
657: thread_t thread = current_thread();
658: struct uthread *uthread;
659: struct sysent *callp;
660: struct proc *p;
661: struct timeval syst;
662: int nargs, error = 0;
663: unsigned short code;
664: caddr_t params;
665: int rval[2];
666:
667: check_for_trace(state);
668:
669: uthread = thread->_uthread;
670: uthread->uu_ar0 = (int *)state;
671: if (p = current_proc())
672: syst = p->p_stats->p_ru.ru_stime;
673:
674: code = regs->eax;
675: params = (caddr_t)frame->esp + sizeof (int);
676: callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
677: if (callp == sysent) {
678: code = fuword(params);
679: params += sizeof (int);
680: callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
681: }
682:
683: if ((nargs = (callp->sy_narg * sizeof (int))) &&
684: (error = copyin(params, (caddr_t)uthread->uu_arg, nargs)) != 0) {
685: regs->eax = error;
686: frame->eflags |= EFL_CF;
687: thread_exception_return();
688: /* NOTREACHED */
689: }
690:
691: rval[0] = 0;
692: rval[1] = regs->edx;
693:
694: error = (*(callp->sy_call))(p, (caddr_t)uthread->uu_arg, rval);
695:
696: if (error == ERESTART) {
697: state->frame.eip -= 7;
698: }
699: else if (error != EJUSTRETURN) {
700: if (error) {
701: state->regs.eax = error;
702: state->frame.eflags |= EFL_CF; /* carry bit */
703: } else { /* (not error) */
704: state->regs.eax = rval[0];
705: state->regs.edx = rval[1];
706: state->frame.eflags &= ~EFL_CF;
707: }
708: }
709: /* else (error == EJUSTRETURN) { nothing } */
710:
711: thread_exception_return();
712: /* NOTREACHED */
713:
714: }
715:
716:
717: void
718: check_for_ast(
719: thread_saved_state_t *state
720: )
721: {
722: thread_t thread = current_thread();
723: struct proc *p = current_proc();
724:
725: while (TRUE) {
726: ast_t reasons;
727: int mycpu = cpu_number();
728: int signum;
729:
730: cli(); // disable interrupts
731:
732: reasons = ast_needed(mycpu);
733:
734: if (p) {
735: if ((p->p_flag & P_OWEUPC) && (p->p_flag & P_PROFIL)) {
736: addupc_task(p, state->frame.eip, 1);
737: p->p_flag &= ~P_OWEUPC;
738: }
739:
740: ast_off(mycpu, AST_UNIX);
741:
742: if (CHECK_SIGNALS(p, thread, thread->_uthread)) {
743: signum = issignal(p);
744: if (signum)
745: postsig(signum);
746: cli();
747: }
748: }
749:
750: ast_off(mycpu, reasons);
751:
752: if (thread_should_halt(thread))
753: thread_halt_self();
754: else
755: if ((reasons & AST_BLOCK) ||
756: csw_needed(thread, current_processor())) {
757: p->p_stats->p_ru.ru_nivcsw++;
758: thread_block_with_continuation(thread_exception_return);
759: }
760: else
761: if (reasons & AST_FP_EXTEN)
762: fp_ast(thread);
763: else
764: break;
765: }
766: }
767:
768: typedef struct _cframe_t {
769: struct _cframe_t *prev;
770: unsigned caller;
771: unsigned args[0];
772: } cframe_t;
773:
774:
775: #define MAX_FRAME_DELTA 65536
776:
777: void
778: _i386_backtrace(
779: void *_frame,
780: int nframes
781: )
782: {
783: cframe_t *frame = (cframe_t *)_frame;
784: int i;
785:
786: for (i=0; i<nframes; i++) {
787: if ((vm_offset_t)frame < VM_MIN_KERNEL_ADDRESS ||
788: (vm_offset_t)frame > VM_MAX_KERNEL_ADDRESS) {
789: goto invalid;
790: }
791: safe_prf("frame %x called by %x ",
792: frame, frame->caller);
793: safe_prf("args %x %x %x %x\n",
794: frame->args[0], frame->args[1],
795: frame->args[2], frame->args[3]);
796: if ((frame->prev < frame) || /* wrong direction */
797: ((frame->prev - frame) > MAX_FRAME_DELTA)) {
798: goto invalid;
799: }
800: frame = frame->prev;
801: }
802: return;
803: invalid:
804: safe_prf("invalid frame pointer %x\n",frame->prev);
805: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.