init iOS module

This commit is contained in:
pengfei.zhou
2019-07-25 19:26:33 +08:00
parent 40416ff3fd
commit f86e7623a2
211 changed files with 20246 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
//
// CwlCatchException.swift
// CwlAssertionTesting
//
// Created by Matt Gallagher on 2016/01/10.
// Copyright © 2016 Matt Gallagher ( http://cocoawithlove.com ). All rights reserved.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
// IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
import Foundation
#if SWIFT_PACKAGE
import CwlCatchExceptionSupport
#endif
private func catchReturnTypeConverter<T: NSException>(_ type: T.Type, block: () -> Void) -> T? {
return catchExceptionOfKind(type, block) as? T
}
extension NSException {
public static func catchException(in block: () -> Void) -> Self? {
return catchReturnTypeConverter(self, block: block)
}
}

View File

@@ -0,0 +1,37 @@
//
// CwlCatchException.m
// CwlAssertionTesting
//
// Created by Matt Gallagher on 2016/01/10.
// Copyright © 2016 Matt Gallagher ( http://cocoawithlove.com ). All rights reserved.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
// IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#import "CwlCatchException.h"
#if !SWIFT_PACKAGE && NON_SWIFT_PACKAGE
__attribute__((visibility("hidden")))
#endif
NSException* catchExceptionOfKind(Class __nonnull type, __attribute__((noescape)) void (^ __nonnull inBlock)(void)) {
@try {
inBlock();
} @catch (NSException *exception) {
if ([exception isKindOfClass:type]) {
return exception;
} else {
@throw;
}
}
return nil;
}

View File

@@ -0,0 +1,32 @@
//
// CwlCatchException.h
// CwlCatchException
//
// Created by Matt Gallagher on 2016/01/10.
// Copyright © 2016 Matt Gallagher ( http://cocoawithlove.com ). All rights reserved.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
// IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#import <Foundation/Foundation.h>
//! Project version number for CwlCatchException.
FOUNDATION_EXPORT double CwlCatchExceptionVersionNumber;
//! Project version string for CwlCatchException.
FOUNDATION_EXPORT const unsigned char CwlCatchExceptionVersionString[];
#if !SWIFT_PACKAGE && NON_SWIFT_PACKAGE
__attribute__((visibility("hidden")))
#endif
NSException* __nullable catchExceptionOfKind(Class __nonnull type, __attribute__((noescape)) void (^ __nonnull inBlock)(void));

View File

@@ -0,0 +1,50 @@
//
// CwlMachBadExceptionHandler.m
// CwlPreconditionTesting
//
// Created by Matt Gallagher on 2016/01/10.
// Copyright © 2016 Matt Gallagher ( http://cocoawithlove.com ). All rights reserved.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
// IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#if defined(__x86_64__)
#import "mach_excServer.h"
#import "CwlMachBadInstructionHandler.h"
@protocol BadInstructionReply <NSObject>
+(NSNumber *)receiveReply:(NSValue *)value;
@end
/// A basic function that receives callbacks from mach_exc_server and relays them to the Swift implemented BadInstructionException.catch_mach_exception_raise_state.
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) {
bad_instruction_exception_reply_t reply = { exception_port, exception, code, codeCnt, flavor, old_state, old_stateCnt, new_state, new_stateCnt };
Class badInstructionClass = NSClassFromString(@"BadInstructionException");
NSValue *value = [NSValue valueWithBytes: &reply objCType: @encode(bad_instruction_exception_reply_t)];
return [[badInstructionClass performSelector: @selector(receiveReply:) withObject: value] intValue];
}
// The mach port should be configured so that this function is never used.
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) {
assert(false);
return KERN_FAILURE;
}
// The mach port should be configured so that this function is never used.
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) {
assert(false);
return KERN_FAILURE;
}
#endif

View File

