1 #include "execserverServer.h"
4 #include <mach/vm_map.h>
10 #include <dispatch/dispatch.h>
14 #include <System/sys/reason.h>
15 #include <System/sys/proc_info.h>
19 static pid_t sChildPid
;
20 static dispatch_semaphore_t sServerRunning
;
21 static bool sChildCrashed
= false;
22 static bool sChildTerminatedByDyld
= false;
25 * setup exception handling port for EXC_CRASH and EXC_CORPSE_NOTIFY.
26 * runs mach_msg_server once for receiving exception messages from kernel.
28 static void* serverCode(void* arg
)
30 mach_port_t exception_port
;
32 kern_return_t kret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &exception_port
);
33 if (kret
!= KERN_SUCCESS
)
34 errx(1, "mach_port_allocate: %s (%d)", mach_error_string(kret
), kret
);
36 kret
= mach_port_insert_right(mach_task_self(), exception_port
, exception_port
, MACH_MSG_TYPE_MAKE_SEND
);
37 if (kret
!= KERN_SUCCESS
)
38 errx(1, "mach_port_insert_right: %s (%d)", mach_error_string(kret
), kret
);
40 kret
= task_set_exception_ports(mach_task_self(), EXC_MASK_CRASH
| EXC_MASK_CORPSE_NOTIFY
, exception_port
,
41 EXCEPTION_DEFAULT
| MACH_EXCEPTION_CODES
, 0);
42 if (kret
!= KERN_SUCCESS
)
43 errx(1, "task_set_exception_ports: %s (%d)", mach_error_string(kret
), kret
);
45 dispatch_semaphore_signal(sServerRunning
);
47 kret
= mach_msg_server(mach_exc_server
, MACH_MSG_SIZE_RELIABLE
, exception_port
, 0);
48 if (kret
!= KERN_SUCCESS
)
49 errx(1, "mach_msg_server: %s (%d)", mach_error_string(kret
), kret
);
55 static void childDied(int sig
)
57 struct proc_exitreasoninfo info
;
58 bzero(&info
, sizeof(info
));
59 uint8_t packReasonData
[OS_REASON_BUFFER_MAX_SIZE
];
60 bzero(packReasonData
, OS_REASON_BUFFER_MAX_SIZE
);
61 info
.eri_reason_buf_size
= OS_REASON_BUFFER_MAX_SIZE
;
62 info
.eri_kcd_buf
= (user_addr_t
)packReasonData
;
63 //fprintf(stderr, "info=%p\n", &info);
64 if ( proc_pidinfo(sChildPid
, PROC_PIDEXITREASONINFO
, 1, &info
, PROC_PIDEXITREASONINFO_SIZE
) != sizeof(struct proc_exitreasoninfo
) ) {
65 printf("bad return size from proc_pidinfo()\n");
68 sChildTerminatedByDyld
= (info
.eri_namespace
== OS_REASON_DYLD
);
72 int main(int argc
, const char* argv
[])
75 fprintf(stderr
, "usage: nocr [-require_crash] prog args...\n");
78 unsigned progArgIndex
= 1;
79 bool requireCrash
= false;
80 const char* testName
= NULL
;
81 if ( strcmp(argv
[1], "-require_crash") == 0 ) {
84 testName
= getenv("NOCR_TEST_NAME");
86 printf("[BEGIN] %s\n", testName
);
89 signal(SIGCHLD
, childDied
);
91 sServerRunning
= dispatch_semaphore_create(0);
93 // start up thread for mach server which handles mach exception ports
94 pthread_t serverThread
;
95 int result
= pthread_create(&serverThread
, NULL
, serverCode
, NULL
);
97 err(EXIT_FAILURE
, "pthread_create");
99 // wait until server is up before starting child
100 dispatch_semaphore_wait(sServerRunning
, DISPATCH_TIME_FOREVER
);
102 // fork and exec child
105 err(EXIT_FAILURE
, "fork");
106 if ( sChildPid
== 0 ) {
108 result
= execvp(argv
[progArgIndex
], (char**)&argv
[progArgIndex
]);
109 err(EXIT_FAILURE
, "exec(\"%s\",...)", argv
[progArgIndex
]);
112 // wait for child to finish (including crash)
115 int childResult
= EXIT_FAILURE
;
117 waitResult
= waitpid(sChildPid
, &status
, 0);
118 } while ( (waitResult
== -1) && (errno
== EINTR
) );
119 if ( waitResult
!= -1 ) {
120 if ( WIFEXITED(status
) ) {
121 childResult
= WEXITSTATUS(status
);
125 if ( requireCrash
) {
127 if ( sChildCrashed
|| sChildTerminatedByDyld
)
128 printf("[PASS] %s\n", testName
);
130 printf("[FAIL] %s\n", testName
);
132 return sChildCrashed
? EXIT_SUCCESS
: EXIT_FAILURE
;
141 // Mach exception handler routines needed by execserverServer.c
144 catch_mach_exception_raise(mach_port_t exception_port
,
147 exception_type_t exception
,
148 mach_exception_data_t code
,
149 mach_msg_type_number_t codeCnt
)
151 //fprintf(stderr, "child crashed\n");
152 sChildCrashed
= true;
157 catch_mach_exception_raise_state(mach_port_t exception_port
,
158 exception_type_t exception
,
159 const mach_exception_data_t code
,
160 mach_msg_type_number_t codeCnt
,
162 const thread_state_t old_state
,
163 mach_msg_type_number_t old_stateCnt
,
164 thread_state_t new_state
,
165 mach_msg_type_number_t
* new_stateCnt
)
167 errx(1, "Unsupported catch_mach_exception_raise_state");
168 return KERN_NOT_SUPPORTED
;
172 catch_mach_exception_raise_state_identity(mach_port_t exception_port
,
175 exception_type_t exception
,
176 mach_exception_data_t code
,
177 mach_msg_type_number_t codeCnt
,
179 thread_state_t old_state
,
180 mach_msg_type_number_t old_stateCnt
,
181 thread_state_t new_state
,
182 mach_msg_type_number_t
* new_stateCnt
)
184 errx(1, "Unsupported catch_mach_exception_raise_state_identity");
185 return KERN_NOT_SUPPORTED
;