|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50: /*
51: */
52:
53: #include <mach_kdb.h>
54:
55: #include <mach/boolean.h>
56: #include <mach/kern_return.h>
57: #include <mach/message.h>
58: #include <mach/port.h>
59: #include <mach/mig_errors.h>
60: #include <mach/thread_status.h>
61: #include <mach/exception_types.h>
62: #include <ipc/port.h>
63: #include <ipc/ipc_entry.h>
64: #include <ipc/ipc_object.h>
65: #include <ipc/ipc_notify.h>
66: #include <ipc/ipc_space.h>
67: #include <ipc/ipc_pset.h>
68: #include <ipc/ipc_machdep.h>
69: #include <kern/etap_macros.h>
70: #include <kern/counters.h>
71: #include <kern/ipc_tt.h>
72: #include <kern/task.h>
73: #include <kern/thread.h>
74: #include <kern/thread_swap.h>
75: #include <kern/processor.h>
76: #include <kern/sched.h>
77: #include <kern/sched_prim.h>
78: #include <kern/host.h>
79: #include <kern/misc_protos.h>
80: #include <string.h>
81: #include <mach/exc.h> /* JMM - will become exception.h */
82: #include <machine/machine_rpc.h>
83:
84: #if MACH_KDB
85: #include <ddb/db_trap.h>
86: #endif /* MACH_KDB */
87:
88: /*
89: * Forward declarations
90: */
91: void exception_try_task(
92: exception_type_t exception,
93: exception_data_t code,
94: mach_msg_type_number_t codeCnt);
95:
96: void exception_no_server(void);
97:
98: kern_return_t alert_exception_try_task(
99: exception_type_t exception,
100: exception_data_t code,
101: int codeCnt);
102:
103: #if MACH_KDB
104:
105: #include <ddb/db_output.h>
106:
107: #if iPSC386 || iPSC860
108: boolean_t debug_user_with_kdb = TRUE;
109: #else
110: boolean_t debug_user_with_kdb = FALSE;
111: #endif
112:
113: #endif /* MACH_KDB */
114:
115: unsigned long c_thr_exc_raise = 0;
116: unsigned long c_thr_exc_raise_state = 0;
117: unsigned long c_thr_exc_raise_state_id = 0;
118: unsigned long c_tsk_exc_raise = 0;
119: unsigned long c_tsk_exc_raise_state = 0;
120: unsigned long c_tsk_exc_raise_state_id = 0;
121:
122:
123: #ifdef MACHINE_FAST_EXCEPTION /* from <machine/thread.h> if at all */
124: /*
125: * This is the fast, MD code, with lots of stuff in-lined.
126: */
127:
128: extern int switch_act_swapins;
129:
130: #ifdef i386
131: /*
132: * Temporary: controls the syscall copyin optimization.
133: * If TRUE, the exception function will copy in the first n
134: * words from the stack of the user thread and store it in
135: * the saved state, so that the server doesn't have to do
136: * this.
137: */
138: boolean_t syscall_exc_copyin = TRUE;
139: #endif
140:
141: /*
142: * Routine: exception
143: * Purpose:
144: * The current thread caught an exception.
145: * We make an up-call to the thread's exception server.
146: * Conditions:
147: * Nothing locked and no resources held.
148: * Called from an exception context, so
149: * thread_exception_return and thread_kdb_return
150: * are possible.
151: * Returns:
152: * Doesn't return.
153: */
154:
155: void
156: exception(
157: exception_type_t exception,
158: exception_data_t code,
159: mach_msg_type_number_t codeCnt )
160: {
161: thread_t self = current_thread();
162: thread_act_t a_self = self->top_act;
163: thread_act_t cln_act;
164: ipc_port_t exc_port;
165: int i;
166: struct exception_action *excp = &a_self->exc_actions[exception];
167: int flavor;
168: kern_return_t kr;
169:
170: assert(exception != EXC_RPC_ALERT);
171:
172: self->ith_scatter_list = MACH_MSG_BODY_NULL;
173:
174: /*
175: * Optimized version of retrieve_thread_exception.
176: */
177:
178: act_lock(a_self);
179: assert(a_self->ith_self != IP_NULL);
180: exc_port = excp->port;
181: if (!IP_VALID(exc_port)) {
182: act_unlock(a_self);
183: exception_try_task(exception, code, codeCnt);
184: /*NOTREACHED*/
185: return;
186: }
187: flavor = excp->flavor;
188:
189: #ifdef i386
190: /* For this flavor, we must copy in the first few procedure call
191: * args from the user's stack, since that is part of the important
192: * state in a syscall exception (this is for performance -- we
193: * can do the copyin much faster than the server, even if it is
194: * kernel-loaded):
195: */
196: if (flavor == i386_SAVED_STATE) {
197: struct i386_saved_state *statep = (struct i386_saved_state *)
198: act_machine_state_ptr(self->top_act);
199: statep->argv_status = FALSE;
200: if (syscall_exc_copyin && copyin((char *)statep->uesp,
201: (char *)statep->argv,
202: i386_SAVED_ARGV_COUNT * sizeof(int)) == 0) {
203: /* Indicate success for the server: */
204: statep->argv_status = TRUE;
205: }
206: }
207: #endif
208:
209: ETAP_EXCEPTION_PROBE(EVENT_BEGIN, self, exception, code);
210:
211: ip_lock(exc_port);
212: act_unlock(a_self);
213: if (!ip_active(exc_port)) {
214: ip_unlock(exc_port);
215: exception_try_task(exception, code, codeCnt);
216: /*NOTREACHED*/
217: return;
218: }
219:
220: /*
221: * Hold a reference to the port over the exception_raise_* calls
222: * so it can't be destroyed. This seems like overkill, but keeps
223: * the port from disappearing between now and when
224: * ipc_object_copyin_from_kernel is finally called.
225: */
226: ip_reference(exc_port);
227: exc_port->ip_srights++;
228: ip_unlock(exc_port);
229:
230: switch (excp->behavior) {
231: case EXCEPTION_STATE: {
232: mach_msg_type_number_t state_cnt;
233: {
234: natural_t state[ THREAD_MACHINE_STATE_MAX ];
235:
236: state_cnt = state_count[flavor];
237: kr = thread_getstatus(a_self, flavor, state, &state_cnt);
238: if (kr == KERN_SUCCESS) {
239: kr = exception_raise_state(exc_port, exception,
240: code, codeCnt,
241: &flavor,
242: state, state_cnt,
243: state, &state_cnt);
244: if (kr == MACH_MSG_SUCCESS)
245: kr = thread_setstatus(a_self, flavor, state, state_cnt);
246: }
247: }
248:
249: if (kr == KERN_SUCCESS ||
250: kr == MACH_RCV_PORT_DIED) {
251: ETAP_EXCEPTION_PROBE(EVENT_END, self, exception, code);
252: thread_exception_return();
253: /* NOTREACHED*/
254: return;
255: }
256: } break;
257:
258: case EXCEPTION_DEFAULT:
259: c_thr_exc_raise++;
260: kr = exception_raise(exc_port,
261: retrieve_act_self_fast(a_self),
262: retrieve_task_self_fast(a_self->task),
263: exception,
264: code, codeCnt);
265:
266: if (kr == KERN_SUCCESS ||
267: kr == MACH_RCV_PORT_DIED) {
268: ETAP_EXCEPTION_PROBE(EVENT_END, self, exception, code);
269: thread_exception_return();
270: /* NOTREACHED*/
271: return;
272: }
273: break;
274:
275: case EXCEPTION_STATE_IDENTITY: {
276: mach_msg_type_number_t state_cnt;
277: natural_t state[ THREAD_MACHINE_STATE_MAX ];
278:
279: c_thr_exc_raise_state_id++;
280: state_cnt = state_count[flavor];
281: kr = thread_getstatus(a_self, flavor, state, &state_cnt);
282: if (kr == KERN_SUCCESS) {
283: kr = exception_raise_state_identity(exc_port,
284: retrieve_act_self_fast(a_self),
285: retrieve_task_self_fast(a_self->task),
286: exception,
287: code, codeCnt,
288: &flavor,
289: state, state_cnt,
290: state, &state_cnt);
291: if (kr == MACH_MSG_SUCCESS)
292: kr = thread_setstatus(a_self, flavor, state, state_cnt);
293: }
294:
295: if (kr == KERN_SUCCESS ||
296: kr == MACH_RCV_PORT_DIED) {
297: ETAP_EXCEPTION_PROBE(EVENT_END, self, exception, code);
298: thread_exception_return();
299: /* NOTREACHED*/
300: return;
301: }
302: } break;
303: default:
304: panic ("bad behavior!");
305: }/* switch */
306:
307: /*
308: * When a task is being terminated, it's no longer ripped
309: * directly out of the rcv from its "kill me" message, and
310: * so returns here. The following causes it to return out
311: * to the glue code and clean itself up.
312: */
313: if ((self->top_act && !self->top_act->active) ||
314: (self->state & TH_ABORT)) {
315: ETAP_EXCEPTION_PROBE(EVENT_END, self, exception, code);
316: thread_exception_return();
317: }
318:
319: exception_try_task(exception, code, codeCnt);
320: /* NOTREACHED */
321: }
322:
323: /*
324: * We only use the machine-independent exception() routine
325: * if a faster MD version isn't available.
326: */
327: #else /* MACHINE_FAST_EXCEPTION */
328: /*
329: * If continuations are not used/supported, the NOTREACHED comments
330: * below are incorrect. The exception function is expected to return.
331: * So the return statements along the slow paths are important.
332: */
333:
334: /*
335: * Routine: exception
336: * Purpose:
337: * The current thread caught an exception.
338: * We make an up-call to the thread's exception server.
339: * Conditions:
340: * Nothing locked and no resources held.
341: * Called from an exception context, so
342: * thread_exception_return and thread_kdb_return
343: * are possible.
344: * Returns:
345: * Doesn't return.
346: */
347:
348: void
349: exception(
350: exception_type_t exception,
351: exception_data_t code,
352: mach_msg_type_number_t codeCnt)
353: {
354: thread_t self = current_thread();
355: thread_act_t a_self = self->top_act;
356: ipc_port_t exc_port;
357: int i;
358: struct exception_action *excp = &a_self->exc_actions[exception];
359: int flavor;
360: kern_return_t kr;
361:
362: assert(exception != EXC_RPC_ALERT);
363:
364: if (exception == KERN_SUCCESS)
365: panic("exception");
366:
367: self->ith_scatter_list = MACH_MSG_BODY_NULL;
368:
369: /*
370: * Optimized version of retrieve_thread_exception.
371: */
372:
373: act_lock(a_self);
374: assert(a_self->ith_self != IP_NULL);
375: exc_port = excp->port;
376: if (!IP_VALID(exc_port)) {
377: act_unlock(a_self);
378: exception_try_task(exception, code, codeCnt);
379: /*NOTREACHED*/
380: return;
381: }
382: flavor = excp->flavor;
383:
384: ip_lock(exc_port);
385: act_unlock(a_self);
386: if (!ip_active(exc_port)) {
387: ip_unlock(exc_port);
388: exception_try_task(exception, code, codeCnt);
389: /*NOTREACHED*/
390: return;
391: }
392:
393: /*
394: * Hold a reference to the port over the exception_raise_* calls
395: * so it can't be destroyed. This seems like overkill, but keeps
396: * the port from disappearing between now and when
397: * ipc_object_copyin_from_kernel is finally called.
398: */
399: ip_reference(exc_port);
400: exc_port->ip_srights++;
401: ip_unlock(exc_port);
402:
403: switch (excp->behavior) {
404: case EXCEPTION_STATE: {
405: mach_msg_type_number_t state_cnt;
406:
407: c_thr_exc_raise_state++;
408: {
409: natural_t state[ THREAD_MACHINE_STATE_MAX ];
410:
411: state_cnt = state_count[flavor];
412: kr = thread_getstatus(a_self, flavor,
413: (thread_state_t)state,
414: &state_cnt);
415: if (kr == KERN_SUCCESS) {
416: kr = exception_raise_state(exc_port, exception,
417: code, codeCnt,
418: &flavor,
419: state, state_cnt,
420: state, &state_cnt);
421: if (kr == MACH_MSG_SUCCESS)
422: kr = thread_setstatus(a_self, flavor,
423: (thread_state_t)state,
424: state_cnt);
425: }
426: }
427:
428: if (kr == KERN_SUCCESS ||
429: kr == MACH_RCV_PORT_DIED) {
430: thread_exception_return();
431: /*NOTREACHED*/
432: return;
433: }
434: } break;
435:
436: case EXCEPTION_DEFAULT:
437: c_thr_exc_raise++;
438: kr = exception_raise(exc_port,
439: retrieve_act_self_fast(a_self),
440: retrieve_task_self_fast(a_self->task),
441: exception,
442: code, codeCnt);
443:
444: if (kr == KERN_SUCCESS ||
445: kr == MACH_RCV_PORT_DIED) {
446: thread_exception_return();
447: /*NOTREACHED*/
448: return;
449: }
450: break;
451:
452: case EXCEPTION_STATE_IDENTITY: {
453: mach_msg_type_number_t state_cnt;
454: natural_t state[ THREAD_MACHINE_STATE_MAX ];
455:
456: c_thr_exc_raise_state_id++;
457: state_cnt = state_count[flavor];
458: kr = thread_getstatus(a_self, flavor,
459: (thread_state_t)state,
460: &state_cnt);
461: if (kr == KERN_SUCCESS) {
462: kr = exception_raise_state_identity(exc_port,
463: retrieve_act_self_fast(a_self),
464: retrieve_task_self_fast(a_self->task),
465: exception,
466: code, codeCnt,
467: &flavor,
468: state, state_cnt,
469: state, &state_cnt);
470: if (kr == MACH_MSG_SUCCESS)
471: kr = thread_setstatus(a_self, flavor,
472: (thread_state_t)state,
473: state_cnt);
474: }
475:
476: if (kr == KERN_SUCCESS ||
477: kr == MACH_RCV_PORT_DIED) {
478: thread_exception_return();
479: /*NOTREACHED*/
480: return;
481: }
482: } break;
483: default:
484: panic ("bad behavior!");
485: }/* switch */
486:
487: /*
488: * When a task is being terminated, it's no longer ripped
489: * directly out of the rcv from its "kill me" message, and
490: * so returns here. The following causes it to return out
491: * to the glue code and clean itself up.
492: */
493: if ((self->top_act && !self->top_act->active) ||
494: (self->state & TH_ABORT)) {
495: thread_exception_return();
496: /*NOTREACHED*/
497: }
498:
499: exception_try_task(exception, code, codeCnt);
500: /* NOTREACHED */
501: return;
502: }
503: #endif /* defined MACHINE_FAST_EXCEPTION */
504:
505: /*
506: * Routine: exception_try_task
507: * Purpose:
508: * The current thread caught an exception.
509: * We make an up-call to the task's exception server.
510: * Conditions:
511: * Nothing locked and no resources held.
512: * Called from an exception context, so
513: * thread_exception_return and thread_kdb_return
514: * are possible.
515: * Returns:
516: * Doesn't return.
517: */
518:
519: void
520: exception_try_task(
521: exception_type_t exception,
522: exception_data_t code,
523: mach_msg_type_number_t codeCnt)
524: {
525: thread_act_t a_self = current_act();
526: thread_t self = a_self->thread;
527: register task_t task = a_self->task;
528: register ipc_port_t exc_port;
529: int flavor, i;
530: kern_return_t kr;
531:
532: assert(exception != EXC_RPC_ALERT);
533:
534: self->ith_scatter_list = MACH_MSG_BODY_NULL;
535:
536: /*
537: * Optimized version of retrieve_task_exception.
538: */
539:
540: itk_lock(task);
541: assert(task->itk_self != IP_NULL);
542: exc_port = task->exc_actions[exception].port;
543: if (exception == EXC_MACH_SYSCALL && exc_port == realhost.host_self) {
544: itk_unlock(task);
545: restart_mach_syscall(); /* magic ! */
546: /* NOTREACHED */
547: }
548: if (!IP_VALID(exc_port)) {
549: itk_unlock(task);
550: exception_no_server();
551: /*NOTREACHED*/
552: return;
553: }
554: flavor = task->exc_actions[exception].flavor;
555:
556: ip_lock(exc_port);
557: itk_unlock(task);
558: if (!ip_active(exc_port)) {
559: ip_unlock(exc_port);
560: exception_no_server();
561: /*NOTREACHED*/
562: return;
563: }
564:
565: /*
566: * Hold a reference to the port over the exception_raise_* calls
567: * (see longer comment in exception())
568: */
569: ip_reference(exc_port);
570: exc_port->ip_srights++;
571: ip_unlock(exc_port);
572:
573: switch (task->exc_actions[exception].behavior) {
574: case EXCEPTION_STATE: {
575: mach_msg_type_number_t state_cnt;
576: {
577: natural_t state[ THREAD_MACHINE_STATE_MAX ];
578:
579: c_tsk_exc_raise_state++;
580: state_cnt = state_count[flavor];
581: kr = thread_getstatus(a_self, flavor, state, &state_cnt);
582: if (kr == KERN_SUCCESS) {
583: kr = exception_raise_state(exc_port, exception,
584: code, codeCnt,
585: &flavor,
586: state, state_cnt,
587: state, &state_cnt);
588: if (kr == MACH_MSG_SUCCESS)
589: kr = thread_setstatus(a_self, flavor, state, state_cnt);
590: }
591: }
592:
593: if (kr == KERN_SUCCESS ||
594: kr == MACH_RCV_PORT_DIED) {
595: ETAP_EXCEPTION_PROBE(EVENT_END, self, exception, code);
596: thread_exception_return();
597: /* NOTREACHED*/
598: return;
599: }
600: } break;
601:
602: case EXCEPTION_DEFAULT:
603: c_tsk_exc_raise++;
604: kr = exception_raise(exc_port,
605: retrieve_act_self_fast(a_self),
606: retrieve_task_self_fast(a_self->task),
607: exception, code, codeCnt);
608:
609: if (kr == KERN_SUCCESS ||
610: kr == MACH_RCV_PORT_DIED) {
611: thread_exception_return();
612: /*NOTREACHED*/
613: return;
614: }
615: break;
616:
617: case EXCEPTION_STATE_IDENTITY: {
618: mach_msg_type_number_t state_cnt;
619: natural_t state[ THREAD_MACHINE_STATE_MAX ];
620:
621: c_tsk_exc_raise_state_id++;
622: state_cnt = state_count[flavor];
623: kr = thread_getstatus(a_self, flavor, state, &state_cnt);
624: if (kr == KERN_SUCCESS) {
625: kr = exception_raise_state_identity(exc_port,
626: retrieve_act_self_fast(a_self),
627: retrieve_task_self_fast(a_self->task),
628: exception,
629: code, codeCnt,
630: &flavor,
631: state, state_cnt,
632: state, &state_cnt);
633: if (kr == KERN_SUCCESS)
634: kr = thread_setstatus(a_self, flavor, state, state_cnt);
635: }
636:
637: if (kr == MACH_MSG_SUCCESS || kr == MACH_RCV_PORT_DIED) {
638: thread_exception_return();
639: /*NOTREACHED*/
640: return;
641: }
642: } break;
643:
644: default:
645: panic ("bad behavior!");
646: }/* switch */
647:
648: exception_no_server();
649: /*NOTREACHED*/
650: }
651:
652: /*
653: * Routine: exception_no_server
654: * Purpose:
655: * The current thread took an exception,
656: * and no exception server took responsibility
657: * for the exception. So good bye, charlie.
658: * Conditions:
659: * Nothing locked and no resources held.
660: * Called from an exception context, so
661: * thread_kdb_return is possible.
662: * Returns:
663: * Doesn't return.
664: */
665:
666: void
667: exception_no_server(void)
668: {
669: register thread_t self = current_thread();
670:
671: /*
672: * If this thread is being terminated, cooperate.
673: *
674: * When a task is dying, it's no longer ripped
675: * directly out of the rcv from its "kill me" message, and
676: * so returns here. The following causes it to return out
677: * to the glue code and clean itself up.
678: */
679: if ((thread_should_halt(self)) || (self->state & TH_ABORT)) {
680: thread_exception_return();
681: panic("exception_no_server - 1");
682: }
683:
684:
685: if (self->top_act->task == kernel_task)
686: panic("kernel task terminating\n");
687:
688: #if MACH_KDB
689: if (debug_user_with_kdb) {
690: /*
691: * Debug the exception with kdb.
692: * If kdb handles the exception,
693: * then thread_kdb_return won't return.
694: */
695: db_printf("No exception server, calling kdb...\n");
696: #if iPSC860
697: db_printf("Dropping into ddb, avoiding thread_kdb_return\n");
698: gimmeabreak();
699: #endif
700: thread_kdb_return();
701: }
702: #endif /* MACH_KDB */
703:
704: /*
705: * All else failed; terminate task.
706: */
707:
708: (void) task_terminate(self->top_act->task);
709: thread_terminate_self();
710: /*NOTREACHED*/
711: panic("exception_no_server: returning!");
712: }
713:
714: #ifdef MACHINE_FAST_EXCEPTION /* from <machine/thread.h> if at all */
715: /*
716: * Routine: alert_exception
717: * Purpose:
718: * The current thread caught an exception.
719: * We make an up-call to the thread's exception server.
720: * Conditions:
721: * Nothing locked and no resources held.
722: * Returns:
723: * KERN_RPC_TERMINATE_ORPHAN - if orphan should be terminated
724: * KERN_RPC_CONTINUE_ORPHAN - if orphan should be allowed to
725: * continue execution
726: */
727:
728: kern_return_t
729: alert_exception(
730: exception_type_t exception,
731: exception_data_t code,
732: int codeCnt )
733: {
734: thread_t self = current_thread();
735: thread_act_t a_self = self->top_act;
736: thread_act_t cln_act;
737: ipc_port_t exc_port;
738: int i;
739: struct exception_action *excp = &a_self->exc_actions[exception];
740: int flavor;
741: kern_return_t kr;
742:
743: assert(exception == EXC_RPC_ALERT);
744:
745: self->ith_scatter_list = MACH_MSG_BODY_NULL;
746:
747: /*
748: * Optimized version of retrieve_thread_exception.
749: */
750:
751: act_lock(a_self);
752: assert(a_self->ith_self != IP_NULL);
753: exc_port = excp->port;
754: if (!IP_VALID(exc_port)) {
755: act_unlock(a_self);
756: return(alert_exception_try_task(exception, code, codeCnt));
757: }
758: flavor = excp->flavor;
759:
760: #ifdef i386
761: /* For this flavor, we must copy in the first few procedure call
762: * args from the user's stack, since that is part of the important
763: * state in a syscall exception (this is for performance -- we
764: * can do the copyin much faster than the server, even if it is
765: * kernel-loaded):
766: */
767: if (flavor == i386_SAVED_STATE) {
768: struct i386_saved_state *statep = (struct i386_saved_state *)
769: act_machine_state_ptr(self->top_act);
770: statep->argv_status = FALSE;
771: if (syscall_exc_copyin && copyin((char *)statep->uesp,
772: (char *)statep->argv,
773: i386_SAVED_ARGV_COUNT * sizeof(int)) == 0) {
774: /* Indicate success for the server: */
775: statep->argv_status = TRUE;
776: }
777: }
778: #endif
779:
780: ip_lock(exc_port);
781: act_unlock(a_self);
782: if (!ip_active(exc_port)) {
783: ip_unlock(exc_port);
784: return(alert_exception_try_task(exception, code, codeCnt));
785: }
786:
787: /*
788: * Hold a reference to the port over the exception_raise_* calls
789: * so it can't be destroyed. This seems like overkill, but keeps
790: * the port from disappearing between now and when
791: * ipc_object_copyin_from_kernel is finally called.
792: */
793: ip_reference(exc_port);
794: /* CHECKME! */
795: /* exc_port->ip_srights++; ipc_object_copy_from_kernel does this */
796: ip_unlock(exc_port);
797:
798: switch (excp->behavior) {
799: case EXCEPTION_STATE: {
800: mach_msg_type_number_t state_cnt;
801: {
802: natural_t state[ THREAD_MACHINE_STATE_MAX ];
803:
804: state_cnt = state_count[flavor];
805: kr = thread_getstatus(a_self, flavor, state, &state_cnt);
806: if (kr == KERN_SUCCESS) {
807: kr = exception_raise_state(exc_port, exception,
808: code, codeCnt,
809: &flavor,
810: state, state_cnt,
811: state, &state_cnt);
812: if (kr == MACH_MSG_SUCCESS)
813: kr = thread_setstatus(a_self, flavor, state, state_cnt);
814: }
815: }
816: ip_lock(exc_port);
817: ip_release(exc_port);
818: ip_unlock(exc_port);
819:
820: if (kr == KERN_SUCCESS ||
821: kr == MACH_RCV_PORT_DIED) {
822: return(KERN_RPC_TERMINATE_ORPHAN);
823: }
824: } break;
825:
826: case EXCEPTION_DEFAULT:
827: c_thr_exc_raise++;
828: kr = exception_raise(exc_port,
829: retrieve_act_self_fast(a_self),
830: retrieve_task_self_fast(a_self->task),
831: exception,
832: code, codeCnt);
833: ip_lock(exc_port);
834: ip_release(exc_port);
835: ip_unlock(exc_port);
836:
837: if (kr == KERN_SUCCESS ||
838: kr == MACH_RCV_PORT_DIED) {
839: return(KERN_RPC_TERMINATE_ORPHAN);
840: }
841: break;
842:
843: case EXCEPTION_STATE_IDENTITY: {
844: mach_msg_type_number_t state_cnt;
845: natural_t state[ THREAD_MACHINE_STATE_MAX ];
846:
847: c_thr_exc_raise_state_id++;
848: state_cnt = state_count[flavor];
849: kr = thread_getstatus(a_self, flavor, state, &state_cnt);
850: if (kr == KERN_SUCCESS) {
851: kr = exception_raise_state_identity(exc_port,
852: retrieve_act_self_fast(a_self),
853: retrieve_task_self_fast(a_self->task),
854: exception,
855: code, codeCnt,
856: &flavor,
857: state, state_cnt,
858: state, &state_cnt);
859: if (kr == MACH_MSG_SUCCESS)
860: kr = thread_setstatus(a_self, flavor, state, state_cnt);
861: }
862: ip_lock(exc_port);
863: ip_release(exc_port);
864: ip_unlock(exc_port);
865:
866: if (kr == KERN_SUCCESS ||
867: kr == MACH_RCV_PORT_DIED) {
868: return(KERN_RPC_TERMINATE_ORPHAN);
869: }
870: } break;
871: default:
872: panic ("bad behavior!");
873: }/* switch */
874:
875: /*
876: * When a task is being terminated, it's no longer ripped
877: * directly out of the rcv from its "kill me" message, and
878: * so returns here. The following causes it to return out
879: * to the glue code and clean itself up.
880: */
881: if (self->top_act && !self->top_act->active)
882: return(KERN_RPC_TERMINATE_ORPHAN);
883:
884: return(alert_exception_try_task(exception, code, codeCnt));
885: }
886: #else /* MACHINE_FAST_EXCEPTION */
887:
888: /*
889: * Routine: alert_exception
890: * Purpose:
891: * The current thread caught an exception.
892: * We make an up-call to the thread's exception server.
893: * Conditions:
894: * Nothing locked and no resources held.
895: * Returns:
896: * KERN_RPC_TERMINATE_ORPHAN - if orphan should be terminated
897: * KERN_RPC_CONTINUE_ORPHAN - if orphan should be allowed to
898: * continue execution
899: */
900:
901: kern_return_t
902: alert_exception(
903: exception_type_t exception,
904: exception_data_t code,
905: int codeCnt )
906: {
907: thread_t self = current_thread();
908: thread_act_t a_self = self->top_act;
909: ipc_port_t exc_port;
910: int i;
911: struct exception_action *excp = &a_self->exc_actions[exception];
912: int flavor;
913: kern_return_t kr;
914:
915: assert(exception == EXC_RPC_ALERT);
916:
917: self->ith_scatter_list = MACH_MSG_BODY_NULL;
918:
919: /*
920: * Optimized version of retrieve_thread_exception.
921: */
922:
923: act_lock(a_self);
924: assert(a_self->ith_self != IP_NULL);
925: exc_port = excp->port;
926: if (!IP_VALID(exc_port)) {
927: act_unlock(a_self);
928: return(alert_exception_try_task(exception, code, codeCnt));
929: }
930: flavor = excp->flavor;
931:
932: ip_lock(exc_port);
933: act_unlock(a_self);
934: if (!ip_active(exc_port)) {
935: ip_unlock(exc_port);
936: return(alert_exception_try_task(exception, code, codeCnt));
937: }
938:
939: /*
940: * Hold a reference to the port over the exception_raise_* calls
941: * so it can't be destroyed. This seems like overkill, but keeps
942: * the port from disappearing between now and when
943: * ipc_object_copyin_from_kernel is finally called.
944: */
945: ip_reference(exc_port);
946: /* CHECKME! */
947: /* exc_port->ip_srights++; ipc_object_copy_from_kernel does this */
948: ip_unlock(exc_port);
949:
950: switch (excp->behavior) {
951: case EXCEPTION_STATE: {
952: mach_msg_type_number_t state_cnt;
953: rpc_subsystem_t subsystem = ((ipc_port_t)exc_port)->ip_subsystem;
954:
955: c_thr_exc_raise_state++;
956: if (flavor == MACHINE_THREAD_STATE &&
957: subsystem &&
958: is_fast_space(exc_port->ip_receiver)) {
959: natural_t *statep;
960: /* Requested flavor is the same format in which
961: * we save state on this machine, so no copy is
962: * necessary. Obtain direct pointer to saved state:
963: */
964: statep = act_machine_state_ptr(self->top_act);
965: state_cnt = MACHINE_THREAD_STATE_COUNT;
966: kr = exception_raise_state(exc_port, exception,
967: code, codeCnt,
968: &flavor,
969: statep, state_cnt,
970: statep, &state_cnt);
971: /* Server is required to return same flavor: */
972: assert(flavor == MACHINE_THREAD_STATE);
973: } else {
974: natural_t state[ THREAD_MACHINE_STATE_MAX ];
975:
976: state_cnt = state_count[flavor];
977: kr = thread_getstatus(a_self, flavor,
978: (thread_state_t)state,
979: &state_cnt);
980: if (kr == KERN_SUCCESS) {
981: kr = exception_raise_state(exc_port, exception,
982: code, codeCnt,
983: &flavor,
984: state, state_cnt,
985: state, &state_cnt);
986: if (kr == MACH_MSG_SUCCESS)
987: kr = thread_setstatus(a_self, flavor,
988: (thread_state_t)state,
989: state_cnt);
990: }
991: }
992: ip_lock(exc_port);
993: ip_release(exc_port);
994: ip_unlock(exc_port);
995:
996: if (kr == KERN_SUCCESS ||
997: kr == MACH_RCV_PORT_DIED) {
998: return(KERN_RPC_TERMINATE_ORPHAN);
999: }
1000: } break;
1001:
1002: case EXCEPTION_DEFAULT:
1003: c_thr_exc_raise++;
1004: kr = exception_raise(exc_port,
1005: retrieve_act_self_fast(a_self),
1006: retrieve_task_self_fast(a_self->task),
1007: exception,
1008: code, codeCnt);
1009: ip_lock(exc_port);
1010: ip_release(exc_port);
1011: ip_unlock(exc_port);
1012:
1013: if (kr == KERN_SUCCESS ||
1014: kr == MACH_RCV_PORT_DIED) {
1015: return(KERN_RPC_TERMINATE_ORPHAN);
1016: }
1017: break;
1018:
1019: case EXCEPTION_STATE_IDENTITY: {
1020: mach_msg_type_number_t state_cnt;
1021: natural_t state[ THREAD_MACHINE_STATE_MAX ];
1022:
1023: c_thr_exc_raise_state_id++;
1024: state_cnt = state_count[flavor];
1025: kr = thread_getstatus(a_self, flavor,
1026: (thread_state_t)state,
1027: &state_cnt);
1028: if (kr == KERN_SUCCESS) {
1029: kr = exception_raise_state_identity(exc_port,
1030: retrieve_act_self_fast(a_self),
1031: retrieve_task_self_fast(a_self->task),
1032: exception,
1033: code, codeCnt,
1034: &flavor,
1035: state, state_cnt,
1036: state, &state_cnt);
1037: if (kr == MACH_MSG_SUCCESS)
1038: kr = thread_setstatus(a_self, flavor,
1039: (thread_state_t)state,
1040: state_cnt);
1041: }
1042: ip_lock(exc_port);
1043: ip_release(exc_port);
1044: ip_unlock(exc_port);
1045:
1046: if (kr == KERN_SUCCESS ||
1047: kr == MACH_RCV_PORT_DIED) {
1048: return(KERN_RPC_TERMINATE_ORPHAN);
1049: }
1050: } break;
1051: default:
1052: panic ("bad behavior!");
1053: }/* switch */
1054:
1055: /*
1056: * When a task is being terminated, it's no longer ripped
1057: * directly out of the rcv from its "kill me" message, and
1058: * so returns here. The following causes it to return out
1059: * to the glue code and clean itself up.
1060: */
1061: if (thread_should_halt(self)) {
1062: return(KERN_RPC_TERMINATE_ORPHAN);
1063: }
1064:
1065: return(alert_exception_try_task(exception, code, codeCnt));
1066: }
1067: #endif /* defined MACHINE_FAST_EXCEPTION */
1068:
1069: /*
1070: * Routine: alert_exception_try_task
1071: * Purpose:
1072: * The current thread caught an exception.
1073: * We make an up-call to the task's exception server.
1074: * Conditions:
1075: * Nothing locked and no resources held.
1076: * Returns:
1077: * KERN_RPC_TERMINATE_ORPHAN - if orphan should be terminated
1078: * KERN_RPC_CONTINUE_ORPHAN - if orphan should be allowed to
1079: * continue execution
1080: */
1081:
1082: kern_return_t
1083: alert_exception_try_task(
1084: exception_type_t exception,
1085: exception_data_t code,
1086: int codeCnt )
1087: {
1088: thread_act_t a_self = current_act();
1089: thread_t self = a_self->thread;
1090: register task_t task = a_self->task;
1091: register ipc_port_t exc_port;
1092: int flavor;
1093: kern_return_t kr;
1094:
1095: assert(exception == EXC_RPC_ALERT);
1096:
1097: self->ith_scatter_list = MACH_MSG_BODY_NULL;
1098:
1099: /*
1100: * Optimized version of retrieve_task_exception.
1101: */
1102:
1103: itk_lock(task);
1104: assert(task->itk_self != IP_NULL);
1105: exc_port = task->exc_actions[exception].port;
1106: if (!IP_VALID(exc_port)) {
1107: itk_unlock(task);
1108: return(KERN_RPC_CONTINUE_ORPHAN);
1109: }
1110: flavor = task->exc_actions[exception].flavor;
1111:
1112: ip_lock(exc_port);
1113: itk_unlock(task);
1114: if (!ip_active(exc_port)) {
1115: ip_unlock(exc_port);
1116: return(KERN_RPC_CONTINUE_ORPHAN);
1117: }
1118:
1119: /*
1120: * Hold a reference to the port over the exception_raise_* calls
1121: * (see longer comment in exception())
1122: */
1123: ip_reference(exc_port);
1124: /* CHECKME! */
1125: /* exc_port->ip_srights++; */
1126: ip_unlock(exc_port);
1127:
1128: switch (task->exc_actions[exception].behavior) {
1129: case EXCEPTION_STATE: {
1130: mach_msg_type_number_t state_cnt;
1131: natural_t state[ THREAD_MACHINE_STATE_MAX ];
1132:
1133: c_tsk_exc_raise_state++;
1134: state_cnt = state_count[flavor];
1135: kr = thread_getstatus(a_self, flavor, state, &state_cnt);
1136: if (kr == KERN_SUCCESS) {
1137: kr = exception_raise_state(exc_port, exception,
1138: code, codeCnt,
1139: &flavor,
1140: state, state_cnt,
1141: state, &state_cnt);
1142: if (kr == KERN_SUCCESS)
1143: kr = thread_setstatus(a_self, flavor, state, state_cnt);
1144: }
1145: ip_lock(exc_port);
1146: ip_release(exc_port);
1147: ip_unlock(exc_port);
1148:
1149: if (kr == MACH_MSG_SUCCESS || kr == MACH_RCV_PORT_DIED) {
1150: return(KERN_RPC_TERMINATE_ORPHAN);
1151: }
1152: } break;
1153:
1154: case EXCEPTION_DEFAULT:
1155: c_tsk_exc_raise++;
1156: kr = exception_raise(exc_port,
1157: retrieve_act_self_fast(a_self),
1158: retrieve_task_self_fast(a_self->task),
1159: exception, code, codeCnt);
1160: ip_lock(exc_port);
1161: ip_release(exc_port);
1162: ip_unlock(exc_port);
1163:
1164: if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) {
1165: return(KERN_RPC_TERMINATE_ORPHAN);
1166: }
1167: break;
1168:
1169: case EXCEPTION_STATE_IDENTITY: {
1170: mach_msg_type_number_t state_cnt;
1171: natural_t state[ THREAD_MACHINE_STATE_MAX ];
1172:
1173: c_tsk_exc_raise_state_id++;
1174: state_cnt = state_count[flavor];
1175: kr = thread_getstatus(a_self, flavor, state, &state_cnt);
1176: if (kr == KERN_SUCCESS) {
1177: kr = exception_raise_state_identity(exc_port,
1178: retrieve_act_self_fast(a_self),
1179: retrieve_task_self_fast(a_self->task),
1180: exception,
1181: code, codeCnt,
1182: &flavor,
1183: state, state_cnt,
1184: state, &state_cnt);
1185: if (kr == KERN_SUCCESS)
1186: kr = thread_setstatus(a_self, flavor, state, state_cnt);
1187: }
1188: ip_lock(exc_port);
1189: ip_release(exc_port);
1190: ip_unlock(exc_port);
1191:
1192: if (kr == MACH_MSG_SUCCESS || kr == MACH_RCV_PORT_DIED) {
1193: return(KERN_RPC_TERMINATE_ORPHAN);
1194: }
1195: } break;
1196:
1197: default:
1198: panic ("bad behavior!");
1199: }/* switch */
1200:
1201: return(KERN_RPC_CONTINUE_ORPHAN);
1202: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.