Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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