Browse Source

Add debug support for MacOS (#367)

rcstuber 5 years ago
parent
commit
dcc7ad058b

+ 10 - 1
CMakeLists.txt

@@ -1,7 +1,7 @@
 cmake_minimum_required(VERSION 3.1)
 
 set(HL_VERSION_MAJOR 1)
-set(HL_VERSION_MINOR 11)
+set(HL_VERSION_MINOR 12)
 set(HL_VERSION_PATCH 0)
 set(HL_VERSION ${HL_VERSION_MAJOR}.${HL_VERSION_MINOR}.${HL_VERSION_PATCH})
 
@@ -50,6 +50,7 @@ endforeach()
 
 include_directories(
     src
+    include
     include/pcre
 )
 
@@ -80,6 +81,14 @@ file(GLOB std_srcs
     src/std/process.c
 )
 
+if(CMAKE_SYSTEM_NAME MATCHES "Darwin")
+    list(APPEND std_srcs
+        include/mdbg/mdbg.c
+        include/mdbg/mach_excServer.c
+        include/mdbg/mach_excUser.c
+    )
+endif()
+
 if(ANDROID)
     list(APPEND std_srcs
         src/std/sys_android.c

+ 6 - 2
Makefile

@@ -6,7 +6,7 @@ INSTALL_DIR ?= $(PREFIX)
 
 LIBS=fmt sdl ssl openal ui uv mysql
 
-CFLAGS = -Wall -O3 -I src -msse2 -mfpmath=sse -std=c11 -I include/pcre -I include/mikktspace -I include/minimp3 -D LIBHL_EXPORTS
+CFLAGS = -Wall -O3 -I src -msse2 -mfpmath=sse -std=c11 -I include -I include/pcre -I include/mikktspace -I include/minimp3 -D LIBHL_EXPORTS
 LFLAGS = -L. -lhl
 LIBFLAGS =
 HLFLAGS = -ldl
@@ -77,6 +77,10 @@ LIBOPENAL = -lopenal
 LIBSSL = -framework Security -framework CoreFoundation
 RELEASE_NAME = osx
 
+# Mac native debug
+HL_DEBUG = include/mdbg/mdbg.o include/mdbg/mach_excServer.o include/mdbg/mach_excUser.o
+LIB += ${HL_DEBUG}
+
 else
 
 # Linux
@@ -207,7 +211,7 @@ release_osx:
 	${CC} ${CFLAGS} -o $@ -c $<
 
 clean_o:
-	rm -f ${STD} ${BOOT} ${RUNTIME} ${PCRE} ${HL} ${FMT} ${SDL} ${SSL} ${OPENAL} ${UI} ${UV}
+	rm -f ${STD} ${BOOT} ${RUNTIME} ${PCRE} ${HL} ${FMT} ${SDL} ${SSL} ${OPENAL} ${UI} ${UV} ${HL_DEBUG}
 
 clean: clean_o
 	rm -f hl hl.exe libhl.$(LIBEXT) *.hdll

+ 133 - 0
include/mdbg/mach_exc.defs

@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ * 
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * @OSF_COPYRIGHT@
+ */
+/* 
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ * 
+ *  Software Distribution Coordinator  or  [email protected]
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ * 
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ */
+/*
+ * Abstract:
+ *	MiG definitions file for Mach exception interface.
+ */
+
+subsystem
+#if	KERNEL_USER
+	  KernelUser
+#endif
+#if	KERNEL_SERVER
+	  KernelServer
+#endif	/* KERNEL_SERVER */
+
+		     mach_exc 2405;
+
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+
+ServerPrefix catch_;
+
+type mach_exception_data_t	= array[*:2] of int64_t;
+type exception_type_t		= int;
+
+routine		mach_exception_raise(
+			exception_port	: mach_port_t;
+			thread		: mach_port_t;
+			task		: mach_port_t;
+			exception	: exception_type_t;
+			code		: mach_exception_data_t
+#if MACH_EXC_SERVER_SECTOKEN
+ ;
+ ServerSecToken stoken	: security_token_t
+#endif
+#if MACH_EXC_SERVER_AUDITTOKEN
+ ;
+ ServerAuditToken atoken: audit_token_t
+#endif
+			);
+
+routine		mach_exception_raise_state(
+			exception_port	: mach_port_t;
+			exception	: exception_type_t;
+			code		: mach_exception_data_t, const;
+		  inout flavor		: int;
+			old_state	: thread_state_t, const;
+		    out new_state	: thread_state_t
+#if MACH_EXC_SERVER_SECTOKEN
+ ;
+ ServerSecToken stoken	: security_token_t
+#endif
+#if MACH_EXC_SERVER_AUDITTOKEN
+ ;
+ ServerAuditToken atoken: audit_token_t
+#endif
+			);
+
+routine		mach_exception_raise_state_identity(
+			exception_port  : mach_port_t;
+			thread          : mach_port_t;
+			task            : mach_port_t;
+			exception       : exception_type_t;
+			code            : mach_exception_data_t;
+		  inout flavor          : int;
+			old_state       : thread_state_t;
+		    out new_state       : thread_state_t
+#if MACH_EXC_SERVER_SECTOKEN
+ ;
+ ServerSecToken stoken	: security_token_t
+#endif
+#if MACH_EXC_SERVER_AUDITTOKEN
+ ;
+ ServerAuditToken atoken: audit_token_t
+#endif
+			);
+
+/* vim: set ft=c : */

+ 306 - 0
include/mdbg/mach_exc.h

@@ -0,0 +1,306 @@
+#ifndef	_mach_exc_user_
+#define	_mach_exc_user_
+
+/* Module mach_exc */
+
+#include <string.h>
+#include <mach/ndr.h>
+#include <mach/boolean.h>
+#include <mach/kern_return.h>
+#include <mach/notify.h>
+#include <mach/mach_types.h>
+#include <mach/message.h>
+#include <mach/mig_errors.h>
+#include <mach/port.h>
+	
+/* BEGIN VOUCHER CODE */
+
+#ifndef KERNEL
+#if defined(__has_include)
+#if __has_include(<mach/mig_voucher_support.h>)
+#ifndef USING_VOUCHERS
+#define USING_VOUCHERS
+#endif
+#ifndef __VOUCHER_FORWARD_TYPE_DECLS__
+#define __VOUCHER_FORWARD_TYPE_DECLS__
+#ifdef __cplusplus
+extern "C" {
+#endif
+	extern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import));
+#ifdef __cplusplus
+}
+#endif
+#endif // __VOUCHER_FORWARD_TYPE_DECLS__
+#endif // __has_include(<mach/mach_voucher_types.h>)
+#endif // __has_include
+#endif // !KERNEL
+	
+/* END VOUCHER CODE */
+
+	
+/* BEGIN MIG_STRNCPY_ZEROFILL CODE */
+
+#if defined(__has_include)
+#if __has_include(<mach/mig_strncpy_zerofill_support.h>)
+#ifndef USING_MIG_STRNCPY_ZEROFILL
+#define USING_MIG_STRNCPY_ZEROFILL
+#endif
+#ifndef __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__
+#define __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__
+#ifdef __cplusplus
+extern "C" {
+#endif
+	extern int mig_strncpy_zerofill(char *dest, const char *src, int len) __attribute__((weak_import));
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ */
+#endif /* __has_include(<mach/mig_strncpy_zerofill_support.h>) */
+#endif /* __has_include */
+	
+/* END MIG_STRNCPY_ZEROFILL CODE */
+
+
+#ifdef AUTOTEST
+#ifndef FUNCTION_PTR_T
+#define FUNCTION_PTR_T
+typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t);
+typedef struct {
+        char            *name;
+        function_ptr_t  function;
+} function_table_entry;
+typedef function_table_entry   *function_table_t;
+#endif /* FUNCTION_PTR_T */
+#endif /* AUTOTEST */
+
+#ifndef	mach_exc_MSG_COUNT
+#define	mach_exc_MSG_COUNT	3
+#endif	/* mach_exc_MSG_COUNT */
+
+#include <mach/std_types.h>
+#include <mach/mig.h>
+#include <mach/mig.h>
+#include <mach/mach_types.h>
+
+#ifdef __BeforeMigUserHeader
+__BeforeMigUserHeader
+#endif /* __BeforeMigUserHeader */
+
+#include <sys/cdefs.h>
+__BEGIN_DECLS
+
+
+/* Routine mach_exception_raise */
+#ifdef	mig_external
+mig_external
+#else
+extern
+#endif	/* mig_external */
+kern_return_t 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 codeCnt
+);
+
+/* Routine mach_exception_raise_state */
+#ifdef	mig_external
+mig_external
+#else
+extern
+#endif	/* mig_external */
+kern_return_t mach_exception_raise_state
+(
+	mach_port_t exception_port,
+	exception_type_t exception,
+	const mach_exception_data_t code,
+	mach_msg_type_number_t codeCnt,
+	int *flavor,
+	const thread_state_t old_state,
+	mach_msg_type_number_t old_stateCnt,
+	thread_state_t new_state,
+	mach_msg_type_number_t *new_stateCnt
+);
+
+/* Routine mach_exception_raise_state_identity */
+#ifdef	mig_external
+mig_external
+#else
+extern
+#endif	/* mig_external */
+kern_return_t mach_exception_raise_state_identity
+(
+	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 codeCnt,
+	int *flavor,
+	thread_state_t old_state,
+	mach_msg_type_number_t old_stateCnt,
+	thread_state_t new_state,
+	mach_msg_type_number_t *new_stateCnt
+);
+
+__END_DECLS
+
+/********************** Caution **************************/
+/* The following data types should be used to calculate  */
+/* maximum message sizes only. The actual message may be */
+/* smaller, and the position of the arguments within the */
+/* message layout may vary from what is presented here.  */
+/* For example, if any of the arguments are variable-    */
+/* sized, and less than the maximum is sent, the data    */
+/* will be packed tight in the actual message to reduce  */
+/* the presence of holes.                                */
+/********************** Caution **************************/
+
+/* typedefs for all requests */
+
+#ifndef __Request__mach_exc_subsystem__defined
+#define __Request__mach_exc_subsystem__defined
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		/* start of the kernel processed data */
+		mach_msg_body_t msgh_body;
+		mach_msg_port_descriptor_t thread;
+		mach_msg_port_descriptor_t task;
+		/* end of the kernel processed data */
+		NDR_record_t NDR;
+		exception_type_t exception;
+		mach_msg_type_number_t codeCnt;
+		int64_t code[2];
+	} __Request__mach_exception_raise_t __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		exception_type_t exception;
+		mach_msg_type_number_t codeCnt;
+		int64_t code[2];
+		int flavor;
+		mach_msg_type_number_t old_stateCnt;
+		natural_t old_state[614];
+	} __Request__mach_exception_raise_state_t __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		/* start of the kernel processed data */
+		mach_msg_body_t msgh_body;
+		mach_msg_port_descriptor_t thread;
+		mach_msg_port_descriptor_t task;
+		/* end of the kernel processed data */
+		NDR_record_t NDR;
+		exception_type_t exception;
+		mach_msg_type_number_t codeCnt;
+		int64_t code[2];
+		int flavor;
+		mach_msg_type_number_t old_stateCnt;
+		natural_t old_state[614];
+	} __Request__mach_exception_raise_state_identity_t __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+#endif /* !__Request__mach_exc_subsystem__defined */
+
+/* union of all requests */
+
+#ifndef __RequestUnion__mach_exc_subsystem__defined
+#define __RequestUnion__mach_exc_subsystem__defined
+union __RequestUnion__mach_exc_subsystem {
+	__Request__mach_exception_raise_t Request_mach_exception_raise;
+	__Request__mach_exception_raise_state_t Request_mach_exception_raise_state;
+	__Request__mach_exception_raise_state_identity_t Request_mach_exception_raise_state_identity;
+};
+#endif /* !__RequestUnion__mach_exc_subsystem__defined */
+/* typedefs for all replies */
+
+#ifndef __Reply__mach_exc_subsystem__defined
+#define __Reply__mach_exc_subsystem__defined
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		kern_return_t RetCode;
+	} __Reply__mach_exception_raise_t __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		kern_return_t RetCode;
+		int flavor;
+		mach_msg_type_number_t new_stateCnt;
+		natural_t new_state[614];
+	} __Reply__mach_exception_raise_state_t __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		kern_return_t RetCode;
+		int flavor;
+		mach_msg_type_number_t new_stateCnt;
+		natural_t new_state[614];
+	} __Reply__mach_exception_raise_state_identity_t __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+#endif /* !__Reply__mach_exc_subsystem__defined */
+
+/* union of all replies */
+
+#ifndef __ReplyUnion__mach_exc_subsystem__defined
+#define __ReplyUnion__mach_exc_subsystem__defined
+union __ReplyUnion__mach_exc_subsystem {
+	__Reply__mach_exception_raise_t Reply_mach_exception_raise;
+	__Reply__mach_exception_raise_state_t Reply_mach_exception_raise_state;
+	__Reply__mach_exception_raise_state_identity_t Reply_mach_exception_raise_state_identity;
+};
+#endif /* !__RequestUnion__mach_exc_subsystem__defined */
+
+#ifndef subsystem_to_name_map_mach_exc
+#define subsystem_to_name_map_mach_exc \
+    { "mach_exception_raise", 2405 },\
+    { "mach_exception_raise_state", 2406 },\
+    { "mach_exception_raise_state_identity", 2407 }
+#endif
+
+#ifdef __AfterMigUserHeader
+__AfterMigUserHeader
+#endif /* __AfterMigUserHeader */
+
+#endif	 /* _mach_exc_user_ */

+ 805 - 0
include/mdbg/mach_excServer.c

