mach_override.c revision 5967c3de18a658e052c07a2af69f02823115655b
1/*******************************************************************************
2	mach_override.c
3		Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
4		Some rights reserved: <http://opensource.org/licenses/mit-license.php>
5
6	***************************************************************************/
7#ifdef __APPLE__
8
9#include "mach_override.h"
10
11#include <mach-o/dyld.h>
12#include <mach/mach_host.h>
13#include <mach/mach_init.h>
14#include <mach/vm_map.h>
15#include <sys/mman.h>
16
17#include <CoreServices/CoreServices.h>
18
19//#define DEBUG_DISASM 1
20#undef DEBUG_DISASM
21
22/**************************
23*
24*	Constants
25*
26**************************/
27#pragma mark	-
28#pragma mark	(Constants)
29
30#if defined(__ppc__) || defined(__POWERPC__)
31
32long kIslandTemplate[] = {
33	0x9001FFFC,	//	stw		r0,-4(SP)
34	0x3C00DEAD,	//	lis		r0,0xDEAD
35	0x6000BEEF,	//	ori		r0,r0,0xBEEF
36	0x7C0903A6,	//	mtctr	r0
37	0x8001FFFC,	//	lwz		r0,-4(SP)
38	0x60000000,	//	nop		; optionally replaced
39	0x4E800420 	//	bctr
40};
41
42#define kAddressHi			3
43#define kAddressLo			5
44#define kInstructionHi		10
45#define kInstructionLo		11
46
47#elif defined(__i386__)
48
49#define kOriginalInstructionsSize 16
50
51char kIslandTemplate[] = {
52	// kOriginalInstructionsSize nop instructions so that we
53	// should have enough space to host original instructions
54	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
55	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
56	// Now the real jump instruction
57	0xE9, 0xEF, 0xBE, 0xAD, 0xDE
58};
59
60#define kInstructions	0
61#define kJumpAddress    kInstructions + kOriginalInstructionsSize + 1
62#elif defined(__x86_64__)
63
64#define kOriginalInstructionsSize 32
65
66#define kJumpAddress    kOriginalInstructionsSize + 6
67
68char kIslandTemplate[] = {
69	// kOriginalInstructionsSize nop instructions so that we
70	// should have enough space to host original instructions
71	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
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	// Now the real jump instruction
76	0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,
77        0x00, 0x00, 0x00, 0x00,
78        0x00, 0x00, 0x00, 0x00
79};
80
81#endif
82
83#define	kAllocateHigh		1
84#define	kAllocateNormal		0
85
86/**************************
87*
88*	Data Types
89*
90**************************/
91#pragma mark	-
92#pragma mark	(Data Types)
93
94typedef	struct	{
95	char	instructions[sizeof(kIslandTemplate)];
96	int		allocatedHigh;
97}	BranchIsland;
98
99/**************************
100*
101*	Funky Protos
102*
103**************************/
104#pragma mark	-
105#pragma mark	(Funky Protos)
106
107	mach_error_t
108allocateBranchIsland(
109		BranchIsland	**island,
110		int				allocateHigh,
111		void *originalFunctionAddress) __attribute__((visibility("hidden")));
112
113	mach_error_t
114freeBranchIsland(
115		BranchIsland	*island ) __attribute__((visibility("hidden")));
116
117	mach_error_t
118defaultIslandMalloc(
119	  void **ptr, size_t unused_size, void *hint) __attribute__((visibility("hidden")));
120
121	mach_error_t
122defaultIslandFree(
123   	void *ptr) __attribute__((visibility("hidden")));
124
125#if defined(__ppc__) || defined(__POWERPC__)
126	mach_error_t
127setBranchIslandTarget(
128		BranchIsland	*island,
129		const void		*branchTo,
130		long			instruction ) __attribute__((visibility("hidden")));
131#endif
132
133#if defined(__i386__) || defined(__x86_64__)
134mach_error_t
135setBranchIslandTarget_i386(
136						   BranchIsland	*island,
137						   const void		*branchTo,
138						   char*			instructions ) __attribute__((visibility("hidden")));
139void
140atomic_mov64(
141		uint64_t *targetAddress,
142		uint64_t value ) __attribute__((visibility("hidden")));
143
144	static Boolean
145eatKnownInstructions(
146	unsigned char	*code,
147	uint64_t		*newInstruction,
148	int				*howManyEaten,
149	char			*originalInstructions,
150	int				*originalInstructionCount,
151	uint8_t			*originalInstructionSizes ) __attribute__((visibility("hidden")));
152
153	static void
154fixupInstructions(
155    void		*originalFunction,
156    void		*escapeIsland,
157    void		*instructionsToFix,
158	int			instructionCount,
159	uint8_t		*instructionSizes ) __attribute__((visibility("hidden")));
160#endif
161
162/*******************************************************************************
163*
164*	Interface
165*
166*******************************************************************************/
167#pragma mark	-
168#pragma mark	(Interface)
169
170#if defined(__i386__) || defined(__x86_64__)
171mach_error_t makeIslandExecutable(void *address) {
172	mach_error_t err = err_none;
173    vm_size_t pageSize;
174    host_page_size( mach_host_self(), &pageSize );
175    uintptr_t page = (uintptr_t)address & ~(uintptr_t)(pageSize-1);
176    int e = err_none;
177    e |= mprotect((void *)page, pageSize, PROT_EXEC | PROT_READ | PROT_WRITE);
178    e |= msync((void *)page, pageSize, MS_INVALIDATE );
179    if (e) {
180        err = err_cannot_override;
181    }
182    return err;
183}
184#endif
185
186		mach_error_t
187defaultIslandMalloc(
188	void **ptr, size_t unused_size, void *hint) {
189  return allocateBranchIsland( (BranchIsland**)ptr, kAllocateHigh, hint );
190}
191		mach_error_t
192defaultIslandFree(
193	void *ptr) {
194	return freeBranchIsland(ptr);
195}
196
197    mach_error_t
198__asan_mach_override_ptr(
199	void *originalFunctionAddress,
200    const void *overrideFunctionAddress,
201    void **originalFunctionReentryIsland )
202{
203  return __asan_mach_override_ptr_custom(originalFunctionAddress,
204		overrideFunctionAddress,
205		originalFunctionReentryIsland,
206		defaultIslandMalloc,
207		defaultIslandFree);
208}
209
210    mach_error_t
211__asan_mach_override_ptr_custom(
212	void *originalFunctionAddress,
213    const void *overrideFunctionAddress,
214    void **originalFunctionReentryIsland,
215		island_malloc *alloc,
216		island_free *dealloc)
217{
218	assert( originalFunctionAddress );
219	assert( overrideFunctionAddress );
220
221	// this addresses overriding such functions as AudioOutputUnitStart()
222	// test with modified DefaultOutputUnit project
223#if defined(__x86_64__)
224    for(;;){
225        if(*(uint16_t*)originalFunctionAddress==0x25FF)    // jmp qword near [rip+0x????????]
226            originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*(int32_t *)((uint16_t*)originalFunctionAddress+1));
227        else break;
228    }
229#elif defined(__i386__)
230    for(;;){
231        if(*(uint16_t*)originalFunctionAddress==0x25FF)    // jmp *0x????????
232            originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1);
233        else break;
234    }
235#endif
236#ifdef DEBUG_DISASM
237  {
238    fprintf(stderr, "Replacing function at %p\n", originalFunctionAddress);
239    fprintf(stderr, "First 16 bytes of the function: ");
240    unsigned char *orig = (unsigned char *)originalFunctionAddress;
241    int i;
242    for (i = 0; i < 16; i++) {
243       fprintf(stderr, "%x ", (unsigned int) orig[i]);
244    }
245    fprintf(stderr, "\n");
246    fprintf(stderr,
247            "To disassemble, save the following function as disas.c"
248            " and run:\n  gcc -c disas.c && gobjdump -d disas.o\n"
249            "The first 16 bytes of the original function will start"
250            " after four nop instructions.\n");
251    fprintf(stderr, "\nvoid foo() {\n  asm volatile(\"nop;nop;nop;nop;\");\n");
252    int j = 0;
253    for (j = 0; j < 2; j++) {
254      fprintf(stderr, "  asm volatile(\".byte ");
255      for (i = 8 * j; i < 8 * (j+1) - 1; i++) {
256        fprintf(stderr, "0x%x, ", (unsigned int) orig[i]);
257      }
258      fprintf(stderr, "0x%x;\");\n", (unsigned int) orig[8 * (j+1) - 1]);
259    }
260    fprintf(stderr, "}\n\n");
261  }
262#endif
263
264	long	*originalFunctionPtr = (long*) originalFunctionAddress;
265	mach_error_t	err = err_none;
266
267#if defined(__ppc__) || defined(__POWERPC__)
268	//	Ensure first instruction isn't 'mfctr'.
269	#define	kMFCTRMask			0xfc1fffff
270	#define	kMFCTRInstruction	0x7c0903a6
271
272	long	originalInstruction = *originalFunctionPtr;
273	if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) )
274		err = err_cannot_override;
275#elif defined(__i386__) || defined(__x86_64__)
276	int eatenCount = 0;
277	int originalInstructionCount = 0;
278	char originalInstructions[kOriginalInstructionsSize];
279	uint8_t originalInstructionSizes[kOriginalInstructionsSize];
280	uint64_t jumpRelativeInstruction = 0; // JMP
281
282	Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr,
283										&jumpRelativeInstruction, &eatenCount,
284										originalInstructions, &originalInstructionCount,
285										originalInstructionSizes );
286#ifdef DEBUG_DISASM
287  if (!overridePossible) fprintf(stderr, "overridePossible = false @%d\n", __LINE__);
288#endif
289	if (eatenCount > kOriginalInstructionsSize) {
290#ifdef DEBUG_DISASM
291		fprintf(stderr, "Too many instructions eaten\n");
292#endif
293		overridePossible = false;
294	}
295	if (!overridePossible) err = err_cannot_override;
296	if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
297#endif
298
299	//	Make the original function implementation writable.
300	if( !err ) {
301		err = vm_protect( mach_task_self(),
302				(vm_address_t) originalFunctionPtr, 8, false,
303				(VM_PROT_ALL | VM_PROT_COPY) );
304		if( err )
305			err = vm_protect( mach_task_self(),
306					(vm_address_t) originalFunctionPtr, 8, false,
307					(VM_PROT_DEFAULT | VM_PROT_COPY) );
308	}
309	if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
310
311	//	Allocate and target the escape island to the overriding function.
312	BranchIsland	*escapeIsland = NULL;
313	if( !err )
314		err = alloc( (void**)&escapeIsland, sizeof(BranchIsland), originalFunctionAddress );
315	if ( err ) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
316
317#if defined(__ppc__) || defined(__POWERPC__)
318	if( !err )
319		err = setBranchIslandTarget( escapeIsland, overrideFunctionAddress, 0 );
320
321	//	Build the branch absolute instruction to the escape island.
322	long	branchAbsoluteInstruction = 0; // Set to 0 just to silence warning.
323	if( !err ) {
324		long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF;
325		branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress;
326	}
327#elif defined(__i386__) || defined(__x86_64__)
328        if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
329
330	if( !err )
331		err = setBranchIslandTarget_i386( escapeIsland, overrideFunctionAddress, 0 );
332
333	if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
334	// Build the jump relative instruction to the escape island
335#endif
336
337
338#if defined(__i386__) || defined(__x86_64__)
339	if (!err) {
340		uint32_t addressOffset = ((char*)escapeIsland - (char*)originalFunctionPtr - 5);
341		addressOffset = OSSwapInt32(addressOffset);
342
343		jumpRelativeInstruction |= 0xE900000000000000LL;
344		jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff) << 24;
345		jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
346	}
347#endif
348
349	//	Optionally allocate & return the reentry island. This may contain relocated
350	//  jmp instructions and so has all the same addressing reachability requirements
351	//  the escape island has to the original function, except the escape island is
352	//  technically our original function.
353	BranchIsland	*reentryIsland = NULL;
354	if( !err && originalFunctionReentryIsland ) {
355		err = alloc( (void**)&reentryIsland, sizeof(BranchIsland), escapeIsland);
356		if( !err )
357			*originalFunctionReentryIsland = reentryIsland;
358	}
359
360#if defined(__ppc__) || defined(__POWERPC__)
361	//	Atomically:
362	//	o If the reentry island was allocated:
363	//		o Insert the original instruction into the reentry island.
364	//		o Target the reentry island at the 2nd instruction of the
365	//		  original function.
366	//	o Replace the original instruction with the branch absolute.
367	if( !err ) {
368		int escapeIslandEngaged = false;
369		do {
370			if( reentryIsland )
371				err = setBranchIslandTarget( reentryIsland,
372						(void*) (originalFunctionPtr+1), originalInstruction );
373			if( !err ) {
374				escapeIslandEngaged = CompareAndSwap( originalInstruction,
375										branchAbsoluteInstruction,
376										(UInt32*)originalFunctionPtr );
377				if( !escapeIslandEngaged ) {
378					//	Someone replaced the instruction out from under us,
379					//	re-read the instruction, make sure it's still not
380					//	'mfctr' and try again.
381					originalInstruction = *originalFunctionPtr;
382					if( (originalInstruction & kMFCTRMask) == kMFCTRInstruction)
383						err = err_cannot_override;
384				}
385			}
386		} while( !err && !escapeIslandEngaged );
387	}
388#elif defined(__i386__) || defined(__x86_64__)
389	// Atomically:
390	//	o If the reentry island was allocated:
391	//		o Insert the original instructions into the reentry island.
392	//		o Target the reentry island at the first non-replaced
393	//        instruction of the original function.
394	//	o Replace the original first instructions with the jump relative.
395	//
396	// Note that on i386, we do not support someone else changing the code under our feet
397	if ( !err ) {
398		fixupInstructions(originalFunctionPtr, reentryIsland, originalInstructions,
399					originalInstructionCount, originalInstructionSizes );
400
401		if( reentryIsland )
402			err = setBranchIslandTarget_i386( reentryIsland,
403										 (void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions );
404		// try making islands executable before planting the jmp
405#if defined(__x86_64__) || defined(__i386__)
406        if( !err )
407            err = makeIslandExecutable(escapeIsland);
408        if( !err && reentryIsland )
409            err = makeIslandExecutable(reentryIsland);
410#endif
411		if ( !err )
412			atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelativeInstruction);
413	}
414#endif
415
416	//	Clean up on error.
417	if( err ) {
418		if( reentryIsland )
419			dealloc( reentryIsland );
420		if( escapeIsland )
421			dealloc( escapeIsland );
422	}
423
424#ifdef DEBUG_DISASM
425  {
426    fprintf(stderr, "First 16 bytes of the function after slicing: ");
427    unsigned char *orig = (unsigned char *)originalFunctionAddress;
428    int i;
429    for (i = 0; i < 16; i++) {
430       fprintf(stderr, "%x ", (unsigned int) orig[i]);
431    }
432    fprintf(stderr, "\n");
433  }
434#endif
435	return err;
436}
437
438/*******************************************************************************
439*
440*	Implementation
441*
442*******************************************************************************/
443#pragma mark	-
444#pragma mark	(Implementation)
445
446/***************************************************************************//**
447	Implementation: Allocates memory for a branch island.
448
449	@param	island			<-	The allocated island.
450	@param	allocateHigh	->	Whether to allocate the island at the end of the
451								address space (for use with the branch absolute
452								instruction).
453	@result					<-	mach_error_t
454
455	***************************************************************************/
456
457	mach_error_t
458allocateBranchIsland(
459		BranchIsland	**island,
460		int				allocateHigh,
461		void *originalFunctionAddress)
462{
463	assert( island );
464
465	mach_error_t	err = err_none;
466
467	if( allocateHigh ) {
468		vm_size_t pageSize;
469		err = host_page_size( mach_host_self(), &pageSize );
470		if( !err ) {
471			assert( sizeof( BranchIsland ) <= pageSize );
472#if defined(__ppc__) || defined(__POWERPC__)
473			vm_address_t first = 0xfeffffff;
474			vm_address_t last = 0xfe000000 + pageSize;
475#elif defined(__x86_64__)
476			vm_address_t first = ((uint64_t)originalFunctionAddress & ~(uint64_t)(((uint64_t)1 << 31) - 1)) | ((uint64_t)1 << 31); // start in the middle of the page?
477			vm_address_t last = 0x0;
478#else
479			vm_address_t first = 0xffc00000;
480			vm_address_t last = 0xfffe0000;
481#endif
482
483			vm_address_t page = first;
484			int allocated = 0;
485			vm_map_t task_self = mach_task_self();
486
487			while( !err && !allocated && page != last ) {
488
489				err = vm_allocate( task_self, &page, pageSize, 0 );
490				if( err == err_none )
491					allocated = 1;
492				else if( err == KERN_NO_SPACE ) {
493#if defined(__x86_64__)
494					page -= pageSize;
495#else
496					page += pageSize;
497#endif
498					err = err_none;
499				}
500			}
501			if( allocated )
502				*island = (BranchIsland*) page;
503			else if( !allocated && !err )
504				err = KERN_NO_SPACE;
505		}
506	} else {
507		void *block = malloc( sizeof( BranchIsland ) );
508		if( block )
509			*island = block;
510		else
511			err = KERN_NO_SPACE;
512	}
513	if( !err )
514		(**island).allocatedHigh = allocateHigh;
515
516	return err;
517}
518
519/***************************************************************************//**
520	Implementation: Deallocates memory for a branch island.
521
522	@param	island	->	The island to deallocate.
523	@result			<-	mach_error_t
524
525	***************************************************************************/
526
527	mach_error_t
528freeBranchIsland(
529		BranchIsland	*island )
530{
531	assert( island );
532	assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] );
533	assert( island->allocatedHigh );
534
535	mach_error_t	err = err_none;
536
537	if( island->allocatedHigh ) {
538		vm_size_t pageSize;
539		err = host_page_size( mach_host_self(), &pageSize );
540		if( !err ) {
541			assert( sizeof( BranchIsland ) <= pageSize );
542			err = vm_deallocate(
543					mach_task_self(),
544					(vm_address_t) island, pageSize );
545		}
546	} else {
547		free( island );
548	}
549
550	return err;
551}
552
553/***************************************************************************//**
554	Implementation: Sets the branch island's target, with an optional
555	instruction.
556
557	@param	island		->	The branch island to insert target into.
558	@param	branchTo	->	The address of the target.
559	@param	instruction	->	Optional instruction to execute prior to branch. Set
560							to zero for nop.
561	@result				<-	mach_error_t
562
563	***************************************************************************/
564#if defined(__ppc__) || defined(__POWERPC__)
565	mach_error_t
566setBranchIslandTarget(
567		BranchIsland	*island,
568		const void		*branchTo,
569		long			instruction )
570{
571	//	Copy over the template code.
572    bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
573
574    //	Fill in the address.
575    ((short*)island->instructions)[kAddressLo] = ((long) branchTo) & 0x0000FFFF;
576    ((short*)island->instructions)[kAddressHi]
577    	= (((long) branchTo) >> 16) & 0x0000FFFF;
578
579    //	Fill in the (optional) instuction.
580    if( instruction != 0 ) {
581        ((short*)island->instructions)[kInstructionLo]
582        	= instruction & 0x0000FFFF;
583        ((short*)island->instructions)[kInstructionHi]
584        	= (instruction >> 16) & 0x0000FFFF;
585    }
586
587    //MakeDataExecutable( island->instructions, sizeof( kIslandTemplate ) );
588	msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
589
590    return err_none;
591}
592#endif
593
594#if defined(__i386__)
595	mach_error_t
596setBranchIslandTarget_i386(
597	BranchIsland	*island,
598	const void		*branchTo,
599	char*			instructions )
600{
601
602	//	Copy over the template code.
603    bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
604
605	// copy original instructions
606	if (instructions) {
607		bcopy (instructions, island->instructions + kInstructions, kOriginalInstructionsSize);
608	}
609
610    // Fill in the address.
611    int32_t addressOffset = (char *)branchTo - (island->instructions + kJumpAddress + 4);
612    *((int32_t *)(island->instructions + kJumpAddress)) = addressOffset;
613
614    msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
615    return err_none;
616}
617
618#elif defined(__x86_64__)
619mach_error_t
620setBranchIslandTarget_i386(
621        BranchIsland	*island,
622        const void		*branchTo,
623        char*			instructions )
624{
625    // Copy over the template code.
626    bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
627
628    // Copy original instructions.
629    if (instructions) {
630        bcopy (instructions, island->instructions, kOriginalInstructionsSize);
631    }
632
633    //	Fill in the address.
634    *((uint64_t *)(island->instructions + kJumpAddress)) = (uint64_t)branchTo;
635    msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
636
637    return err_none;
638}
639#endif
640
641
642#if defined(__i386__) || defined(__x86_64__)
643// simplistic instruction matching
644typedef struct {
645	unsigned int length; // max 15
646	unsigned char mask[15]; // sequence of bytes in memory order
647	unsigned char constraint[15]; // sequence of bytes in memory order
648}	AsmInstructionMatch;
649
650#if defined(__i386__)
651static AsmInstructionMatch possibleInstructions[] = {
652	{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} },	// jmp 0x????????
653	{ 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} },	// push %esp; mov %esp,%ebp; leave; ret
654	{ 0x1, {0xFF}, {0x90} },							// nop
655	{ 0x1, {0xF8}, {0x50} },							// push %reg
656	{ 0x2, {0xFF, 0xFF}, {0x89, 0xE5} },				                // mov %esp,%ebp
657	{ 0x3, {0xFF, 0xFF, 0xFF}, {0x89, 0x1C, 0x24} },				                // mov %ebx,(%esp)
658	{ 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} },	                        // sub 0x??, %esp
659	{ 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x00, 0x00} },	// sub 0x??, %esp with 32bit immediate
660	{ 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },						// xor %eax, %eax
661	{ 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} },  // mov $imm(%ebp), %reg
662	{ 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} },  // mov $imm(%eax-%edx), %reg
663	{ 0x3, {0xFF, 0xCF, 0x00}, {0x8B, 0x4D, 0x00} },  // mov $imm(%rpb), %reg
664	{ 0x3, {0xFF, 0x4F, 0x00}, {0x8A, 0x4D, 0x00} },  // mov $imm(%ebp), %cl
665	{ 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x8B, 0x4C, 0x24, 0x00} },  			// mov $imm(%esp), %ecx
666	{ 0x4, {0xFF, 0x00, 0x00, 0x00}, {0x8B, 0x00, 0x00, 0x00} },  			// mov r16,r/m16 or r32,r/m32
667	{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB9, 0x00, 0x00, 0x00, 0x00} }, 	// mov $imm, %ecx
668	{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, 	// mov $imm, %eax
669	{ 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x66, 0x0F, 0xEF, 0x00} },             	// pxor xmm2/128, xmm1
670	{ 0x2, {0xFF, 0xFF}, {0xDB, 0xE3} }, 						// fninit
671	{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE8, 0x00, 0x00, 0x00, 0x00} },	// call $imm
672	{ 0x0 }
673};
674#elif defined(__x86_64__)
675// TODO(glider): disassembling the "0x48, 0x89" sequences is trickier than it's done below.
676// If it stops working, refer to http://ref.x86asm.net/geek.html#modrm_byte_32_64 to do it
677// more accurately.
678// Note: 0x48 is in fact the REX.W prefix, but it might be wrong to treat it as a separate
679// instruction.
680static AsmInstructionMatch possibleInstructions[] = {
681	{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} },	// jmp 0x????????
682	{ 0x1, {0xFF}, {0x90} },							// nop
683	{ 0x1, {0xF8}, {0x50} },							// push %rX
684	{ 0x1, {0xFF}, {0x65} },							// GS prefix
685	{ 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} },				// mov %rsp,%rbp
686	{ 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} },	                // sub 0x??, %rsp
687	{ 0x4, {0xFB, 0xFF, 0x07, 0x00}, {0x48, 0x89, 0x05, 0x00} },	                // move onto rbp
688	{ 0x3, {0xFB, 0xFF, 0x00}, {0x48, 0x89, 0x00} },	                            // mov %reg, %reg
689	{ 0x3, {0xFB, 0xFF, 0x00}, {0x49, 0x89, 0x00} },	                            // mov %reg, %reg (REX.WB)
690	{ 0x2, {0xFF, 0x00}, {0x41, 0x00} },						// push %rXX
691	{ 0x2, {0xFF, 0x00}, {0x85, 0x00} },						// test %rX,%rX
692	{ 0x2, {0xFF, 0x00}, {0x77, 0x00} },						// ja $i8
693	{ 0x2, {0xFF, 0x00}, {0x74, 0x00} },						// je $i8
694	{ 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} },	// mov $imm, %reg
695	{ 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} },				// pushq $imm(%rdi)
696	{ 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },						// xor %eax, %eax
697	{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0x25, 0x00, 0x00, 0x00, 0x00} },	// and $imm, %eax
698	{ 0x3, {0xFF, 0xFF, 0xFF}, {0x80, 0x3F, 0x00} },				// cmpb $imm, (%rdi)
699
700  { 0x8, {0xFF, 0xFF, 0xCF, 0xFF, 0x00, 0x00, 0x00, 0x00},
701         {0x48, 0x8B, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00}, },                     // mov $imm, %{rax,rdx,rsp,rsi}
702  { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xFA, 0x00}, },   // cmp $i8, %rdx
703	{ 0x4, {0xFF, 0xFF, 0x00, 0x00}, {0x83, 0x7f, 0x00, 0x00}, },			// cmpl $imm, $imm(%rdi)
704	{ 0xa, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
705               {0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },    // mov $imm, %rax
706        { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00},
707               {0x81, 0xE6, 0x00, 0x00, 0x00, 0x00} },                            // and $imm, %esi
708        { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00},
709               {0xFF, 0x25, 0x00, 0x00, 0x00, 0x00} },                            // jmpq *(%rip)
710        { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x66, 0x0F, 0xEF, 0x00} },              // pxor xmm2/128, xmm1
711        { 0x2, {0xFF, 0x00}, {0x89, 0x00} },                               // mov r/m32,r32 or r/m16,r16
712        { 0x3, {0xFF, 0xFF, 0xFF}, {0x49, 0x89, 0xF8} },                   // mov %rdi,%r8
713        { 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} },  // pushq $imm(%rdi)
714        { 0x2, {0xFF, 0xFF}, {0xDB, 0xE3} }, // fninit
715	{ 0x0 }
716};
717#endif
718
719static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch* instruction)
720{
721	Boolean match = true;
722
723	size_t i;
724  assert(instruction);
725#ifdef DEBUG_DISASM
726	fprintf(stderr, "Matching: ");
727#endif
728	for (i=0; i<instruction->length; i++) {
729		unsigned char mask = instruction->mask[i];
730		unsigned char constraint = instruction->constraint[i];
731		unsigned char codeValue = code[i];
732#ifdef DEBUG_DISASM
733		fprintf(stderr, "%x ", (unsigned)codeValue);
734#endif
735		match = ((codeValue & mask) == constraint);
736		if (!match) break;
737	}
738#ifdef DEBUG_DISASM
739	if (match) {
740		fprintf(stderr, " OK\n");
741	} else {
742		fprintf(stderr, " FAIL\n");
743	}
744#endif
745	return match;
746}
747
748#if defined(__i386__) || defined(__x86_64__)
749	static Boolean
750eatKnownInstructions(
751	unsigned char	*code,
752	uint64_t		*newInstruction,
753	int				*howManyEaten,
754	char			*originalInstructions,
755	int				*originalInstructionCount,
756	uint8_t			*originalInstructionSizes )
757{
758	Boolean allInstructionsKnown = true;
759	int totalEaten = 0;
760	unsigned char* ptr = code;
761	int remainsToEat = 5; // a JMP instruction takes 5 bytes
762	int instructionIndex = 0;
763
764	if (howManyEaten) *howManyEaten = 0;
765	if (originalInstructionCount) *originalInstructionCount = 0;
766	while (remainsToEat > 0) {
767		Boolean curInstructionKnown = false;
768
769		// See if instruction matches one  we know
770		AsmInstructionMatch* curInstr = possibleInstructions;
771		do {
772			if ((curInstructionKnown = codeMatchesInstruction(ptr, curInstr))) break;
773			curInstr++;
774		} while (curInstr->length > 0);
775
776		// if all instruction matches failed, we don't know current instruction then, stop here
777		if (!curInstructionKnown) {
778			allInstructionsKnown = false;
779			fprintf(stderr, "mach_override: some instructions unknown! Need to update mach_override.c\n");
780			break;
781		}
782
783		// At this point, we've matched curInstr
784		int eaten = curInstr->length;
785		ptr += eaten;
786		remainsToEat -= eaten;
787		totalEaten += eaten;
788
789		if (originalInstructionSizes) originalInstructionSizes[instructionIndex] = eaten;
790		instructionIndex += 1;
791		if (originalInstructionCount) *originalInstructionCount = instructionIndex;
792	}
793
794
795	if (howManyEaten) *howManyEaten = totalEaten;
796
797	if (originalInstructions) {
798		Boolean enoughSpaceForOriginalInstructions = (totalEaten < kOriginalInstructionsSize);
799
800		if (enoughSpaceForOriginalInstructions) {
801			memset(originalInstructions, 0x90 /* NOP */, kOriginalInstructionsSize); // fill instructions with NOP
802			bcopy(code, originalInstructions, totalEaten);
803		} else {
804#ifdef DEBUG_DISASM
805			fprintf(stderr, "Not enough space in island to store original instructions. Adapt the island definition and kOriginalInstructionsSize\n");
806#endif
807			return false;
808		}
809	}
810
811	if (allInstructionsKnown) {
812		// save last 3 bytes of first 64bits of codre we'll replace
813		uint64_t currentFirst64BitsOfCode = *((uint64_t *)code);
814		currentFirst64BitsOfCode = OSSwapInt64(currentFirst64BitsOfCode); // back to memory representation
815		currentFirst64BitsOfCode &= 0x0000000000FFFFFFLL;
816
817		// keep only last 3 instructions bytes, first 5 will be replaced by JMP instr
818		*newInstruction &= 0xFFFFFFFFFF000000LL; // clear last 3 bytes
819		*newInstruction |= (currentFirst64BitsOfCode & 0x0000000000FFFFFFLL); // set last 3 bytes
820	}
821
822	return allInstructionsKnown;
823}
824
825	static void
826fixupInstructions(
827    void		*originalFunction,
828    void		*escapeIsland,
829    void		*instructionsToFix,
830	int			instructionCount,
831	uint8_t		*instructionSizes )
832{
833	int	index;
834	for (index = 0;index < instructionCount;index += 1)
835	{
836		if ((*(uint8_t*)instructionsToFix == 0xE9) || // 32-bit jump relative
837		    (*(uint8_t*)instructionsToFix == 0xE8))   // 32-bit call relative
838		{
839			uint32_t offset = (uintptr_t)originalFunction - (uintptr_t)escapeIsland;
840			uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 1);
841			*jumpOffsetPtr += offset;
842		}
843
844
845		originalFunction = (void*)((uintptr_t)originalFunction + instructionSizes[index]);
846		escapeIsland = (void*)((uintptr_t)escapeIsland + instructionSizes[index]);
847		instructionsToFix = (void*)((uintptr_t)instructionsToFix + instructionSizes[index]);
848    }
849}
850#endif
851
852#if defined(__i386__)
853__asm(
854			".text;"
855			".align 2, 0x90;"
856			"_atomic_mov64:;"
857			"	pushl %ebp;"
858			"	movl %esp, %ebp;"
859			"	pushl %esi;"
860			"	pushl %ebx;"
861			"	pushl %ecx;"
862			"	pushl %eax;"
863			"	pushl %edx;"
864
865			// atomic push of value to an address
866			// we use cmpxchg8b, which compares content of an address with
867			// edx:eax. If they are equal, it atomically puts 64bit value
868			// ecx:ebx in address.
869			// We thus put contents of address in edx:eax to force ecx:ebx
870			// in address
871			"	mov		8(%ebp), %esi;"  // esi contains target address
872			"	mov		12(%ebp), %ebx;"
873			"	mov		16(%ebp), %ecx;" // ecx:ebx now contains value to put in target address
874			"	mov		(%esi), %eax;"
875			"	mov		4(%esi), %edx;"  // edx:eax now contains value currently contained in target address
876			"	lock; cmpxchg8b	(%esi);" // atomic move.
877
878			// restore registers
879			"	popl %edx;"
880			"	popl %eax;"
881			"	popl %ecx;"
882			"	popl %ebx;"
883			"	popl %esi;"
884			"	popl %ebp;"
885			"	ret"
886);
887#elif defined(__x86_64__)
888void atomic_mov64(
889		uint64_t *targetAddress,
890		uint64_t value )
891{
892    *targetAddress = value;
893}
894#endif
895#endif
896#endif  // __APPLE__
897