1 /*
2  * sigsegv_darwin_x86.cpp - x86 Darwin SIGSEGV handler
3  *
4  * Copyright (c) 2006 Milan Jurik of ARAnyM dev team (see AUTHORS)
5  *
6  * Inspired by Bernie Meyer's UAE-JIT and Gwenole Beauchesne's Basilisk II-JIT
7  *
8  * This file is part of the ARAnyM project which builds a new and powerful
9  * TOS/FreeMiNT compatible virtual machine running on almost any hardware.
10  *
11  * ARAnyM is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * ARAnyM is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with ARAnyM; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  *
25  * Last modified: 2013-06-16 Jens Heitmann
26  *
27  */
28 
29 #include "sysdeps.h"
30 #include "cpu_emulation.h"
31 #include "memory-uae.h"
32 #define DEBUG 0
33 #include "debug.h"
34 
35 //
36 //
37 //  Darwin segmentation violation handler
38 //  based on the code of Basilisk II
39 //
40 #include <pthread.h>
41 
42 // Address type
43 typedef char * sigsegv_address_t;
44 
45 // SIGSEGV handler return state
46 enum sigsegv_return_t {
47   SIGSEGV_RETURN_SUCCESS,
48   SIGSEGV_RETURN_FAILURE,
49 //  SIGSEGV_RETURN_SKIP_INSTRUCTION,
50 };
51 
52 // Define an address that is bound to be invalid for a program counter
53 const sigsegv_address_t SIGSEGV_INVALID_PC = (sigsegv_address_t)(-1);
54 
55 extern "C" {
56 #include <mach/mach.h>
57 #include <mach/mach_error.h>
58 
59 #ifdef CPU_i386
60 #	undef MACH_EXCEPTION_CODES
61 #	define MACH_EXCEPTION_CODES						0
62 #	define MACH_EXCEPTION_DATA_T					exception_data_t
63 #	define MACH_EXCEPTION_DATA_TYPE_T				exception_data_type_t
64 #	define MACH_EXC_SERVER							exc_server
65 #	define CATCH_MACH_EXCEPTION_RAISE				catch_exception_raise
66 #	define MACH_EXCEPTION_RAISE						exception_raise
67 #	define MACH_EXCEPTION_RAISE_STATE				exception_raise_state
68 #	define MACH_EXCEPTION_RAISE_STATE_IDENTITY		exception_raise_state_identity
69 
70 #else
71 
72 #	define MACH_EXCEPTION_DATA_T					mach_exception_data_t
73 #	define MACH_EXCEPTION_DATA_TYPE_T				mach_exception_data_type_t
74 #	define MACH_EXC_SERVER							mach_exc_server
75 #	define CATCH_MACH_EXCEPTION_RAISE				catch_mach_exception_raise
76 #	define MACH_EXCEPTION_RAISE						mach_exception_raise
77 #	define MACH_EXCEPTION_RAISE_STATE				mach_exception_raise_state
78 #	define MACH_EXCEPTION_RAISE_STATE_IDENTITY		mach_exception_raise_state_identity
79 
80 #endif
81 
82 
83 // Extern declarations of mach functions
84 // dependend on the underlying architecture this are extern declarations
85 // for "mach" or "non mach" function names. 64 Bit requieres "mach_xxx"
86 //	functions
87 //
88 extern boolean_t MACH_EXC_SERVER(mach_msg_header_t *, mach_msg_header_t *);
89 
90 extern kern_return_t CATCH_MACH_EXCEPTION_RAISE(mach_port_t, mach_port_t,
91 	mach_port_t, exception_type_t, MACH_EXCEPTION_DATA_T, mach_msg_type_number_t);
92 
93 extern kern_return_t MACH_EXCEPTION_RAISE(mach_port_t, mach_port_t, mach_port_t,
94 	exception_type_t, MACH_EXCEPTION_DATA_T, mach_msg_type_number_t);
95 
96 extern kern_return_t MACH_EXCEPTION_RAISE_STATE(mach_port_t, exception_type_t,
97 	MACH_EXCEPTION_DATA_T, mach_msg_type_number_t, thread_state_flavor_t *,
98 	thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
99 
100 extern kern_return_t MACH_EXCEPTION_RAISE_STATE_IDENTITY(mach_port_t, mach_port_t, mach_port_t,
101 	exception_type_t, MACH_EXCEPTION_DATA_T, mach_msg_type_number_t, thread_state_flavor_t *,
102 	thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
103 
104 extern kern_return_t catch_mach_exception_raise_state(mach_port_t,
105 	exception_type_t, MACH_EXCEPTION_DATA_T, mach_msg_type_number_t,
106 	int *, thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
107 
108 extern kern_return_t catch_mach_exception_raise_state_identity(mach_port_t,
109 	mach_port_t, mach_port_t, exception_type_t, MACH_EXCEPTION_DATA_T, mach_msg_type_number_t,
110     int *, thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t *);
111 
112 }
113 
114 // Could make this dynamic by looking for a result of MIG_ARRAY_TOO_LARGE
115 #define HANDLER_COUNT 64
116 
117 // structure to tuck away existing exception handlers
118 typedef struct _ExceptionPorts {
119 	mach_msg_type_number_t maskCount;
120 	exception_mask_t masks[HANDLER_COUNT];
121 	exception_handler_t handlers[HANDLER_COUNT];
122 	exception_behavior_t behaviors[HANDLER_COUNT];
123 	thread_state_flavor_t flavors[HANDLER_COUNT];
124 } ExceptionPorts;
125 
126 #ifdef CPU_i386
127 #	define STATE_REGISTER_TYPE	uint32
128 #	ifdef i386_SAVED_STATE
129 #		define SIGSEGV_THREAD_STATE_TYPE		struct i386_saved_state
130 #		define SIGSEGV_THREAD_STATE_FLAVOR		i386_SAVED_STATE
131 #		define SIGSEGV_THREAD_STATE_COUNT		i386_SAVED_STATE_COUNT
132 #		define SIGSEGV_REGISTER_FILE			((unsigned long *)&state->edi) /* EDI is the first GPR we consider */
133 #	else
134 #		ifdef x86_THREAD_STATE32
135 /* MacOS X 10.5 or newer introduces the new names and deprecates the old ones */
136 #			define SIGSEGV_THREAD_STATE_TYPE		x86_thread_state32_t
137 #			define SIGSEGV_THREAD_STATE_FLAVOR		x86_THREAD_STATE32
138 #			define SIGSEGV_THREAD_STATE_COUNT		x86_THREAD_STATE32_COUNT
139 #			define SIGSEGV_REGISTER_FILE			((unsigned long *)&state->__eax) /* EAX is the first GPR we consider */
140 #			define SIGSEGV_FAULT_INSTRUCTION		state->__eip
141 
142 #		else
143 /* MacOS X 10.4 and below */
144 #			define SIGSEGV_THREAD_STATE_TYPE		struct i386_thread_state
145 #			define SIGSEGV_THREAD_STATE_FLAVOR		i386_THREAD_STATE
146 #			define SIGSEGV_THREAD_STATE_COUNT		i386_THREAD_STATE_COUNT
147 #			define SIGSEGV_REGISTER_FILE			((unsigned long *)&state->eax) /* EAX is the first GPR we consider */
148 #			define SIGSEGV_FAULT_INSTRUCTION		state->eip
149 
150 #		endif
151 #	endif
152 #endif
153 
154 #ifdef CPU_x86_64
155 #	define STATE_REGISTER_TYPE	uint64
156 #	ifdef x86_THREAD_STATE64
157 #		define SIGSEGV_THREAD_STATE_TYPE		x86_thread_state64_t
158 #		define SIGSEGV_THREAD_STATE_FLAVOR		x86_THREAD_STATE64
159 #		define SIGSEGV_THREAD_STATE_COUNT		x86_THREAD_STATE64_COUNT
160 #		define SIGSEGV_REGISTER_FILE			((unsigned long *)&state->__rax) /* EAX is the first GPR we consider */
161 #		define SIGSEGV_FAULT_INSTRUCTION		state->__rip
162 #	endif
163 #endif
164 
165 #define SIGSEGV_ERROR_CODE				KERN_INVALID_ADDRESS
166 #define SIGSEGV_ERROR_CODE2				KERN_PROTECTION_FAILURE
167 
168 #define SIGSEGV_FAULT_ADDRESS			code[1]
169 
170 enum {
171 #ifdef CPU_i386
172 #ifdef i386_SAVED_STATE
173 	// same as FreeBSD (in Open Darwin 8.0.1)
174 	REG_RIP = 10,
175 	REG_RAX = 7,
176 	REG_RCX = 6,
177 	REG_RDX = 5,
178 	REG_RBX = 4,
179 	REG_RSP = 13,
180 	REG_RBP = 2,
181 	REG_RSI = 1,
182 	REG_RDI = 0
183 #else
184 	// new layout (MacOS X 10.4.4 for x86)
185 	REG_RIP = 10,
186 	REG_RAX = 0,
187 	REG_RCX = 2,
188 	REG_RDX = 3,
189 	REG_RBX = 1,
190 	REG_RSP = 7,
191 	REG_RBP = 6,
192 	REG_RSI = 5,
193 	REG_RDI = 4
194 #endif
195 #else
196 #ifdef CPU_x86_64
197 	REG_R8  = 8,
198 	REG_R9  = 9,
199 	REG_R10 = 10,
200 	REG_R11 = 11,
201 	REG_R12 = 12,
202 	REG_R13 = 13,
203 	REG_R14 = 14,
204 	REG_R15 = 15,
205 	REG_RDI = 4,
206 	REG_RSI = 5,
207 	REG_RBP = 6,
208 	REG_RBX = 1,
209 	REG_RDX = 3,
210 	REG_RAX = 0,
211 	REG_RCX = 2,
212 	REG_RSP = 7,
213 	REG_RIP = 16
214 #endif
215 #endif
216 };
217 
218 // Type of a SIGSEGV handler. Returns boolean expressing successful operation
219 typedef sigsegv_return_t (*sigsegv_fault_handler_t)(sigsegv_address_t fault_address, sigsegv_address_t instruction_address,
220 										 SIGSEGV_THREAD_STATE_TYPE *state );
221 
222 // Install a SIGSEGV handler. Returns boolean expressing success
223 extern bool sigsegv_install_handler(sigsegv_fault_handler_t handler);
224 
225 // exception handler thread
226 static pthread_t exc_thread;
227 
228 static mach_port_t _exceptionPort = MACH_PORT_NULL;
229 
230 // place where old exception handler info is stored
231 static ExceptionPorts ports;
232 
233 // User's SIGSEGV handler
234 static sigsegv_fault_handler_t sigsegv_fault_handler = 0;
235 
236 
237 #define MACH_CHECK_ERROR(name,ret) \
238 if (ret != KERN_SUCCESS) { \
239 	mach_error(#name, ret); \
240 	exit (1); \
241 }
242 
243 #define MSG_SIZE 512
244 static char msgbuf[MSG_SIZE];
245 static char replybuf[MSG_SIZE];
246 
247 #define CONTEXT_NAME	state
248 #define CONTEXT_TYPE	SIGSEGV_THREAD_STATE_TYPE
249 #define CONTEXT_ATYPE	CONTEXT_TYPE *
250 #define CONTEXT_REGS    SIGSEGV_REGISTER_FILE
251 #define CONTEXT_AEIP	CONTEXT_REGS[REG_RIP]
252 #define CONTEXT_AEAX	CONTEXT_REGS[REG_RAX]
253 #define CONTEXT_AEBX	CONTEXT_REGS[REG_RBX]
254 #define CONTEXT_AECX	CONTEXT_REGS[REG_RCX]
255 #define CONTEXT_AEDX	CONTEXT_REGS[REG_RDX]
256 #define CONTEXT_AEBP	CONTEXT_REGS[REG_RBP]
257 #define CONTEXT_AESI	CONTEXT_REGS[REG_RSI]
258 #define CONTEXT_AEDI	CONTEXT_REGS[REG_RDI]
259 
260 #ifdef CPU_x86_64
261 #define CONTEXT_AEFLAGS	CONTEXT_NAME->__rflags
262 #else
263 #ifdef x86_THREAD_STATE32
264 #define CONTEXT_AEFLAGS	CONTEXT_NAME->__eflags
265 #else
266 #define CONTEXT_AEFLAGS	CONTEXT_NAME->eflags
267 #endif
268 #endif
269 
270 #if defined(CPU_i386) || defined(CPU_x86_64)
271 
272 #include "sigsegv_common_x86.h"
273 
sigsegv_handler(sigsegv_address_t fault_address,sigsegv_address_t,SIGSEGV_THREAD_STATE_TYPE * state)274 static sigsegv_return_t sigsegv_handler(sigsegv_address_t fault_address,
275 										sigsegv_address_t /* fault_instruction */,
276 										 SIGSEGV_THREAD_STATE_TYPE *state) {
277 	memptr addr = (memptr)(uintptr)((char *)fault_address - fixed_memory_offset);
278 #if DEBUG
279 	if (addr >= 0xff000000)
280 		addr &= 0x00ffffff;
281 	if (addr < 0x00f00000 || addr > 0x00ffffff) // YYY
282 		bug("\nsegfault: pc=%08x, " REG_RIP_NAME " =%p, addr=%p (0x%08x)", m68k_getpc(), (void *)CONTEXT_AEIP, fault_address, addr);
283 	if (fault_address < (uintptr)(fixed_memory_offset - 0x1000000UL)
284 #ifdef CPU_x86_64
285 		|| fault_address >= ((uintptr)fixed_memory_offset + 0x100000000UL)
286 #endif
287 		)
288 	{
289 #ifdef HAVE_DISASM_X86
290 		if (CONTEXT_AEIP != 0)
291 		{
292 			char buf[256];
293 
294 			x86_disasm((const uint8 *)CONTEXT_AEIP, buf, 1);
295 			panicbug("%s", buf);
296 		}
297 #endif
298 		// raise(SIGBUS);
299 	}
300 #endif
301 	if (fault_address == 0 || CONTEXT_AEIP == 0)
302 	{
303 		real_segmentationfault();
304 		/* not reached (hopefully) */
305 		return SIGSEGV_RETURN_FAILURE;
306 	}
307 	handle_access_fault((CONTEXT_ATYPE) CONTEXT_NAME, addr);
308 	return SIGSEGV_RETURN_SUCCESS;
309 }
310 
311 #endif /* CPU_i386 || CPU_x86_64 */
312 
313 
314 /*
315  *  SIGSEGV global handler
316  */
317 
318 // This function handles the badaccess to memory.
319 // It is called from the signal handler or the exception handler.
handle_badaccess(mach_port_t thread,MACH_EXCEPTION_DATA_T code,SIGSEGV_THREAD_STATE_TYPE * state)320 static bool handle_badaccess(mach_port_t thread, MACH_EXCEPTION_DATA_T code, SIGSEGV_THREAD_STATE_TYPE *state)
321 {
322 	// We must match the initial count when writing back the CPU state registers
323 	kern_return_t krc;
324 	mach_msg_type_number_t count;
325 
326 	D2(panicbug("handle badaccess"));
327 
328 	count = SIGSEGV_THREAD_STATE_COUNT;
329 	krc = thread_get_state(thread, SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)state, &count);
330 	MACH_CHECK_ERROR (thread_get_state, krc);
331 
332 	sigsegv_address_t fault_address = (sigsegv_address_t)SIGSEGV_FAULT_ADDRESS;
333 	sigsegv_address_t fault_instruction = (sigsegv_address_t)SIGSEGV_FAULT_INSTRUCTION;
334 
335 	D2(panicbug("code:%lx %lx %lx %lx", (long)code[0], (long)code[1], (long)code[2], (long)code[3]));
336 	D2(panicbug("regs eax:%lx", CONTEXT_AEAX));
337 	D2(panicbug("regs ebx:%lx", CONTEXT_AEBX));
338 	D2(panicbug("regs ecx:%lx", CONTEXT_AECX));
339 	D2(panicbug("regs edx:%lx", CONTEXT_AEDX));
340 	D2(panicbug("regs ebp:%lx", CONTEXT_AEBP));
341 	D2(panicbug("regs esi:%lx", CONTEXT_AESI));
342 	D2(panicbug("regs edi:%lx", CONTEXT_AEDI));
343 	D2(panicbug("regs eip:%lx", CONTEXT_AEIP));
344 	D2(panicbug("regs eflags:%lx", CONTEXT_AEFLAGS));
345 
346 	// Call user's handler
347 	if (sigsegv_fault_handler(fault_address, fault_instruction, state) == SIGSEGV_RETURN_SUCCESS) {
348 		D2(panicbug("esi:%lx", CONTEXT_AESI));
349 		krc = thread_set_state(thread,
350 								SIGSEGV_THREAD_STATE_FLAVOR, (thread_state_t)state,
351 								count);
352 		MACH_CHECK_ERROR (thread_set_state, krc);
353 		D(panicbug("return from handle bad access with true"));
354 		return true;
355 	}
356 
357 	D(panicbug("return from handle bad access with false"));
358 	return false;
359 }
360 
361 
362 /*
363  * We need to forward all exceptions that we do not handle.
364  * This is important, there are many exceptions that may be
365  * handled by other exception handlers. For example debuggers
366  * use exceptions and the exception handler is in another
367  * process in such a case. (Timothy J. Wood states in his
368  * message to the list that he based this code on that from
369  * gdb for Darwin.)
370  */
371 static inline kern_return_t
forward_exception(mach_port_t thread_port,mach_port_t task_port,exception_type_t exception_type,MACH_EXCEPTION_DATA_T exception_data,mach_msg_type_number_t data_count,ExceptionPorts * oldExceptionPorts)372 forward_exception(mach_port_t thread_port,
373 				  mach_port_t task_port,
374 				  exception_type_t exception_type,
375 				  MACH_EXCEPTION_DATA_T exception_data,
376 				  mach_msg_type_number_t data_count,
377 				  ExceptionPorts *oldExceptionPorts)
378 {
379 	kern_return_t kret;
380 	unsigned int portIndex;
381 	mach_port_t port;
382 	exception_behavior_t behavior;
383 	thread_state_flavor_t flavor;
384 	thread_state_data_t thread_state;
385 	mach_msg_type_number_t thread_state_count;
386 
387 	D(panicbug("forward_exception\n"));
388 
389 	for (portIndex = 0; portIndex < oldExceptionPorts->maskCount; portIndex++) {
390 		if (oldExceptionPorts->masks[portIndex] & (1 << exception_type)) {
391 			// This handler wants the exception
392 			break;
393 		}
394 	}
395 
396 	if (portIndex >= oldExceptionPorts->maskCount) {
397 		panicbug("No handler for exception_type = %d. Not fowarding\n", exception_type);
398 		return KERN_FAILURE;
399 	}
400 
401 	port = oldExceptionPorts->handlers[portIndex];
402 	behavior = oldExceptionPorts->behaviors[portIndex];
403 	flavor = oldExceptionPorts->flavors[portIndex];
404 
405 	if (flavor && !VALID_THREAD_STATE_FLAVOR(flavor)) {
406 		fprintf(stderr, "Invalid thread_state flavor = %d. Not forwarding\n", flavor);
407 		return KERN_FAILURE;
408 	}
409 
410 	/*
411 	 fprintf(stderr, "forwarding exception, port = 0x%x, behaviour = %d, flavor = %d\n", port, behavior, flavor);
412 	 */
413 
414 	if (behavior != EXCEPTION_DEFAULT) {
415 		thread_state_count = THREAD_STATE_MAX;
416 		kret = thread_get_state (thread_port, flavor, (natural_t *)&thread_state,
417 								 &thread_state_count);
418 		MACH_CHECK_ERROR (thread_get_state, kret);
419 	}
420 
421 	switch (behavior) {
422 	case EXCEPTION_DEFAULT:
423 	  // fprintf(stderr, "forwarding to exception_raise\n");
424 	  kret = MACH_EXCEPTION_RAISE(port, thread_port, task_port, exception_type,
425 							 exception_data, data_count);
426 	  MACH_CHECK_ERROR (MACH_EXCEPTION_RAISE, kret);
427 	  break;
428 	case EXCEPTION_STATE:
429 	  // fprintf(stderr, "forwarding to exception_raise_state\n");
430 	  kret = MACH_EXCEPTION_RAISE_STATE(port, exception_type, exception_data,
431 								   data_count, &flavor,
432 								   (natural_t *)&thread_state, thread_state_count,
433 								   (natural_t *)&thread_state, &thread_state_count);
434 	  MACH_CHECK_ERROR (MACH_EXCEPTION_RAISE_STATE, kret);
435 	  break;
436 	case EXCEPTION_STATE_IDENTITY:
437 	  // fprintf(stderr, "forwarding to exception_raise_state_identity\n");
438 	  kret = MACH_EXCEPTION_RAISE_STATE_IDENTITY(port, thread_port, task_port,
439 											exception_type, exception_data,
440 											data_count, &flavor,
441 											(natural_t *)&thread_state, thread_state_count,
442 											(natural_t *)&thread_state, &thread_state_count);
443 	  MACH_CHECK_ERROR (MACH_EXCEPTION_RAISE_STATE_IDENTITY, kret);
444 	  break;
445 	default:
446 	  panicbug("forward_exception got unknown behavior");
447 	  kret = KERN_FAILURE;
448 	  break;
449 	}
450 
451 	if (behavior != EXCEPTION_DEFAULT) {
452 		kret = thread_set_state (thread_port, flavor, (natural_t *)&thread_state,
453 								 thread_state_count);
454 		MACH_CHECK_ERROR (thread_set_state, kret);
455 	}
456 
457 	return kret;
458 }
459 
460 /*
461  * This is the code that actually handles the exception.
462  * It is called by exc_server. For Darwin 5 Apple changed
463  * this a bit from how this family of functions worked in
464  * Mach. If you are familiar with that it is a little
465  * different. The main variation that concerns us here is
466  * that code is an array of exception specific codes and
467  * codeCount is a count of the number of codes in the code
468  * array. In typical Mach all exceptions have a code
469  * and sub-code. It happens to be the case that for a
470  * EXC_BAD_ACCESS exception the first entry is the type of
471  * bad access that occurred and the second entry is the
472  * faulting address so these entries correspond exactly to
473  * how the code and sub-code are used on Mach.
474  *
475  * This is a MIG interface. No code in Basilisk II should
476  * call this directley. This has to have external C
477  * linkage because that is what exc_server expects.
478  */
479 __attribute__ ((visibility("default")))
480 kern_return_t
CATCH_MACH_EXCEPTION_RAISE(mach_port_t exception_port,mach_port_t thread,mach_port_t task,exception_type_t exception,MACH_EXCEPTION_DATA_T code,mach_msg_type_number_t codeCount)481 CATCH_MACH_EXCEPTION_RAISE(mach_port_t exception_port,
482 					  mach_port_t thread,
483 					  mach_port_t task,
484 					  exception_type_t exception,
485 					  MACH_EXCEPTION_DATA_T code,
486 					  mach_msg_type_number_t codeCount)
487 {
488 	SIGSEGV_THREAD_STATE_TYPE state;
489 	kern_return_t krc;
490 
491 	D(panicbug("catch_exception_raise: %d", exception));
492 
493 	if (exception == EXC_BAD_ACCESS) {
494 		switch (code[0]) {
495 			case KERN_PROTECTION_FAILURE:
496 			case KERN_INVALID_ADDRESS:
497 				if (handle_badaccess(thread, code, &state))
498 					return KERN_SUCCESS;
499 				break;
500 		}
501 	}
502 
503 
504 	// In Mach we do not need to remove the exception handler.
505 	// If we forward the exception, eventually some exception handler
506 	// will take care of this exception.
507 	krc = forward_exception(thread, task, exception, code, codeCount, &ports);
508 
509 	return krc;
510 }
511 
512 /* XXX: borrowed from launchd and gdb */
513 kern_return_t
catch_mach_exception_raise_state(mach_port_t exception_port,exception_type_t exception,MACH_EXCEPTION_DATA_T code,mach_msg_type_number_t code_count,int * flavor,thread_state_t old_state,mach_msg_type_number_t old_state_count,thread_state_t new_state,mach_msg_type_number_t * new_state_count)514 catch_mach_exception_raise_state(mach_port_t exception_port,
515 								 exception_type_t exception,
516 								 MACH_EXCEPTION_DATA_T code,
517 								 mach_msg_type_number_t code_count,
518 								 int *flavor,
519 								 thread_state_t old_state,
520 								 mach_msg_type_number_t old_state_count,
521 								 thread_state_t new_state,
522 								 mach_msg_type_number_t *new_state_count)
523 {
524 	memcpy(new_state, old_state, old_state_count * sizeof(old_state[0]));
525 	*new_state_count = old_state_count;
526 	return KERN_SUCCESS;
527 }
528 
529 /* XXX: borrowed from launchd and gdb */
530 kern_return_t
catch_mach_exception_raise_state_identity(mach_port_t exception_port,mach_port_t thread_port,mach_port_t task_port,exception_type_t exception,MACH_EXCEPTION_DATA_T code,mach_msg_type_number_t code_count,int * flavor,thread_state_t old_state,mach_msg_type_number_t old_state_count,thread_state_t new_state,mach_msg_type_number_t * new_state_count)531 catch_mach_exception_raise_state_identity(mach_port_t exception_port,
532 										  mach_port_t thread_port,
533 										  mach_port_t task_port,
534 										  exception_type_t exception,
535 										  MACH_EXCEPTION_DATA_T code,
536 										  mach_msg_type_number_t code_count,
537 										  int *flavor,
538 										  thread_state_t old_state,
539 										  mach_msg_type_number_t old_state_count,
540 										  thread_state_t new_state,
541 										  mach_msg_type_number_t *new_state_count)
542 {
543 	kern_return_t kret;
544 
545 	memcpy(new_state, old_state, old_state_count * sizeof(old_state[0]));
546 	*new_state_count = old_state_count;
547 
548 	kret = mach_port_deallocate(mach_task_self(), task_port);
549 	MACH_CHECK_ERROR(mach_port_deallocate, kret);
550 	kret = mach_port_deallocate(mach_task_self(), thread_port);
551 	MACH_CHECK_ERROR(mach_port_deallocate, kret);
552 
553 	return KERN_SUCCESS;
554 }
555 
556 /*
557  * This is the entry point for the exception handler thread. The job
558  * of this thread is to wait for exception messages on the exception
559  * port that was setup beforehand and to pass them on to exc_server.
560  * exc_server is a MIG generated function that is a part of Mach.
561  * Its job is to decide what to do with the exception message. In our
562  * case exc_server calls catch_exception_raise on our behalf. After
563  * exc_server returns, it is our responsibility to send the reply.
564  */
565 static void *
handleExceptions(void *)566 handleExceptions(void * /*priv*/)
567 {
568 	D(panicbug("handleExceptions\n"));
569 
570 	mach_msg_header_t *msg, *reply;
571 	kern_return_t krc;
572 
573 	msg = (mach_msg_header_t *)msgbuf;
574 	reply = (mach_msg_header_t *)replybuf;
575 
576 	for (;;) {
577 		krc = mach_msg(msg, MACH_RCV_MSG, MSG_SIZE, MSG_SIZE,
578 				_exceptionPort, 0, MACH_PORT_NULL);
579 		MACH_CHECK_ERROR(mach_msg, krc);
580 
581 		if (!MACH_EXC_SERVER(msg, reply)) {
582 			fprintf(stderr, "exc_server hated the message\n");
583 			exit(1);
584 		}
585 
586 		krc = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0,
587 				 msg->msgh_local_port, 0, MACH_PORT_NULL);
588 		if (krc != KERN_SUCCESS) {
589 			fprintf(stderr, "Error sending message to original reply port, krc = %d, %s",
590 				krc, mach_error_string(krc));
591 			exit(1);
592 		}
593 	}
594 }
595 
sigsegv_do_install_handler(sigsegv_fault_handler_t handler)596 static bool sigsegv_do_install_handler(sigsegv_fault_handler_t handler)
597 {
598 	D(panicbug("sigsegv_do_install_handler\n"));
599 
600 	//
601 	//Except for the exception port functions, this should be
602 	//pretty much stock Mach. If later you choose to support
603 	//other Mach's besides Darwin, just check for __MACH__
604 	//here and __APPLE__ where the actual differences are.
605 	//
606 	if (sigsegv_fault_handler != NULL) {
607 		sigsegv_fault_handler = handler;
608 		return true;
609 	}
610 
611 	kern_return_t krc;
612 
613 	// create the the exception port
614 	krc = mach_port_allocate(mach_task_self(),
615 			  MACH_PORT_RIGHT_RECEIVE, &_exceptionPort);
616 	if (krc != KERN_SUCCESS) {
617 		mach_error("mach_port_allocate", krc);
618 		return false;
619 	}
620 
621 	// add a port send right
622 	krc = mach_port_insert_right(mach_task_self(),
623 			      _exceptionPort, _exceptionPort,
624 			      MACH_MSG_TYPE_MAKE_SEND);
625 	if (krc != KERN_SUCCESS) {
626 		mach_error("mach_port_insert_right", krc);
627 		return false;
628 	}
629 
630 	// get the old exception ports
631 	ports.maskCount = sizeof (ports.masks) / sizeof (ports.masks[0]);
632 	krc = thread_get_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, ports.masks,
633  				&ports.maskCount, ports.handlers, ports.behaviors, ports.flavors);
634  	if (krc != KERN_SUCCESS) {
635  		mach_error("thread_get_exception_ports", krc);
636  		return false;
637  	}
638 
639 	// set the new exception port
640 	//
641 	// We could have used EXCEPTION_STATE_IDENTITY instead of
642 	// EXCEPTION_DEFAULT to get the thread state in the initial
643 	// message, but it turns out that in the common case this is not
644 	// neccessary. If we need it we can later ask for it from the
645 	// suspended thread.
646 	//
647 	// Even with THREAD_STATE_NONE, Darwin provides the program
648 	// counter in the thread state.  The comments in the header file
649 	// seem to imply that you can count on the GPR's on an exception
650 	// as well but just to be safe I use MACHINE_THREAD_STATE because
651 	// you have to ask for all of the GPR's anyway just to get the
652 	// program counter. In any case because of update effective
653 	// address from immediate and update address from effective
654 	// addresses of ra and rb modes (as good an name as any for these
655 	// addressing modes) used in PPC instructions, you will need the
656 	// GPR state anyway.
657 	krc = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, _exceptionPort,
658 				EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, SIGSEGV_THREAD_STATE_FLAVOR);
659 	if (krc != KERN_SUCCESS) {
660 		mach_error("thread_set_exception_ports", krc);
661 		return false;
662 	}
663 
664 	// create the exception handler thread
665 	if (pthread_create(&exc_thread, NULL, &handleExceptions, NULL) != 0) {
666 		panicbug("creation of exception thread failed\n");
667 		return false;
668 	}
669 
670 	// do not care about the exception thread any longer, let is run standalone
671 	(void)pthread_detach(exc_thread);
672 
673 	D(panicbug("Sigsegv installed\n"));
674 	sigsegv_fault_handler = handler;
675 	return true;
676 }
677 
install_sigsegv()678 void install_sigsegv() {
679 	sigsegv_do_install_handler(sigsegv_handler);
680 }
681 
uninstall_sigsegv()682 void uninstall_sigsegv()
683 {
684 	/* TODO */
685 }
686