// mach_override.h semver:1.2.0
//   Copyright (c) 2003-2012 Jonathan 'Wolf' Rentzsch: http://rentzsch.com
//   Some rights reserved: http://opensource.org/licenses/mit
//   https://github.com/rentzsch/mach_override

#ifndef		_mach_override_
#define		_mach_override_

#include <sys/types.h>
#include <mach/error.h>

#define	err_cannot_override	(err_local|1)

__BEGIN_DECLS

/****************************************************************************************
	Dynamically overrides the function implementation referenced by
	originalFunctionAddress with the implentation pointed to by overrideFunctionAddress.
	Optionally returns a pointer to a "reentry island" which, if jumped to, will resume
	the original implementation.
	
	@param	originalFunctionAddress			->	Required address of the function to
												override (with overrideFunctionAddress).
	@param	overrideFunctionAddress			->	Required address to the overriding
												function.
	@param	originalFunctionReentryIsland	<-	Optional pointer to pointer to the
												reentry island. Can be NULL.
	@result									<-	err_cannot_override if the original
												function's implementation begins with
												the 'mfctr' instruction.

	************************************************************************************/

    mach_error_t
mach_override_ptr(
	void *originalFunctionAddress,
    const void *overrideFunctionAddress,
    void **originalFunctionReentryIsland );

__END_DECLS

/****************************************************************************************
	If you're using C++ this macro will ease the tedium of typedef'ing, naming, keeping
	track of reentry islands and defining your override code. See test_mach_override.cp
	for example usage.

	************************************************************************************/
 
#ifdef	__cplusplus
#define MACH_OVERRIDE( ORIGINAL_FUNCTION_RETURN_TYPE, ORIGINAL_FUNCTION_NAME, ORIGINAL_FUNCTION_ARGS, ERR )		\
{																												\
	static ORIGINAL_FUNCTION_RETURN_TYPE (*ORIGINAL_FUNCTION_NAME##_reenter)ORIGINAL_FUNCTION_ARGS;				\
	static bool ORIGINAL_FUNCTION_NAME##_overriden = false;														\
	class mach_override_class__##ORIGINAL_FUNCTION_NAME {														\
	public:																										\
		static kern_return_t override(void *originalFunctionPtr) {												\
			kern_return_t result = err_none;																	\
			if (!ORIGINAL_FUNCTION_NAME##_overriden) {															\
				ORIGINAL_FUNCTION_NAME##_overriden = true;														\
				result = mach_override_ptr( (void*)originalFunctionPtr,											\
											(void*)mach_override_class__##ORIGINAL_FUNCTION_NAME::replacement,	\
											(void**)&ORIGINAL_FUNCTION_NAME##_reenter );						\
			}																									\
			return result;																						\
		}																										\
		static ORIGINAL_FUNCTION_RETURN_TYPE replacement ORIGINAL_FUNCTION_ARGS {

#define END_MACH_OVERRIDE( ORIGINAL_FUNCTION_NAME )																\
		}																										\
	};																											\
																												\
	err = mach_override_class__##ORIGINAL_FUNCTION_NAME::override((void*)ORIGINAL_FUNCTION_NAME);				\
}
#endif

#endif	//	_mach_override_
