1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/build/mach_override.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,121 @@ 1.4 +/******************************************************************************* 1.5 + mach_override.h 1.6 + Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com> 1.7 + Some rights reserved: <http://opensource.org/licenses/mit-license.php> 1.8 + 1.9 + ***************************************************************************/ 1.10 + 1.11 +/***************************************************************************//** 1.12 + @mainpage mach_override 1.13 + @author Jonathan 'Wolf' Rentzsch: <http://rentzsch.com> 1.14 + 1.15 + This package, coded in C to the Mach API, allows you to override ("patch") 1.16 + program- and system-supplied functions at runtime. You can fully replace 1.17 + functions with your implementations, or merely head- or tail-patch the 1.18 + original implementations. 1.19 + 1.20 + Use it by #include'ing mach_override.h from your .c, .m or .mm file(s). 1.21 + 1.22 + @todo Discontinue use of Carbon's MakeDataExecutable() and 1.23 + CompareAndSwap() calls and start using the Mach equivalents, if they 1.24 + exist. If they don't, write them and roll them in. That way, this 1.25 + code will be pure Mach, which will make it easier to use everywhere. 1.26 + Update: MakeDataExecutable() has been replaced by 1.27 + msync(MS_INVALIDATE). There is an OSCompareAndSwap in libkern, but 1.28 + I'm currently unsure if I can link against it. May have to roll in 1.29 + my own version... 1.30 + @todo Stop using an entire 4K high-allocated VM page per 28-byte escape 1.31 + branch island. Done right, this will dramatically speed up escape 1.32 + island allocations when they number over 250. Then again, if you're 1.33 + overriding more than 250 functions, maybe speed isn't your main 1.34 + concern... 1.35 + @todo Add detection of: b, bl, bla, bc, bcl, bcla, bcctrl, bclrl 1.36 + first-instructions. Initially, we should refuse to override 1.37 + functions beginning with these instructions. Eventually, we should 1.38 + dynamically rewrite them to make them position-independent. 1.39 + @todo Write mach_unoverride(), which would remove an override placed on a 1.40 + function. Must be multiple-override aware, which means an almost 1.41 + complete rewrite under the covers, because the target address can't 1.42 + be spread across two load instructions like it is now since it will 1.43 + need to be atomically updatable. 1.44 + @todo Add non-rentry variants of overrides to test_mach_override. 1.45 + 1.46 + ***************************************************************************/ 1.47 + 1.48 +#ifndef _mach_override_ 1.49 +#define _mach_override_ 1.50 + 1.51 +#include <sys/types.h> 1.52 +#include <mach/error.h> 1.53 + 1.54 +#ifdef __cplusplus 1.55 + extern "C" { 1.56 +#endif 1.57 + 1.58 +/** 1.59 + Returned if the function to be overrided begins with a 'mfctr' instruction. 1.60 +*/ 1.61 +#define err_cannot_override (err_local|1) 1.62 + 1.63 +/************************************************************************************//** 1.64 + Dynamically overrides the function implementation referenced by 1.65 + originalFunctionAddress with the implentation pointed to by overrideFunctionAddress. 1.66 + Optionally returns a pointer to a "reentry island" which, if jumped to, will resume 1.67 + the original implementation. 1.68 + 1.69 + @param originalFunctionAddress -> Required address of the function to 1.70 + override (with overrideFunctionAddress). 1.71 + @param overrideFunctionAddress -> Required address to the overriding 1.72 + function. 1.73 + @param originalFunctionReentryIsland <- Optional pointer to pointer to the 1.74 + reentry island. Can be nullptr. 1.75 + @result <- err_cannot_override if the original 1.76 + function's implementation begins with 1.77 + the 'mfctr' instruction. 1.78 + 1.79 + ************************************************************************************/ 1.80 + 1.81 + mach_error_t 1.82 +mach_override_ptr( 1.83 + void *originalFunctionAddress, 1.84 + const void *overrideFunctionAddress, 1.85 + void **originalFunctionReentryIsland ); 1.86 + 1.87 +/************************************************************************************//** 1.88 + 1.89 + 1.90 + ************************************************************************************/ 1.91 + 1.92 +#ifdef __cplusplus 1.93 + 1.94 +#define MACH_OVERRIDE( ORIGINAL_FUNCTION_RETURN_TYPE, ORIGINAL_FUNCTION_NAME, ORIGINAL_FUNCTION_ARGS, ERR ) \ 1.95 + { \ 1.96 + static ORIGINAL_FUNCTION_RETURN_TYPE (*ORIGINAL_FUNCTION_NAME##_reenter)ORIGINAL_FUNCTION_ARGS; \ 1.97 + static bool ORIGINAL_FUNCTION_NAME##_overriden = false; \ 1.98 + class mach_override_class__##ORIGINAL_FUNCTION_NAME { \ 1.99 + public: \ 1.100 + static kern_return_t override(void *originalFunctionPtr) { \ 1.101 + kern_return_t result = err_none; \ 1.102 + if (!ORIGINAL_FUNCTION_NAME##_overriden) { \ 1.103 + ORIGINAL_FUNCTION_NAME##_overriden = true; \ 1.104 + result = mach_override_ptr( (void*)originalFunctionPtr, \ 1.105 + (void*)mach_override_class__##ORIGINAL_FUNCTION_NAME::replacement, \ 1.106 + (void**)&ORIGINAL_FUNCTION_NAME##_reenter ); \ 1.107 + } \ 1.108 + return result; \ 1.109 + } \ 1.110 + static ORIGINAL_FUNCTION_RETURN_TYPE replacement ORIGINAL_FUNCTION_ARGS { 1.111 + 1.112 +#define END_MACH_OVERRIDE( ORIGINAL_FUNCTION_NAME ) \ 1.113 + } \ 1.114 + }; \ 1.115 + \ 1.116 + err = mach_override_class__##ORIGINAL_FUNCTION_NAME::override((void*)ORIGINAL_FUNCTION_NAME); \ 1.117 + } 1.118 + 1.119 +#endif 1.120 + 1.121 +#ifdef __cplusplus 1.122 + } 1.123 +#endif 1.124 +#endif // _mach_override_