@@ -0,0 +1,70 @@
//
// CwlMachBadInstructionHandler.h
// CwlPreconditionTesting
//
// Created by Matt Gallagher on 2016/01/10.
// Copyright © 2016 Matt Gallagher ( http://cocoawithlove.com ). All rights reserved.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
// IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#import <Foundation/Foundation.h>
#import <mach/mach.h>
NS_ASSUME_NONNULL_BEGIN
extern boolean_t mach_exc_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
// The request_mach_exception_raise_t struct is passed to mach_msg which assumes its exact layout. To avoid problems with different layouts, we keep the definition in C rather than Swift.
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[224];
} request_mach_exception_raise_t;
// The reply_mach_exception_raise_state_t struct is passed to mach_msg which assumes its exact layout. To avoid problems with different layouts, we keep the definition in C rather than Swift.
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[224];
} reply_mach_exception_raise_state_t;
typedef struct
{
mach_port_t exception_port;
exception_type_t exception;
mach_exception_data_type_t const * _Nullable code;
mach_msg_type_number_t codeCnt;
int32_t * _Nullable flavor;
natural_t const * _Nullable old_state;
mach_msg_type_number_t old_stateCnt;
thread_state_t _Nullable new_state;
mach_msg_type_number_t * _Nullable new_stateCnt;
} bad_instruction_exception_reply_t;
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,537 @@
/*
* IDENTIFICATION:
* stub generated Sun Jan 29 19:05:29 2017
* with a MiG generated by bootstrap_cmds-96.20.2
* OPTIONS:
*/
#if defined(__x86_64__)
/* Module mach_exc */
#define __MIG_check__Request__mach_exc_subsystem__ 1
#include "mach_excServer.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 __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;\
}
/* 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 */
mig_internal novalue _Xmach_exception_raise
(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
{
#ifdef __MigPackStructs
#pragma pack(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()
#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) - 912)) || (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) - 912)) / 8 < In0P->codeCnt) ||
(msgh_size < (mach_msg_size_t)(sizeof(__Request) - 912) + (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 > 224 )
return MIG_BAD_ARGUMENTS;
if (((msgh_size - (mach_msg_size_t)(sizeof(__Request) - 912)) / 4 < In1P->old_stateCnt) ||
(msgh_size != (mach_msg_size_t)(sizeof(__Request) - 912) + (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 */
mig_internal novalue _Xmach_exception_raise_state
(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
{
#ifdef __MigPackStructs
#pragma pack(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[224];
mach_msg_trailer_t trailer;
} Request __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#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 = 224;
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) - 896) + (((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) - 912)) || (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) - 912)) / 8 < In0P->codeCnt) ||
(msgh_size < (mach_msg_size_t)(sizeof(__Request) - 912) + (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 > 224 )
return MIG_BAD_ARGUMENTS;
if (((msgh_size - (mach_msg_size_t)(sizeof(__Request) - 912)) / 4 < In1P->old_stateCnt) ||
(msgh_size != (mach_msg_size_t)(sizeof(__Request) - 912) + (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 */
mig_internal novalue _Xmach_exception_raise_state_identity
(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
{
#ifdef __MigPackStructs
#pragma pack(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[224];
mach_msg_trailer_t trailer;
} Request __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#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 = 224;
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) - 896) + (((4 * OutP->new_stateCnt)));
__AfterRcvRpc(2407, "mach_exception_raise_state_identity")
}
/* Description of this subsystem, for use in direct RPC */
const struct catch_mach_exc_subsystem 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;
*/
register 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)
{
register 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;
}
#endif

View File

@@ -0,0 +1,321 @@
#ifndef _mach_exc_server_
#define _mach_exc_server_
/* 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 __BeforeMigServerHeader
__BeforeMigServerHeader
#endif /* __BeforeMigServerHeader */
/* Routine mach_exception_raise */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
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_state */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
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_identity */
#ifdef mig_external
mig_external
#else
extern
#endif /* mig_external */
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
);
#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 */
extern 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;
/* typedefs for all requests */
#ifndef __Request__mach_exc_subsystem__defined
#define __Request__mach_exc_subsystem__defined
#ifdef __MigPackStructs
#pragma pack(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()
#endif
#ifdef __MigPackStructs
#pragma pack(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[224];
} __Request__mach_exception_raise_state_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(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[224];
} __Request__mach_exception_raise_state_identity_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#endif /* !__Request__mach_exc_subsystem__defined */
/* union of all requests */
#ifndef __RequestUnion__catch_mach_exc_subsystem__defined
#define __RequestUnion__catch_mach_exc_subsystem__defined
union __RequestUnion__catch_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__catch_mach_exc_subsystem__defined */
/* typedefs for all replies */
#ifndef __Reply__mach_exc_subsystem__defined
#define __Reply__mach_exc_subsystem__defined
#ifdef __MigPackStructs
#pragma pack(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()
#endif
#ifdef __MigPackStructs
#pragma pack(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[224];
} __Reply__mach_exception_raise_state_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#endif
#ifdef __MigPackStructs
#pragma pack(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[224];
} __Reply__mach_exception_raise_state_identity_t __attribute__((unused));
#ifdef __MigPackStructs
#pragma pack()
#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 /* __RequestUnion__catch_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 __AfterMigServerHeader
__AfterMigServerHeader
#endif /* __AfterMigServerHeader */
#endif /* _mach_exc_server_ */

