xpcom/build/mach_override.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 // Copied from upstream at revision 195c13743fe0ebc658714e2a9567d86529f20443.
     2 // mach_override.c semver:1.2.0
     3 //   Copyright (c) 2003-2012 Jonathan 'Wolf' Rentzsch: http://rentzsch.com
     4 //   Some rights reserved: http://opensource.org/licenses/mit
     5 //   https://github.com/rentzsch/mach_override
     7 #include "mach_override.h"
     9 #include <mach-o/dyld.h>
    10 #include <mach/mach_host.h>
    11 #include <mach/mach_init.h>
    12 #include <mach/vm_map.h>
    13 #include <sys/mman.h>
    15 #include <CoreServices/CoreServices.h>
    17 /**************************
    18 *	
    19 *	Constants
    20 *	
    21 **************************/
    22 #pragma mark	-
    23 #pragma mark	(Constants)
    25 #define kPageSize 4096
    26 #if defined(__ppc__) || defined(__POWERPC__)
    28 long kIslandTemplate[] = {
    29 	0x9001FFFC,	//	stw		r0,-4(SP)
    30 	0x3C00DEAD,	//	lis		r0,0xDEAD
    31 	0x6000BEEF,	//	ori		r0,r0,0xBEEF
    32 	0x7C0903A6,	//	mtctr	r0
    33 	0x8001FFFC,	//	lwz		r0,-4(SP)
    34 	0x60000000,	//	nop		; optionally replaced
    35 	0x4E800420 	//	bctr
    36 };
    38 #define kAddressHi			3
    39 #define kAddressLo			5
    40 #define kInstructionHi		10
    41 #define kInstructionLo		11
    43 #elif defined(__i386__) 
    45 #define kOriginalInstructionsSize 16
    46 // On X86 we migh need to instert an add with a 32 bit immediate after the
    47 // original instructions.
    48 #define kMaxFixupSizeIncrease 5
    50 unsigned char kIslandTemplate[] = {
    51 	// kOriginalInstructionsSize nop instructions so that we 
    52 	// should have enough space to host original instructions 
    53 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 
    54 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
    55 	// Now the real jump instruction
    56 	0xE9, 0xEF, 0xBE, 0xAD, 0xDE
    57 };
    59 #define kInstructions	0
    60 #define kJumpAddress    kInstructions + kOriginalInstructionsSize + 1
    61 #elif defined(__x86_64__)
    63 #define kOriginalInstructionsSize 32
    64 // On X86-64 we never need to instert a new instruction.
    65 #define kMaxFixupSizeIncrease 0
    67 #define kJumpAddress    kOriginalInstructionsSize + 6
    69 unsigned char kIslandTemplate[] = {
    70 	// kOriginalInstructionsSize nop instructions so that we 
    71 	// should have enough space to host original instructions 
    72 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 
    73 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
    74 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 
    75 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
    76 	// Now the real jump instruction
    77 	0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,
    78         0x00, 0x00, 0x00, 0x00,
    79         0x00, 0x00, 0x00, 0x00
    80 };
    82 #endif
    84 /**************************
    85 *	
    86 *	Data Types
    87 *	
    88 **************************/
    89 #pragma mark	-
    90 #pragma mark	(Data Types)
    92 typedef	struct	{
    93 	char	instructions[sizeof(kIslandTemplate)];
    94 }	BranchIsland;
    96 /**************************
    97 *	
    98 *	Funky Protos
    99 *	
   100 **************************/
   101 #pragma mark	-
   102 #pragma mark	(Funky Protos)
   104 static mach_error_t
   105 allocateBranchIsland(
   106 		BranchIsland	**island,
   107 		void *originalFunctionAddress);
   109 	mach_error_t
   110 freeBranchIsland(
   111 		BranchIsland	*island );
   113 #if defined(__ppc__) || defined(__POWERPC__)
   114 	mach_error_t
   115 setBranchIslandTarget(
   116 		BranchIsland	*island,
   117 		const void		*branchTo,
   118 		long			instruction );
   119 #endif 
   121 #if defined(__i386__) || defined(__x86_64__)
   122 mach_error_t
   123 setBranchIslandTarget_i386(
   124 						   BranchIsland	*island,
   125 						   const void		*branchTo,
   126 						   char*			instructions );
   127 void 
   128 atomic_mov64(
   129 		uint64_t *targetAddress,
   130 		uint64_t value );
   132 	static Boolean 
   133 eatKnownInstructions( 
   134 	unsigned char	*code, 
   135 	uint64_t		*newInstruction,
   136 	int				*howManyEaten, 
   137 	char			*originalInstructions,
   138 	int				*originalInstructionCount, 
   139 	uint8_t			*originalInstructionSizes );
   141 	static void
   142 fixupInstructions(
   143     uint32_t		offset,
   144     void		*instructionsToFix,
   145 	int			instructionCount,
   146 	uint8_t		*instructionSizes );
   147 #endif
   149 /*******************************************************************************
   150 *	
   151 *	Interface
   152 *	
   153 *******************************************************************************/
   154 #pragma mark	-
   155 #pragma mark	(Interface)
   157 #if defined(__i386__) || defined(__x86_64__)
   158 mach_error_t makeIslandExecutable(void *address) {
   159 	mach_error_t err = err_none;
   160     uintptr_t page = (uintptr_t)address & ~(uintptr_t)(kPageSize-1);
   161     int e = err_none;
   162     e |= mprotect((void *)page, kPageSize, PROT_EXEC | PROT_READ | PROT_WRITE);
   163     e |= msync((void *)page, kPageSize, MS_INVALIDATE );
   164     if (e) {
   165         err = err_cannot_override;
   166     }
   167     return err;
   168 }
   169 #endif
   171     mach_error_t
   172 mach_override_ptr(
   173 	void *originalFunctionAddress,
   174     const void *overrideFunctionAddress,
   175     void **originalFunctionReentryIsland )
   176 {
   177 	assert( originalFunctionAddress );
   178 	assert( overrideFunctionAddress );
   180 	// this addresses overriding such functions as AudioOutputUnitStart()
   181 	// test with modified DefaultOutputUnit project
   182 #if defined(__x86_64__)
   183     for(;;){
   184         if(*(uint16_t*)originalFunctionAddress==0x25FF)    // jmp qword near [rip+0x????????]
   185             originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*(int32_t *)((uint16_t*)originalFunctionAddress+1));
   186         else break;
   187     }
   188 #elif defined(__i386__)
   189     for(;;){
   190         if(*(uint16_t*)originalFunctionAddress==0x25FF)    // jmp *0x????????
   191             originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1);
   192         else break;
   193     }
   194 #endif
   196 	long	*originalFunctionPtr = (long*) originalFunctionAddress;
   197 	mach_error_t	err = err_none;
   199 #if defined(__ppc__) || defined(__POWERPC__)
   200 	//	Ensure first instruction isn't 'mfctr'.
   201 	#define	kMFCTRMask			0xfc1fffff
   202 	#define	kMFCTRInstruction	0x7c0903a6
   204 	long	originalInstruction = *originalFunctionPtr;
   205 	if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) )
   206 		err = err_cannot_override;
   207 #elif defined(__i386__) || defined(__x86_64__)
   208 	int eatenCount = 0;
   209 	int originalInstructionCount = 0;
   210 	char originalInstructions[kOriginalInstructionsSize];
   211 	uint8_t originalInstructionSizes[kOriginalInstructionsSize];
   212 	uint64_t jumpRelativeInstruction = 0; // JMP
   214 	Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr, 
   215 										&jumpRelativeInstruction, &eatenCount, 
   216 										originalInstructions, &originalInstructionCount, 
   217 										originalInstructionSizes );
   218 	if (eatenCount + kMaxFixupSizeIncrease > kOriginalInstructionsSize) {
   219 		//printf ("Too many instructions eaten\n");
   220 		overridePossible = false;
   221 	}
   222 	if (!overridePossible) err = err_cannot_override;
   223 	if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
   224 #endif
   226 	//	Make the original function implementation writable.
   227 	if( !err ) {
   228 		err = vm_protect( mach_task_self(),
   229 				(vm_address_t) originalFunctionPtr, 8, false,
   230 				(VM_PROT_ALL | VM_PROT_COPY) );
   231 		if( err )
   232 			err = vm_protect( mach_task_self(),
   233 					(vm_address_t) originalFunctionPtr, 8, false,
   234 					(VM_PROT_DEFAULT | VM_PROT_COPY) );
   235 	}
   236 	if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
   238 	//	Allocate and target the escape island to the overriding function.
   239 	BranchIsland	*escapeIsland = NULL;
   240 	if( !err )	
   241 		err = allocateBranchIsland( &escapeIsland, originalFunctionAddress );
   242 		if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
   245 #if defined(__ppc__) || defined(__POWERPC__)
   246 	if( !err )
   247 		err = setBranchIslandTarget( escapeIsland, overrideFunctionAddress, 0 );
   249 	//	Build the branch absolute instruction to the escape island.
   250 	long	branchAbsoluteInstruction = 0; // Set to 0 just to silence warning.
   251 	if( !err ) {
   252 		long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF;
   253 		branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress;
   254 	}
   255 #elif defined(__i386__) || defined(__x86_64__)
   256         if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
   258 	if( !err )
   259 		err = setBranchIslandTarget_i386( escapeIsland, overrideFunctionAddress, 0 );
   261 	if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
   262 	// Build the jump relative instruction to the escape island
   263 #endif
   266 #if defined(__i386__) || defined(__x86_64__)
   267 	if (!err) {
   268 		uint32_t addressOffset = ((char*)escapeIsland - (char*)originalFunctionPtr - 5);
   269 		addressOffset = OSSwapInt32(addressOffset);
   271 		jumpRelativeInstruction |= 0xE900000000000000LL; 
   272 		jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff) << 24;
   273 		jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);		
   274 	}
   275 #endif
   277 	//	Optionally allocate & return the reentry island. This may contain relocated
   278 	//  jmp instructions and so has all the same addressing reachability requirements
   279 	//  the escape island has to the original function, except the escape island is
   280 	//  technically our original function.
   281 	BranchIsland	*reentryIsland = NULL;
   282 	if( !err && originalFunctionReentryIsland ) {
   283 		err = allocateBranchIsland( &reentryIsland, escapeIsland);
   284 		if( !err )
   285 			*originalFunctionReentryIsland = reentryIsland;
   286 	}
   288 #if defined(__ppc__) || defined(__POWERPC__)	
   289 	//	Atomically:
   290 	//	o If the reentry island was allocated:
   291 	//		o Insert the original instruction into the reentry island.
   292 	//		o Target the reentry island at the 2nd instruction of the
   293 	//		  original function.
   294 	//	o Replace the original instruction with the branch absolute.
   295 	if( !err ) {
   296 		int escapeIslandEngaged = false;
   297 		do {
   298 			if( reentryIsland )
   299 				err = setBranchIslandTarget( reentryIsland,
   300 						(void*) (originalFunctionPtr+1), originalInstruction );
   301 			if( !err ) {
   302 				escapeIslandEngaged = CompareAndSwap( originalInstruction,
   303 										branchAbsoluteInstruction,
   304 										(UInt32*)originalFunctionPtr );
   305 				if( !escapeIslandEngaged ) {
   306 					//	Someone replaced the instruction out from under us,
   307 					//	re-read the instruction, make sure it's still not
   308 					//	'mfctr' and try again.
   309 					originalInstruction = *originalFunctionPtr;
   310 					if( (originalInstruction & kMFCTRMask) == kMFCTRInstruction)
   311 						err = err_cannot_override;
   312 				}
   313 			}
   314 		} while( !err && !escapeIslandEngaged );
   315 	}
   316 #elif defined(__i386__) || defined(__x86_64__)
   317 	// Atomically:
   318 	//	o If the reentry island was allocated:
   319 	//		o Insert the original instructions into the reentry island.
   320 	//		o Target the reentry island at the first non-replaced 
   321 	//        instruction of the original function.
   322 	//	o Replace the original first instructions with the jump relative.
   323 	//
   324 	// Note that on i386, we do not support someone else changing the code under our feet
   325 	if ( !err ) {
   326 		uint32_t offset = (uintptr_t)originalFunctionPtr - (uintptr_t)reentryIsland;
   327 		fixupInstructions(offset, originalInstructions,
   328 					originalInstructionCount, originalInstructionSizes );
   330 		if( reentryIsland )
   331 			err = setBranchIslandTarget_i386( reentryIsland,
   332 										 (void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions );
   333 		// try making islands executable before planting the jmp
   334 #if defined(__x86_64__) || defined(__i386__)
   335         if( !err )
   336             err = makeIslandExecutable(escapeIsland);
   337         if( !err && reentryIsland )
   338             err = makeIslandExecutable(reentryIsland);
   339 #endif
   340 		if ( !err )
   341 			atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelativeInstruction);
   342 	}
   343 #endif
   345 	//	Clean up on error.
   346 	if( err ) {
   347 		if( reentryIsland )
   348 			freeBranchIsland( reentryIsland );
   349 		if( escapeIsland )
   350 			freeBranchIsland( escapeIsland );
   351 	}
   353 	return err;
   354 }
   356 /*******************************************************************************
   357 *	
   358 *	Implementation
   359 *	
   360 *******************************************************************************/
   361 #pragma mark	-
   362 #pragma mark	(Implementation)
   364 static bool jump_in_range(intptr_t from, intptr_t to) {
   365   intptr_t field_value = to - from - 5;
   366   int32_t field_value_32 = field_value;
   367   return field_value == field_value_32;
   368 }
   370 /*******************************************************************************
   371 	Implementation: Allocates memory for a branch island.
   373 	@param	island			<-	The allocated island.
   374 	@result					<-	mach_error_t
   376 	***************************************************************************/
   378 static mach_error_t
   379 allocateBranchIslandAux(
   380 		BranchIsland	**island,
   381 		void *originalFunctionAddress,
   382 		bool forward)
   383 {
   384 	assert( island );
   385 	assert( sizeof( BranchIsland ) <= kPageSize );
   387 	vm_map_t task_self = mach_task_self();
   388 	vm_address_t original_address = (vm_address_t) originalFunctionAddress;
   389 	vm_address_t address = original_address;
   391 	for (;;) {
   392 		vm_size_t vmsize = 0;
   393 		memory_object_name_t object = 0;
   394 		kern_return_t kr = 0;
   395 		vm_region_flavor_t flavor = VM_REGION_BASIC_INFO;
   396 		// Find the region the address is in.
   397 #if __WORDSIZE == 32
   398 		vm_region_basic_info_data_t info;
   399 		mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
   400 		kr = vm_region(task_self, &address, &vmsize, flavor,
   401 			       (vm_region_info_t)&info, &info_count, &object);
   402 #else
   403 		vm_region_basic_info_data_64_t info;
   404 		mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
   405 		kr = vm_region_64(task_self, &address, &vmsize, flavor,
   406 				  (vm_region_info_t)&info, &info_count, &object);
   407 #endif
   408 		if (kr != KERN_SUCCESS)
   409 			return kr;
   410 		assert((address & (kPageSize - 1)) == 0);
   412 		// Go to the first page before or after this region
   413 		vm_address_t new_address = forward ? address + vmsize : address - kPageSize;
   414 #if __WORDSIZE == 64
   415 		if(!jump_in_range(original_address, new_address))
   416 			break;
   417 #endif
   418 		address = new_address;
   420 		// Try to allocate this page.
   421 		kr = vm_allocate(task_self, &address, kPageSize, 0);
   422 		if (kr == KERN_SUCCESS) {
   423 			*island = (BranchIsland*) address;
   424 			return err_none;
   425 		}
   426 		if (kr != KERN_NO_SPACE)
   427 			return kr;
   428 	}
   430 	return KERN_NO_SPACE;
   431 }
   433 static mach_error_t
   434 allocateBranchIsland(
   435 		BranchIsland	**island,
   436 		void *originalFunctionAddress)
   437 {
   438   mach_error_t err =
   439     allocateBranchIslandAux(island, originalFunctionAddress, true);
   440   if (!err)
   441     return err;
   442   return allocateBranchIslandAux(island, originalFunctionAddress, false);
   443 }
   446 /*******************************************************************************
   447 	Implementation: Deallocates memory for a branch island.
   449 	@param	island	->	The island to deallocate.
   450 	@result			<-	mach_error_t
   452 	***************************************************************************/
   454 	mach_error_t
   455 freeBranchIsland(
   456 		BranchIsland	*island )
   457 {
   458 	assert( island );
   459 	assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] );
   460 	assert( sizeof( BranchIsland ) <= kPageSize );
   461 	return vm_deallocate( mach_task_self(), (vm_address_t) island,
   462 			      kPageSize );
   463 }
   465 /*******************************************************************************
   466 	Implementation: Sets the branch island's target, with an optional
   467 	instruction.
   469 	@param	island		->	The branch island to insert target into.
   470 	@param	branchTo	->	The address of the target.
   471 	@param	instruction	->	Optional instruction to execute prior to branch. Set
   472 							to zero for nop.
   473 	@result				<-	mach_error_t
   475 	***************************************************************************/
   476 #if defined(__ppc__) || defined(__POWERPC__)
   477 	mach_error_t
   478 setBranchIslandTarget(
   479 		BranchIsland	*island,
   480 		const void		*branchTo,
   481 		long			instruction )
   482 {
   483 	//	Copy over the template code.
   484     bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
   486     //	Fill in the address.
   487     ((short*)island->instructions)[kAddressLo] = ((long) branchTo) & 0x0000FFFF;
   488     ((short*)island->instructions)[kAddressHi]
   489     	= (((long) branchTo) >> 16) & 0x0000FFFF;
   491     //	Fill in the (optional) instuction.
   492     if( instruction != 0 ) {
   493         ((short*)island->instructions)[kInstructionLo]
   494         	= instruction & 0x0000FFFF;
   495         ((short*)island->instructions)[kInstructionHi]
   496         	= (instruction >> 16) & 0x0000FFFF;
   497     }
   499     //MakeDataExecutable( island->instructions, sizeof( kIslandTemplate ) );
   500 	msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
   502     return err_none;
   503 }
   504 #endif 
   506 #if defined(__i386__)
   507 	mach_error_t
   508 setBranchIslandTarget_i386(
   509 	BranchIsland	*island,
   510 	const void		*branchTo,
   511 	char*			instructions )
   512 {
   514 	//	Copy over the template code.
   515     bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
   517 	// copy original instructions
   518 	if (instructions) {
   519 		bcopy (instructions, island->instructions + kInstructions, kOriginalInstructionsSize);
   520 	}
   522     // Fill in the address.
   523     int32_t addressOffset = (char *)branchTo - (island->instructions + kJumpAddress + 4);
   524     *((int32_t *)(island->instructions + kJumpAddress)) = addressOffset; 
   526     msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
   527     return err_none;
   528 }
   530 #elif defined(__x86_64__)
   531 mach_error_t
   532 setBranchIslandTarget_i386(
   533         BranchIsland	*island,
   534         const void		*branchTo,
   535         char*			instructions )
   536 {
   537     // Copy over the template code.
   538     bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
   540     // Copy original instructions.
   541     if (instructions) {
   542         bcopy (instructions, island->instructions, kOriginalInstructionsSize);
   543     }
   545     //	Fill in the address.
   546     *((uint64_t *)(island->instructions + kJumpAddress)) = (uint64_t)branchTo; 
   547     msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
   549     return err_none;
   550 }
   551 #endif
   554 #if defined(__i386__) || defined(__x86_64__)
   555 // simplistic instruction matching
   556 typedef struct {
   557 	unsigned int length; // max 15
   558 	unsigned char mask[15]; // sequence of bytes in memory order
   559 	unsigned char constraint[15]; // sequence of bytes in memory order
   560 }	AsmInstructionMatch;
   562 #if defined(__i386__)
   563 static AsmInstructionMatch possibleInstructions[] = {
   564 	{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} },	// jmp 0x????????
   565 	{ 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} },	// push %ebp; mov %esp,%ebp; leave; ret
   566 	{ 0x1, {0xFF}, {0x90} },							// nop
   567 	{ 0x1, {0xFF}, {0x55} },							// push %esp
   568 	{ 0x2, {0xFF, 0xFF}, {0x89, 0xE5} },				                // mov %esp,%ebp
   569 	{ 0x1, {0xFF}, {0x53} },							// push %ebx
   570 	{ 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} },	                        // sub 0x??, %esp
   571 	{ 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x00, 0x00} },	// sub 0x??, %esp with 32bit immediate
   572 	{ 0x1, {0xFF}, {0x57} },							// push %edi
   573 	{ 0x1, {0xFF}, {0x56} },							// push %esi
   574 	{ 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },						// xor %eax, %eax
   575 	{ 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} },  // mov $imm(%ebp), %reg
   576 	{ 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} },  // mov $imm(%eax-%edx), %reg
   577 	{ 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x8B, 0x4C, 0x24, 0x00} },  // mov $imm(%esp), %ecx
   578 	{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} },	// mov $imm, %eax
   579 	{ 0x6, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0xE8, 0x00, 0x00, 0x00, 0x00, 0x58} },	// call $imm; pop %eax
   580 	{ 0x0 }
   581 };
   582 #elif defined(__x86_64__)
   583 static AsmInstructionMatch possibleInstructions[] = {
   584 	{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} },	// jmp 0x????????
   585 	{ 0x1, {0xFF}, {0x90} },							// nop
   586 	{ 0x1, {0xF8}, {0x50} },							// push %rX
   587 	{ 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} },				// mov %rsp,%rbp
   588 	{ 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} },	                // sub 0x??, %rsp
   589 	{ 0x4, {0xFB, 0xFF, 0x00, 0x00}, {0x48, 0x89, 0x00, 0x00} },	                // move onto rbp
   590 	{ 0x4, {0xFF, 0xFF, 0xFF, 0xFF}, {0x40, 0x0f, 0xbe, 0xce} },			// movsbl %sil, %ecx
   591 	{ 0x2, {0xFF, 0x00}, {0x41, 0x00} },						// push %rXX
   592 	{ 0x2, {0xFF, 0x00}, {0x85, 0x00} },						// test %rX,%rX
   593 	{ 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} },   // mov $imm, %reg
   594 	{ 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} },  // pushq $imm(%rdi)
   595 	{ 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },						// xor %eax, %eax
   596 	{ 0x2, {0xFF, 0xFF}, {0x89, 0xF8} },			// mov %edi, %eax
   598 	//leaq offset(%rip),%rax
   599 	{ 0x7, {0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x48, 0x8d, 0x05, 0x00, 0x00, 0x00, 0x00} },
   601 	{ 0x0 }
   602 };
   603 #endif
   605 static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch* instruction) 
   606 {
   607 	Boolean match = true;
   609 	size_t i;
   610 	for (i=0; i<instruction->length; i++) {
   611 		unsigned char mask = instruction->mask[i];
   612 		unsigned char constraint = instruction->constraint[i];
   613 		unsigned char codeValue = code[i];
   615 		match = ((codeValue & mask) == constraint);
   616 		if (!match) break;
   617 	}
   619 	return match;
   620 }
   622 #if defined(__i386__) || defined(__x86_64__)
   623 	static Boolean 
   624 eatKnownInstructions( 
   625 	unsigned char	*code, 
   626 	uint64_t		*newInstruction,
   627 	int				*howManyEaten, 
   628 	char			*originalInstructions,
   629 	int				*originalInstructionCount, 
   630 	uint8_t			*originalInstructionSizes )
   631 {
   632 	Boolean allInstructionsKnown = true;
   633 	int totalEaten = 0;
   634 	unsigned char* ptr = code;
   635 	int remainsToEat = 5; // a JMP instruction takes 5 bytes
   636 	int instructionIndex = 0;
   638 	if (howManyEaten) *howManyEaten = 0;
   639 	if (originalInstructionCount) *originalInstructionCount = 0;
   640 	while (remainsToEat > 0) {
   641 		Boolean curInstructionKnown = false;
   643 		// See if instruction matches one  we know
   644 		AsmInstructionMatch* curInstr = possibleInstructions;
   645 		do { 
   646 			if ((curInstructionKnown = codeMatchesInstruction(ptr, curInstr))) break;
   647 			curInstr++;
   648 		} while (curInstr->length > 0);
   650 		// if all instruction matches failed, we don't know current instruction then, stop here
   651 		if (!curInstructionKnown) { 
   652 			allInstructionsKnown = false;
   653 			fprintf(stderr, "mach_override: some instructions unknown! Need to update mach_override.c\n");
   654 			break;
   655 		}
   657 		// At this point, we've matched curInstr
   658 		int eaten = curInstr->length;
   659 		ptr += eaten;
   660 		remainsToEat -= eaten;
   661 		totalEaten += eaten;
   663 		if (originalInstructionSizes) originalInstructionSizes[instructionIndex] = eaten;
   664 		instructionIndex += 1;
   665 		if (originalInstructionCount) *originalInstructionCount = instructionIndex;
   666 	}
   669 	if (howManyEaten) *howManyEaten = totalEaten;
   671 	if (originalInstructions) {
   672 		Boolean enoughSpaceForOriginalInstructions = (totalEaten < kOriginalInstructionsSize);
   674 		if (enoughSpaceForOriginalInstructions) {
   675 			memset(originalInstructions, 0x90 /* NOP */, kOriginalInstructionsSize); // fill instructions with NOP
   676 			bcopy(code, originalInstructions, totalEaten);
   677 		} else {
   678 			// printf ("Not enough space in island to store original instructions. Adapt the island definition and kOriginalInstructionsSize\n");
   679 			return false;
   680 		}
   681 	}
   683 	if (allInstructionsKnown) {
   684 		// save last 3 bytes of first 64bits of codre we'll replace
   685 		uint64_t currentFirst64BitsOfCode = *((uint64_t *)code);
   686 		currentFirst64BitsOfCode = OSSwapInt64(currentFirst64BitsOfCode); // back to memory representation
   687 		currentFirst64BitsOfCode &= 0x0000000000FFFFFFLL; 
   689 		// keep only last 3 instructions bytes, first 5 will be replaced by JMP instr
   690 		*newInstruction &= 0xFFFFFFFFFF000000LL; // clear last 3 bytes
   691 		*newInstruction |= (currentFirst64BitsOfCode & 0x0000000000FFFFFFLL); // set last 3 bytes
   692 	}
   694 	return allInstructionsKnown;
   695 }
   697 	static void
   698 fixupInstructions(
   699 	uint32_t	offset,
   700     void		*instructionsToFix,
   701 	int			instructionCount,
   702 	uint8_t		*instructionSizes )
   703 {
   704 	// The start of "leaq offset(%rip),%rax"
   705 	static const uint8_t LeaqHeader[] = {0x48, 0x8d, 0x05};
   707 	int	index;
   708 	for (index = 0;index < instructionCount;index += 1)
   709 	{
   710 		if (*(uint8_t*)instructionsToFix == 0xE9) // 32-bit jump relative
   711 		{
   712 			uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 1);
   713 			*jumpOffsetPtr += offset;
   714 		}
   716 		// leaq offset(%rip),%rax
   717 		if (memcmp(instructionsToFix, LeaqHeader, 3) == 0) {
   718 			uint32_t *LeaqOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 3);
   719 			*LeaqOffsetPtr += offset;
   720 		}
   722 		// 32-bit call relative to the next addr; pop %eax
   723 		if (*(uint8_t*)instructionsToFix == 0xE8)
   724 		{
   725 			// Just this call is larger than the jump we use, so we
   726 			// know this is the last instruction.
   727 			assert(index == (instructionCount - 1));
   728 			assert(instructionSizes[index] == 6);
   730                         // Insert "addl $offset, %eax" in the end so that when
   731                         // we jump to the rest of the function %eax has the
   732                         // value it would have if eip had been pushed by the
   733                         // call in its original position.
   734 			uint8_t *op = instructionsToFix;
   735 			op += 6;
   736 			*op = 0x05; // addl
   737 			uint32_t *addImmPtr = (uint32_t*)(op + 1);
   738 			*addImmPtr = offset;
   739 		}
   741 		instructionsToFix = (void*)((uintptr_t)instructionsToFix + instructionSizes[index]);
   742     }
   743 }
   744 #endif
   746 #if defined(__i386__)
   747 __asm(
   748 			".text;"
   749 			".align 2, 0x90;"
   750 			"_atomic_mov64:;"
   751 			"	pushl %ebp;"
   752 			"	movl %esp, %ebp;"
   753 			"	pushl %esi;"
   754 			"	pushl %ebx;"
   755 			"	pushl %ecx;"
   756 			"	pushl %eax;"
   757 			"	pushl %edx;"
   759 			// atomic push of value to an address
   760 			// we use cmpxchg8b, which compares content of an address with 
   761 			// edx:eax. If they are equal, it atomically puts 64bit value 
   762 			// ecx:ebx in address. 
   763 			// We thus put contents of address in edx:eax to force ecx:ebx
   764 			// in address
   765 			"	mov		8(%ebp), %esi;"  // esi contains target address
   766 			"	mov		12(%ebp), %ebx;"
   767 			"	mov		16(%ebp), %ecx;" // ecx:ebx now contains value to put in target address
   768 			"	mov		(%esi), %eax;"
   769 			"	mov		4(%esi), %edx;"  // edx:eax now contains value currently contained in target address
   770 			"	lock; cmpxchg8b	(%esi);" // atomic move.
   772 			// restore registers
   773 			"	popl %edx;"
   774 			"	popl %eax;"
   775 			"	popl %ecx;"
   776 			"	popl %ebx;"
   777 			"	popl %esi;"
   778 			"	popl %ebp;"
   779 			"	ret"
   780 );
   781 #elif defined(__x86_64__)
   782 void atomic_mov64(
   783 		uint64_t *targetAddress,
   784 		uint64_t value )
   785 {
   786     *targetAddress = value;
   787 }
   788 #endif
   789 #endif

mercurial