@@ -0,0 +1,805 @@
+/*
+ * IDENTIFICATION:
+ * stub generated Tue Apr  7 09:10:21 2020
+ * with a MiG generated by bootstrap_cmds-116
+ * OPTIONS: 
+ */
+
+/* Module mach_exc */
+
+#define	__MIG_check__Request__mach_exc_subsystem__ 1
+
+#include <string.h>
+#include <mach/ndr.h>
+#include <mach/boolean.h>
+#include <mach/kern_return.h>
+#include <mach/notify.h>
+#include <mach/mach_types.h>
+#include <mach/message.h>
+#include <mach/mig_errors.h>
+#include <mach/port.h>
+	
+/* BEGIN VOUCHER CODE */
+
+#ifndef KERNEL
+#if defined(__has_include)
+#if __has_include(<mach/mig_voucher_support.h>)
+#ifndef USING_VOUCHERS
+#define USING_VOUCHERS
+#endif
+#ifndef __VOUCHER_FORWARD_TYPE_DECLS__
+#define __VOUCHER_FORWARD_TYPE_DECLS__
+#ifdef __cplusplus
+extern "C" {
+#endif
+	extern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import));
+#ifdef __cplusplus
+}
+#endif
+#endif // __VOUCHER_FORWARD_TYPE_DECLS__
+#endif // __has_include(<mach/mach_voucher_types.h>)
+#endif // __has_include
+#endif // !KERNEL
+	
+/* END VOUCHER CODE */
+
+	
+/* BEGIN MIG_STRNCPY_ZEROFILL CODE */
+
+#if defined(__has_include)
+#if __has_include(<mach/mig_strncpy_zerofill_support.h>)
+#ifndef USING_MIG_STRNCPY_ZEROFILL
+#define USING_MIG_STRNCPY_ZEROFILL
+#endif
+#ifndef __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__
+#define __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__
+#ifdef __cplusplus
+extern "C" {
+#endif
+	extern int mig_strncpy_zerofill(char *dest, const char *src, int len) __attribute__((weak_import));
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ */
+#endif /* __has_include(<mach/mig_strncpy_zerofill_support.h>) */
+#endif /* __has_include */
+	
+/* END MIG_STRNCPY_ZEROFILL CODE */
+
+
+#include <mach/std_types.h>
+#include <mach/mig.h>
+#include <mach/mig.h>
+#include <mach/mach_types.h>
+
+#ifndef	mig_internal
+#define	mig_internal	static __inline__
+#endif	/* mig_internal */
+
+#ifndef	mig_external
+#define mig_external
+#endif	/* mig_external */
+
+#if	!defined(__MigTypeCheck) && defined(TypeCheck)
+#define	__MigTypeCheck		TypeCheck	/* Legacy setting */
+#endif	/* !defined(__MigTypeCheck) */
+
+#if	!defined(__MigKernelSpecificCode) && defined(_MIG_KERNEL_SPECIFIC_CODE_)
+#define	__MigKernelSpecificCode	_MIG_KERNEL_SPECIFIC_CODE_	/* Legacy setting */
+#endif	/* !defined(__MigKernelSpecificCode) */
+
+#ifndef	LimitCheck
+#define	LimitCheck 0
+#endif	/* LimitCheck */
+
+#ifndef	min
+#define	min(a,b)  ( ((a) < (b))? (a): (b) )
+#endif	/* min */
+
+#if !defined(_WALIGN_)
+#define _WALIGN_(x) (((x) + 3) & ~3)
+#endif /* !defined(_WALIGN_) */
+
+#if !defined(_WALIGNSZ_)
+#define _WALIGNSZ_(x) _WALIGN_(sizeof(x))
+#endif /* !defined(_WALIGNSZ_) */
+
+#ifndef	UseStaticTemplates
+#define	UseStaticTemplates	0
+#endif	/* UseStaticTemplates */
+
+#ifndef MIG_SERVER_ROUTINE
+#define MIG_SERVER_ROUTINE
+#endif
+
+#ifndef	__DeclareRcvRpc
+#define	__DeclareRcvRpc(_NUM_, _NAME_)
+#endif	/* __DeclareRcvRpc */
+
+#ifndef	__BeforeRcvRpc
+#define	__BeforeRcvRpc(_NUM_, _NAME_)
+#endif	/* __BeforeRcvRpc */
+
+#ifndef	__AfterRcvRpc
+#define	__AfterRcvRpc(_NUM_, _NAME_)
+#endif	/* __AfterRcvRpc */
+
+#ifndef	__DeclareRcvSimple
+#define	__DeclareRcvSimple(_NUM_, _NAME_)
+#endif	/* __DeclareRcvSimple */
+
+#ifndef	__BeforeRcvSimple
+#define	__BeforeRcvSimple(_NUM_, _NAME_)
+#endif	/* __BeforeRcvSimple */
+
+#ifndef	__AfterRcvSimple
+#define	__AfterRcvSimple(_NUM_, _NAME_)
+#endif	/* __AfterRcvSimple */
+
+#define novalue void
+
+#define msgh_request_port	msgh_local_port
+#define MACH_MSGH_BITS_REQUEST(bits)	MACH_MSGH_BITS_LOCAL(bits)
+#define msgh_reply_port		msgh_remote_port
+#define MACH_MSGH_BITS_REPLY(bits)	MACH_MSGH_BITS_REMOTE(bits)
+
+#define MIG_RETURN_ERROR(X, code)	{\
+				((mig_reply_error_t *)X)->RetCode = code;\
+				((mig_reply_error_t *)X)->NDR = NDR_record;\
+				return;\
+				}
+
+/* typedefs for all requests */
+
+#ifndef __Request__mach_exc_subsystem__defined
+#define __Request__mach_exc_subsystem__defined
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		/* start of the kernel processed data */
+		mach_msg_body_t msgh_body;
+		mach_msg_port_descriptor_t thread;
+		mach_msg_port_descriptor_t task;
+		/* end of the kernel processed data */
+		NDR_record_t NDR;
+		exception_type_t exception;
+		mach_msg_type_number_t codeCnt;
+		int64_t code[2];
+	} __Request__mach_exception_raise_t __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		exception_type_t exception;
+		mach_msg_type_number_t codeCnt;
+		int64_t code[2];
+		int flavor;
+		mach_msg_type_number_t old_stateCnt;
+		natural_t old_state[614];
+	} __Request__mach_exception_raise_state_t __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		/* start of the kernel processed data */
+		mach_msg_body_t msgh_body;
+		mach_msg_port_descriptor_t thread;
+		mach_msg_port_descriptor_t task;
+		/* end of the kernel processed data */
+		NDR_record_t NDR;
+		exception_type_t exception;
+		mach_msg_type_number_t codeCnt;
+		int64_t code[2];
+		int flavor;
+		mach_msg_type_number_t old_stateCnt;
+		natural_t old_state[614];
+	} __Request__mach_exception_raise_state_identity_t __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+#endif /* !__Request__mach_exc_subsystem__defined */
+
+/* typedefs for all replies */
+
+#ifndef __Reply__mach_exc_subsystem__defined
+#define __Reply__mach_exc_subsystem__defined
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		kern_return_t RetCode;
+	} __Reply__mach_exception_raise_t __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		kern_return_t RetCode;
+		int flavor;
+		mach_msg_type_number_t new_stateCnt;
+		natural_t new_state[614];
+	} __Reply__mach_exception_raise_state_t __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		kern_return_t RetCode;
+		int flavor;
+		mach_msg_type_number_t new_stateCnt;
+		natural_t new_state[614];
+	} __Reply__mach_exception_raise_state_identity_t __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+#endif /* !__Reply__mach_exc_subsystem__defined */
+
+
+/* union of all replies */
+
+#ifndef __ReplyUnion__catch_mach_exc_subsystem__defined
+#define __ReplyUnion__catch_mach_exc_subsystem__defined
+union __ReplyUnion__catch_mach_exc_subsystem {
+	__Reply__mach_exception_raise_t Reply_mach_exception_raise;
+	__Reply__mach_exception_raise_state_t Reply_mach_exception_raise_state;
+	__Reply__mach_exception_raise_state_identity_t Reply_mach_exception_raise_state_identity;
+};
+#endif /* __ReplyUnion__catch_mach_exc_subsystem__defined */
+/* Forward Declarations */
+
+
+mig_internal novalue _Xmach_exception_raise
+	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
+
+mig_internal novalue _Xmach_exception_raise_state
+	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
+
+mig_internal novalue _Xmach_exception_raise_state_identity
+	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
+
+
+#if ( __MigTypeCheck )
+#if __MIG_check__Request__mach_exc_subsystem__
+#if !defined(__MIG_check__Request__mach_exception_raise_t__defined)
+#define __MIG_check__Request__mach_exception_raise_t__defined
+
+mig_internal kern_return_t __MIG_check__Request__mach_exception_raise_t(__attribute__((__unused__)) __Request__mach_exception_raise_t *In0P)
+{
+
+	typedef __Request__mach_exception_raise_t __Request;
+#if	__MigTypeCheck
+	unsigned int msgh_size;
+#endif	/* __MigTypeCheck */
+
+#if	__MigTypeCheck
+	msgh_size = In0P->Head.msgh_size;
+	if (!(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||
+	    (In0P->msgh_body.msgh_descriptor_count != 2) ||
+	    (msgh_size < (mach_msg_size_t)(sizeof(__Request) - 16)) ||  (msgh_size > (mach_msg_size_t)sizeof(__Request)))
+		return MIG_BAD_ARGUMENTS;
+#endif	/* __MigTypeCheck */
+
+#if	__MigTypeCheck
+	if (In0P->thread.type != MACH_MSG_PORT_DESCRIPTOR ||
+	    In0P->thread.disposition != 17)
+		return MIG_TYPE_ERROR;
+#endif	/* __MigTypeCheck */
+
+#if	__MigTypeCheck
+	if (In0P->task.type != MACH_MSG_PORT_DESCRIPTOR ||
+	    In0P->task.disposition != 17)
+		return MIG_TYPE_ERROR;
+#endif	/* __MigTypeCheck */
+
+#if defined(__NDR_convert__int_rep__Request__mach_exception_raise_t__codeCnt__defined)
+	if (In0P->NDR.int_rep != NDR_record.int_rep)
+		__NDR_convert__int_rep__Request__mach_exception_raise_t__codeCnt(&In0P->codeCnt, In0P->NDR.int_rep);
+#endif	/* __NDR_convert__int_rep__Request__mach_exception_raise_t__codeCnt__defined */
+#if	__MigTypeCheck
+	if ( In0P->codeCnt > 2 )
+		return MIG_BAD_ARGUMENTS;
+	if (((msgh_size - (mach_msg_size_t)(sizeof(__Request) - 16)) / 8 < In0P->codeCnt) ||
+	    (msgh_size != (mach_msg_size_t)(sizeof(__Request) - 16) + (8 * In0P->codeCnt)))
+		return MIG_BAD_ARGUMENTS;
+#endif	/* __MigTypeCheck */
+
+	return MACH_MSG_SUCCESS;
+}
+#endif /* !defined(__MIG_check__Request__mach_exception_raise_t__defined) */
+#endif /* __MIG_check__Request__mach_exc_subsystem__ */
+#endif /* ( __MigTypeCheck ) */
+
+
+/* Routine mach_exception_raise */
+#ifdef	mig_external
+mig_external
+#else
+extern
+#endif	/* mig_external */
+MIG_SERVER_ROUTINE
+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 codeCnt
+);
+
+/* Routine mach_exception_raise */
+mig_internal novalue _Xmach_exception_raise
+	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
+{
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		/* start of the kernel processed data */
+		mach_msg_body_t msgh_body;
+		mach_msg_port_descriptor_t thread;
+		mach_msg_port_descriptor_t task;
+		/* end of the kernel processed data */
+		NDR_record_t NDR;
+		exception_type_t exception;
+		mach_msg_type_number_t codeCnt;
+		int64_t code[2];
+		mach_msg_trailer_t trailer;
+	} Request __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+	typedef __Request__mach_exception_raise_t __Request;
+	typedef __Reply__mach_exception_raise_t Reply __attribute__((unused));
+
+	/*
+	 * typedef struct {
+	 * 	mach_msg_header_t Head;
+	 * 	NDR_record_t NDR;
+	 * 	kern_return_t RetCode;
+	 * } mig_reply_error_t;
+	 */
+
+	Request *In0P = (Request *) InHeadP;
+	Reply *OutP = (Reply *) OutHeadP;
+#ifdef	__MIG_check__Request__mach_exception_raise_t__defined
+	kern_return_t check_result;
+#endif	/* __MIG_check__Request__mach_exception_raise_t__defined */
+
+	__DeclareRcvRpc(2405, "mach_exception_raise")
+	__BeforeRcvRpc(2405, "mach_exception_raise")
+
+#if	defined(__MIG_check__Request__mach_exception_raise_t__defined)
+	check_result = __MIG_check__Request__mach_exception_raise_t((__Request *)In0P);
+	if (check_result != MACH_MSG_SUCCESS)
+		{ MIG_RETURN_ERROR(OutP, check_result); }
+#endif	/* defined(__MIG_check__Request__mach_exception_raise_t__defined) */
+
+	OutP->RetCode = catch_mach_exception_raise(In0P->Head.msgh_request_port, In0P->thread.name, In0P->task.name, In0P->exception, In0P->code, In0P->codeCnt);
+
+	OutP->NDR = NDR_record;
+
+
+	__AfterRcvRpc(2405, "mach_exception_raise")
+}
+
+#if ( __MigTypeCheck )
+#if __MIG_check__Request__mach_exc_subsystem__
+#if !defined(__MIG_check__Request__mach_exception_raise_state_t__defined)
+#define __MIG_check__Request__mach_exception_raise_state_t__defined
+
+mig_internal kern_return_t __MIG_check__Request__mach_exception_raise_state_t(__attribute__((__unused__)) __Request__mach_exception_raise_state_t *In0P, __attribute__((__unused__)) __Request__mach_exception_raise_state_t **In1PP)
+{
+
+	typedef __Request__mach_exception_raise_state_t __Request;
+	__Request *In1P;
+#if	__MigTypeCheck
+	unsigned int msgh_size;
+#endif	/* __MigTypeCheck */
+	unsigned int msgh_size_delta;
+
+#if	__MigTypeCheck
+	msgh_size = In0P->Head.msgh_size;
+	if ((In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||
+	    (msgh_size < (mach_msg_size_t)(sizeof(__Request) - 2472)) ||  (msgh_size > (mach_msg_size_t)sizeof(__Request)))
+		return MIG_BAD_ARGUMENTS;
+#endif	/* __MigTypeCheck */
+
+#if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_t__codeCnt__defined)
+	if (In0P->NDR.int_rep != NDR_record.int_rep)
+		__NDR_convert__int_rep__Request__mach_exception_raise_state_t__codeCnt(&In0P->codeCnt, In0P->NDR.int_rep);
+#endif	/* __NDR_convert__int_rep__Request__mach_exception_raise_state_t__codeCnt__defined */
+	msgh_size_delta = (8 * In0P->codeCnt);
+#if	__MigTypeCheck
+	if ( In0P->codeCnt > 2 )
+		return MIG_BAD_ARGUMENTS;
+	if (((msgh_size - (mach_msg_size_t)(sizeof(__Request) - 2472)) / 8 < In0P->codeCnt) ||
+	    (msgh_size < (mach_msg_size_t)(sizeof(__Request) - 2472) + (8 * In0P->codeCnt)))
+		return MIG_BAD_ARGUMENTS;
+	msgh_size -= msgh_size_delta;
+#endif	/* __MigTypeCheck */
+
+	*In1PP = In1P = (__Request *) ((pointer_t) In0P + msgh_size_delta - 16);
+
+#if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_stateCnt__defined)
+	if (In0P->NDR.int_rep != NDR_record.int_rep)
+		__NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_stateCnt(&In1P->old_stateCnt, In1P->NDR.int_rep);
+#endif	/* __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_stateCnt__defined */
+#if	__MigTypeCheck
+	if ( In1P->old_stateCnt > 614 )
+		return MIG_BAD_ARGUMENTS;
+	if (((msgh_size - (mach_msg_size_t)(sizeof(__Request) - 2472)) / 4 < In1P->old_stateCnt) ||
+	    (msgh_size != (mach_msg_size_t)(sizeof(__Request) - 2472) + (4 * In1P->old_stateCnt)))
+		return MIG_BAD_ARGUMENTS;
+#endif	/* __MigTypeCheck */
+
+	return MACH_MSG_SUCCESS;
+}
+#endif /* !defined(__MIG_check__Request__mach_exception_raise_state_t__defined) */
+#endif /* __MIG_check__Request__mach_exc_subsystem__ */
+#endif /* ( __MigTypeCheck ) */
+
+
+/* Routine mach_exception_raise_state */
+#ifdef	mig_external
+mig_external
+#else
+extern
+#endif	/* mig_external */
+MIG_SERVER_ROUTINE
+kern_return_t catch_mach_exception_raise_state
+(
+	mach_port_t exception_port,
+	exception_type_t exception,
+	const mach_exception_data_t code,
+	mach_msg_type_number_t codeCnt,
+	int *flavor,
+	const thread_state_t old_state,
+	mach_msg_type_number_t old_stateCnt,
+	thread_state_t new_state,
+	mach_msg_type_number_t *new_stateCnt
+);
+
+/* Routine mach_exception_raise_state */
+mig_internal novalue _Xmach_exception_raise_state
+	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
+{
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		exception_type_t exception;
+		mach_msg_type_number_t codeCnt;
+		int64_t code[2];
+		int flavor;
+		mach_msg_type_number_t old_stateCnt;
+		natural_t old_state[614];
+		mach_msg_trailer_t trailer;
+	} Request __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+	typedef __Request__mach_exception_raise_state_t __Request;
+	typedef __Reply__mach_exception_raise_state_t Reply __attribute__((unused));
+
+	/*
+	 * typedef struct {
+	 * 	mach_msg_header_t Head;
+	 * 	NDR_record_t NDR;
+	 * 	kern_return_t RetCode;
+	 * } mig_reply_error_t;
+	 */
+
+	Request *In0P = (Request *) InHeadP;
+	Request *In1P;
+	Reply *OutP = (Reply *) OutHeadP;
+#ifdef	__MIG_check__Request__mach_exception_raise_state_t__defined
+	kern_return_t check_result;
+#endif	/* __MIG_check__Request__mach_exception_raise_state_t__defined */
+
+	__DeclareRcvRpc(2406, "mach_exception_raise_state")
+	__BeforeRcvRpc(2406, "mach_exception_raise_state")
+
+#if	defined(__MIG_check__Request__mach_exception_raise_state_t__defined)
+	check_result = __MIG_check__Request__mach_exception_raise_state_t((__Request *)In0P, (__Request **)&In1P);
+	if (check_result != MACH_MSG_SUCCESS)
+		{ MIG_RETURN_ERROR(OutP, check_result); }
+#endif	/* defined(__MIG_check__Request__mach_exception_raise_state_t__defined) */
+
+	OutP->new_stateCnt = 614;
+
+	OutP->RetCode = catch_mach_exception_raise_state(In0P->Head.msgh_request_port, In0P->exception, In0P->code, In0P->codeCnt, &In1P->flavor, In1P->old_state, In1P->old_stateCnt, OutP->new_state, &OutP->new_stateCnt);
+	if (OutP->RetCode != KERN_SUCCESS) {
+		MIG_RETURN_ERROR(OutP, OutP->RetCode);
+	}
+
+	OutP->NDR = NDR_record;
+
+
+	OutP->flavor = In1P->flavor;
+	OutP->Head.msgh_size = (mach_msg_size_t)(sizeof(Reply) - 2456) + (((4 * OutP->new_stateCnt)));
+
+	__AfterRcvRpc(2406, "mach_exception_raise_state")
+}
+
+#if ( __MigTypeCheck )
+#if __MIG_check__Request__mach_exc_subsystem__
+#if !defined(__MIG_check__Request__mach_exception_raise_state_identity_t__defined)
+#define __MIG_check__Request__mach_exception_raise_state_identity_t__defined
+
+mig_internal kern_return_t __MIG_check__Request__mach_exception_raise_state_identity_t(__attribute__((__unused__)) __Request__mach_exception_raise_state_identity_t *In0P, __attribute__((__unused__)) __Request__mach_exception_raise_state_identity_t **In1PP)
+{
+
+	typedef __Request__mach_exception_raise_state_identity_t __Request;
+	__Request *In1P;
+#if	__MigTypeCheck
+	unsigned int msgh_size;
+#endif	/* __MigTypeCheck */
+	unsigned int msgh_size_delta;
+
+#if	__MigTypeCheck
+	msgh_size = In0P->Head.msgh_size;
+	if (!(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||
+	    (In0P->msgh_body.msgh_descriptor_count != 2) ||
+	    (msgh_size < (mach_msg_size_t)(sizeof(__Request) - 2472)) ||  (msgh_size > (mach_msg_size_t)sizeof(__Request)))
+		return MIG_BAD_ARGUMENTS;
+#endif	/* __MigTypeCheck */
+
+#if	__MigTypeCheck
+	if (In0P->thread.type != MACH_MSG_PORT_DESCRIPTOR ||
+	    In0P->thread.disposition != 17)
+		return MIG_TYPE_ERROR;
+#endif	/* __MigTypeCheck */
+
+#if	__MigTypeCheck
+	if (In0P->task.type != MACH_MSG_PORT_DESCRIPTOR ||
+	    In0P->task.disposition != 17)
+		return MIG_TYPE_ERROR;
+#endif	/* __MigTypeCheck */
+
+#if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__codeCnt__defined)
+	if (In0P->NDR.int_rep != NDR_record.int_rep)
+		__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__codeCnt(&In0P->codeCnt, In0P->NDR.int_rep);
+#endif	/* __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__codeCnt__defined */
+	msgh_size_delta = (8 * In0P->codeCnt);
+#if	__MigTypeCheck
+	if ( In0P->codeCnt > 2 )
+		return MIG_BAD_ARGUMENTS;
+	if (((msgh_size - (mach_msg_size_t)(sizeof(__Request) - 2472)) / 8 < In0P->codeCnt) ||
+	    (msgh_size < (mach_msg_size_t)(sizeof(__Request) - 2472) + (8 * In0P->codeCnt)))
+		return MIG_BAD_ARGUMENTS;
+	msgh_size -= msgh_size_delta;
+#endif	/* __MigTypeCheck */
+
+	*In1PP = In1P = (__Request *) ((pointer_t) In0P + msgh_size_delta - 16);
+
+#if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_stateCnt__defined)
+	if (In0P->NDR.int_rep != NDR_record.int_rep)
+		__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_stateCnt(&In1P->old_stateCnt, In1P->NDR.int_rep);
+#endif	/* __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_stateCnt__defined */
+#if	__MigTypeCheck
+	if ( In1P->old_stateCnt > 614 )
+		return MIG_BAD_ARGUMENTS;
+	if (((msgh_size - (mach_msg_size_t)(sizeof(__Request) - 2472)) / 4 < In1P->old_stateCnt) ||
+	    (msgh_size != (mach_msg_size_t)(sizeof(__Request) - 2472) + (4 * In1P->old_stateCnt)))
+		return MIG_BAD_ARGUMENTS;
+#endif	/* __MigTypeCheck */
+
+	return MACH_MSG_SUCCESS;
+}
+#endif /* !defined(__MIG_check__Request__mach_exception_raise_state_identity_t__defined) */
+#endif /* __MIG_check__Request__mach_exc_subsystem__ */
+#endif /* ( __MigTypeCheck ) */
+
+
+/* Routine mach_exception_raise_state_identity */
+#ifdef	mig_external
+mig_external
+#else
+extern
+#endif	/* mig_external */
+MIG_SERVER_ROUTINE
+kern_return_t catch_mach_exception_raise_state_identity
+(
+	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 codeCnt,
+	int *flavor,
+	thread_state_t old_state,
+	mach_msg_type_number_t old_stateCnt,
+	thread_state_t new_state,
+	mach_msg_type_number_t *new_stateCnt
+);
+
+/* Routine mach_exception_raise_state_identity */
+mig_internal novalue _Xmach_exception_raise_state_identity
+	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
+{
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		/* start of the kernel processed data */
+		mach_msg_body_t msgh_body;
+		mach_msg_port_descriptor_t thread;
+		mach_msg_port_descriptor_t task;
+		/* end of the kernel processed data */
+		NDR_record_t NDR;
+		exception_type_t exception;
+		mach_msg_type_number_t codeCnt;
+		int64_t code[2];
+		int flavor;
+		mach_msg_type_number_t old_stateCnt;
+		natural_t old_state[614];
+		mach_msg_trailer_t trailer;
+	} Request __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+	typedef __Request__mach_exception_raise_state_identity_t __Request;
+	typedef __Reply__mach_exception_raise_state_identity_t Reply __attribute__((unused));
+
+	/*
+	 * typedef struct {
+	 * 	mach_msg_header_t Head;
+	 * 	NDR_record_t NDR;
+	 * 	kern_return_t RetCode;
+	 * } mig_reply_error_t;
+	 */
+
+	Request *In0P = (Request *) InHeadP;
+	Request *In1P;
+	Reply *OutP = (Reply *) OutHeadP;
+#ifdef	__MIG_check__Request__mach_exception_raise_state_identity_t__defined
+	kern_return_t check_result;
+#endif	/* __MIG_check__Request__mach_exception_raise_state_identity_t__defined */
+
+	__DeclareRcvRpc(2407, "mach_exception_raise_state_identity")
+	__BeforeRcvRpc(2407, "mach_exception_raise_state_identity")
+
+#if	defined(__MIG_check__Request__mach_exception_raise_state_identity_t__defined)
+	check_result = __MIG_check__Request__mach_exception_raise_state_identity_t((__Request *)In0P, (__Request **)&In1P);
+	if (check_result != MACH_MSG_SUCCESS)
+		{ MIG_RETURN_ERROR(OutP, check_result); }
+#endif	/* defined(__MIG_check__Request__mach_exception_raise_state_identity_t__defined) */
+
+	OutP->new_stateCnt = 614;
+
+	OutP->RetCode = catch_mach_exception_raise_state_identity(In0P->Head.msgh_request_port, In0P->thread.name, In0P->task.name, In0P->exception, In0P->code, In0P->codeCnt, &In1P->flavor, In1P->old_state, In1P->old_stateCnt, OutP->new_state, &OutP->new_stateCnt);
+	if (OutP->RetCode != KERN_SUCCESS) {
+		MIG_RETURN_ERROR(OutP, OutP->RetCode);
+	}
+
+	OutP->NDR = NDR_record;
+
+
+	OutP->flavor = In1P->flavor;
+	OutP->Head.msgh_size = (mach_msg_size_t)(sizeof(Reply) - 2456) + (((4 * OutP->new_stateCnt)));
+
+	__AfterRcvRpc(2407, "mach_exception_raise_state_identity")
+}
+
+
+#ifdef	mig_external
+mig_external
+#else
+extern
+#endif	/* mig_external */
+boolean_t mach_exc_server(
+		mach_msg_header_t *InHeadP,
+		mach_msg_header_t *OutHeadP);
+
+#ifdef	mig_external
+mig_external
+#else
+extern
+#endif	/* mig_external */
+mig_routine_t mach_exc_server_routine(
+		mach_msg_header_t *InHeadP);
+
+
+/* Description of this subsystem, for use in direct RPC */
+const struct catch_mach_exc_subsystem {
+	mig_server_routine_t 	server;	/* Server routine */
+	mach_msg_id_t	start;	/* Min routine number */
+	mach_msg_id_t	end;	/* Max routine number + 1 */
+	unsigned int	maxsize;	/* Max msg size */
+	vm_address_t	reserved;	/* Reserved */
+	struct routine_descriptor	/*Array of routine descriptors */
+		routine[3];
+} catch_mach_exc_subsystem = {
+	mach_exc_server_routine,
+	2405,
+	2408,
+	(mach_msg_size_t)sizeof(union __ReplyUnion__catch_mach_exc_subsystem),
+	(vm_address_t)0,
+	{
+          { (mig_impl_routine_t) 0,
+          (mig_stub_routine_t) _Xmach_exception_raise, 6, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__mach_exception_raise_t)},
+          { (mig_impl_routine_t) 0,
+          (mig_stub_routine_t) _Xmach_exception_raise_state, 9, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__mach_exception_raise_state_t)},
+          { (mig_impl_routine_t) 0,
+          (mig_stub_routine_t) _Xmach_exception_raise_state_identity, 11, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__mach_exception_raise_state_identity_t)},
+	}
+};
+
+mig_external boolean_t mach_exc_server
+	(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
+{
+	/*
+	 * typedef struct {
+	 * 	mach_msg_header_t Head;
+	 * 	NDR_record_t NDR;
+	 * 	kern_return_t RetCode;
+	 * } mig_reply_error_t;
+	 */
+
+	mig_routine_t routine;
+
+	OutHeadP->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InHeadP->msgh_bits), 0);
+	OutHeadP->msgh_remote_port = InHeadP->msgh_reply_port;
+	/* Minimal size: routine() will update it if different */
+	OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);
+	OutHeadP->msgh_local_port = MACH_PORT_NULL;
+	OutHeadP->msgh_id = InHeadP->msgh_id + 100;
+	OutHeadP->msgh_reserved = 0;
+
+	if ((InHeadP->msgh_id > 2407) || (InHeadP->msgh_id < 2405) ||
+	    ((routine = catch_mach_exc_subsystem.routine[InHeadP->msgh_id - 2405].stub_routine) == 0)) {
+		((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;
+		((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID;
+		return FALSE;
+	}
+	(*routine) (InHeadP, OutHeadP);
+	return TRUE;
+}
+
+mig_external mig_routine_t mach_exc_server_routine
+	(mach_msg_header_t *InHeadP)
+{
+	int msgh_id;
+
+	msgh_id = InHeadP->msgh_id - 2405;
+
+	if ((msgh_id > 2) || (msgh_id < 0))
+		return 0;
+
+	return catch_mach_exc_subsystem.routine[msgh_id].stub_routine;
+}

+ 810 - 0
include/mdbg/mach_excUser.c

@@ -0,0 +1,810 @@
+/*
+ * IDENTIFICATION:
+ * stub generated Tue Apr  7 09:10:21 2020
+ * with a MiG generated by bootstrap_cmds-116
+ * OPTIONS: 
+ */
+#define	__MIG_check__Reply__mach_exc_subsystem__ 1
+
+#include "mach_exc.h"
+
+/* TODO: #include <mach/mach.h> */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+extern void mach_msg_destroy(mach_msg_header_t *);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#ifndef	mig_internal
+#define	mig_internal	static __inline__
+#endif	/* mig_internal */
+
+#ifndef	mig_external
+#define mig_external
+#endif	/* mig_external */
+
+#if	!defined(__MigTypeCheck) && defined(TypeCheck)
+#define	__MigTypeCheck		TypeCheck	/* Legacy setting */
+#endif	/* !defined(__MigTypeCheck) */
+
+#if	!defined(__MigKernelSpecificCode) && defined(_MIG_KERNEL_SPECIFIC_CODE_)
+#define	__MigKernelSpecificCode	_MIG_KERNEL_SPECIFIC_CODE_	/* Legacy setting */
+#endif	/* !defined(__MigKernelSpecificCode) */
+
+#ifndef	LimitCheck
+#define	LimitCheck 0
+#endif	/* LimitCheck */
+
+#ifndef	min
+#define	min(a,b)  ( ((a) < (b))? (a): (b) )
+#endif	/* min */
+
+#if !defined(_WALIGN_)
+#define _WALIGN_(x) (((x) + 3) & ~3)
+#endif /* !defined(_WALIGN_) */
+
+#if !defined(_WALIGNSZ_)
+#define _WALIGNSZ_(x) _WALIGN_(sizeof(x))
+#endif /* !defined(_WALIGNSZ_) */
+
+#ifndef	UseStaticTemplates
+#define	UseStaticTemplates	0
+#endif	/* UseStaticTemplates */
+
+#ifndef MIG_SERVER_ROUTINE
+#define MIG_SERVER_ROUTINE
+#endif
+
+#ifndef	__MachMsgErrorWithTimeout
+#define	__MachMsgErrorWithTimeout(_R_) { \
+	switch (_R_) { \
+	case MACH_SEND_INVALID_DATA: \
+	case MACH_SEND_INVALID_DEST: \
+	case MACH_SEND_INVALID_HEADER: \
+		mig_put_reply_port(InP->Head.msgh_reply_port); \
+		break; \
+	case MACH_SEND_TIMED_OUT: \
+	case MACH_RCV_TIMED_OUT: \
+	default: \
+		mig_dealloc_reply_port(InP->Head.msgh_reply_port); \
+	} \
+}
+#endif	/* __MachMsgErrorWithTimeout */
+
+#ifndef	__MachMsgErrorWithoutTimeout
+#define	__MachMsgErrorWithoutTimeout(_R_) { \
+	switch (_R_) { \
+	case MACH_SEND_INVALID_DATA: \
+	case MACH_SEND_INVALID_DEST: \
+	case MACH_SEND_INVALID_HEADER: \
+		mig_put_reply_port(InP->Head.msgh_reply_port); \
+		break; \
+	default: \
+		mig_dealloc_reply_port(InP->Head.msgh_reply_port); \
+	} \
+}
+#endif	/* __MachMsgErrorWithoutTimeout */
+
+#ifndef	__DeclareSendRpc
+#define	__DeclareSendRpc(_NUM_, _NAME_)
+#endif	/* __DeclareSendRpc */
+
+#ifndef	__BeforeSendRpc
+#define	__BeforeSendRpc(_NUM_, _NAME_)
+#endif	/* __BeforeSendRpc */
+
+#ifndef	__AfterSendRpc
+#define	__AfterSendRpc(_NUM_, _NAME_)
+#endif	/* __AfterSendRpc */
+
+#ifndef	__DeclareSendSimple
+#define	__DeclareSendSimple(_NUM_, _NAME_)
+#endif	/* __DeclareSendSimple */
+
+#ifndef	__BeforeSendSimple
+#define	__BeforeSendSimple(_NUM_, _NAME_)
+#endif	/* __BeforeSendSimple */
+
+#ifndef	__AfterSendSimple
+#define	__AfterSendSimple(_NUM_, _NAME_)
+#endif	/* __AfterSendSimple */
+
+#define msgh_request_port	msgh_remote_port
+#define msgh_reply_port		msgh_local_port
+
+
+
+#if ( __MigTypeCheck )
+#if __MIG_check__Reply__mach_exc_subsystem__
+#if !defined(__MIG_check__Reply__mach_exception_raise_t__defined)
+#define __MIG_check__Reply__mach_exception_raise_t__defined
+
+mig_internal kern_return_t __MIG_check__Reply__mach_exception_raise_t(__Reply__mach_exception_raise_t *Out0P)
+{
+
+	typedef __Reply__mach_exception_raise_t __Reply __attribute__((unused));
+	if (Out0P->Head.msgh_id != 2505) {
+	    if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)
+		{ return MIG_SERVER_DIED; }
+	    else
+		{ return MIG_REPLY_MISMATCH; }
+	}
+
+#if	__MigTypeCheck
+	if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||
+	    (Out0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Reply)))
+		{ return MIG_TYPE_ERROR ; }
+#endif	/* __MigTypeCheck */
+
+#if	__MigTypeCheck
+	if (Out0P->Head.msgh_request_port != MACH_PORT_NULL) {
+		return MIG_TYPE_ERROR;
+	}
+#endif	/* __MigTypeCheck */
+	{
+		return Out0P->RetCode;
+	}
+}
+#endif /* !defined(__MIG_check__Reply__mach_exception_raise_t__defined) */
+#endif /* __MIG_check__Reply__mach_exc_subsystem__ */
+#endif /* ( __MigTypeCheck ) */
+
+
+/* Routine mach_exception_raise */
+mig_external kern_return_t 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 codeCnt
+)
+{
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		/* start of the kernel processed data */
+		mach_msg_body_t msgh_body;
+		mach_msg_port_descriptor_t thread;
+		mach_msg_port_descriptor_t task;
+		/* end of the kernel processed data */
+		NDR_record_t NDR;
+		exception_type_t exception;
+		mach_msg_type_number_t codeCnt;
+		int64_t code[2];
+	} Request __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		kern_return_t RetCode;
+		mach_msg_trailer_t trailer;
+	} Reply __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		kern_return_t RetCode;
+	} __Reply __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+	/*
+	 * typedef struct {
+	 * 	mach_msg_header_t Head;
+	 * 	NDR_record_t NDR;
+	 * 	kern_return_t RetCode;
+	 * } mig_reply_error_t;
+	 */
+
+	union {
+		Request In;
+		Reply Out;
+	} Mess;
+
+	Request *InP = &Mess.In;
+	Reply *Out0P = &Mess.Out;
+
+	mach_msg_return_t msg_result;
+	unsigned int msgh_size;
+
+#ifdef	__MIG_check__Reply__mach_exception_raise_t__defined
+	kern_return_t check_result;
+#endif	/* __MIG_check__Reply__mach_exception_raise_t__defined */
+
+	__DeclareSendRpc(2405, "mach_exception_raise")
+
+#if	UseStaticTemplates
+	const static mach_msg_port_descriptor_t threadTemplate = {
+		/* name = */		MACH_PORT_NULL,
+		/* pad1 = */		0,
+		/* pad2 = */		0,
+		/* disp = */		19,
+		/* type = */		MACH_MSG_PORT_DESCRIPTOR,
+	};
+#endif	/* UseStaticTemplates */
+
+#if	UseStaticTemplates
+	const static mach_msg_port_descriptor_t taskTemplate = {
+		/* name = */		MACH_PORT_NULL,
+		/* pad1 = */		0,
+		/* pad2 = */		0,
+		/* disp = */		19,
+		/* type = */		MACH_MSG_PORT_DESCRIPTOR,
+	};
+#endif	/* UseStaticTemplates */
+
+	InP->msgh_body.msgh_descriptor_count = 2;
+#if	UseStaticTemplates
+	InP->thread = threadTemplate;
+	InP->thread.name = thread;
+#else	/* UseStaticTemplates */
+	InP->thread.name = thread;
+	InP->thread.disposition = 19;
+	InP->thread.type = MACH_MSG_PORT_DESCRIPTOR;
+#endif	/* UseStaticTemplates */
+
+#if	UseStaticTemplates
+	InP->task = taskTemplate;
+	InP->task.name = task;
+#else	/* UseStaticTemplates */
+	InP->task.name = task;
+	InP->task.disposition = 19;
+	InP->task.type = MACH_MSG_PORT_DESCRIPTOR;
+#endif	/* UseStaticTemplates */
+
+	InP->NDR = NDR_record;
+
+	InP->exception = exception;
+
+	if (codeCnt > 2) {
+		{ return MIG_ARRAY_TOO_LARGE; }
+	}
+	(void)memcpy((char *) InP->code, (const char *) code, 8 * codeCnt);
+
+	InP->codeCnt = codeCnt;
+
+	msgh_size = (mach_msg_size_t)(sizeof(Request) - 16) + ((8 * codeCnt));
+	InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX|
+		MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+	/* msgh_size passed as argument */
+	InP->Head.msgh_request_port = exception_port;
+	InP->Head.msgh_reply_port = mig_get_reply_port();
+	InP->Head.msgh_id = 2405;
+	InP->Head.msgh_reserved = 0;
+	
+/* BEGIN VOUCHER CODE */
+
+#ifdef USING_VOUCHERS
+	if (voucher_mach_msg_set != NULL) {
+		voucher_mach_msg_set(&InP->Head);
+	}
+#endif // USING_VOUCHERS
+	
+/* END VOUCHER CODE */
+
+	__BeforeSendRpc(2405, "mach_exception_raise")
+	msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+	__AfterSendRpc(2405, "mach_exception_raise")
+	if (msg_result != MACH_MSG_SUCCESS) {
+		__MachMsgErrorWithoutTimeout(msg_result);
+	}
+	if (msg_result != MACH_MSG_SUCCESS) {
+		{ return msg_result; }
+	}
+
+
+#if	defined(__MIG_check__Reply__mach_exception_raise_t__defined)
+	check_result = __MIG_check__Reply__mach_exception_raise_t((__Reply__mach_exception_raise_t *)Out0P);
+	if (check_result != MACH_MSG_SUCCESS) {
+		mach_msg_destroy(&Out0P->Head);
+		{ return check_result; }
+	}
+#endif	/* defined(__MIG_check__Reply__mach_exception_raise_t__defined) */
+
+	return KERN_SUCCESS;
+}
+
+#if ( __MigTypeCheck )
+#if __MIG_check__Reply__mach_exc_subsystem__
+#if !defined(__MIG_check__Reply__mach_exception_raise_state_t__defined)
+#define __MIG_check__Reply__mach_exception_raise_state_t__defined
+
+mig_internal kern_return_t __MIG_check__Reply__mach_exception_raise_state_t(__Reply__mach_exception_raise_state_t *Out0P)
+{
+
+	typedef __Reply__mach_exception_raise_state_t __Reply __attribute__((unused));
+#if	__MigTypeCheck
+	unsigned int msgh_size;
+#endif	/* __MigTypeCheck */
+
+	if (Out0P->Head.msgh_id != 2506) {
+	    if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)
+		{ return MIG_SERVER_DIED; }
+	    else
+		{ return MIG_REPLY_MISMATCH; }
+	}
+
+#if	__MigTypeCheck
+	msgh_size = Out0P->Head.msgh_size;
+
+	if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||
+	    ((msgh_size > (mach_msg_size_t)sizeof(__Reply) || msgh_size < (mach_msg_size_t)(sizeof(__Reply) - 2456)) &&
+	     (msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||
+	      Out0P->RetCode == KERN_SUCCESS)))
+		{ return MIG_TYPE_ERROR ; }
+#endif	/* __MigTypeCheck */
+
+#if	__MigTypeCheck
+	if (Out0P->Head.msgh_request_port != MACH_PORT_NULL) {
+		return MIG_TYPE_ERROR;
+	}
+#endif	/* __MigTypeCheck */
+	if (Out0P->RetCode != KERN_SUCCESS) {
+		return ((mig_reply_error_t *)Out0P)->RetCode;
+	}
+
+#if	__MigTypeCheck
+	if ( Out0P->new_stateCnt > 614 )
+		return MIG_TYPE_ERROR;
+	if (((msgh_size - (mach_msg_size_t)(sizeof(__Reply) - 2456)) / 4< Out0P->new_stateCnt) ||
+	    (msgh_size != (mach_msg_size_t)(sizeof(__Reply) - 2456) + Out0P->new_stateCnt * 4))
+		{ return MIG_TYPE_ERROR ; }
+#endif	/* __MigTypeCheck */
+
+	return MACH_MSG_SUCCESS;
+}
+#endif /* !defined(__MIG_check__Reply__mach_exception_raise_state_t__defined) */
+#endif /* __MIG_check__Reply__mach_exc_subsystem__ */
+#endif /* ( __MigTypeCheck ) */
+
+
+/* Routine mach_exception_raise_state */
+mig_external kern_return_t mach_exception_raise_state
+(
+	mach_port_t exception_port,
+	exception_type_t exception,
+	const mach_exception_data_t code,
+	mach_msg_type_number_t codeCnt,
+	int *flavor,
+	const thread_state_t old_state,
+	mach_msg_type_number_t old_stateCnt,
+	thread_state_t new_state,
+	mach_msg_type_number_t *new_stateCnt
+)
+{
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		exception_type_t exception;
+		mach_msg_type_number_t codeCnt;
+		int64_t code[2];
+		int flavor;
+		mach_msg_type_number_t old_stateCnt;
+		natural_t old_state[614];
+	} Request __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		kern_return_t RetCode;
+		int flavor;
+		mach_msg_type_number_t new_stateCnt;
+		natural_t new_state[614];
+		mach_msg_trailer_t trailer;
+	} Reply __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		kern_return_t RetCode;
+		int flavor;
+		mach_msg_type_number_t new_stateCnt;
+		natural_t new_state[614];
+	} __Reply __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+	/*
+	 * typedef struct {
+	 * 	mach_msg_header_t Head;
+	 * 	NDR_record_t NDR;
+	 * 	kern_return_t RetCode;
+	 * } mig_reply_error_t;
+	 */
+
+	union {
+		Request In;
+		Reply Out;
+	} Mess;
+
+	Request *InP = &Mess.In;
+	Reply *Out0P = &Mess.Out;
+
+	mach_msg_return_t msg_result;
+	unsigned int msgh_size;
+	unsigned int msgh_size_delta;
+
+
+#ifdef	__MIG_check__Reply__mach_exception_raise_state_t__defined
+	kern_return_t check_result;
+#endif	/* __MIG_check__Reply__mach_exception_raise_state_t__defined */
+
+	__DeclareSendRpc(2406, "mach_exception_raise_state")
+
+	InP->NDR = NDR_record;
+
+	InP->exception = exception;
+
+	if (codeCnt > 2) {
+		{ return MIG_ARRAY_TOO_LARGE; }
+	}
+	(void)memcpy((char *) InP->code, (const char *) code, 8 * codeCnt);
+
+	InP->codeCnt = codeCnt;
+
+	msgh_size_delta = (8 * codeCnt);
+	msgh_size = (mach_msg_size_t)(sizeof(Request) - 2472) + msgh_size_delta;
+	InP = (Request *) ((pointer_t) InP + msgh_size_delta - 16);
+
+	InP->flavor = *flavor;
+
+	if (old_stateCnt > 614) {
+		{ return MIG_ARRAY_TOO_LARGE; }
+	}
+	(void)memcpy((char *) InP->old_state, (const char *) old_state, 4 * old_stateCnt);
+
+	InP->old_stateCnt = old_stateCnt;
+
+	msgh_size += (4 * old_stateCnt);
+	InP = &Mess.In;
+	InP->Head.msgh_bits =
+		MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+	/* msgh_size passed as argument */
+	InP->Head.msgh_request_port = exception_port;
+	InP->Head.msgh_reply_port = mig_get_reply_port();
+	InP->Head.msgh_id = 2406;
+	InP->Head.msgh_reserved = 0;
+	
+/* BEGIN VOUCHER CODE */
+
+#ifdef USING_VOUCHERS
+	if (voucher_mach_msg_set != NULL) {
+		voucher_mach_msg_set(&InP->Head);
+	}
+#endif // USING_VOUCHERS
+	
+/* END VOUCHER CODE */
+
+	__BeforeSendRpc(2406, "mach_exception_raise_state")
+	msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+	__AfterSendRpc(2406, "mach_exception_raise_state")
+	if (msg_result != MACH_MSG_SUCCESS) {
+		__MachMsgErrorWithoutTimeout(msg_result);
+	}
+	if (msg_result != MACH_MSG_SUCCESS) {
+		{ return msg_result; }
+	}
+
+
+#if	defined(__MIG_check__Reply__mach_exception_raise_state_t__defined)
+	check_result = __MIG_check__Reply__mach_exception_raise_state_t((__Reply__mach_exception_raise_state_t *)Out0P);
+	if (check_result != MACH_MSG_SUCCESS) {
+		mach_msg_destroy(&Out0P->Head);
+		{ return check_result; }
+	}
+#endif	/* defined(__MIG_check__Reply__mach_exception_raise_state_t__defined) */
+
+	*flavor = Out0P->flavor;
+
+	if (Out0P->new_stateCnt > 614) {
+		(void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 *  614);
+		*new_stateCnt = Out0P->new_stateCnt;
+		{ return MIG_ARRAY_TOO_LARGE; }
+	}
+	(void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * Out0P->new_stateCnt);
+
+	*new_stateCnt = Out0P->new_stateCnt;
+
+	return KERN_SUCCESS;
+}
+
+#if ( __MigTypeCheck )
+#if __MIG_check__Reply__mach_exc_subsystem__
+#if !defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined)
+#define __MIG_check__Reply__mach_exception_raise_state_identity_t__defined
+
+mig_internal kern_return_t __MIG_check__Reply__mach_exception_raise_state_identity_t(__Reply__mach_exception_raise_state_identity_t *Out0P)
+{
+
+	typedef __Reply__mach_exception_raise_state_identity_t __Reply __attribute__((unused));
+#if	__MigTypeCheck
+	unsigned int msgh_size;
+#endif	/* __MigTypeCheck */
+
+	if (Out0P->Head.msgh_id != 2507) {
+	    if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)
+		{ return MIG_SERVER_DIED; }
+	    else
+		{ return MIG_REPLY_MISMATCH; }
+	}
+
+#if	__MigTypeCheck
+	msgh_size = Out0P->Head.msgh_size;
+
+	if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||
+	    ((msgh_size > (mach_msg_size_t)sizeof(__Reply) || msgh_size < (mach_msg_size_t)(sizeof(__Reply) - 2456)) &&
+	     (msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||
+	      Out0P->RetCode == KERN_SUCCESS)))
+		{ return MIG_TYPE_ERROR ; }
+#endif	/* __MigTypeCheck */
+
+#if	__MigTypeCheck
+	if (Out0P->Head.msgh_request_port != MACH_PORT_NULL) {
+		return MIG_TYPE_ERROR;
+	}
+#endif	/* __MigTypeCheck */
+	if (Out0P->RetCode != KERN_SUCCESS) {
+		return ((mig_reply_error_t *)Out0P)->RetCode;
+	}
+
+#if	__MigTypeCheck
+	if ( Out0P->new_stateCnt > 614 )
+		return MIG_TYPE_ERROR;
+	if (((msgh_size - (mach_msg_size_t)(sizeof(__Reply) - 2456)) / 4< Out0P->new_stateCnt) ||
+	    (msgh_size != (mach_msg_size_t)(sizeof(__Reply) - 2456) + Out0P->new_stateCnt * 4))
+		{ return MIG_TYPE_ERROR ; }
+#endif	/* __MigTypeCheck */
+
+	return MACH_MSG_SUCCESS;
+}
+#endif /* !defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined) */
+#endif /* __MIG_check__Reply__mach_exc_subsystem__ */
+#endif /* ( __MigTypeCheck ) */
+
+
+/* Routine mach_exception_raise_state_identity */
+mig_external kern_return_t mach_exception_raise_state_identity
+(
+	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 codeCnt,
+	int *flavor,
+	thread_state_t old_state,
+	mach_msg_type_number_t old_stateCnt,
+	thread_state_t new_state,
+	mach_msg_type_number_t *new_stateCnt
+)
+{
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		/* start of the kernel processed data */
+		mach_msg_body_t msgh_body;
+		mach_msg_port_descriptor_t thread;
+		mach_msg_port_descriptor_t task;
+		/* end of the kernel processed data */
+		NDR_record_t NDR;
+		exception_type_t exception;
+		mach_msg_type_number_t codeCnt;
+		int64_t code[2];
+		int flavor;
+		mach_msg_type_number_t old_stateCnt;
+		natural_t old_state[614];
+	} Request __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		kern_return_t RetCode;
+		int flavor;
+		mach_msg_type_number_t new_stateCnt;
+		natural_t new_state[614];
+		mach_msg_trailer_t trailer;
+	} Reply __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+
+#ifdef  __MigPackStructs
+#pragma pack(push, 4)
+#endif
+	typedef struct {
+		mach_msg_header_t Head;
+		NDR_record_t NDR;
+		kern_return_t RetCode;
+		int flavor;
+		mach_msg_type_number_t new_stateCnt;
+		natural_t new_state[614];
+	} __Reply __attribute__((unused));
+#ifdef  __MigPackStructs
+#pragma pack(pop)
+#endif
+	/*
+	 * typedef struct {
+	 * 	mach_msg_header_t Head;
+	 * 	NDR_record_t NDR;
+	 * 	kern_return_t RetCode;
+	 * } mig_reply_error_t;
+	 */
+
+	union {
+		Request In;
+		Reply Out;
+	} Mess;
+
+	Request *InP = &Mess.In;
+	Reply *Out0P = &Mess.Out;
+
+	mach_msg_return_t msg_result;
+	unsigned int msgh_size;
+	unsigned int msgh_size_delta;
+
+
+#ifdef	__MIG_check__Reply__mach_exception_raise_state_identity_t__defined
+	kern_return_t check_result;
+#endif	/* __MIG_check__Reply__mach_exception_raise_state_identity_t__defined */
+
+	__DeclareSendRpc(2407, "mach_exception_raise_state_identity")
+
+#if	UseStaticTemplates
+	const static mach_msg_port_descriptor_t threadTemplate = {
+		/* name = */		MACH_PORT_NULL,
+		/* pad1 = */		0,
+		/* pad2 = */		0,
+		/* disp = */		19,
+		/* type = */		MACH_MSG_PORT_DESCRIPTOR,
+	};
+#endif	/* UseStaticTemplates */
+
+#if	UseStaticTemplates
+	const static mach_msg_port_descriptor_t taskTemplate = {
+		/* name = */		MACH_PORT_NULL,
+		/* pad1 = */		0,
+		/* pad2 = */		0,
+		/* disp = */		19,
+		/* type = */		MACH_MSG_PORT_DESCRIPTOR,
+	};
+#endif	/* UseStaticTemplates */
+
+	InP->msgh_body.msgh_descriptor_count = 2;
+#if	UseStaticTemplates
+	InP->thread = threadTemplate;
+	InP->thread.name = thread;
+#else	/* UseStaticTemplates */
+	InP->thread.name = thread;
+	InP->thread.disposition = 19;
+	InP->thread.type = MACH_MSG_PORT_DESCRIPTOR;
+#endif	/* UseStaticTemplates */
+
+#if	UseStaticTemplates
+	InP->task = taskTemplate;
+	InP->task.name = task;
+#else	/* UseStaticTemplates */
+	InP->task.name = task;
+	InP->task.disposition = 19;
+	InP->task.type = MACH_MSG_PORT_DESCRIPTOR;
+#endif	/* UseStaticTemplates */
+
+	InP->NDR = NDR_record;
+
+	InP->exception = exception;
+
+	if (codeCnt > 2) {
+		{ return MIG_ARRAY_TOO_LARGE; }
+	}
+	(void)memcpy((char *) InP->code, (const char *) code, 8 * codeCnt);
+
+	InP->codeCnt = codeCnt;
+
+	msgh_size_delta = (8 * codeCnt);
+	msgh_size = (mach_msg_size_t)(sizeof(Request) - 2472) + msgh_size_delta;
+	InP = (Request *) ((pointer_t) InP + msgh_size_delta - 16);
+
+	InP->flavor = *flavor;
+
+	if (old_stateCnt > 614) {
+		{ return MIG_ARRAY_TOO_LARGE; }
+	}
+	(void)memcpy((char *) InP->old_state, (const char *) old_state, 4 * old_stateCnt);
+
+	InP->old_stateCnt = old_stateCnt;
+
+	msgh_size += (4 * old_stateCnt);
+	InP = &Mess.In;
+	InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX|
+		MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+	/* msgh_size passed as argument */
+	InP->Head.msgh_request_port = exception_port;
+	InP->Head.msgh_reply_port = mig_get_reply_port();
+	InP->Head.msgh_id = 2407;
+	InP->Head.msgh_reserved = 0;
+	
+/* BEGIN VOUCHER CODE */
+
+#ifdef USING_VOUCHERS
+	if (voucher_mach_msg_set != NULL) {
+		voucher_mach_msg_set(&InP->Head);
+	}
+#endif // USING_VOUCHERS
+	
+/* END VOUCHER CODE */
+
+	__BeforeSendRpc(2407, "mach_exception_raise_state_identity")
+	msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+	__AfterSendRpc(2407, "mach_exception_raise_state_identity")
+	if (msg_result != MACH_MSG_SUCCESS) {
+		__MachMsgErrorWithoutTimeout(msg_result);
+	}
+	if (msg_result != MACH_MSG_SUCCESS) {
+		{ return msg_result; }
+	}
+
+
+#if	defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined)
+	check_result = __MIG_check__Reply__mach_exception_raise_state_identity_t((__Reply__mach_exception_raise_state_identity_t *)Out0P);
+	if (check_result != MACH_MSG_SUCCESS) {
+		mach_msg_destroy(&Out0P->Head);
+		{ return check_result; }
+	}
+#endif	/* defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined) */
+
+	*flavor = Out0P->flavor;
+
+	if (Out0P->new_stateCnt > 614) {
+		(void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 *  614);
+		*new_stateCnt = Out0P->new_stateCnt;
+		{ return MIG_ARRAY_TOO_LARGE; }
+	}
+	(void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * Out0P->new_stateCnt);
+
+	*new_stateCnt = Out0P->new_stateCnt;
+
+	return KERN_SUCCESS;
+}

