Parse and histogram LevelDB corruption errors.
[chromium-blink-merge.git] / third_party / mach_override / mach_override.c
blob549409d0b30b01a17c54d0f158773117a79a7e9f
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>
6 ***************************************************************************/
8 #include "mach_override.h"
10 #include <mach-o/dyld.h>
11 #include <mach/mach_host.h>
12 #include <mach/mach_init.h>
13 #include <mach/vm_map.h>
14 #include <sys/mman.h>
16 #include <CoreServices/CoreServices.h>
18 /**************************
20 * Constants
22 **************************/
23 #pragma mark -
24 #pragma mark (Constants)
26 #define kPageSize 4096
27 #if defined(__ppc__) || defined(__POWERPC__)
29 long kIslandTemplate[] = {
30 0x9001FFFC, // stw r0,-4(SP)
31 0x3C00DEAD, // lis r0,0xDEAD
32 0x6000BEEF, // ori r0,r0,0xBEEF
33 0x7C0903A6, // mtctr r0
34 0x8001FFFC, // lwz r0,-4(SP)
35 0x60000000, // nop ; optionally replaced
36 0x4E800420 // bctr
39 #define kAddressHi 3
40 #define kAddressLo 5
41 #define kInstructionHi 10
42 #define kInstructionLo 11
44 #elif defined(__i386__)
46 #define kOriginalInstructionsSize 16
48 char kIslandTemplate[] = {
49 // kOriginalInstructionsSize nop instructions so that we
50 // should have enough space to host original instructions
51 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
52 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
53 // Now the real jump instruction
54 0xE9, 0xEF, 0xBE, 0xAD, 0xDE
57 #define kInstructions 0
58 #define kJumpAddress kInstructions + kOriginalInstructionsSize + 1
59 #elif defined(__x86_64__)
61 #define kOriginalInstructionsSize 32
63 #define kJumpAddress kOriginalInstructionsSize + 6
65 char kIslandTemplate[] = {
66 // kOriginalInstructionsSize nop instructions so that we
67 // should have enough space to host original instructions
68 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
69 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
70 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
71 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
72 // Now the real jump instruction
73 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,
74 0x00, 0x00, 0x00, 0x00,
75 0x00, 0x00, 0x00, 0x00
78 #endif
80 /**************************
82 * Data Types
84 **************************/
85 #pragma mark -
86 #pragma mark (Data Types)
88 typedef struct {
89 char instructions[sizeof(kIslandTemplate)];
90 } BranchIsland;
92 /**************************
94 * Funky Protos
96 **************************/
97 #pragma mark -
98 #pragma mark (Funky Protos)
100 mach_error_t
101 allocateBranchIsland(
102 BranchIsland **island,
103 void *originalFunctionAddress);
105 mach_error_t
106 freeBranchIsland(
107 BranchIsland *island );
109 #if defined(__ppc__) || defined(__POWERPC__)
110 mach_error_t
111 setBranchIslandTarget(
112 BranchIsland *island,
113 const void *branchTo,
114 long instruction );
115 #endif
117 #if defined(__i386__) || defined(__x86_64__)
118 mach_error_t
119 setBranchIslandTarget_i386(
120 BranchIsland *island,
121 const void *branchTo,
122 char* instructions );
123 void
124 atomic_mov64(
125 uint64_t *targetAddress,
126 uint64_t value );
128 static Boolean
129 eatKnownInstructions(
130 unsigned char *code,
131 uint64_t *newInstruction,
132 int *howManyEaten,
133 char *originalInstructions,
134 int *originalInstructionCount,
135 uint8_t *originalInstructionSizes );
137 static void
138 fixupInstructions(
139 void *originalFunction,
140 void *escapeIsland,
141 void *instructionsToFix,
142 int instructionCount,
143 uint8_t *instructionSizes );
144 #endif
146 /*******************************************************************************
148 * Interface
150 *******************************************************************************/
151 #pragma mark -
152 #pragma mark (Interface)
154 #if defined(__i386__) || defined(__x86_64__)
155 mach_error_t makeIslandExecutable(void *address) {
156 mach_error_t err = err_none;
157 uintptr_t page = (uintptr_t)address & ~(uintptr_t)(kPageSize-1);
158 int e = err_none;
159 e |= mprotect((void *)page, kPageSize, PROT_EXEC | PROT_READ | PROT_WRITE);
160 e |= msync((void *)page, kPageSize, MS_INVALIDATE );
161 if (e) {
162 err = err_cannot_override;
164 return err;
166 #endif
168 mach_error_t
169 mach_override_ptr(
170 void *originalFunctionAddress,
171 const void *overrideFunctionAddress,
172 void **originalFunctionReentryIsland )
174 assert( originalFunctionAddress );
175 assert( overrideFunctionAddress );
177 // this addresses overriding such functions as AudioOutputUnitStart()
178 // test with modified DefaultOutputUnit project
179 #if defined(__x86_64__)
180 for(;;){
181 if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp qword near [rip+0x????????]
182 originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*(int32_t *)((uint16_t*)originalFunctionAddress+1));
183 else break;
185 #elif defined(__i386__)
186 for(;;){
187 if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x????????
188 originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1);
189 else break;
191 #endif
193 long *originalFunctionPtr = (long*) originalFunctionAddress;
194 mach_error_t err = err_none;
196 #if defined(__ppc__) || defined(__POWERPC__)
197 // Ensure first instruction isn't 'mfctr'.
198 #define kMFCTRMask 0xfc1fffff
199 #define kMFCTRInstruction 0x7c0903a6
201 long originalInstruction = *originalFunctionPtr;
202 if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) )
203 err = err_cannot_override;
204 #elif defined(__i386__) || defined(__x86_64__)
205 int eatenCount = 0;
206 int originalInstructionCount = 0;
207 char originalInstructions[kOriginalInstructionsSize];
208 uint8_t originalInstructionSizes[kOriginalInstructionsSize];
209 uint64_t jumpRelativeInstruction = 0; // JMP
211 Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr,
212 &jumpRelativeInstruction, &eatenCount,
213 originalInstructions, &originalInstructionCount,
214 originalInstructionSizes );
215 if (eatenCount > kOriginalInstructionsSize) {
216 //printf ("Too many instructions eaten\n");
217 overridePossible = false;
219 if (!overridePossible) err = err_cannot_override;
220 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
221 #endif
223 // Make the original function implementation writable.
224 if( !err ) {
225 err = vm_protect( mach_task_self(),
226 (vm_address_t) originalFunctionPtr, 8, false,
227 (VM_PROT_ALL | VM_PROT_COPY) );
228 if( err )
229 err = vm_protect( mach_task_self(),
230 (vm_address_t) originalFunctionPtr, 8, false,
231 (VM_PROT_DEFAULT | VM_PROT_COPY) );
233 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
235 // Allocate and target the escape island to the overriding function.
236 BranchIsland *escapeIsland = NULL;
237 if( !err )
238 err = allocateBranchIsland( &escapeIsland, originalFunctionAddress );
239 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
242 #if defined(__ppc__) || defined(__POWERPC__)
243 if( !err )
244 err = setBranchIslandTarget( escapeIsland, overrideFunctionAddress, 0 );
246 // Build the branch absolute instruction to the escape island.
247 long branchAbsoluteInstruction = 0; // Set to 0 just to silence warning.
248 if( !err ) {
249 long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF;
250 branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress;
252 #elif defined(__i386__) || defined(__x86_64__)
253 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
255 if( !err )
256 err = setBranchIslandTarget_i386( escapeIsland, overrideFunctionAddress, 0 );
258 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
259 // Build the jump relative instruction to the escape island
260 #endif
263 #if defined(__i386__) || defined(__x86_64__)
264 if (!err) {
265 uint32_t addressOffset = ((char*)escapeIsland - (char*)originalFunctionPtr - 5);
266 addressOffset = OSSwapInt32(addressOffset);
268 jumpRelativeInstruction |= 0xE900000000000000LL;
269 jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff) << 24;
270 jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
272 #endif
274 // Optionally allocate & return the reentry island. This may contain relocated
275 // jmp instructions and so has all the same addressing reachability requirements
276 // the escape island has to the original function, except the escape island is
277 // technically our original function.
278 BranchIsland *reentryIsland = NULL;
279 if( !err && originalFunctionReentryIsland ) {
280 err = allocateBranchIsland( &reentryIsland, escapeIsland);
281 if( !err )
282 *originalFunctionReentryIsland = reentryIsland;
285 #if defined(__ppc__) || defined(__POWERPC__)
286 // Atomically:
287 // o If the reentry island was allocated:
288 // o Insert the original instruction into the reentry island.
289 // o Target the reentry island at the 2nd instruction of the
290 // original function.
291 // o Replace the original instruction with the branch absolute.
292 if( !err ) {
293 int escapeIslandEngaged = false;
294 do {
295 if( reentryIsland )
296 err = setBranchIslandTarget( reentryIsland,
297 (void*) (originalFunctionPtr+1), originalInstruction );
298 if( !err ) {
299 escapeIslandEngaged = CompareAndSwap( originalInstruction,
300 branchAbsoluteInstruction,
301 (UInt32*)originalFunctionPtr );
302 if( !escapeIslandEngaged ) {
303 // Someone replaced the instruction out from under us,
304 // re-read the instruction, make sure it's still not
305 // 'mfctr' and try again.
306 originalInstruction = *originalFunctionPtr;
307 if( (originalInstruction & kMFCTRMask) == kMFCTRInstruction)
308 err = err_cannot_override;
311 } while( !err && !escapeIslandEngaged );
313 #elif defined(__i386__) || defined(__x86_64__)
314 // Atomically:
315 // o If the reentry island was allocated:
316 // o Insert the original instructions into the reentry island.
317 // o Target the reentry island at the first non-replaced
318 // instruction of the original function.
319 // o Replace the original first instructions with the jump relative.
321 // Note that on i386, we do not support someone else changing the code under our feet
322 if ( !err ) {
323 fixupInstructions(originalFunctionPtr, reentryIsland, originalInstructions,
324 originalInstructionCount, originalInstructionSizes );
326 if( reentryIsland )
327 err = setBranchIslandTarget_i386( reentryIsland,
328 (void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions );
329 // try making islands executable before planting the jmp
330 #if defined(__x86_64__) || defined(__i386__)
331 if( !err )
332 err = makeIslandExecutable(escapeIsland);
333 if( !err && reentryIsland )
334 err = makeIslandExecutable(reentryIsland);
335 #endif
336 if ( !err )
337 atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelativeInstruction);
339 #endif
341 // Clean up on error.
342 if( err ) {
343 if( reentryIsland )
344 freeBranchIsland( reentryIsland );
345 if( escapeIsland )
346 freeBranchIsland( escapeIsland );
349 return err;
352 /*******************************************************************************
354 * Implementation
356 *******************************************************************************/
357 #pragma mark -
358 #pragma mark (Implementation)
360 /***************************************************************************//**
361 Implementation: Allocates memory for a branch island.
363 @param island <- The allocated island.
364 @result <- mach_error_t
366 ***************************************************************************/
368 mach_error_t
369 allocateBranchIsland(
370 BranchIsland **island,
371 void *originalFunctionAddress)
373 assert( island );
375 assert( sizeof( BranchIsland ) <= kPageSize );
376 #if defined(__ppc__) || defined(__POWERPC__)
377 vm_address_t first = 0xfeffffff;
378 vm_address_t last = 0xfe000000 + kPageSize;
379 #elif defined(__x86_64__)
380 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?
381 vm_address_t last = 0x0;
382 #else
383 vm_address_t first = 0xffc00000;
384 vm_address_t last = 0xfffe0000;
385 #endif
387 vm_address_t page = first;
388 vm_map_t task_self = mach_task_self();
390 while( page != last ) {
391 mach_error_t err = vm_allocate( task_self, &page, kPageSize, 0 );
392 if( err == err_none ) {
393 *island = (BranchIsland*) page;
394 return err_none;
396 if( err != KERN_NO_SPACE )
397 return err;
398 #if defined(__x86_64__)
399 page -= kPageSize;
400 #else
401 page += kPageSize;
402 #endif
403 err = err_none;
406 return KERN_NO_SPACE;
409 /***************************************************************************//**
410 Implementation: Deallocates memory for a branch island.
412 @param island -> The island to deallocate.
413 @result <- mach_error_t
415 ***************************************************************************/
417 mach_error_t
418 freeBranchIsland(
419 BranchIsland *island )
421 assert( island );
422 assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] );
423 assert( sizeof( BranchIsland ) <= kPageSize );
424 return vm_deallocate( mach_task_self(), (vm_address_t) island,
425 kPageSize );
428 /***************************************************************************//**
429 Implementation: Sets the branch island's target, with an optional
430 instruction.
432 @param island -> The branch island to insert target into.
433 @param branchTo -> The address of the target.
434 @param instruction -> Optional instruction to execute prior to branch. Set
435 to zero for nop.
436 @result <- mach_error_t
438 ***************************************************************************/
439 #if defined(__ppc__) || defined(__POWERPC__)
440 mach_error_t
441 setBranchIslandTarget(
442 BranchIsland *island,
443 const void *branchTo,
444 long instruction )
446 // Copy over the template code.
447 bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
449 // Fill in the address.
450 ((short*)island->instructions)[kAddressLo] = ((long) branchTo) & 0x0000FFFF;
451 ((short*)island->instructions)[kAddressHi]
452 = (((long) branchTo) >> 16) & 0x0000FFFF;
454 // Fill in the (optional) instuction.
455 if( instruction != 0 ) {
456 ((short*)island->instructions)[kInstructionLo]
457 = instruction & 0x0000FFFF;
458 ((short*)island->instructions)[kInstructionHi]
459 = (instruction >> 16) & 0x0000FFFF;
462 //MakeDataExecutable( island->instructions, sizeof( kIslandTemplate ) );
463 msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
465 return err_none;
467 #endif
469 #if defined(__i386__)
470 mach_error_t
471 setBranchIslandTarget_i386(
472 BranchIsland *island,
473 const void *branchTo,
474 char* instructions )
477 // Copy over the template code.
478 bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
480 // copy original instructions
481 if (instructions) {
482 bcopy (instructions, island->instructions + kInstructions, kOriginalInstructionsSize);
485 // Fill in the address.
486 int32_t addressOffset = (char *)branchTo - (island->instructions + kJumpAddress + 4);
487 *((int32_t *)(island->instructions + kJumpAddress)) = addressOffset;
489 msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
490 return err_none;
493 #elif defined(__x86_64__)
494 mach_error_t
495 setBranchIslandTarget_i386(
496 BranchIsland *island,
497 const void *branchTo,
498 char* instructions )
500 // Copy over the template code.
501 bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
503 // Copy original instructions.
504 if (instructions) {
505 bcopy (instructions, island->instructions, kOriginalInstructionsSize);
508 // Fill in the address.
509 *((uint64_t *)(island->instructions + kJumpAddress)) = (uint64_t)branchTo;
510 msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
512 return err_none;
514 #endif
517 #if defined(__i386__) || defined(__x86_64__)
518 // simplistic instruction matching
519 typedef struct {
520 unsigned int length; // max 15
521 unsigned char mask[15]; // sequence of bytes in memory order
522 unsigned char constraint[15]; // sequence of bytes in memory order
523 } AsmInstructionMatch;
525 #if defined(__i386__)
526 static AsmInstructionMatch possibleInstructions[] = {
527 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} }, // jmp 0x????????
528 { 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} }, // push %ebp; mov %esp,%ebp; leave; ret
529 { 0x1, {0xFF}, {0x90} }, // nop
530 { 0x1, {0xFF}, {0x55} }, // push %esp
531 { 0x2, {0xFF, 0xFF}, {0x89, 0xE5} }, // mov %esp,%ebp
532 { 0x1, {0xFF}, {0x53} }, // push %ebx
533 { 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} }, // sub 0x??, %esp
534 { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x00, 0x00} }, // sub 0x??, %esp with 32bit immediate
535 { 0x1, {0xFF}, {0x57} }, // push %edi
536 { 0x1, {0xFF}, {0x56} }, // push %esi
537 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} }, // xor %eax, %eax
538 { 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} }, // mov $imm(%ebp), %reg
539 { 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} }, // mov $imm(%eax-%edx), %reg
540 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x8B, 0x4C, 0x24, 0x00} }, // mov $imm(%esp), %ecx
541 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %eax
542 { 0x0 }
544 #elif defined(__x86_64__)
545 static AsmInstructionMatch possibleInstructions[] = {
546 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} }, // jmp 0x????????
547 { 0x1, {0xFF}, {0x90} }, // nop
548 { 0x1, {0xF8}, {0x50} }, // push %rX
549 { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} }, // mov %rsp,%rbp
550 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} }, // sub 0x??, %rsp
551 { 0x4, {0xFB, 0xFF, 0x00, 0x00}, {0x48, 0x89, 0x00, 0x00} }, // move onto rbp
552 { 0x2, {0xFF, 0x00}, {0x41, 0x00} }, // push %rXX
553 { 0x2, {0xFF, 0x00}, {0x85, 0x00} }, // test %rX,%rX
554 { 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %reg
555 { 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} }, // pushq $imm(%rdi)
556 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} }, // xor %eax, %eax
557 { 0x2, {0xFF, 0xFF}, {0x89, 0xF8} }, // mov %edi, %eax
558 { 0x0 }
560 #endif
562 static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch* instruction)
564 Boolean match = true;
566 size_t i;
567 for (i=0; i<instruction->length; i++) {
568 unsigned char mask = instruction->mask[i];
569 unsigned char constraint = instruction->constraint[i];
570 unsigned char codeValue = code[i];
572 match = ((codeValue & mask) == constraint);
573 if (!match) break;
576 return match;
579 #if defined(__i386__) || defined(__x86_64__)
580 static Boolean
581 eatKnownInstructions(
582 unsigned char *code,
583 uint64_t *newInstruction,
584 int *howManyEaten,
585 char *originalInstructions,
586 int *originalInstructionCount,
587 uint8_t *originalInstructionSizes )
589 Boolean allInstructionsKnown = true;
590 int totalEaten = 0;
591 unsigned char* ptr = code;
592 int remainsToEat = 5; // a JMP instruction takes 5 bytes
593 int instructionIndex = 0;
595 if (howManyEaten) *howManyEaten = 0;
596 if (originalInstructionCount) *originalInstructionCount = 0;
597 while (remainsToEat > 0) {
598 Boolean curInstructionKnown = false;
600 // See if instruction matches one we know
601 AsmInstructionMatch* curInstr = possibleInstructions;
602 do {
603 if ((curInstructionKnown = codeMatchesInstruction(ptr, curInstr))) break;
604 curInstr++;
605 } while (curInstr->length > 0);
607 // if all instruction matches failed, we don't know current instruction then, stop here
608 if (!curInstructionKnown) {
609 allInstructionsKnown = false;
610 fprintf(stderr, "mach_override: some instructions unknown! Need to update mach_override.c\n");
611 break;
614 // At this point, we've matched curInstr
615 int eaten = curInstr->length;
616 ptr += eaten;
617 remainsToEat -= eaten;
618 totalEaten += eaten;
620 if (originalInstructionSizes) originalInstructionSizes[instructionIndex] = eaten;
621 instructionIndex += 1;
622 if (originalInstructionCount) *originalInstructionCount = instructionIndex;
626 if (howManyEaten) *howManyEaten = totalEaten;
628 if (originalInstructions) {
629 Boolean enoughSpaceForOriginalInstructions = (totalEaten < kOriginalInstructionsSize);
631 if (enoughSpaceForOriginalInstructions) {
632 memset(originalInstructions, 0x90 /* NOP */, kOriginalInstructionsSize); // fill instructions with NOP
633 bcopy(code, originalInstructions, totalEaten);
634 } else {
635 // printf ("Not enough space in island to store original instructions. Adapt the island definition and kOriginalInstructionsSize\n");
636 return false;
640 if (allInstructionsKnown) {
641 // save last 3 bytes of first 64bits of codre we'll replace
642 uint64_t currentFirst64BitsOfCode = *((uint64_t *)code);
643 currentFirst64BitsOfCode = OSSwapInt64(currentFirst64BitsOfCode); // back to memory representation
644 currentFirst64BitsOfCode &= 0x0000000000FFFFFFLL;
646 // keep only last 3 instructions bytes, first 5 will be replaced by JMP instr
647 *newInstruction &= 0xFFFFFFFFFF000000LL; // clear last 3 bytes
648 *newInstruction |= (currentFirst64BitsOfCode & 0x0000000000FFFFFFLL); // set last 3 bytes
651 return allInstructionsKnown;
654 static void
655 fixupInstructions(
656 void *originalFunction,
657 void *escapeIsland,
658 void *instructionsToFix,
659 int instructionCount,
660 uint8_t *instructionSizes )
662 int index;
663 for (index = 0;index < instructionCount;index += 1)
665 if (*(uint8_t*)instructionsToFix == 0xE9) // 32-bit jump relative
667 uint32_t offset = (uintptr_t)originalFunction - (uintptr_t)escapeIsland;
668 uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 1);
669 *jumpOffsetPtr += offset;
672 originalFunction = (void*)((uintptr_t)originalFunction + instructionSizes[index]);
673 escapeIsland = (void*)((uintptr_t)escapeIsland + instructionSizes[index]);
674 instructionsToFix = (void*)((uintptr_t)instructionsToFix + instructionSizes[index]);
677 #endif
679 #if defined(__i386__)
680 __asm(
681 ".text;"
682 ".align 2, 0x90;"
683 "_atomic_mov64:;"
684 " pushl %ebp;"
685 " movl %esp, %ebp;"
686 " pushl %esi;"
687 " pushl %ebx;"
688 " pushl %ecx;"
689 " pushl %eax;"
690 " pushl %edx;"
692 // atomic push of value to an address
693 // we use cmpxchg8b, which compares content of an address with
694 // edx:eax. If they are equal, it atomically puts 64bit value
695 // ecx:ebx in address.
696 // We thus put contents of address in edx:eax to force ecx:ebx
697 // in address
698 " mov 8(%ebp), %esi;" // esi contains target address
699 " mov 12(%ebp), %ebx;"
700 " mov 16(%ebp), %ecx;" // ecx:ebx now contains value to put in target address
701 " mov (%esi), %eax;"
702 " mov 4(%esi), %edx;" // edx:eax now contains value currently contained in target address
703 " lock; cmpxchg8b (%esi);" // atomic move.
705 // restore registers
706 " popl %edx;"
707 " popl %eax;"
708 " popl %ecx;"
709 " popl %ebx;"
710 " popl %esi;"
711 " popl %ebp;"
712 " ret"
714 #elif defined(__x86_64__)
715 void atomic_mov64(
716 uint64_t *targetAddress,
717 uint64_t value )
719 *targetAddress = value;
721 #endif
722 #endif