View File

@@ -0,0 +1,89 @@
//
// CwlBadInstructionException.swift
// CwlPreconditionTesting
//
// Created by Matt Gallagher on 2016/01/10.
// Copyright © 2016 Matt Gallagher ( http://cocoawithlove.com ). All rights reserved.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
// IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
import Foundation
#if SWIFT_PACKAGE
import CwlMachBadInstructionHandler
#endif
private func raiseBadInstructionException() {
BadInstructionException().raise()
}
/// A simple NSException subclass. It's not required to subclass NSException (since the exception type is represented in the name) but this helps for identifying the exception through runtime type.
@objc(BadInstructionException)
public class BadInstructionException: NSException {
static var name: String = "com.cocoawithlove.BadInstruction"
init() {
super.init(name: NSExceptionName(rawValue: BadInstructionException.name), reason: nil, userInfo: nil)
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
/// An Objective-C callable function, invoked from the `mach_exc_server` callback function `catch_mach_exception_raise_state` to push the `raiseBadInstructionException` function onto the stack.
@objc(receiveReply:)
public class func receiveReply(_ value: NSValue) -> NSNumber {
#if arch(x86_64)
var reply = bad_instruction_exception_reply_t(exception_port: 0, exception: 0, code: nil, codeCnt: 0, flavor: nil, old_state: nil, old_stateCnt: 0, new_state: nil, new_stateCnt: nil)
withUnsafeMutablePointer(to: &reply) { value.getValue(UnsafeMutableRawPointer($0)) }
let old_state: UnsafePointer<natural_t> = reply.old_state!
let old_stateCnt: mach_msg_type_number_t = reply.old_stateCnt
let new_state: thread_state_t = reply.new_state!
let new_stateCnt: UnsafeMutablePointer<mach_msg_type_number_t> = reply.new_stateCnt!
// Make sure we've been given enough memory
if old_stateCnt != x86_THREAD_STATE64_COUNT || new_stateCnt.pointee < x86_THREAD_STATE64_COUNT {
return NSNumber(value: KERN_INVALID_ARGUMENT)
}
// Read the old thread state
var state = old_state.withMemoryRebound(to: x86_thread_state64_t.self, capacity: 1) { return $0.pointee }
// 1. Decrement the stack pointer
state.__rsp -= __uint64_t(MemoryLayout<Int>.size)
// 2. Save the old Instruction Pointer to the stack.
if let pointer = UnsafeMutablePointer<__uint64_t>(bitPattern: UInt(state.__rsp)) {
pointer.pointee = state.__rip
} else {
return NSNumber(value: KERN_INVALID_ARGUMENT)
}
// 3. Set the Instruction Pointer to the new function's address
var f: @convention(c) () -> Void = raiseBadInstructionException
withUnsafePointer(to: &f) {
state.__rip = $0.withMemoryRebound(to: __uint64_t.self, capacity: 1) { return $0.pointee }
}
// Write the new thread state
new_state.withMemoryRebound(to: x86_thread_state64_t.self, capacity: 1) { $0.pointee = state }
new_stateCnt.pointee = x86_THREAD_STATE64_COUNT
return NSNumber(value: KERN_SUCCESS)
#else
fatalError("Unavailable for this CPU architecture")
#endif
}
}

View File

@@ -0,0 +1,197 @@
//
// CwlCatchBadInstruction.swift
// CwlPreconditionTesting
//
// Created by Matt Gallagher on 2016/01/10.
// Copyright © 2016 Matt Gallagher ( http://cocoawithlove.com ). All rights reserved.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
// IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
import Foundation
#if SWIFT_PACKAGE
import CwlMachBadInstructionHandler
#endif
#if arch(x86_64)
private enum PthreadError: Error { case code(Int32) }
private enum MachExcServer: Error { case code(kern_return_t) }
/// A quick function for converting Mach error results into Swift errors
private func kernCheck(_ f: () -> Int32) throws {
let r = f()
guard r == KERN_SUCCESS else {
throw NSError(domain: NSMachErrorDomain, code: Int(r), userInfo: nil)
}
}
extension request_mach_exception_raise_t {
mutating func withMsgHeaderPointer<R>(in block: (UnsafeMutablePointer<mach_msg_header_t>) -> R) -> R {
return withUnsafeMutablePointer(to: &self) { p -> R in
return p.withMemoryRebound(to: mach_msg_header_t.self, capacity: 1) { ptr -> R in
return block(ptr)
}
}
}
}
extension reply_mach_exception_raise_state_t {
mutating func withMsgHeaderPointer<R>(in block: (UnsafeMutablePointer<mach_msg_header_t>) -> R) -> R {
return withUnsafeMutablePointer(to: &self) { p -> R in
return p.withMemoryRebound(to: mach_msg_header_t.self, capacity: 1) { ptr -> R in
return block(ptr)
}
}
}
}
/// A structure used to store context associated with the Mach message port
private struct MachContext {
var masks = execTypesCountTuple<exception_mask_t>()
var count: mach_msg_type_number_t = 0
var ports = execTypesCountTuple<mach_port_t>()
var behaviors = execTypesCountTuple<exception_behavior_t>()
var flavors = execTypesCountTuple<thread_state_flavor_t>()
var currentExceptionPort: mach_port_t = 0
var handlerThread: pthread_t? = nil
static func internalMutablePointers<R>(_ m: UnsafeMutablePointer<execTypesCountTuple<exception_mask_t>>, _ c: UnsafeMutablePointer<mach_msg_type_number_t>, _ p: UnsafeMutablePointer<execTypesCountTuple<mach_port_t>>, _ b: UnsafeMutablePointer<execTypesCountTuple<exception_behavior_t>>, _ f: UnsafeMutablePointer<execTypesCountTuple<thread_state_flavor_t>>, _ block: (UnsafeMutablePointer<exception_mask_t>, UnsafeMutablePointer<mach_msg_type_number_t>, UnsafeMutablePointer<mach_port_t>, UnsafeMutablePointer<exception_behavior_t>, UnsafeMutablePointer<thread_state_flavor_t>) -> R) -> R {
return m.withMemoryRebound(to: exception_mask_t.self, capacity: 1) { masksPtr in
return c.withMemoryRebound(to: mach_msg_type_number_t.self, capacity: 1) { countPtr in
return p.withMemoryRebound(to: mach_port_t.self, capacity: 1) { portsPtr in
return b.withMemoryRebound(to: exception_behavior_t.self, capacity: 1) { behaviorsPtr in
return f.withMemoryRebound(to: thread_state_flavor_t.self, capacity: 1) { flavorsPtr in
return block(masksPtr, countPtr, portsPtr, behaviorsPtr, flavorsPtr)
}
}
}
}
}
}
mutating func withUnsafeMutablePointers<R>(in block: @escaping (UnsafeMutablePointer<exception_mask_t>, UnsafeMutablePointer<mach_msg_type_number_t>, UnsafeMutablePointer<mach_port_t>, UnsafeMutablePointer<exception_behavior_t>, UnsafeMutablePointer<thread_state_flavor_t>) -> R) -> R {
return MachContext.internalMutablePointers(&masks, &count, &ports, &behaviors, &flavors, block)
}
}
/// A function for receiving mach messages and parsing the first with mach_exc_server (and if any others are received, throwing them away).
private func machMessageHandler(_ arg: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer? {
let context = arg.assumingMemoryBound(to: MachContext.self).pointee
var request = request_mach_exception_raise_t()
var reply = reply_mach_exception_raise_state_t()
var handledfirstException = false
repeat { do {
// Request the next mach message from the port
request.Head.msgh_local_port = context.currentExceptionPort
request.Head.msgh_size = UInt32(MemoryLayout<request_mach_exception_raise_t>.size)
let requestSize = request.Head.msgh_size
try kernCheck { request.withMsgHeaderPointer { requestPtr in
mach_msg(requestPtr, MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0, requestSize, context.currentExceptionPort, 0, UInt32(MACH_PORT_NULL))
} }
// Prepare the reply structure
reply.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(request.Head.msgh_bits), 0)
reply.Head.msgh_local_port = UInt32(MACH_PORT_NULL)
reply.Head.msgh_remote_port = request.Head.msgh_remote_port
reply.Head.msgh_size = UInt32(MemoryLayout<reply_mach_exception_raise_state_t>.size)
reply.NDR = NDR_record
if !handledfirstException {
// Use the MiG generated server to invoke our handler for the request and fill in the rest of the reply structure
guard request.withMsgHeaderPointer(in: { requestPtr in reply.withMsgHeaderPointer { replyPtr in
mach_exc_server(requestPtr, replyPtr)
} }) != 0 else { throw MachExcServer.code(reply.RetCode) }
handledfirstException = true
} else {
// If multiple fatal errors occur, don't handle subsquent errors (let the program crash)
reply.RetCode = KERN_FAILURE
}
// Send the reply
let replySize = reply.Head.msgh_size
try kernCheck { reply.withMsgHeaderPointer { replyPtr in
mach_msg(replyPtr, MACH_SEND_MSG, replySize, 0, UInt32(MACH_PORT_NULL), 0, UInt32(MACH_PORT_NULL))
} }
} catch let error as NSError where (error.domain == NSMachErrorDomain && (error.code == Int(MACH_RCV_PORT_CHANGED) || error.code == Int(MACH_RCV_INVALID_NAME))) {
// Port was already closed before we started or closed while we were listening.
// This means the controlling thread shut down.
return nil
} catch {
// Should never be reached but this is testing code, don't try to recover, just abort
fatalError("Mach message error: \(error)")
} } while true
}
/// Run the provided block. If a mach "BAD_INSTRUCTION" exception is raised, catch it and return a BadInstructionException (which captures stack information about the throw site, if desired). Otherwise return nil.
/// NOTE: This function is only intended for use in test harnesses use in a distributed build is almost certainly a bad choice. If a "BAD_INSTRUCTION" exception is raised, the block will be exited before completion via Objective-C exception. The risks associated with an Objective-C exception apply here: most Swift/Objective-C functions are *not* exception-safe. Memory may be leaked and the program will not necessarily be left in a safe state.
/// - parameter block: a function without parameters that will be run
/// - returns: if an EXC_BAD_INSTRUCTION is raised during the execution of `block` then a BadInstructionException will be returned, otherwise `nil`.
public func catchBadInstruction(in block: () -> Void) -> BadInstructionException? {
var context = MachContext()
var result: BadInstructionException? = nil
do {
var handlerThread: pthread_t? = nil
defer {
// 8. Wait for the thread to terminate *if* we actually made it to the creation point
// The mach port should be destroyed *before* calling pthread_join to avoid a deadlock.
if handlerThread != nil {
pthread_join(handlerThread!, nil)
}
}
try kernCheck {
// 1. Create the mach port
mach_port_allocate(mach_task_self_, MACH_PORT_RIGHT_RECEIVE, &context.currentExceptionPort)
}
defer {
// 7. Cleanup the mach port
mach_port_destroy(mach_task_self_, context.currentExceptionPort)
}
try kernCheck {
// 2. Configure the mach port
mach_port_insert_right(mach_task_self_, context.currentExceptionPort, context.currentExceptionPort, MACH_MSG_TYPE_MAKE_SEND)
}
let currentExceptionPtr = context.currentExceptionPort
try kernCheck { context.withUnsafeMutablePointers { masksPtr, countPtr, portsPtr, behaviorsPtr, flavorsPtr in
// 3. Apply the mach port as the handler for this thread
thread_swap_exception_ports(mach_thread_self(), EXC_MASK_BAD_INSTRUCTION, currentExceptionPtr, Int32(bitPattern: UInt32(EXCEPTION_STATE) | MACH_EXCEPTION_CODES), x86_THREAD_STATE64, masksPtr, countPtr, portsPtr, behaviorsPtr, flavorsPtr)
} }
defer { context.withUnsafeMutablePointers { masksPtr, countPtr, portsPtr, behaviorsPtr, flavorsPtr in
// 6. Unapply the mach port
_ = thread_swap_exception_ports(mach_thread_self(), EXC_MASK_BAD_INSTRUCTION, 0, EXCEPTION_DEFAULT, THREAD_STATE_NONE, masksPtr, countPtr, portsPtr, behaviorsPtr, flavorsPtr)
} }
try withUnsafeMutablePointer(to: &context) { c throws in
// 4. Create the thread
let e = pthread_create(&handlerThread, nil, machMessageHandler, c)
guard e == 0 else { throw PthreadError.code(e) }
// 5. Run the block
result = BadInstructionException.catchException(in: block)
}
} catch {
// Should never be reached but this is testing code, don't try to recover, just abort
fatalError("Mach port error: \(error)")
}
return result
}
#endif

View File

@@ -0,0 +1,55 @@
//
// CwlDarwinDefinitions.swift
// CwlPreconditionTesting
//
// Created by Matt Gallagher on 2016/01/10.
// Copyright © 2016 Matt Gallagher ( http://cocoawithlove.com ). All rights reserved.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
// IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
import Darwin
#if arch(x86_64)
// From /usr/include/mach/message.h
// #define MACH_MSG_TYPE_MAKE_SEND 20 /* Must hold receive right */
// #define MACH_MSGH_BITS_REMOTE(bits) \
// ((bits) & MACH_MSGH_BITS_REMOTE_MASK)
// #define MACH_MSGH_BITS(remote, local) /* legacy */ \
// ((remote) | ((local) << 8))
public let MACH_MSG_TYPE_MAKE_SEND: UInt32 = 20
public func MACH_MSGH_BITS_REMOTE(_ bits: UInt32) -> UInt32 { return bits & UInt32(MACH_MSGH_BITS_REMOTE_MASK) }
public func MACH_MSGH_BITS(_ remote: UInt32, _ local: UInt32) -> UInt32 { return ((remote) | ((local) << 8)) }
// From /usr/include/mach/exception_types.h
// #define EXC_BAD_INSTRUCTION 2 /* Instruction failed */
// #define EXC_MASK_BAD_INSTRUCTION (1 << EXC_BAD_INSTRUCTION)
public let EXC_BAD_INSTRUCTION: UInt32 = 2
public let EXC_MASK_BAD_INSTRUCTION: UInt32 = 1 << EXC_BAD_INSTRUCTION
// From /usr/include/mach/i386/thread_status.h
// #define x86_THREAD_STATE64_COUNT ((mach_msg_type_number_t) \
// ( sizeof (x86_thread_state64_t) / sizeof (int) ))
public let x86_THREAD_STATE64_COUNT = UInt32(MemoryLayout<x86_thread_state64_t>.size / MemoryLayout<Int32>.size)
public let EXC_TYPES_COUNT = 14
public struct execTypesCountTuple<T: ExpressibleByIntegerLiteral> {
// From /usr/include/mach/i386/exception.h
// #define EXC_TYPES_COUNT 14 /* incl. illegal exception 0 */
public var value: (T, T, T, T, T, T, T, T, T, T, T, T, T, T) = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
public init() {
}
}
#endif

View File

@@ -0,0 +1,32 @@
//
// CwlPreconditionTesting.h
// CwlPreconditionTesting
//
// Created by Matt Gallagher on 2016/01/10.
// Copyright © 2016 Matt Gallagher ( http://cocoawithlove.com ). All rights reserved.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
// IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#import <Foundation/Foundation.h>
extern bool _swift_reportFatalErrorsToDebugger;
//! Project version number for CwlUtils.
FOUNDATION_EXPORT double CwlPreconditionTestingVersionNumber;
//! Project version string for CwlUtils.
FOUNDATION_EXPORT const unsigned char CwlAssertingTestingVersionString[];
#include "CwlMachBadInstructionHandler.h"
#include "CwlCatchException.h"