+ 884 - 0
include/mdbg/mdbg.c

@@ -0,0 +1,884 @@
+/*
+ * Copyright (C)2005-2020 Haxe Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <time.h>
+#include <signal.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/ptrace.h>
+#include <sys/event.h>
+#include <sys/sysctl.h>
+#include <mach/mach.h>
+#include <mach/mach_types.h>
+#include <mach/mach_vm.h>
+#include <mach/vm_prot.h>
+#include <mach/exception_types.h>
+
+
+#include <mdbg/mach_exc.h>
+
+#include "mdbg.h"
+
+
+#pragma mark Defines
+
+
+#define     STATUS_TIMEOUT          -1
+#define     STATUS_EXIT              0
+#define     STATUS_BREAKPOINT        1
+#define     STATUS_SINGLESTEP        2
+#define     STATUS_ERROR             3
+#define     STATUS_HANDLED           4
+#define     STATUS_STACKOVERFLOW     5
+#define     STATUS_WATCHBREAK        0x100
+
+#define     SINGLESTEP_TRAP          0x00000100
+
+#define     MAX_EXCEPTION_PORTS      16
+
+/* Forward declarations */
+
+boolean_t mach_exc_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
+static struct debug_session *find_session(mach_port_t task);
+static mach_port_t get_task(pid_t pid);
+static mach_port_t get_thread(mach_port_t mach_task, uint thread_num);
+static uint64_t get_thread_id(thread_t thread);
+static x86_thread_state64_t* get_thread_state(mach_port_t mach_thread);
+static kern_return_t set_thread_state(thread_t mach_thread, x86_thread_state64_t *break_state);
+static x86_debug_state64_t* get_debug_state(thread_t mach_thread);
+static kern_return_t set_debug_state(thread_t mach_thread, x86_debug_state64_t *break_state);
+
+static void* task_exception_server (mach_port_t exception_port);
+
+
+#pragma mark Structs
+
+typedef struct {
+    debug_session **list;
+    unsigned int count;
+} pointer_list;
+
+pointer_list sessions;
+
+
+typedef struct {
+    mach_msg_type_number_t  count;
+    exception_mask_t        masks[MAX_EXCEPTION_PORTS];
+    exception_handler_t     ports[MAX_EXCEPTION_PORTS];
+    exception_behavior_t    behaviors[MAX_EXCEPTION_PORTS];
+    thread_state_flavor_t   flavors[MAX_EXCEPTION_PORTS];
+} exception_ports_info;
+
+
+#pragma mark Helpers
+
+static void* safe_malloc(size_t x) {
+    void *mal = malloc(x);
+    if(mal == NULL) {
+        fprintf(stderr, "[-safe_malloc] Error Exiting\n");
+        exit(-1);
+    }
+    memset(mal, 0, x);
+    return mal;
+}
+
+#pragma mark Debug
+
+#if MDBG_DEBUG
+#   define DEBUG_PRINT(fmt,...) \
+        do { fprintf(stdout, "%s[%d] %s(): " fmt "\n",__FILE__, __LINE__, __func__, ##__VA_ARGS__); } while (0);
+#   if MDBG_LOG_LEVEL > 0
+#   define DEBUG_PRINT_VERBOSE(fmt,...) \
+        do { fprintf(stdout, "%s[%d] %s(): " fmt "\n",__FILE__, __LINE__, __func__, ##__VA_ARGS__); } while (0);
+#   else
+#   define DEBUG_PRINT_VERBOSE(fmt,...)
+#endif
+#else
+#   define DEBUG_PRINT(fmt,...)
+#   define DEBUG_PRINT_VERBOSE(fmt,...)
+#endif
+
+
+#define RETURN_ON_MACH_ERROR(code,msg,...) \
+    if (code != KERN_SUCCESS) {\
+        DEBUG_PRINT(msg,##__VA_ARGS__);\
+        return code;\
+    }
+
+#define EXIT_ON_MACH_ERROR(code,msg,...) \
+    if (code != KERN_SUCCESS) {\
+        DEBUG_PRINT(msg,##__VA_ARGS__);\
+        exit(0);\
+    }
+
+#if MDBG_DEBUG
+static void log_buffer(unsigned char *buf, int size) {
+	for (int i=0; i<size; i++) {
+		printf("%02lx\t", (unsigned long)buf[i]);
+		if ((i+1)%16 == 0) printf("\n");
+	}
+}
+
+static char* get_signal_name(int sig) {
+    switch(sig) {
+        case 1: return "SIGHUP";
+        case 2: return "SIGINT";
+        case 3: return "SIGQUIT";
+        case 4: return "SIGILL";
+        case 5: return "SIGTRAP";
+        case 6: return "SIGABRT";
+        case 7: return "SIGEMT";
+        case 8: return "SIGFPE";
+        case 9: return "SIGKILL";
+        case 10: return "SIGBUS";
+        case 11: return "SIGSEGV";
+        case 12: return "SIGSYS";
+        case 13: return "SIGPIPE";
+        case 14: return "SIGALRM";
+        case 15: return "SIGTERM";
+        case 16: return "SIGURG";
+        case 17: return "SIGSTOP";
+        case 18: return "SIGTSTP";
+        case 19: return "SIGCONT";
+        case 20: return "SIGCHLD";
+        case 21: return "SIGTTIN";
+        case 22: return "SIGTTOU";
+        case 23: return "SIGIO";
+        case 24: return "SIGXCPU";
+        case 25: return "SIGXFSZ";
+        case 26: return "SIGVTALRM";
+        case 27: return "SIGPROF";
+        case 28: return "SIGWINCH";
+        case 29: return "SIGINFO";
+        case 30: return "SIGUSR1";
+        case 31: return "SIGUSR2";
+        default: return "UNKNOWN";
+    }
+}
+
+static char* exception_to_string(exception_type_t exc) {
+    switch(exc) {
+        case EXC_BREAKPOINT     : return "EXC_BREAKPOINT";
+        case EXC_BAD_ACCESS     : return "EXC_BAD_ACCESS";
+        case EXC_BAD_INSTRUCTION: return "EXC_BAD_INSTRUCTION";
+        case EXC_ARITHMETIC     : return "EXC_ARITHMETIC";
+        case EXC_EMULATION      : return "EXC_EMULATION";
+        case EXC_SOFTWARE       : return "EXC_SOFTWARE";
+        case EXC_SYSCALL        : return "EXC_SYSCALL";
+        case EXC_MACH_SYSCALL   : return "EXC_MACH_SYSCALL";
+        case EXC_RPC_ALERT      : return "EXC_RPC_ALERT";
+        case EXC_CRASH          : return "EXC_CRASH";
+        case EXC_RESOURCE       : return "EXC_RESOURCE";
+        case EXC_GUARD          : return "EXC_GUARD";
+        case NOTE_EXEC          : return "EXEC";
+        case NOTE_FORK          : return "FORK";
+        case NOTE_SIGNAL        : return "SIGNAL";
+        case NOTE_EXIT          : return "EXIT";
+
+        default:
+            return "[-exception_to_string] unknown exception type!";
+    }
+}
+
+static char* get_register_name(int reg) {
+    switch(reg) {
+        case REG_RAX: return "Rax";
+        case REG_RBX: return "Rbx";
+        case REG_RCX: return "Rcx";
+        case REG_RDX: return "Rdx";
+        case REG_RDI: return "Rdi";
+        case REG_RSI: return "Rsi";
+        case REG_RBP: return "Rbp";
+        case REG_RSP: return "Rsp";
+        case REG_R8:  return "R8";
+        case REG_R9:  return "R9";
+        case REG_R10: return "R10";
+        case REG_R11: return "R11";
+        case REG_R12: return "R12";
+        case REG_R13: return "R13";
+        case REG_R14: return "R14";
+        case REG_R15: return "R15";
+        case REG_RIP: return "Rip";
+        case REG_RFLAGS: return "Rflags";
+
+        case REG_DR0: return "Dr0";
+        case REG_DR1: return "Dr1";
+        case REG_DR2: return "Dr2";
+        case REG_DR3: return "Dr3";
+        case REG_DR4: return "Dr4";
+        case REG_DR5: return "Dr5";
+        case REG_DR6: return "Dr6";
+        case REG_DR7: return "Dr7";
+
+        default: return "invalid register";
+    }
+}
+#endif
+
+#pragma mark Debug helpers
+
+// From: https://developer.apple.com/library/archive/qa/qa1361/_index.html
+// Returns true if the current process is being debugged (either 
+// running under the debugger or has a debugger attached post facto).
+bool is_debugger_attached(void) {
+    int                 junk;
+    int                 mib[4];
+    struct kinfo_proc   info;
+    size_t              size;
+
+    info.kp_proc.p_flag = 0;
+
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_PROC;
+    mib[2] = KERN_PROC_PID;
+    mib[3] = getpid();
+
+    size = sizeof(info);
+    junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
+    assert(junk == 0);
+
+    // We're being debugged if the P_TRACED flag is set.
+    return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
+}
+
+
+#pragma mark Debug sessions
+
+
+static debug_session *create_debug_session(mach_port_t task, pid_t pid) {
+    debug_session *exists = find_session(task);
+    if(exists != NULL) {
+        return exists;
+    }
+
+    debug_session *sess = malloc(sizeof(debug_session));
+    memset(sess, 0, sizeof(debug_session));
+
+    sess->task = task;
+    sess->pid = pid;
+    sess->exception_port = 0;
+    sess->old_exception_ports = (struct exception_ports_info*)malloc(sizeof(exception_ports_info));
+    sess->process_status = STATUS_HANDLED;
+
+    // create a semaphore `wait_sem` to handle signaling between exception port thread and main thread
+    kern_return_t kret = semaphore_create(task, &sess->wait_sem, 0, 0);
+    EXIT_ON_MACH_ERROR(kret, "Fatal error: failed to create semaphore!");
+
+    // add `debug_session` to `sessions` list for future lookup
+    sessions.list = realloc(sessions.list, sizeof(debug_session*) * (sessions.count + 1));
+    sessions.list[sessions.count++] = sess;
+
+    DEBUG_PRINT("created session num: %i", sessions.count);
+    return sess;
+}
+
+static bool destroy_debug_session(debug_session *sess) {
+    semaphore_destroy(sess->task, sess->wait_sem);
+
+    free(sess);
+
+    if(sessions.count > 1) {
+        debug_session **new_list = malloc(sizeof(debug_session*) * (sessions.count-1));
+        int j = 0;
+        for(int i = 0; i < sessions.count; i++) {
+            if(sessions.list[i] != sess) {
+                new_list[j++] = sessions.list[i];
+            }
+        }
+        free(sessions.list);
+        sessions.list = new_list;
+    } else {
+        free(sessions.list);
+        sessions.list = NULL;
+    }
+    sessions.count--;
+
+    return true;
+}
+
+static debug_session *find_session(mach_port_t task) {
+    int i = 0;
+    while(i < sessions.count) {
+        if(sessions.list[i]->task == task) {
+            return sessions.list[i];
+        }
+        i++;
+    }
+    return NULL;
+}
+
+static debug_session *find_session_by_pid(pid_t pid) {
+    int i = 0;
+    while(i < sessions.count) {
+        if(sessions.list[i]->pid == pid) {
+            return sessions.list[i];
+        }
+        i++;
+    }
+    return NULL;
+}
+
+
+#pragma mark Registers
+
+
+__uint64_t *get_reg( x86_thread_state64_t *regs, int r ) {
+    switch( r ) {
+        case REG_RAX: return &regs->__rax;
+        case REG_RBX: return &regs->__rbx;
+        case REG_RCX: return &regs->__rcx;
+        case REG_RDX: return &regs->__rdx;
+        case REG_RDI: return &regs->__rdi;
+        case REG_RSI: return &regs->__rsi;
+        case REG_RBP: return &regs->__rbp;
+        case REG_RSP: return &regs->__rsp;
+        case REG_R8:  return &regs->__r8;
+        case REG_R9:  return &regs->__r9;
+        case REG_R10: return &regs->__r10;
+        case REG_R11: return &regs->__r11;
+        case REG_R12: return &regs->__r12;
+        case REG_R13: return &regs->__r13;
+        case REG_R14: return &regs->__r14;
+        case REG_R15: return &regs->__r15;
+        case REG_RIP: return &regs->__rip;
+        case REG_RFLAGS: return &regs->__rflags;
+    }
+    return NULL;
+}
+
+__uint64_t *get_debug_reg( x86_debug_state64_t *regs, int r ) {
+    switch( r ) {
+        case REG_DR0: return &regs->__dr0;
+        case REG_DR1: return &regs->__dr1;
+        case REG_DR2: return &regs->__dr2;
+        case REG_DR3: return &regs->__dr3;
+        case REG_DR4: return &regs->__dr4;
+        case REG_DR5: return &regs->__dr5;
+        case REG_DR6: return &regs->__dr6;
+        case REG_DR7: return &regs->__dr7;
+    }
+    return NULL;
+}
+
+__uint64_t read_register(mach_port_t task, int thread, int reg, bool is64 ) {
+    __uint64_t *rdata;
+    mach_port_t mach_thread = get_thread(task, thread);
+
+    if(reg >= REG_DR0) {
+        x86_debug_state64_t *regs = get_debug_state(mach_thread);
+        rdata = get_debug_reg(regs, reg - 4);
+    } else {
+        x86_thread_state64_t *regs = get_thread_state(mach_thread);
+        rdata = get_reg(regs, reg);
+    }
+
+    DEBUG_PRINT_VERBOSE("register %s is: 0x%08x\n", get_register_name(reg), *rdata);
+
+    return *rdata;
+}
+
+static kern_return_t write_register(mach_port_t task, int thread, int reg, void *value, bool is64 ) {
+    DEBUG_PRINT_VERBOSE("write register %i (%s) on thread %i", reg, get_register_name(reg), thread);
+
+    __uint64_t *rdata;
+    mach_port_t mach_thread = get_thread(task, thread);
+
+    if(reg >= REG_DR0) {
+        x86_debug_state64_t *regs = get_debug_state(mach_thread);
+        rdata = get_debug_reg(regs, reg - 4);
+        DEBUG_PRINT_VERBOSE("register flag for %s was: 0x%08x\n",get_register_name(reg), *rdata);
+
+        *rdata = (__uint64_t)value;
+        set_debug_state(mach_thread, regs);
+    } else {
+        x86_thread_state64_t *regs = get_thread_state(mach_thread);
+        rdata = get_reg(regs, reg);
+        DEBUG_PRINT_VERBOSE("register flag for %s was: 0x%08x\n",get_register_name(reg), *rdata);
+
+        *rdata = (__uint64_t)value;
+        set_thread_state(mach_thread, regs);
+    }
+
+    DEBUG_PRINT_VERBOSE("register flag for %s now is: 0x%08x\n",get_register_name(reg), *rdata);
+
+    return KERN_SUCCESS;
+}
+
+
+#pragma mark Memory IO
+
+
+static kern_return_t read_memory(mach_port_t task, mach_vm_address_t addr, mach_vm_address_t dest, int size) {
+    mach_vm_size_t nread;
+	kern_return_t kret = mach_vm_read_overwrite(task, addr, size, dest, &nread);
+	
+    EXIT_ON_MACH_ERROR(kret,"Error: probably reading from invalid address!");
+
+    DEBUG_PRINT_VERBOSE("read %i bytes from %p", nread, addr);
+    #if MDBG_DEBUG && MDBG_LOG_LEVEL > 1
+    log_buffer(dest, size);
+    printf("\n\n");
+    #endif
+
+    return kret;
+}
+
+static kern_return_t write_memory(mach_port_t task, mach_vm_address_t addr, mach_vm_address_t src, int size) {
+    kern_return_t kret = mach_vm_protect(task, addr, size, 0, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
+    EXIT_ON_MACH_ERROR(kret,"Fatal error: failed to acquire write permission!");
+
+    kret = mach_vm_write(task, addr, src, size);
+    EXIT_ON_MACH_ERROR(kret,"Fatal error: failed to write to traced process memory!");
+
+    kret = mach_vm_protect(task, addr, size, 0, VM_PROT_READ | VM_PROT_EXECUTE);
+    EXIT_ON_MACH_ERROR(kret,"Fatal error: failed to reset write permission!");
+
+    DEBUG_PRINT_VERBOSE("wrote %i bytes to %p",size, addr);
+    #if MDBG_DEBUG && MDBG_LOG_LEVEL
+        log_buffer(src, size);
+        printf("\n\n");
+    #endif
+    return kret;
+}
+
+
+#pragma mark Threads
+
+static thread_act_port_array_t get_task_threads(mach_port_t mach_task, mach_msg_type_number_t *threadCount) {
+    thread_act_port_array_t threadList;
+    task_threads(mach_task, &threadList, threadCount);
+
+    return threadList;
+}
+
+static mach_port_t get_thread(mach_port_t mach_task, uint thread_id) {
+    thread_act_port_array_t threadList;
+    mach_msg_type_number_t threadCount;
+
+    kern_return_t kret = task_threads(mach_task, &threadList, &threadCount);
+    if (kret != KERN_SUCCESS) {
+        DEBUG_PRINT("get_thread() failed with message %s!\n", mach_error_string(kret));
+        exit(0);
+    }
+    for(int i=0;i<threadCount;i++) {
+        if(get_thread_id(threadList[i]) == thread_id) {
+            return threadList[i];
+        }
+    }
+    exit(0); // TODO: catch better
+}
+
+static thread_identifier_info_data_t* get_thread_info(thread_t thread) {
+
+  thread_identifier_info_data_t *tident = safe_malloc(sizeof(thread_identifier_info_data_t));
+  mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
+  kern_return_t kret = thread_info (thread, THREAD_IDENTIFIER_INFO, (thread_info_t)tident, &tident_count);
+
+  EXIT_ON_MACH_ERROR(kret, "failed to get thread info");
+
+  return tident;
+}
+
+static uint64_t get_thread_id(thread_t thread) {
+    thread_identifier_info_data_t *tinfo = get_thread_info(thread);
+    return tinfo->thread_id;
+}
+
+static x86_thread_state64_t* get_thread_state(thread_t mach_thread) {
+
+    x86_thread_state64_t* state;
+    mach_msg_type_number_t stateCount = x86_THREAD_STATE64_COUNT;
+
+    state = safe_malloc(sizeof(x86_thread_state64_t));
+    kern_return_t kret = thread_get_state( mach_thread, x86_THREAD_STATE64, (thread_state_t)state, &stateCount);
+    if (kret != KERN_SUCCESS) {
+        DEBUG_PRINT("Error failed with message %s!\n", mach_error_string(kret));
+        exit(0);
+    }
+    return state;
+}
+
+static kern_return_t set_thread_state(thread_t mach_thread, x86_thread_state64_t *break_state) {
+
+    kern_return_t kret = thread_set_state(mach_thread, x86_THREAD_STATE64, (thread_state_t)break_state, x86_THREAD_STATE64_COUNT);
+    if (kret != KERN_SUCCESS) {
+        DEBUG_PRINT("Error failed with message %s!\n", mach_error_string(kret));
+        exit(0);
+    }
+    return kret;
+}
+
+
+// Debug register state
+
+static x86_debug_state64_t* get_debug_state(thread_t mach_thread) {
+
+    x86_debug_state64_t* state;
+    mach_msg_type_number_t stateCount = x86_DEBUG_STATE64_COUNT;
+
+    state = safe_malloc(sizeof(x86_debug_state64_t));
+    kern_return_t kret = thread_get_state( mach_thread, x86_DEBUG_STATE64, (thread_state_t)state, &stateCount);
+    if (kret != KERN_SUCCESS) {
+        DEBUG_PRINT("Error failed with message %s!\n", mach_error_string(kret));
+        exit(0);
+    }
+    return state;
+}
+
+static kern_return_t set_debug_state(thread_t mach_thread, x86_debug_state64_t *break_state) {
+
+    kern_return_t kret = thread_set_state(mach_thread, x86_DEBUG_STATE64, (thread_state_t)break_state, x86_DEBUG_STATE64_COUNT);
+    if (kret != KERN_SUCCESS) {
+        DEBUG_PRINT("Error failed with message %s!\n", mach_error_string(kret));
+        exit(0);
+    }
+    return kret;
+}
+
+
+#pragma mark Exception ports
+
+static kern_return_t save_exception_ports(task_t task, exception_ports_info *info) {
+    info->count = (sizeof (info->ports) / sizeof (info->ports[0]));
+
+    return task_get_exception_ports(task, EXC_MASK_ALL, info->masks, &info->count, info->ports, info->behaviors, info->flavors);
+}
+
+static kern_return_t restore_exception_ports(task_t task, exception_ports_info *info) {
+    int i;
+    kern_return_t kret;
+
+    for (i = 0; i < info->count; i++) {
+        kret = task_set_exception_ports(task, info->masks[i], info->ports[i], info->behaviors[i], info->flavors[i]);
+        if (kret != KERN_SUCCESS)
+            return kret;
+    }
+    return KERN_SUCCESS;
+}
+
+#pragma mark Tasks
+
+static mach_port_t get_task(pid_t pid) {
+    debug_session *sess = find_session_by_pid(pid);
+    if(sess != NULL) {
+        return sess->task;
+    }
+
+    mach_port_t task;
+    kern_return_t kret = task_for_pid(mach_task_self(), pid, &task);
+
+    EXIT_ON_MACH_ERROR(kret,"Fatal error: failed to get task for pid %i",pid);
+
+    return task;
+}
+
+static kern_return_t attach_to_task(mach_port_t task, pid_t pid) {
+
+    if(find_session(task) != NULL) {
+        DEBUG_PRINT("Warning already attached to task (%i). Not attaching again!",task);
+        return KERN_SUCCESS;
+    }
+    debug_session *sess = create_debug_session(task, pid);
+
+    kern_return_t kret;
+    int err;
+
+    kret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &sess->exception_port);
+    RETURN_ON_MACH_ERROR(kret,"mach_port_allocate failed");
+
+    kret = mach_port_insert_right(mach_task_self(), sess->exception_port, sess->exception_port, MACH_MSG_TYPE_MAKE_SEND);
+    RETURN_ON_MACH_ERROR(kret,"mach_port_insert_right failed");
+
+    // store current exception ports
+    save_exception_ports(task, (exception_ports_info*)sess->old_exception_ports);
+
+    kret = task_set_exception_ports(task, EXC_MASK_ALL, sess->exception_port, EXCEPTION_STATE_IDENTITY|MACH_EXCEPTION_CODES, x86_THREAD_STATE64);
+    RETURN_ON_MACH_ERROR(kret,"task_set_exception_ports failed");
+
+    // launch mach exception port thread //
+    err = pthread_create(&sess->exception_handler_thread, NULL, (void *(*)(void*))task_exception_server, (void *(*)(void*))(unsigned long long)sess->exception_port);
+    EXIT_ON_MACH_ERROR(err,"can't create *task_exception_server* thread :[%s]",strerror(err));
+
+    DEBUG_PRINT("successfully created mach exception port thread %d\n", 0);
+
+    return KERN_SUCCESS;
+}
+
+static kern_return_t attach_to_pid(pid_t pid) {
+    attach_to_task(get_task(pid), pid);
+
+    return ptrace(PT_ATTACHEXC, pid, 0, 0) == 0 ? KERN_SUCCESS : KERN_FAILURE;
+}
+
+static kern_return_t detach_from_pid(pid_t pid) {
+    debug_session *sess = find_session_by_pid( pid );
+
+    if(sess != NULL) {
+        DEBUG_PRINT("cleaning up debug session...");
+        restore_exception_ports(sess->task, (exception_ports_info*)sess->old_exception_ports);
+        ptrace(PT_DETACH, pid, 0, 0);
+        destroy_debug_session(sess);
+
+        DEBUG_PRINT("successfully ended session!");
+    } else {
+        DEBUG_PRINT("found no session to cleanup!");
+    }
+
+    return KERN_SUCCESS;
+}
+
+
+#pragma mark Exceptions
+
+
+extern kern_return_t catch_mach_exception_raise /* stub – will not be called */
+(
+	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 codeCnt
+) {
+    DEBUG_PRINT("this handler should not be called");  
+    return MACH_RCV_INVALID_TYPE;
+}
+
+extern kern_return_t catch_mach_exception_raise_state /* stub – will not be called */
+(
+	mach_port_t exception_port,
+	exception_type_t exception,
+	const mach_exception_data_t code,
+	mach_msg_type_number_t codeCnt,
+	int *flavor,
+	const thread_state_t old_state,
+	mach_msg_type_number_t old_stateCnt,
+	thread_state_t new_state,
+	mach_msg_type_number_t *new_stateCnt
+) {
+    DEBUG_PRINT("this handler should not be called");                           
+    return MACH_RCV_INVALID_TYPE;
+}
+
+extern kern_return_t catch_mach_exception_raise_state_identity(
+	mach_port_t             exception_port,
+	mach_port_t             thread,
+	mach_port_t             task,
+	exception_type_t        exception,
+	exception_data_t        code,
+	mach_msg_type_number_t  codeCnt,
+	int *                   flavor,
+	thread_state_t          old_state,
+	mach_msg_type_number_t  old_stateCnt,
+	thread_state_t          new_state,
+	mach_msg_type_number_t *new_stateCnt
+) {
+
+    x86_thread_state64_t *state = (x86_thread_state64_t *) old_state;
+    x86_thread_state64_t *newState = (x86_thread_state64_t *) new_state;
+
+    debug_session *sess = find_session(task);
+    sess->current_thread = get_thread_id(thread); /* set system-wide thread id */
+
+    DEBUG_PRINT("exception occured on thread (%i): %s",sess->current_thread, exception_to_string(exception));
+    DEBUG_PRINT("stack address: 0x%02lx", state->__rip);
+
+
+    if (exception == EXC_SOFTWARE && code[0] == EXC_SOFT_SIGNAL) { // handling UNIX soft signal
+        int subcode = code[2];
+
+        DEBUG_PRINT("EXC_SOFTWARE signal: %s",get_signal_name(code[2]));
+
+        if (subcode == SIGSTOP || subcode == SIGTRAP) {
+             // clear signal to prevent default OS handling //
+            ptrace(PT_THUPDATE,
+                sess->pid,
+                (caddr_t)(uintptr_t)thread,
+            0);
+
+            task_suspend(sess->task);
+            sess->process_status = STATUS_BREAKPOINT;
+
+            semaphore_signal(sess->wait_sem);
+
+            return KERN_SUCCESS;
+        }
+        /*else if(subcode == SIGTERM) { // TODO: Check if we need this
+            sess->process_status = STATUS_EXIT;
+            return KERN_SUCCESS;
+        }*/
+    }
+    else if(exception == EXC_BREAKPOINT) {
+        task_suspend(sess->task);
+
+        // check if single step mode
+        if(state->__rflags & SINGLESTEP_TRAP) {
+            state->__rflags &= ~SINGLESTEP_TRAP; // clear single-step
+            sess->process_status = STATUS_SINGLESTEP;
+            DEBUG_PRINT("SINGLE STEP");
+        } else {
+            sess->process_status = STATUS_BREAKPOINT;
+        }
+
+        // move past breakpoint by setting old to new thread state
+        *newState = *state;
+        *new_stateCnt = old_stateCnt;
+        *flavor = x86_THREAD_STATE64;
+
+        semaphore_signal(sess->wait_sem);
+
+        return KERN_SUCCESS;
+    }
+    else if(exception == EXC_BAD_INSTRUCTION) {
+         task_suspend(sess->task);
+         sess->process_status = STATUS_BREAKPOINT;
+
+         return KERN_SUCCESS;
+    }
+    else if(exception == EXC_BAD_ACCESS) {
+        task_suspend(sess->task);
+        sess->process_status = STATUS_ERROR;
+
+        return KERN_SUCCESS;
+    }
+    else {
+        DEBUG_PRINT("not handling this exception (%s)!", exception_to_string(exception));
+    }
+
+    return KERN_FAILURE;
+}
+
+static void* task_exception_server (mach_port_t exception_port) {
+    mach_msg_return_t rt;
+    mach_msg_header_t *msg;
+    mach_msg_header_t *reply;
+
+    msg   = safe_malloc(sizeof(union __RequestUnion__mach_exc_subsystem));
+    reply = safe_malloc(sizeof(union __ReplyUnion__mach_exc_subsystem));
+
+    DEBUG_PRINT("launching exception server...");
+
+    int i = 0;
+    while (1) {
+        DEBUG_PRINT("waiting for next exception (%i)...",i);
+        i++;
+
+        rt = mach_msg(msg, MACH_RCV_MSG, 0, sizeof(union __RequestUnion__mach_exc_subsystem), exception_port, 0, MACH_PORT_NULL);
+
+        if (rt!= MACH_MSG_SUCCESS) {
+            DEBUG_PRINT("MACH_RCV_MSG stopped, exit from task_exception_server thread :%d\n", 1);
+            return "MACH_RCV_MSG_FAILURE";
+        }
+        /*
+        * Call out to the mach_exc_server generated by mig and mach_exc.defs.
+        * This will in turn invoke one of:
+        * mach_catch_exception_raise()
+        * mach_catch_exception_raise_state()
+        * mach_catch_exception_raise_state_identity()
+        * .. depending on the behavior specified when registering the Mach exception port.
+        */
+        mach_exc_server(msg, reply);
+
+        // Send the now-initialized reply
+        rt = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
+
+        if (rt!= MACH_MSG_SUCCESS) {
+            return "MACH_SEND_MSG_FAILURE";
+        }
+    }
+}
+
+static void wait_for_exception(debug_session *sess, int timeout /*in millis*/) {
+    DEBUG_PRINT("waiting for next exception...");
+
+    kern_return_t kret = semaphore_timedwait(sess->wait_sem, (struct mach_timespec){0,timeout * 1000000});
+    if(kret == KERN_OPERATION_TIMED_OUT) {
+        sess->process_status = STATUS_TIMEOUT;
+        DEBUG_PRINT("wait timed out!");
+    } else {
+        DEBUG_PRINT("got notified of an exception!");
+    }
+}
+
+#pragma mark Debug API
+
+
+status_t MDBG_API(session_attach)( pid_t pid ) {
+    return attach_to_pid(pid) == KERN_SUCCESS;
+}
+
+status_t MDBG_API(session_detach)( pid_t pid ) {
+    return detach_from_pid(pid) == KERN_SUCCESS;
+}
+
+status_t MDBG_API(session_pause)( pid_t pid ) {
+    return kill(pid, SIGTRAP) == 0;
+}
+
+int MDBG_API(session_wait)( pid_t pid, int *thread, int timeout ) {
+    debug_session *sess = find_session_by_pid( pid );
+    if(sess != NULL) {
+        wait_for_exception(sess, timeout);
+        *thread = sess->current_thread;
+
+        return sess->process_status;
+    }
+    return 4;
+}
+
+status_t MDBG_API(session_resume)( pid_t pid ) {
+    debug_session *sess = find_session_by_pid( pid );
+    if(sess != NULL) {
+        sess->process_status = STATUS_HANDLED;
+        task_resume(sess->task);
+
+        return true;
+    }
+    return false;
+}
+
+debug_session *MDBG_API(session_get)( pid_t pid ) {
+    return find_session_by_pid( pid );
+}
+
+status_t MDBG_API(read_memory)( pid_t pid, unsigned char* addr, unsigned char* dest, int size ) {
+    return read_memory( get_task(pid), (mach_vm_address_t)addr, (mach_vm_address_t)dest, size ) == KERN_SUCCESS;
+}
+
+status_t MDBG_API(write_memory)( pid_t pid, unsigned char* addr, unsigned char* src, int size ) {
+    return write_memory( get_task(pid), (mach_vm_address_t)addr, (mach_vm_address_t)src, size ) == KERN_SUCCESS;
+}
+
+void* MDBG_API(read_register)( pid_t pid, int thread, int reg, bool is64 ) {
+    return (void*)read_register( get_task(pid), thread, reg, is64 );
+}
+
+status_t MDBG_API(write_register)( pid_t pid, int thread, int reg, void *value, bool is64 ) {
+    return write_register( get_task(pid), thread, reg, value, is64 ) == KERN_SUCCESS;
+}

+ 109 - 0
include/mdbg/mdbg.h

@@ -0,0 +1,109 @@
+/*
+ * Copyright (C)2005-2020 Haxe Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include <pthread.h>
+#include <mach/mach_types.h>
+
+#ifndef MDBG_DEBUG
+#define MDBG_DEBUG 0
+#endif
+
+#ifndef MDBG_LOG_LEVEL
+#define MDBG_LOG_LEVEL 0
+#endif
+
+#define MDBG_API(func)    mdbg_##func
+
+typedef bool        status_t;
+
+struct exception_ports_info;
+
+typedef struct debug_session {
+    mach_port_t task;
+    pid_t pid;
+    uint64_t current_thread;
+
+    mach_port_t exception_port;
+    struct exception_ports_info* old_exception_ports;
+    pthread_t exception_handler_thread;
+    mach_port_t wait_sem;
+
+    int process_status;
+} debug_session;
+
+
+/* x64 Registers */
+
+#define     REG_RAX     1
+#define     REG_RBX     2
+#define     REG_RCX     3
+#define     REG_RDX     4
+#define     REG_RDI     5
+#define     REG_RSI     6
+#define     REG_RBP     7
+#define     REG_RSP     8
+#define     REG_R8      9
+#define     REG_R9      10
+#define     REG_R10     11
+#define     REG_R11     12
+#define     REG_R12     13
+#define     REG_R13     14
+#define     REG_R14     15
+#define     REG_R15     16
+#define     REG_RIP     17
+#define     REG_RFLAGS  18
+
+
+/* x64 Debug Registers */
+
+#define     REG_DR0     100
+#define     REG_DR1     101
+#define     REG_DR2     102
+#define     REG_DR3     103
+#define     REG_DR4     104
+#define     REG_DR5     105
+#define     REG_DR6     106
+#define     REG_DR7     107
+
+
+/** Public API **/
+
+extern status_t        MDBG_API(session_attach)( pid_t pid );
+
+extern status_t        MDBG_API(session_detach)( pid_t pid );
+
+extern int             MDBG_API(session_wait)(pid_t pid, int *thread, int timeout );
+
+extern status_t        MDBG_API(session_pause)( pid_t pid) ;
+
+extern status_t        MDBG_API(session_resume)( pid_t pid );
+
+extern debug_session*  MDBG_API(session_get)( pid_t pid);
+
+extern status_t        MDBG_API(read_memory)( pid_t pid, unsigned char* addr, unsigned char* dest, int size );
+
+extern status_t        MDBG_API(write_memory)( pid_t pid, unsigned char* addr, unsigned char* src, int size );
+
+extern void*           MDBG_API(read_register)( pid_t pid, int thread, int reg, bool is64 );
+
+extern status_t        MDBG_API(write_register)( pid_t pid, int thread, int reg, void *value, bool is64 );

+ 1 - 1
other/azure-pipelines/build-linux.yml

@@ -96,7 +96,7 @@ jobs:
         - task: PublishPipelineArtifact@1
           inputs:
             artifactName: ${{ parameters.name }}Binaries
-            targetPath: bin/hashlink-1.11.0-Linux.tar.gz
+            targetPath: bin/hashlink-1.12.0-Linux.tar.gz
       - ${{ if eq(parameters.buildSystem, 'make') }}:
         - script: make
           displayName: Build

+ 1 - 1
other/azure-pipelines/build-mac.yml

@@ -40,7 +40,7 @@ jobs:
         - task: PublishPipelineArtifact@1
           inputs:
             artifactName: ${{ parameters.name }}Binaries
-            targetPath: bin/hashlink-1.11.0-Darwin.tar.gz
+            targetPath: bin/hashlink-1.12.0-Darwin.tar.gz
       - ${{ if eq(parameters.buildSystem, 'make') }}:
         - script: make
           displayName: Build

+ 1 - 1
other/azure-pipelines/build-windows.yml

@@ -64,7 +64,7 @@ jobs:
         - task: PublishPipelineArtifact@1
           inputs:
             artifactName: ${{ parameters.name }}Binaries
-            targetPath: bin/hashlink-1.11.0-win$(MARCH).zip
+            targetPath: bin/hashlink-1.12.0-win$(MARCH).zip
       - ${{ if eq(parameters.buildSystem, 'vs') }}:
         - task: MSBuild@1
           inputs:

+ 6 - 1
src/hl.h

@@ -27,7 +27,7 @@
 	https://github.com/HaxeFoundation/hashlink/wiki/
 **/
 
-#define HL_VERSION	0x010B00
+#define HL_VERSION	0x010C00
 
 #if defined(_WIN32)
 #	define HL_WIN
@@ -285,6 +285,11 @@ C_FUNCTION_END
 			    ".long 0b;" \
 			    ".popsection")
 #	endif
+#elif defined(HL_MAC)
+#include <signal.h>
+#	define hl_debug_break() \
+		if( hl_detect_debugger() ) \
+			raise(SIGTRAP);//__builtin_trap();
 #else
 #	define hl_debug_break()
 #endif

+ 35 - 0
src/std/debug.c

@@ -28,6 +28,21 @@
 #	define USE_PTRACE
 #endif
 
+#ifdef HL_MAC
+#	include <mdbg/mdbg.h>
+
+static int get_reg( int r ) {
+	switch( r ) {
+		case 0: return REG_RSP;
+		case 1: return REG_RBP;
+		case 2: return REG_RIP;
+		case 3: return REG_RFLAGS;
+		case 4: return REG_DR0 + (r-4);
+	}
+	return -1;
+}
+#endif
+
 #if defined(HL_WIN)
 static HANDLE last_process = NULL, last_thread = NULL;
 static int last_pid = -1;
@@ -62,6 +77,8 @@ HL_API bool hl_debug_start( int pid ) {
 #	if defined(HL_WIN)
 	last_pid = -1;
 	return (bool)DebugActiveProcess(pid);
+#	elif defined(HL_MAC)
+	return mdbg_session_attach(pid);
 #	elif defined(USE_PTRACE)
 	return ptrace(PTRACE_ATTACH,pid,0,0) >= 0;
 #	else
@@ -74,6 +91,8 @@ HL_API bool hl_debug_stop( int pid ) {
 	BOOL b = DebugActiveProcessStop(pid);
 	CleanHandles();
 	return (bool)b;
+#	elif defined(HL_MAC)
+	return mdbg_session_detach(pid);
 #	elif defined(USE_PTRACE)
 	return ptrace(PTRACE_DETACH,pid,0,0) >= 0;
 #	else
@@ -84,6 +103,8 @@ HL_API bool hl_debug_stop( int pid ) {
 HL_API bool hl_debug_breakpoint( int pid ) {
 #	if defined(HL_WIN)
 	return (bool)DebugBreakProcess(OpenPID(pid));
+#	elif defined(HL_MAC)
+	return mdbg_session_pause(pid);
 #	elif defined(USE_PTRACE)
 	return kill(pid,SIGTRAP) == 0;
 #	else
@@ -94,6 +115,8 @@ HL_API bool hl_debug_breakpoint( int pid ) {
 HL_API bool hl_debug_read( int pid, vbyte *addr, vbyte *buffer, int size ) {
 #	if defined(HL_WIN)
 	return (bool)ReadProcessMemory(OpenPID(pid),addr,buffer,size,NULL);
+#	elif defined(HL_MAC)
+	return mdbg_read_memory(pid, addr, buffer, size);
 #	elif defined(USE_PTRACE)
 	while( size ) {
 		long v = ptrace(PTRACE_PEEKDATA,pid,addr,0);
@@ -116,6 +139,8 @@ HL_API bool hl_debug_read( int pid, vbyte *addr, vbyte *buffer, int size ) {
 HL_API bool hl_debug_write( int pid, vbyte *addr, vbyte *buffer, int size ) {
 #	if defined(HL_WIN)
 	return (bool)WriteProcessMemory(OpenPID(pid),addr,buffer,size,NULL);
+#	elif defined(HL_MAC)
+	return mdbg_write_memory(pid, addr, buffer, size);
 #	elif defined(USE_PTRACE)
 	while( size ) {
 		int sz = size >= sizeof(long) ? sizeof(long) : size;
@@ -139,6 +164,8 @@ HL_API bool hl_debug_write( int pid, vbyte *addr, vbyte *buffer, int size ) {
 HL_API bool hl_debug_flush( int pid, vbyte *addr, int size ) {
 #	if defined(HL_WIN)
 	return (bool)FlushInstructionCache(OpenPID(pid),addr,size);
+#	elif defined(HL_MAC)
+	return true;
 #	elif defined(USE_PTRACE)
 	return true;
 #	else
@@ -201,6 +228,8 @@ HL_API int hl_debug_wait( int pid, int *thread, int timeout ) {
 		break;
 	}
 	return 4;
+#	elif defined(HL_MAC)
+	return mdbg_session_wait(pid, thread, timeout);
 #	elif defined(USE_PTRACE)
 	int status;
 	int ret = waitpid(pid,&status,0);
@@ -224,6 +253,8 @@ HL_API int hl_debug_wait( int pid, int *thread, int timeout ) {
 HL_API bool hl_debug_resume( int pid, int thread ) {
 #	if defined(HL_WIN)
 	return (bool)ContinueDebugEvent(pid, thread, DBG_CONTINUE);
+#	elif defined(HL_MAC)
+	return mdbg_session_resume(pid);
 #	elif defined(USE_PTRACE)
 	return ptrace(PTRACE_CONT,pid,0,0) >= 0;
 #	else
@@ -285,6 +316,8 @@ HL_API void *hl_debug_read_register( int pid, int thread, int reg, bool is64 ) {
 	if( reg == 3 )
 		return (void*)(int_val)c.EFlags;
 	return (void*)*GetContextReg(&c,reg);
+#	elif defined(HL_MAC)
+	return mdbg_read_register(pid, thread, get_reg(reg), is64);
 #	elif defined(USE_PTRACE)
 	return (void*)ptrace(PTRACE_PEEKUSER,thread,get_reg(reg),0);
 #	else
@@ -318,6 +351,8 @@ HL_API bool hl_debug_write_register( int pid, int thread, int reg, void *value,
 	else
 		*GetContextReg(&c,reg) = (REGDATA)value;
 	return (bool)SetThreadContext(OpenTID(thread),&c);
+#	elif defined(HL_MAC)
+	return mdbg_write_register(pid, thread, get_reg(reg), value, is64);
 #	elif defined(USE_PTRACE)
 	return ptrace(PTRACE_POKEUSER,thread,get_reg(reg),value) >= 0;
 #	else

+ 6 - 0
src/std/error.c

@@ -211,6 +211,10 @@ static void _sigtrap_handler(int signum) {
 }
 #endif
 
+#ifdef HL_MAC
+	extern bool is_debugger_attached(void);
+#endif
+
 HL_PRIM bool hl_detect_debugger() {
 #	if defined(HL_WIN)
 	return (bool)IsDebuggerPresent();
@@ -221,6 +225,8 @@ HL_PRIM bool hl_detect_debugger() {
 		raise(SIGTRAP);
 	}
 	return (bool)debugger_present;
+#	elif defined(HL_MAC)
+	return is_debugger_attached();
 #	else
 	return false;
 #	endif