dyld-733.8.tar.gz
[apple/dyld.git] / testing / nocr / nocr.c
1 #include "execserverServer.h"
2
3 #include <mach/mach.h>
4 #include <mach/vm_map.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <err.h>
8 #include <pthread.h>
9 #include <unistd.h>
10 #include <dispatch/dispatch.h>
11 #include <errno.h>
12 #include <signal.h>
13 #include <libproc.h>
14 #include <System/sys/reason.h>
15 #include <System/sys/proc_info.h>
16
17
18
19 static pid_t sChildPid;
20 static dispatch_semaphore_t sServerRunning;
21 static bool sChildCrashed = false;
22 static bool sChildTerminatedByDyld = false;
23
24 /*
25 * setup exception handling port for EXC_CRASH and EXC_CORPSE_NOTIFY.
26 * runs mach_msg_server once for receiving exception messages from kernel.
27 */
28 static void* serverCode(void* arg)
29 {
30 mach_port_t exception_port;
31
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);
35
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);
39
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);
44
45 dispatch_semaphore_signal(sServerRunning);
46
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);
50
51 return NULL;
52 }
53
54
55 static void childDied(int sig)
56 {
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");
66 return;
67 }
68 sChildTerminatedByDyld = (info.eri_namespace == OS_REASON_DYLD);
69 }
70
71
72 int main(int argc, const char* argv[])
73 {
74 if ( argc < 2 ) {
75 fprintf(stderr, "usage: nocr [-require_crash] prog args...\n");
76 return EXIT_FAILURE;
77 }
78 unsigned progArgIndex = 1;
79 bool requireCrash = false;
80 const char* testName = NULL;
81 if ( strcmp(argv[1], "-require_crash") == 0 ) {
82 progArgIndex = 2;
83 requireCrash = true;
84 testName = getenv("NOCR_TEST_NAME");
85 if ( testName )
86 printf("[BEGIN] %s\n", testName);
87 }
88
89 signal(SIGCHLD, childDied);
90
91 sServerRunning = dispatch_semaphore_create(0);
92
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);
96 if ( result )
97 err(EXIT_FAILURE, "pthread_create");
98
99 // wait until server is up before starting child
100 dispatch_semaphore_wait(sServerRunning, DISPATCH_TIME_FOREVER);
101
102 // fork and exec child
103 sChildPid = fork();
104 if ( sChildPid < 0 )
105 err(EXIT_FAILURE, "fork");
106 if ( sChildPid == 0 ) {
107 // child side
108 result = execvp(argv[progArgIndex], (char**)&argv[progArgIndex]);
109 err(EXIT_FAILURE, "exec(\"%s\",...)", argv[progArgIndex]);
110 }
111
112 // wait for child to finish (including crash)
113 int status;
114 int waitResult;
115 int childResult = EXIT_FAILURE;
116 do {
117 waitResult = waitpid(sChildPid, &status, 0);
118 } while ( (waitResult == -1) && (errno == EINTR) );
119 if ( waitResult != -1 ) {
120 if ( WIFEXITED(status) ) {
121 childResult = WEXITSTATUS(status);
122 }
123 }
124
125 if ( requireCrash ) {
126 if ( testName ) {
127 if ( sChildCrashed || sChildTerminatedByDyld )
128 printf("[PASS] %s\n", testName);
129 else
130 printf("[FAIL] %s\n", testName);
131 }
132 return sChildCrashed ? EXIT_SUCCESS : EXIT_FAILURE;
133 }
134 else
135 return childResult;
136 }
137
138
139
140
141 // Mach exception handler routines needed by execserverServer.c
142
143 kern_return_t
144 catch_mach_exception_raise(mach_port_t exception_port,
145 mach_port_t thread,
146 mach_port_t task,
147 exception_type_t exception,
148 mach_exception_data_t code,
149 mach_msg_type_number_t codeCnt)
150 {
151 //fprintf(stderr, "child crashed\n");
152 sChildCrashed = true;
153 return KERN_SUCCESS;
154 }
155
156 kern_return_t
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,
161 int * flavor,
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)
166 {
167 errx(1, "Unsupported catch_mach_exception_raise_state");
168 return KERN_NOT_SUPPORTED;
169 }
170
171 kern_return_t
172 catch_mach_exception_raise_state_identity(mach_port_t exception_port,
173 mach_port_t thread,
174 mach_port_t task,
175 exception_type_t exception,
176 mach_exception_data_t code,
177 mach_msg_type_number_t codeCnt,
178 int * flavor,
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)
183 {
184 errx(1, "Unsupported catch_mach_exception_raise_state_identity");
185 return KERN_NOT_SUPPORTED;
186 }
187
188
189