summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/chrome_renderer.gypi8
-rw-r--r--chrome/renderer/DEPS1
-rw-r--r--chrome/renderer/renderer_main.cc34
-rw-r--r--third_party/mach_override/LICENSE2
-rw-r--r--third_party/mach_override/README.chromium29
-rw-r--r--third_party/mach_override/chromium.diff139
-rw-r--r--third_party/mach_override/mach_override.c682
-rw-r--r--third_party/mach_override/mach_override.gyp28
-rw-r--r--third_party/mach_override/mach_override.h121
9 files changed, 1041 insertions, 3 deletions
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi
index 1530296..5bcb197 100644
--- a/chrome/chrome_renderer.gypi
+++ b/chrome/chrome_renderer.gypi
@@ -184,7 +184,11 @@
'renderer/nacl_desc_wrapper_chrome.cc',
],
}],
- # Linux-specific rules.
+ ['OS=="mac"', {
+ 'dependencies': [
+ '../third_party/mach_override/mach_override.gyp:mach_override',
+ ],
+ }],
['OS=="linux"', {
'conditions': [
[ 'linux_use_tcmalloc==1', {
@@ -199,13 +203,11 @@
'../sandbox/sandbox.gyp:sandbox',
],
}],
- # BSD-specific rules.
['OS=="openbsd" or OS=="freebsd"', {
'dependencies': [
'../build/linux/system.gyp:gtk',
],
}],
- # Windows-specific rules.
['OS=="win"', {
'include_dirs': [
'<(DEPTH)/third_party/wtl/include',
diff --git a/chrome/renderer/DEPS b/chrome/renderer/DEPS
index 3025ecf..f928926 100644
--- a/chrome/renderer/DEPS
+++ b/chrome/renderer/DEPS
@@ -18,6 +18,7 @@ include_rules = [
"+webkit/plugins",
"+v8/include",
"+third_party/cld/encodings/compact_lang_det/win",
+ "+third_party/mach_override",
"+third_party/npapi/bindings",
"+third_party/sqlite",
"+third_party/tcmalloc",
diff --git a/chrome/renderer/renderer_main.cc b/chrome/renderer/renderer_main.cc
index df75219e..c72fe20 100644
--- a/chrome/renderer/renderer_main.cc
+++ b/chrome/renderer/renderer_main.cc
@@ -38,14 +38,46 @@
#include "ui/base/ui_base_switches.h"
#if defined(OS_MACOSX)
+#include <Carbon/Carbon.h> // TISCreateInputSourceList
+
#include "base/eintr_wrapper.h"
+#include "base/sys_info.h"
#include "chrome/app/breakpad_mac.h"
+#include "third_party/mach_override/mach_override.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#endif // OS_MACOSX
#if defined(OS_MACOSX)
namespace {
+CFArrayRef ChromeTISCreateInputSourceList(
+ CFDictionaryRef properties,
+ Boolean includeAllInstalled) {
+ CFTypeRef values[] = { CFSTR("") };
+ return CFArrayCreate(
+ kCFAllocatorDefault, values, arraysize(values), &kCFTypeArrayCallBacks);
+}
+
+void InstallFrameworkHacks() {
+ int32 os_major, os_minor, os_bugfix;
+ base::SysInfo::OperatingSystemVersionNumbers(
+ &os_major, &os_minor, &os_bugfix);
+
+ // See http://crbug.com/31225
+ // TODO: Don't do this on newer OS X revisions that have a fix for
+ // http://openradar.appspot.com/radar?id=1156410
+ if (os_major == 10 && os_minor >= 6) {
+ // Chinese Handwriting was introduced in 10.6. Since doing this override
+ // regresses page cycler memory usage on 10.5, don't do the unnecessary
+ // override there.
+ mach_error_t err = mach_override_ptr(
+ (void*)&TISCreateInputSourceList,
+ (void*)&ChromeTISCreateInputSourceList,
+ NULL);
+ CHECK_EQ(err_none, err);
+ }
+}
+
// TODO(viettrungluu): crbug.com/28547: The following signal handling is needed,
// as a stopgap, to avoid leaking due to not releasing Breakpad properly.
// Without this problem, this could all be eliminated. Remove when Breakpad is
@@ -231,6 +263,8 @@ int RendererMain(const MainFunctionParams& parameters) {
memset(&action, 0, sizeof(action));
action.sa_handler = SIGTERMHandler;
CHECK(sigaction(SIGTERM, &action, NULL) == 0);
+
+ InstallFrameworkHacks();
#endif // OS_MACOSX
#if defined(OS_CHROMEOS)
diff --git a/third_party/mach_override/LICENSE b/third_party/mach_override/LICENSE
new file mode 100644
index 0000000..5f6ba7e
--- /dev/null
+++ b/third_party/mach_override/LICENSE
@@ -0,0 +1,2 @@
+Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
+Some rights reserved: <http://opensource.org/licenses/mit-license.php>
diff --git a/third_party/mach_override/README.chromium b/third_party/mach_override/README.chromium
new file mode 100644
index 0000000..385ba92
--- /dev/null
+++ b/third_party/mach_override/README.chromium
@@ -0,0 +1,29 @@
+Name: mach_override
+Short Name: Part of the mach_star project
+Version: Unknown
+URL: https://github.com/rentzsch/mach_star
+Date: 04/11/2011
+Revision: 2cd209e090640220b48e5f97e7a366165f9de3f9
+License: MIT
+Security Critical: Yes.
+
+
+Description:
+This is the mach_override part of the lastest (as of 04/11/2011) revision of
+mach_star, namely:
+
+ https://github.com/rentzsch/mach_star/tree/2cd209e090640220b48e5f97e7a366165f9de3f9
+
+This package is used to replace framework functions with different
+implementations at run time.
+
+
+Local Modifications:
+
+* Minor fixes to make the file buildable with -std=c99 -Wall -Werror
+* Support for |sub %esp| with a 32bit immediate
+* atomic_mov64 is no longer .globl
+* Removed function mach_override() because it used deprecated functions
+* Added a gyp file
+
+See chromium.diff for details.
diff --git a/third_party/mach_override/chromium.diff b/third_party/mach_override/chromium.diff
new file mode 100644
index 0000000..2f65cea
--- /dev/null
+++ b/third_party/mach_override/chromium.diff
@@ -0,0 +1,139 @@
+--- /Users/thakis/src/mach_star/mach_override/mach_override.c 2011-04-11 09:35:25.000000000 -0700
++++ third_party/mach_override/mach_override.c 2011-04-12 16:21:19.000000000 -0700
+@@ -145,36 +145,6 @@
+ #pragma mark -
+ #pragma mark (Interface)
+
+- mach_error_t
+-mach_override(
+- char *originalFunctionSymbolName,
+- const char *originalFunctionLibraryNameHint,
+- const void *overrideFunctionAddress,
+- void **originalFunctionReentryIsland )
+-{
+- assert( originalFunctionSymbolName );
+- assert( strlen( originalFunctionSymbolName ) );
+- assert( overrideFunctionAddress );
+-
+- // Lookup the original function's code pointer.
+- long *originalFunctionPtr;
+- if( originalFunctionLibraryNameHint )
+- _dyld_lookup_and_bind_with_hint(
+- originalFunctionSymbolName,
+- originalFunctionLibraryNameHint,
+- (void*) &originalFunctionPtr,
+- NULL );
+- else
+- _dyld_lookup_and_bind(
+- originalFunctionSymbolName,
+- (void*) &originalFunctionPtr,
+- NULL );
+-
+- //printf ("In mach_override\n");
+- return mach_override_ptr( originalFunctionPtr, overrideFunctionAddress,
+- originalFunctionReentryIsland );
+-}
+-
+ #if defined(__x86_64__)
+ mach_error_t makeIslandExecutable(void *address) {
+ mach_error_t err = err_none;
+@@ -563,8 +533,10 @@
+ { 0x2, {0xFF, 0xFF}, {0x89, 0xE5} }, // mov %esp,%ebp
+ { 0x1, {0xFF}, {0x53} }, // push %ebx
+ { 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} }, // sub 0x??, %esp
++ { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x00, 0x00} }, // sub 0x??, %esp with 32bit immediate
+ { 0x1, {0xFF}, {0x57} }, // push %edi
+ { 0x1, {0xFF}, {0x56} }, // push %esi
++ { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} }, // xor %eax, %eax
+ { 0x0 }
+ };
+ #elif defined(__x86_64__)
+@@ -584,7 +556,7 @@
+ {
+ Boolean match = true;
+
+- int i;
++ size_t i;
+ for (i=0; i<instruction->length; i++) {
+ unsigned char mask = instruction->mask[i];
+ unsigned char constraint = instruction->constraint[i];
+@@ -617,7 +589,7 @@
+ // See if instruction matches one we know
+ AsmInstructionMatch* curInstr = possibleInstructions;
+ do {
+- if (curInstructionKnown = codeMatchesInstruction(ptr, curInstr)) break;
++ if ((curInstructionKnown = codeMatchesInstruction(ptr, curInstr))) break;
+ curInstr++;
+ } while (curInstr->length > 0);
+
+@@ -665,10 +637,9 @@
+ #endif
+
+ #if defined(__i386__)
+-asm(
++__asm(
+ ".text;"
+ ".align 2, 0x90;"
+- ".globl _atomic_mov64;"
+ "_atomic_mov64:;"
+ " pushl %ebp;"
+ " movl %esp, %ebp;"
+@@ -708,4 +679,4 @@
+ *targetAddress = value;
+ }
+ #endif
+-#endif
+\ No newline at end of file
++#endif
+--- /Users/thakis/src/mach_star/mach_override/mach_override.h 2011-04-11 09:35:25.000000000 -0700
++++ third_party/mach_override/mach_override.h 2011-04-12 14:17:34.000000000 -0700
+@@ -57,42 +57,6 @@
+ */
+ #define err_cannot_override (err_local|1)
+
+-/***************************************************************************//**
+- Dynamically overrides the function implementation referenced by
+- originalFunctionSymbolName with the implentation pointed to by
+- overrideFunctionAddress. Optionally returns a pointer to a "reentry island"
+- which, if jumped to, will resume the original implementation.
+-
+- @param originalFunctionSymbolName -> Required symbol name of the
+- function to override (with
+- overrideFunctionAddress).
+- Remember, C function name
+- symbols are prepended with an
+- underscore.
+- @param originalFunctionLibraryNameHint -> Optional name of the library
+- which contains
+- originalFunctionSymbolName. Can
+- be NULL, but this may result in
+- the wrong function being
+- overridden and/or a crash.
+- @param overrideFunctionAddress -> Required address to the
+- overriding function.
+- @param originalFunctionReentryIsland <- Optional pointer to pointer to
+- the reentry island. Can be NULL.
+- @result <- err_cannot_override if the
+- original function's
+- implementation begins with the
+- 'mfctr' instruction.
+-
+- ***************************************************************************/
+-
+- mach_error_t
+-mach_override(
+- char *originalFunctionSymbolName,
+- const char *originalFunctionLibraryNameHint,
+- const void *overrideFunctionAddress,
+- void **originalFunctionReentryIsland );
+-
+ /************************************************************************************//**
+ Dynamically overrides the function implementation referenced by
+ originalFunctionAddress with the implentation pointed to by overrideFunctionAddress.
+@@ -154,4 +118,4 @@
+ #ifdef __cplusplus
+ }
+ #endif
+-#endif // _mach_override_
+\ No newline at end of file
++#endif // _mach_override_
diff --git a/third_party/mach_override/mach_override.c b/third_party/mach_override/mach_override.c
new file mode 100644
index 0000000..30b6afd
--- /dev/null
+++ b/third_party/mach_override/mach_override.c
@@ -0,0 +1,682 @@
+/*******************************************************************************
+ mach_override.c
+ Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
+ Some rights reserved: <http://opensource.org/licenses/mit-license.php>
+
+ ***************************************************************************/
+
+#include "mach_override.h"
+
+#include <mach-o/dyld.h>
+#include <mach/mach_host.h>
+#include <mach/mach_init.h>
+#include <mach/vm_map.h>
+#include <sys/mman.h>
+
+#include <CoreServices/CoreServices.h>
+
+/**************************
+*
+* Constants
+*
+**************************/
+#pragma mark -
+#pragma mark (Constants)
+
+#if defined(__ppc__) || defined(__POWERPC__)
+
+long kIslandTemplate[] = {
+ 0x9001FFFC, // stw r0,-4(SP)
+ 0x3C00DEAD, // lis r0,0xDEAD
+ 0x6000BEEF, // ori r0,r0,0xBEEF
+ 0x7C0903A6, // mtctr r0
+ 0x8001FFFC, // lwz r0,-4(SP)
+ 0x60000000, // nop ; optionally replaced
+ 0x4E800420 // bctr
+};
+
+#define kAddressHi 3
+#define kAddressLo 5
+#define kInstructionHi 10
+#define kInstructionLo 11
+
+#elif defined(__i386__)
+
+#define kOriginalInstructionsSize 16
+
+char kIslandTemplate[] = {
+ // kOriginalInstructionsSize nop instructions so that we
+ // should have enough space to host original instructions
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ // Now the real jump instruction
+ 0xE9, 0xEF, 0xBE, 0xAD, 0xDE
+};
+
+#define kInstructions 0
+#define kJumpAddress kInstructions + kOriginalInstructionsSize + 1
+#elif defined(__x86_64__)
+
+#define kOriginalInstructionsSize 32
+
+#define kJumpAddress kOriginalInstructionsSize + 6
+
+char kIslandTemplate[] = {
+ // kOriginalInstructionsSize nop instructions so that we
+ // should have enough space to host original instructions
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ // Now the real jump instruction
+ 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+#endif
+
+#define kAllocateHigh 1
+#define kAllocateNormal 0
+
+/**************************
+*
+* Data Types
+*
+**************************/
+#pragma mark -
+#pragma mark (Data Types)
+
+typedef struct {
+ char instructions[sizeof(kIslandTemplate)];
+ int allocatedHigh;
+} BranchIsland;
+
+/**************************
+*
+* Funky Protos
+*
+**************************/
+#pragma mark -
+#pragma mark (Funky Protos)
+
+ mach_error_t
+allocateBranchIsland(
+ BranchIsland **island,
+ int allocateHigh,
+ void *originalFunctionAddress);
+
+ mach_error_t
+freeBranchIsland(
+ BranchIsland *island );
+
+#if defined(__ppc__) || defined(__POWERPC__)
+ mach_error_t
+setBranchIslandTarget(
+ BranchIsland *island,
+ const void *branchTo,
+ long instruction );
+#endif
+
+#if defined(__i386__) || defined(__x86_64__)
+mach_error_t
+setBranchIslandTarget_i386(
+ BranchIsland *island,
+ const void *branchTo,
+ char* instructions );
+void
+atomic_mov64(
+ uint64_t *targetAddress,
+ uint64_t value );
+
+ static Boolean
+eatKnownInstructions(
+ unsigned char *code,
+ uint64_t *newInstruction,
+ int *howManyEaten,
+ char *originalInstructions );
+#endif
+
+/*******************************************************************************
+*
+* Interface
+*
+*******************************************************************************/
+#pragma mark -
+#pragma mark (Interface)
+
+#if defined(__x86_64__)
+mach_error_t makeIslandExecutable(void *address) {
+ mach_error_t err = err_none;
+ vm_size_t pageSize;
+ host_page_size( mach_host_self(), &pageSize );
+ uint64_t page = (uint64_t)address & ~(uint64_t)(pageSize-1);
+ int e = err_none;
+ e |= mprotect((void *)page, pageSize, PROT_EXEC | PROT_READ | PROT_WRITE);
+ e |= msync((void *)page, pageSize, MS_INVALIDATE );
+ if (e) {
+ err = err_cannot_override;
+ }
+ return err;
+}
+#endif
+
+ mach_error_t
+mach_override_ptr(
+ void *originalFunctionAddress,
+ const void *overrideFunctionAddress,
+ void **originalFunctionReentryIsland )
+{
+ assert( originalFunctionAddress );
+ assert( overrideFunctionAddress );
+
+ long *originalFunctionPtr = (long*) originalFunctionAddress;
+ mach_error_t err = err_none;
+
+#if defined(__ppc__) || defined(__POWERPC__)
+ // Ensure first instruction isn't 'mfctr'.
+ #define kMFCTRMask 0xfc1fffff
+ #define kMFCTRInstruction 0x7c0903a6
+
+ long originalInstruction = *originalFunctionPtr;
+ if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) )
+ err = err_cannot_override;
+#elif defined(__i386__) || defined(__x86_64__)
+ int eatenCount = 0;
+ char originalInstructions[kOriginalInstructionsSize];
+ uint64_t jumpRelativeInstruction = 0; // JMP
+
+ Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr,
+ &jumpRelativeInstruction, &eatenCount, originalInstructions);
+ if (eatenCount > kOriginalInstructionsSize) {
+ //printf ("Too many instructions eaten\n");
+ overridePossible = false;
+ }
+ if (!overridePossible) err = err_cannot_override;
+ if (err) printf("err = %x %d\n", err, __LINE__);
+#endif
+
+ // Make the original function implementation writable.
+ if( !err ) {
+ err = vm_protect( mach_task_self(),
+ (vm_address_t) originalFunctionPtr,
+ sizeof(long), false, (VM_PROT_ALL | VM_PROT_COPY) );
+ if( err )
+ err = vm_protect( mach_task_self(),
+ (vm_address_t) originalFunctionPtr, sizeof(long), false,
+ (VM_PROT_DEFAULT | VM_PROT_COPY) );
+ }
+ if (err) printf("err = %x %d\n", err, __LINE__);
+
+ // Allocate and target the escape island to the overriding function.
+ BranchIsland *escapeIsland = NULL;
+ if( !err )
+ err = allocateBranchIsland( &escapeIsland, kAllocateHigh, originalFunctionAddress );
+ if (err) printf("err = %x %d\n", err, __LINE__);
+
+
+#if defined(__ppc__) || defined(__POWERPC__)
+ if( !err )
+ err = setBranchIslandTarget( escapeIsland, overrideFunctionAddress, 0 );
+
+ // Build the branch absolute instruction to the escape island.
+ long branchAbsoluteInstruction = 0; // Set to 0 just to silence warning.
+ if( !err ) {
+ long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF;
+ branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress;
+ }
+#elif defined(__i386__) || defined(__x86_64__)
+ if (err) printf("err = %x %d\n", err, __LINE__);
+
+ if( !err )
+ err = setBranchIslandTarget_i386( escapeIsland, overrideFunctionAddress, 0 );
+
+ if (err) printf("err = %x %d\n", err, __LINE__);
+ // Build the jump relative instruction to the escape island
+#endif
+
+
+#if defined(__i386__) || defined(__x86_64__)
+ if (!err) {
+ uint32_t addressOffset = ((void*)escapeIsland - (void*)originalFunctionPtr - 5);
+ addressOffset = OSSwapInt32(addressOffset);
+
+ jumpRelativeInstruction |= 0xE900000000000000LL;
+ jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff) << 24;
+ jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
+ }
+#endif
+
+ // Optionally allocate & return the reentry island.
+ BranchIsland *reentryIsland = NULL;
+ if( !err && originalFunctionReentryIsland ) {
+ err = allocateBranchIsland( &reentryIsland, kAllocateNormal, NULL);
+ if( !err )
+ *originalFunctionReentryIsland = reentryIsland;
+ }
+
+#if defined(__ppc__) || defined(__POWERPC__)
+ // Atomically:
+ // o If the reentry island was allocated:
+ // o Insert the original instruction into the reentry island.
+ // o Target the reentry island at the 2nd instruction of the
+ // original function.
+ // o Replace the original instruction with the branch absolute.
+ if( !err ) {
+ int escapeIslandEngaged = false;
+ do {
+ if( reentryIsland )
+ err = setBranchIslandTarget( reentryIsland,
+ (void*) (originalFunctionPtr+1), originalInstruction );
+ if( !err ) {
+ escapeIslandEngaged = CompareAndSwap( originalInstruction,
+ branchAbsoluteInstruction,
+ (UInt32*)originalFunctionPtr );
+ if( !escapeIslandEngaged ) {
+ // Someone replaced the instruction out from under us,
+ // re-read the instruction, make sure it's still not
+ // 'mfctr' and try again.
+ originalInstruction = *originalFunctionPtr;
+ if( (originalInstruction & kMFCTRMask) == kMFCTRInstruction)
+ err = err_cannot_override;
+ }
+ }
+ } while( !err && !escapeIslandEngaged );
+ }
+#elif defined(__i386__) || defined(__x86_64__)
+ // Atomically:
+ // o If the reentry island was allocated:
+ // o Insert the original instructions into the reentry island.
+ // o Target the reentry island at the first non-replaced
+ // instruction of the original function.
+ // o Replace the original first instructions with the jump relative.
+ //
+ // Note that on i386, we do not support someone else changing the code under our feet
+ if ( !err ) {
+ if( reentryIsland )
+ err = setBranchIslandTarget_i386( reentryIsland,
+ (void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions );
+ if ( !err )
+ atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelativeInstruction);
+ }
+#endif
+
+ // Clean up on error.
+ if( err ) {
+ if( reentryIsland )
+ freeBranchIsland( reentryIsland );
+ if( escapeIsland )
+ freeBranchIsland( escapeIsland );
+ }
+
+#if defined(__x86_64__)
+ err = makeIslandExecutable(escapeIsland);
+ err = makeIslandExecutable(reentryIsland);
+#endif
+
+ return err;
+}
+
+/*******************************************************************************
+*
+* Implementation
+*
+*******************************************************************************/
+#pragma mark -
+#pragma mark (Implementation)
+
+/***************************************************************************//**
+ Implementation: Allocates memory for a branch island.
+
+ @param island <- The allocated island.
+ @param allocateHigh -> Whether to allocate the island at the end of the
+ address space (for use with the branch absolute
+ instruction).
+ @result <- mach_error_t
+
+ ***************************************************************************/
+
+ mach_error_t
+allocateBranchIsland(
+ BranchIsland **island,
+ int allocateHigh,
+ void *originalFunctionAddress)
+{
+ assert( island );
+
+ mach_error_t err = err_none;
+
+ if( allocateHigh ) {
+ vm_size_t pageSize;
+ err = host_page_size( mach_host_self(), &pageSize );
+ if( !err ) {
+ assert( sizeof( BranchIsland ) <= pageSize );
+#if defined(__x86_64__)
+ 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?
+ vm_address_t last = 0x0;
+#else
+ vm_address_t first = 0xfeffffff;
+ vm_address_t last = 0xfe000000 + pageSize;
+#endif
+
+ vm_address_t page = first;
+ int allocated = 0;
+ vm_map_t task_self = mach_task_self();
+
+ while( !err && !allocated && page != last ) {
+
+ err = vm_allocate( task_self, &page, pageSize, 0 );
+ if( err == err_none )
+ allocated = 1;
+ else if( err == KERN_NO_SPACE ) {
+#if defined(__x86_64__)
+ page -= pageSize;
+#else
+ page += pageSize;
+#endif
+ err = err_none;
+ }
+ }
+ if( allocated )
+ *island = (void*) page;
+ else if( !allocated && !err )
+ err = KERN_NO_SPACE;
+ }
+ } else {
+ void *block = malloc( sizeof( BranchIsland ) );
+ if( block )
+ *island = block;
+ else
+ err = KERN_NO_SPACE;
+ }
+ if( !err )
+ (**island).allocatedHigh = allocateHigh;
+
+ return err;
+}
+
+/***************************************************************************//**
+ Implementation: Deallocates memory for a branch island.
+
+ @param island -> The island to deallocate.
+ @result <- mach_error_t
+
+ ***************************************************************************/
+
+ mach_error_t
+freeBranchIsland(
+ BranchIsland *island )
+{
+ assert( island );
+ assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] );
+ assert( island->allocatedHigh );
+
+ mach_error_t err = err_none;
+
+ if( island->allocatedHigh ) {
+ vm_size_t pageSize;
+ err = host_page_size( mach_host_self(), &pageSize );
+ if( !err ) {
+ assert( sizeof( BranchIsland ) <= pageSize );
+ err = vm_deallocate(
+ mach_task_self(),
+ (vm_address_t) island, pageSize );
+ }
+ } else {
+ free( island );
+ }
+
+ return err;
+}
+
+/***************************************************************************//**
+ Implementation: Sets the branch island's target, with an optional
+ instruction.
+
+ @param island -> The branch island to insert target into.
+ @param branchTo -> The address of the target.
+ @param instruction -> Optional instruction to execute prior to branch. Set
+ to zero for nop.
+ @result <- mach_error_t
+
+ ***************************************************************************/
+#if defined(__ppc__) || defined(__POWERPC__)
+ mach_error_t
+setBranchIslandTarget(
+ BranchIsland *island,
+ const void *branchTo,
+ long instruction )
+{
+ // Copy over the template code.
+ bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
+
+ // Fill in the address.
+ ((short*)island->instructions)[kAddressLo] = ((long) branchTo) & 0x0000FFFF;
+ ((short*)island->instructions)[kAddressHi]
+ = (((long) branchTo) >> 16) & 0x0000FFFF;
+
+ // Fill in the (optional) instuction.
+ if( instruction != 0 ) {
+ ((short*)island->instructions)[kInstructionLo]
+ = instruction & 0x0000FFFF;
+ ((short*)island->instructions)[kInstructionHi]
+ = (instruction >> 16) & 0x0000FFFF;
+ }
+
+ //MakeDataExecutable( island->instructions, sizeof( kIslandTemplate ) );
+ msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
+
+ return err_none;
+}
+#endif
+
+#if defined(__i386__)
+ mach_error_t
+setBranchIslandTarget_i386(
+ BranchIsland *island,
+ const void *branchTo,
+ char* instructions )
+{
+
+ // Copy over the template code.
+ bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
+
+ // copy original instructions
+ if (instructions) {
+ bcopy (instructions, island->instructions + kInstructions, kOriginalInstructionsSize);
+ }
+
+ // Fill in the address.
+ int32_t addressOffset = (char *)branchTo - (island->instructions + kJumpAddress + 4);
+ *((int32_t *)(island->instructions + kJumpAddress)) = addressOffset;
+
+ msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
+ return err_none;
+}
+
+#elif defined(__x86_64__)
+mach_error_t
+setBranchIslandTarget_i386(
+ BranchIsland *island,
+ const void *branchTo,
+ char* instructions )
+{
+ // Copy over the template code.
+ bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
+
+ // Copy original instructions.
+ if (instructions) {
+ bcopy (instructions, island->instructions, kOriginalInstructionsSize);
+ }
+
+ // Fill in the address.
+ *((uint64_t *)(island->instructions + kJumpAddress)) = (uint64_t)branchTo;
+ msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
+
+ return err_none;
+}
+#endif
+
+
+#if defined(__i386__) || defined(__x86_64__)
+// simplistic instruction matching
+typedef struct {
+ unsigned int length; // max 15
+ unsigned char mask[15]; // sequence of bytes in memory order
+ unsigned char constraint[15]; // sequence of bytes in memory order
+} AsmInstructionMatch;
+
+#if defined(__i386__)
+static AsmInstructionMatch possibleInstructions[] = {
+ { 0x1, {0xFF}, {0x90} }, // nop
+ { 0x1, {0xFF}, {0x55} }, // push %esp
+ { 0x2, {0xFF, 0xFF}, {0x89, 0xE5} }, // mov %esp,%ebp
+ { 0x1, {0xFF}, {0x53} }, // push %ebx
+ { 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} }, // sub 0x??, %esp
+ { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x00, 0x00} }, // sub 0x??, %esp with 32bit immediate
+ { 0x1, {0xFF}, {0x57} }, // push %edi
+ { 0x1, {0xFF}, {0x56} }, // push %esi
+ { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} }, // xor %eax, %eax
+ { 0x0 }
+};
+#elif defined(__x86_64__)
+static AsmInstructionMatch possibleInstructions[] = {
+ { 0x1, {0xFF}, {0x90} }, // nop
+ { 0x1, {0xF8}, {0x50} }, // push %rX
+ { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} }, // mov %rsp,%rbp
+ { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} }, // sub 0x??, %rsp
+ { 0x4, {0xFB, 0xFF, 0x00, 0x00}, {0x48, 0x89, 0x00, 0x00} }, // move onto rbp
+ { 0x2, {0xFF, 0x00}, {0x41, 0x00} }, // push %rXX
+ { 0x2, {0xFF, 0x00}, {0x85, 0x00} }, // test %rX,%rX
+ { 0x0 }
+};
+#endif
+
+static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch* instruction)
+{
+ Boolean match = true;
+
+ size_t i;
+ for (i=0; i<instruction->length; i++) {
+ unsigned char mask = instruction->mask[i];
+ unsigned char constraint = instruction->constraint[i];
+ unsigned char codeValue = code[i];
+
+ match = ((codeValue & mask) == constraint);
+ if (!match) break;
+ }
+
+ return match;
+}
+
+#if defined(__i386__) || defined(__x86_64__)
+ static Boolean
+eatKnownInstructions(
+ unsigned char *code,
+ uint64_t* newInstruction,
+ int* howManyEaten,
+ char* originalInstructions )
+{
+ Boolean allInstructionsKnown = true;
+ int totalEaten = 0;
+ unsigned char* ptr = code;
+ int remainsToEat = 5; // a JMP instruction takes 5 bytes
+
+ if (howManyEaten) *howManyEaten = 0;
+ while (remainsToEat > 0) {
+ Boolean curInstructionKnown = false;
+
+ // See if instruction matches one we know
+ AsmInstructionMatch* curInstr = possibleInstructions;
+ do {
+ if ((curInstructionKnown = codeMatchesInstruction(ptr, curInstr))) break;
+ curInstr++;
+ } while (curInstr->length > 0);
+
+ // if all instruction matches failed, we don't know current instruction then, stop here
+ if (!curInstructionKnown) {
+ allInstructionsKnown = false;
+ break;
+ }
+
+ // At this point, we've matched curInstr
+ int eaten = curInstr->length;
+ ptr += eaten;
+ remainsToEat -= eaten;
+ totalEaten += eaten;
+ }
+
+
+ if (howManyEaten) *howManyEaten = totalEaten;
+
+ if (originalInstructions) {
+ Boolean enoughSpaceForOriginalInstructions = (totalEaten < kOriginalInstructionsSize);
+
+ if (enoughSpaceForOriginalInstructions) {
+ memset(originalInstructions, 0x90 /* NOP */, kOriginalInstructionsSize); // fill instructions with NOP
+ bcopy(code, originalInstructions, totalEaten);
+ } else {
+ // printf ("Not enough space in island to store original instructions. Adapt the island definition and kOriginalInstructionsSize\n");
+ return false;
+ }
+ }
+
+ if (allInstructionsKnown) {
+ // save last 3 bytes of first 64bits of codre we'll replace
+ uint64_t currentFirst64BitsOfCode = *((uint64_t *)code);
+ currentFirst64BitsOfCode = OSSwapInt64(currentFirst64BitsOfCode); // back to memory representation
+ currentFirst64BitsOfCode &= 0x0000000000FFFFFFLL;
+
+ // keep only last 3 instructions bytes, first 5 will be replaced by JMP instr
+ *newInstruction &= 0xFFFFFFFFFF000000LL; // clear last 3 bytes
+ *newInstruction |= (currentFirst64BitsOfCode & 0x0000000000FFFFFFLL); // set last 3 bytes
+ }
+
+ return allInstructionsKnown;
+}
+#endif
+
+#if defined(__i386__)
+__asm(
+ ".text;"
+ ".align 2, 0x90;"
+ "_atomic_mov64:;"
+ " pushl %ebp;"
+ " movl %esp, %ebp;"
+ " pushl %esi;"
+ " pushl %ebx;"
+ " pushl %ecx;"
+ " pushl %eax;"
+ " pushl %edx;"
+
+ // atomic push of value to an address
+ // we use cmpxchg8b, which compares content of an address with
+ // edx:eax. If they are equal, it atomically puts 64bit value
+ // ecx:ebx in address.
+ // We thus put contents of address in edx:eax to force ecx:ebx
+ // in address
+ " mov 8(%ebp), %esi;" // esi contains target address
+ " mov 12(%ebp), %ebx;"
+ " mov 16(%ebp), %ecx;" // ecx:ebx now contains value to put in target address
+ " mov (%esi), %eax;"
+ " mov 4(%esi), %edx;" // edx:eax now contains value currently contained in target address
+ " lock; cmpxchg8b (%esi);" // atomic move.
+
+ // restore registers
+ " popl %edx;"
+ " popl %eax;"
+ " popl %ecx;"
+ " popl %ebx;"
+ " popl %esi;"
+ " popl %ebp;"
+ " ret"
+);
+#elif defined(__x86_64__)
+void atomic_mov64(
+ uint64_t *targetAddress,
+ uint64_t value )
+{
+ *targetAddress = value;
+}
+#endif
+#endif
diff --git a/third_party/mach_override/mach_override.gyp b/third_party/mach_override/mach_override.gyp
new file mode 100644
index 0000000..3dbb1d1
--- /dev/null
+++ b/third_party/mach_override/mach_override.gyp
@@ -0,0 +1,28 @@
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ ],
+ 'conditions': [
+ ['OS=="mac"', {
+ 'targets' : [
+ {
+ 'target_name' : 'mach_override',
+ 'type': '<(library)',
+ 'sources': [
+ 'mach_override.c',
+ 'mach_override.h',
+ ],
+ },
+ ],
+ }],
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/third_party/mach_override/mach_override.h b/third_party/mach_override/mach_override.h
new file mode 100644
index 0000000..76fdb1b
--- /dev/null
+++ b/third_party/mach_override/mach_override.h
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ mach_override.h
+ Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
+ Some rights reserved: <http://opensource.org/licenses/mit-license.php>
+
+ ***************************************************************************/
+
+/***************************************************************************//**
+ @mainpage mach_override
+ @author Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
+
+ This package, coded in C to the Mach API, allows you to override ("patch")
+ program- and system-supplied functions at runtime. You can fully replace
+ functions with your implementations, or merely head- or tail-patch the
+ original implementations.
+
+ Use it by #include'ing mach_override.h from your .c, .m or .mm file(s).
+
+ @todo Discontinue use of Carbon's MakeDataExecutable() and
+ CompareAndSwap() calls and start using the Mach equivalents, if they
+ exist. If they don't, write them and roll them in. That way, this
+ code will be pure Mach, which will make it easier to use everywhere.
+ Update: MakeDataExecutable() has been replaced by
+ msync(MS_INVALIDATE). There is an OSCompareAndSwap in libkern, but
+ I'm currently unsure if I can link against it. May have to roll in
+ my own version...
+ @todo Stop using an entire 4K high-allocated VM page per 28-byte escape
+ branch island. Done right, this will dramatically speed up escape
+ island allocations when they number over 250. Then again, if you're
+ overriding more than 250 functions, maybe speed isn't your main
+ concern...
+ @todo Add detection of: b, bl, bla, bc, bcl, bcla, bcctrl, bclrl
+ first-instructions. Initially, we should refuse to override
+ functions beginning with these instructions. Eventually, we should
+ dynamically rewrite them to make them position-independent.
+ @todo Write mach_unoverride(), which would remove an override placed on a
+ function. Must be multiple-override aware, which means an almost
+ complete rewrite under the covers, because the target address can't
+ be spread across two load instructions like it is now since it will
+ need to be atomically updatable.
+ @todo Add non-rentry variants of overrides to test_mach_override.
+
+ ***************************************************************************/
+
+#ifndef _mach_override_
+#define _mach_override_
+
+#include <sys/types.h>
+#include <mach/error.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/**
+ Returned if the function to be overrided begins with a 'mfctr' instruction.
+*/
+#define err_cannot_override (err_local|1)
+
+/************************************************************************************//**
+ Dynamically overrides the function implementation referenced by
+ originalFunctionAddress with the implentation pointed to by overrideFunctionAddress.
+ Optionally returns a pointer to a "reentry island" which, if jumped to, will resume
+ the original implementation.
+
+ @param originalFunctionAddress -> Required address of the function to
+ override (with overrideFunctionAddress).
+ @param overrideFunctionAddress -> Required address to the overriding
+ function.
+ @param originalFunctionReentryIsland <- Optional pointer to pointer to the
+ reentry island. Can be NULL.
+ @result <- err_cannot_override if the original
+ function's implementation begins with
+ the 'mfctr' instruction.
+
+ ************************************************************************************/
+
+ mach_error_t
+mach_override_ptr(
+ void *originalFunctionAddress,
+ const void *overrideFunctionAddress,
+ void **originalFunctionReentryIsland );
+
+/************************************************************************************//**
+
+
+ ************************************************************************************/
+
+#ifdef __cplusplus
+
+#define MACH_OVERRIDE( ORIGINAL_FUNCTION_RETURN_TYPE, ORIGINAL_FUNCTION_NAME, ORIGINAL_FUNCTION_ARGS, ERR ) \
+ { \
+ static ORIGINAL_FUNCTION_RETURN_TYPE (*ORIGINAL_FUNCTION_NAME##_reenter)ORIGINAL_FUNCTION_ARGS; \
+ static bool ORIGINAL_FUNCTION_NAME##_overriden = false; \
+ class mach_override_class__##ORIGINAL_FUNCTION_NAME { \
+ public: \
+ static kern_return_t override(void *originalFunctionPtr) { \
+ kern_return_t result = err_none; \
+ if (!ORIGINAL_FUNCTION_NAME##_overriden) { \
+ ORIGINAL_FUNCTION_NAME##_overriden = true; \
+ result = mach_override_ptr( (void*)originalFunctionPtr, \
+ (void*)mach_override_class__##ORIGINAL_FUNCTION_NAME::replacement, \
+ (void**)&ORIGINAL_FUNCTION_NAME##_reenter ); \
+ } \
+ return result; \
+ } \
+ static ORIGINAL_FUNCTION_RETURN_TYPE replacement ORIGINAL_FUNCTION_ARGS {
+
+#define END_MACH_OVERRIDE( ORIGINAL_FUNCTION_NAME ) \
+ } \
+ }; \
+ \
+ err = mach_override_class__##ORIGINAL_FUNCTION_NAME::override((void*)ORIGINAL_FUNCTION_NAME); \
+ }
+
+#endif
+
+#ifdef __cplusplus
+ }
+#endif
+#endif // _mach_override_