]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[libsanitizer] add mach_override and enable libsanitizer on darwin
authorJack Howarth <howarth@bromo.med.uc.edu>
Sat, 24 Nov 2012 18:24:13 +0000 (18:24 +0000)
committerKostya Serebryany <kcc@gcc.gnu.org>
Sat, 24 Nov 2012 18:24:13 +0000 (18:24 +0000)
From-SVN: r193781

gcc/ChangeLog
gcc/config/darwin.h
libsanitizer/ChangeLog
libsanitizer/configure
libsanitizer/configure.ac
libsanitizer/configure.tgt
libsanitizer/interception/Makefile.am
libsanitizer/interception/Makefile.in
libsanitizer/interception/mach_override/LICENSE.txt [new file with mode: 0644]
libsanitizer/interception/mach_override/mach_override.c [new file with mode: 0644]
libsanitizer/interception/mach_override/mach_override.h [new file with mode: 0644]

index ea18d43c2403c4cc3f31c8756c06fa26ab6c36b4..3bcbf790ed4c01459ca9c190ce63c6a70a22ef0f 100644 (file)
@@ -1,3 +1,7 @@
+2012-11-24  Jack Howarth <howarth@bromo.med.uc.edu>
+
+       * config/darwin.h (LINK_COMMAND_SPEC_A): Deal with -fsanitize=address.
+
 2012-11-24  Matthias Klose  <doko@ubuntu.com>
 
        * configure.ac (multiarch): Use $enableval instead of $withval.
index 2b1a4268e3d6f7b51f1709185c429d5a360e6ab5..0eb3474ecdd714b34b4b70b1433cb92584fc9bde 100644 (file)
@@ -180,6 +180,9 @@ extern GTY(()) int darwin_ms_struct;
     %{L*} %(link_libgcc) %o %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} \
     %{fopenmp|ftree-parallelize-loops=*: \
       %{static|static-libgcc|static-libstdc++|static-libgfortran: libgomp.a%s; : -lgomp } } \
+    %{fsanitize=address: \
+      %{static|static-libasan|static-libgcc|static-libgfortran: -framework CoreFoundation -lstdc++ libasan.a%s; \
+      static-libstdc++: -framework CoreFoundation libstdc++.a%s libasan.a%s; : -framework CoreFoundation -lasan } } \
     %{fgnu-tm: \
       %{static|static-libgcc|static-libstdc++|static-libgfortran: libitm.a%s; : -litm } } \
     %{!nostdlib:%{!nodefaultlibs:\
index 2c7c289a70286d6b6f425041efa06a5a913e13b8..90053021bd5358936d9d8b64ab0166fdd4d0dc01 100644 (file)
@@ -1,3 +1,16 @@
+2012-11-24  Kostya Serebryany kcc@google.com
+           Jack Howarth <howarth@bromo.med.uc.edu>
+
+       * interception/mach_override/mach_override.c: Migrate from llvm.
+       * interception/mach_override/mach_override.h: Likewise.
+       * interception/mach_override/LICENSE.txt: Likewise.
+       * configure.tgt: Add darwin to supported targets.
+       * configure.ac: Define USING_MACH_OVERRIDE when on darwin.
+       * interception/Makefile.am: Compile mach_override.c when
+       USING_MACH_OVERRIDE defined.
+       * configure: Regenerated.
+       * interception/Makefile.in: Likewise.
+
 2012-11-23  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR sanitizer/55450
index 198a94d32724b19148c41fbdae69bc0434adc026..48f984c7bbbb493f5dd5bf99757c191f83601e64 100755 (executable)
@@ -604,6 +604,8 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+USING_MACH_OVERRIDE_FALSE
+USING_MACH_OVERRIDE_TRUE
 TSAN_SUPPORTED_FALSE
 TSAN_SUPPORTED_TRUE
 enable_static
@@ -11078,7 +11080,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11081 "configure"
+#line 11083 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11184,7 +11186,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11187 "configure"
+#line 11189 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -14494,6 +14496,19 @@ else
 fi
 
 
+case "$host" in
+  *-*-darwin*) MACH_OVERRIDE=true ;;
+  *) MACH_OVERRIDE=false ;;
+esac
+ if $MACH_OVERRIDE; then
+  USING_MACH_OVERRIDE_TRUE=
+  USING_MACH_OVERRIDE_FALSE='#'
+else
+  USING_MACH_OVERRIDE_TRUE='#'
+  USING_MACH_OVERRIDE_FALSE=
+fi
+
+
 ac_config_files="$ac_config_files Makefile"
 
 
@@ -14670,6 +14685,10 @@ if test -z "${TSAN_SUPPORTED_TRUE}" && test -z "${TSAN_SUPPORTED_FALSE}"; then
   as_fn_error "conditional \"TSAN_SUPPORTED\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${USING_MACH_OVERRIDE_TRUE}" && test -z "${USING_MACH_OVERRIDE_FALSE}"; then
+  as_fn_error "conditional \"USING_MACH_OVERRIDE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 
 : ${CONFIG_STATUS=./config.status}
 ac_write_fail=0
index 45183db609fe64ef7204f513a362f9c7c14d1e3b..2d62ec4ecc0eb6b31938247037bd6f3e89183a28 100644 (file)
@@ -80,6 +80,12 @@ unset TSAN_SUPPORTED
 . ${srcdir}/configure.tgt
 AM_CONDITIONAL(TSAN_SUPPORTED, [test "x$TSAN_SUPPORTED" = "xyes"])
 
+case "$host" in
+  *-*-darwin*) MACH_OVERRIDE=true ;;
+  *) MACH_OVERRIDE=false ;;
+esac
+AM_CONDITIONAL(USING_MACH_OVERRIDE, $MACH_OVERRIDE)
+
 AC_CONFIG_FILES([Makefile])
 
 AC_CONFIG_FILES(AC_FOREACH([DIR], [interception sanitizer_common asan], [DIR/Makefile ]),
index 1506a20dab151e7b2fc5c7d84d66009793c7a5f1..26335391c4a39b1b50c81a3de213e043d534a94a 100644 (file)
@@ -27,6 +27,9 @@ case "${target}" in
        ;;
   sparc*-*-linux*)
        ;;
+  x86_64-*-darwin* | i?86-*-darwin*)
+       TSAN_SUPPORTED=no
+       ;;
   *)
        UNSUPPORTED=1
        ;;
index b92a18033f022c983f7a5aa4fe3ab21afd571095..029417f46e517f326b6682cf43dbcbac858829b3 100644 (file)
@@ -14,7 +14,11 @@ interception_files = \
         interception_mac.cc \
         interception_win.cc
 
-libinterception_la_SOURCES = $(interception_files) 
+if USING_MACH_OVERRIDE
+libinterception_la_SOURCES = $(interception_files) mach_override/mach_override.c
+else
+libinterception_la_SOURCES = $(interception_files)
+endif
 
 # Work around what appears to be a GNU make bug handling MAKEFLAGS
 # values defined in terms of make variables, as is the case for CC and
index b32e86ecdf25824c0d7edeb3f2150dfb2be221b1..bd58c4d47a069e943e18385233873f3c17820b6f 100644 (file)
@@ -53,14 +53,29 @@ CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 libinterception_la_LIBADD =
+am__libinterception_la_SOURCES_DIST = interception_linux.cc \
+       interception_mac.cc interception_win.cc \
+       mach_override/mach_override.c
 am__objects_1 = interception_linux.lo interception_mac.lo \
        interception_win.lo
-am_libinterception_la_OBJECTS = $(am__objects_1)
+@USING_MACH_OVERRIDE_FALSE@am_libinterception_la_OBJECTS =  \
+@USING_MACH_OVERRIDE_FALSE@    $(am__objects_1)
+@USING_MACH_OVERRIDE_TRUE@am_libinterception_la_OBJECTS =  \
+@USING_MACH_OVERRIDE_TRUE@     $(am__objects_1) mach_override.lo
 libinterception_la_OBJECTS = $(am_libinterception_la_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@
 depcomp = $(SHELL) $(top_srcdir)/../depcomp
 am__depfiles_maybe = depfiles
 am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+       $(LDFLAGS) -o $@
 CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
        $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
 LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
@@ -71,7 +86,7 @@ CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
        --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
        $(LDFLAGS) -o $@
 SOURCES = $(libinterception_la_SOURCES)
-DIST_SOURCES = $(libinterception_la_SOURCES)
+DIST_SOURCES = $(am__libinterception_la_SOURCES_DIST)
 ETAGS = etags
 CTAGS = ctags
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -215,7 +230,8 @@ interception_files = \
         interception_mac.cc \
         interception_win.cc
 
-libinterception_la_SOURCES = $(interception_files) 
+@USING_MACH_OVERRIDE_FALSE@libinterception_la_SOURCES = $(interception_files)
+@USING_MACH_OVERRIDE_TRUE@libinterception_la_SOURCES = $(interception_files) mach_override/mach_override.c
 
 # Work around what appears to be a GNU make bug handling MAKEFLAGS
 # values defined in terms of make variables, as is the case for CC and
@@ -261,7 +277,7 @@ MAKEOVERRIDES =
 all: all-am
 
 .SUFFIXES:
-.SUFFIXES: .cc .lo .o .obj
+.SUFFIXES: .c .cc .lo .o .obj
 $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
        @for dep in $?; do \
          case '$(am__configure_deps)' in \
@@ -313,6 +329,35 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_linux.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_mac.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_win.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mach_override.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LTCOMPILE) -c -o $@ $<
+
+mach_override.lo: mach_override/mach_override.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mach_override.lo -MD -MP -MF $(DEPDIR)/mach_override.Tpo -c -o mach_override.lo `test -f 'mach_override/mach_override.c' || echo '$(srcdir)/'`mach_override/mach_override.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/mach_override.Tpo $(DEPDIR)/mach_override.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='mach_override/mach_override.c' object='mach_override.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mach_override.lo `test -f 'mach_override/mach_override.c' || echo '$(srcdir)/'`mach_override/mach_override.c
 
 .cc.o:
 @am__fastdepCXX_TRUE@  $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
diff --git a/libsanitizer/interception/mach_override/LICENSE.txt b/libsanitizer/interception/mach_override/LICENSE.txt
new file mode 100644 (file)
index 0000000..9446965
--- /dev/null
@@ -0,0 +1,3 @@
+Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
+Some rights reserved: <http://opensource.org/licenses/mit-license.php>
+
diff --git a/libsanitizer/interception/mach_override/mach_override.c b/libsanitizer/interception/mach_override/mach_override.c
new file mode 100644 (file)
index 0000000..7511a7b
--- /dev/null
@@ -0,0 +1,970 @@
+/*******************************************************************************
+       mach_override.c
+               Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
+               Some rights reserved: <http://opensource.org/licenses/mit-license.php>
+
+       ***************************************************************************/
+#ifdef __APPLE__
+
+#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>
+
+//#define DEBUG_DISASM 1
+#undef DEBUG_DISASM
+
+/**************************
+*      
+*      Constants
+*      
+**************************/
+#pragma mark   -
+#pragma mark   (Constants)
+
+#if defined(__ppc__) || defined(__POWERPC__)
+
+static
+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
+
+static
+unsigned 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
+
+static
+unsigned 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)
+
+
+       static mach_error_t
+allocateBranchIsland(
+               BranchIsland    **island,
+               int                             allocateHigh,
+               void *originalFunctionAddress);
+
+       static mach_error_t
+freeBranchIsland(
+               BranchIsland    *island );
+
+       static mach_error_t
+defaultIslandMalloc(
+         void **ptr, size_t unused_size, void *hint);
+
+       static mach_error_t
+defaultIslandFree(
+       void *ptr);
+
+#if defined(__ppc__) || defined(__POWERPC__)
+       static mach_error_t
+setBranchIslandTarget(
+               BranchIsland    *island,
+               const void              *branchTo,
+               long                    instruction );
+#endif 
+
+#if defined(__i386__) || defined(__x86_64__)
+static mach_error_t
+setBranchIslandTarget_i386(
+                                                  BranchIsland *island,
+                                                  const void           *branchTo,
+                                                  char*                        instructions );
+// Can't be made static because there's no C implementation for atomic_mov64
+// on i386.
+void 
+atomic_mov64(
+               uint64_t *targetAddress,
+               uint64_t value ) __attribute__((visibility("hidden")));
+
+       static Boolean 
+eatKnownInstructions( 
+       unsigned char   *code, 
+       uint64_t                *newInstruction,
+       int                             *howManyEaten, 
+       char                    *originalInstructions,
+       int                             *originalInstructionCount, 
+       uint8_t                 *originalInstructionSizes );
+
+       static void
+fixupInstructions(
+    void               *originalFunction,
+    void               *escapeIsland,
+    void               *instructionsToFix,
+       int                     instructionCount,
+       uint8_t         *instructionSizes );
+
+#ifdef DEBUG_DISASM
+       static void
+dump16Bytes(
+       void    *ptr);
+#endif  // DEBUG_DISASM
+#endif
+
+/*******************************************************************************
+*      
+*      Interface
+*      
+*******************************************************************************/
+#pragma mark   -
+#pragma mark   (Interface)
+
+#if defined(__i386__) || defined(__x86_64__)
+static mach_error_t makeIslandExecutable(void *address) {
+       mach_error_t err = err_none;
+    vm_size_t pageSize;
+    host_page_size( mach_host_self(), &pageSize );
+    uintptr_t page = (uintptr_t)address & ~(uintptr_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
+
+               static mach_error_t
+defaultIslandMalloc(
+       void **ptr, size_t unused_size, void *hint) {
+  return allocateBranchIsland( (BranchIsland**)ptr, kAllocateHigh, hint );
+}
+               static mach_error_t
+defaultIslandFree(
+       void *ptr) {
+       return freeBranchIsland(ptr);
+}
+
+    mach_error_t
+__asan_mach_override_ptr(
+       void *originalFunctionAddress,
+    const void *overrideFunctionAddress,
+    void **originalFunctionReentryIsland )
+{
+  return __asan_mach_override_ptr_custom(originalFunctionAddress,
+               overrideFunctionAddress,
+               originalFunctionReentryIsland,
+               defaultIslandMalloc,
+               defaultIslandFree);
+}
+
+    mach_error_t
+__asan_mach_override_ptr_custom(
+       void *originalFunctionAddress,
+    const void *overrideFunctionAddress,
+    void **originalFunctionReentryIsland,
+               island_malloc *alloc,
+               island_free *dealloc)
+{
+       assert( originalFunctionAddress );
+       assert( overrideFunctionAddress );
+       
+       // this addresses overriding such functions as AudioOutputUnitStart()
+       // test with modified DefaultOutputUnit project
+#if defined(__x86_64__)
+    for(;;){
+        if(*(uint16_t*)originalFunctionAddress==0x25FF)    // jmp qword near [rip+0x????????]
+            originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*(int32_t *)((uint16_t*)originalFunctionAddress+1));
+        else break;
+    }
+#elif defined(__i386__)
+    for(;;){
+        if(*(uint16_t*)originalFunctionAddress==0x25FF)    // jmp *0x????????
+            originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1);
+        else break;
+    }
+#endif
+#ifdef DEBUG_DISASM
+  {
+    fprintf(stderr, "Replacing function at %p\n", originalFunctionAddress);
+    fprintf(stderr, "First 16 bytes of the function: ");
+    unsigned char *orig = (unsigned char *)originalFunctionAddress;
+    int i;
+    for (i = 0; i < 16; i++) {
+       fprintf(stderr, "%x ", (unsigned int) orig[i]);
+    }
+    fprintf(stderr, "\n");
+    fprintf(stderr, 
+            "To disassemble, save the following function as disas.c"
+            " and run:\n  gcc -c disas.c && gobjdump -d disas.o\n"
+            "The first 16 bytes of the original function will start"
+            " after four nop instructions.\n");
+    fprintf(stderr, "\nvoid foo() {\n  asm volatile(\"nop;nop;nop;nop;\");\n");
+    int j = 0;
+    for (j = 0; j < 2; j++) {
+      fprintf(stderr, "  asm volatile(\".byte ");
+      for (i = 8 * j; i < 8 * (j+1) - 1; i++) {
+        fprintf(stderr, "0x%x, ", (unsigned int) orig[i]);
+      }
+      fprintf(stderr, "0x%x;\");\n", (unsigned int) orig[8 * (j+1) - 1]);
+    }
+    fprintf(stderr, "}\n\n");
+  }
+#endif
+
+       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;
+       int originalInstructionCount = 0;
+       char originalInstructions[kOriginalInstructionsSize];
+       uint8_t originalInstructionSizes[kOriginalInstructionsSize];
+       uint64_t jumpRelativeInstruction = 0; // JMP
+
+       Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr, 
+                                                                               &jumpRelativeInstruction, &eatenCount, 
+                                                                               originalInstructions, &originalInstructionCount, 
+                                                                               originalInstructionSizes );
+#ifdef DEBUG_DISASM
+  if (!overridePossible) fprintf(stderr, "overridePossible = false @%d\n", __LINE__);
+#endif
+       if (eatenCount > kOriginalInstructionsSize) {
+#ifdef DEBUG_DISASM
+               fprintf(stderr, "Too many instructions eaten\n");
+#endif    
+               overridePossible = false;
+       }
+       if (!overridePossible) err = err_cannot_override;
+       if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
+#endif
+       
+       //      Make the original function implementation writable.
+       if( !err ) {
+               err = vm_protect( mach_task_self(),
+                               (vm_address_t) originalFunctionPtr, 8, false,
+                               (VM_PROT_ALL | VM_PROT_COPY) );
+               if( err )
+                       err = vm_protect( mach_task_self(),
+                                       (vm_address_t) originalFunctionPtr, 8, false,
+                                       (VM_PROT_DEFAULT | VM_PROT_COPY) );
+       }
+       if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
+       
+       //      Allocate and target the escape island to the overriding function.
+       BranchIsland    *escapeIsland = NULL;
+       if( !err )
+               err = alloc( (void**)&escapeIsland, sizeof(BranchIsland), originalFunctionAddress );
+       if ( err ) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __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) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
+
+       if( !err )
+               err = setBranchIslandTarget_i386( escapeIsland, overrideFunctionAddress, 0 );
+       if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
+       // Build the jump relative instruction to the escape island
+#endif
+
+
+#if defined(__i386__) || defined(__x86_64__)
+       if (!err) {
+               uint32_t addressOffset = ((char*)escapeIsland - (char*)originalFunctionPtr - 5);
+               addressOffset = OSSwapInt32(addressOffset);
+               
+               jumpRelativeInstruction |= 0xE900000000000000LL; 
+               jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff) << 24;
+               jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);         
+       }
+#endif
+       
+       //      Optionally allocate & return the reentry island. This may contain relocated
+       //  jmp instructions and so has all the same addressing reachability requirements
+       //  the escape island has to the original function, except the escape island is
+       //  technically our original function.
+       BranchIsland    *reentryIsland = NULL;
+       if( !err && originalFunctionReentryIsland ) {
+               err = alloc( (void**)&reentryIsland, sizeof(BranchIsland), escapeIsland);
+               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 ) {
+               fixupInstructions(originalFunctionPtr, reentryIsland, originalInstructions,
+                                       originalInstructionCount, originalInstructionSizes );
+       
+               if( reentryIsland )
+                       err = setBranchIslandTarget_i386( reentryIsland,
+                                                                                (void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions );
+               // try making islands executable before planting the jmp
+#if defined(__x86_64__) || defined(__i386__)
+        if( !err )
+            err = makeIslandExecutable(escapeIsland);
+        if( !err && reentryIsland )
+            err = makeIslandExecutable(reentryIsland);
+#endif
+               if ( !err )
+                       atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelativeInstruction);
+       }
+#endif
+       
+       //      Clean up on error.
+       if( err ) {
+               if( reentryIsland )
+                       dealloc( reentryIsland );
+               if( escapeIsland )
+                       dealloc( escapeIsland );
+       }
+
+#ifdef DEBUG_DISASM
+  {
+    fprintf(stderr, "First 16 bytes of the function after slicing: ");
+    unsigned char *orig = (unsigned char *)originalFunctionAddress;
+    int i;
+    for (i = 0; i < 16; i++) {
+       fprintf(stderr, "%x ", (unsigned int) orig[i]);
+    }
+    fprintf(stderr, "\n");
+  }
+#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
+
+       ***************************************************************************/
+
+       static 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(__ppc__) || defined(__POWERPC__)
+                       vm_address_t first = 0xfeffffff;
+                       vm_address_t last = 0xfe000000 + pageSize;
+#elif 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 = 0xffc00000;
+                       vm_address_t last = 0xfffe0000;
+#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 = (BranchIsland*) 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
+
+       ***************************************************************************/
+
+       static 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__)
+       static 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__)
+       static 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__)
+static 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[] = {
+       { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} },        // jmp 0x????????
+       { 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} },        // push %esp; mov %esp,%ebp; leave; ret
+       { 0x1, {0xFF}, {0x90} },                                                        // nop
+       { 0x1, {0xF8}, {0x50} },                                                        // push %reg
+       { 0x2, {0xFF, 0xFF}, {0x89, 0xE5} },                                            // mov %esp,%ebp
+       { 0x3, {0xFF, 0xFF, 0xFF}, {0x89, 0x1C, 0x24} },                                                // mov %ebx,(%esp)
+       { 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
+       { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },                                            // xor %eax, %eax
+       { 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} },  // mov $imm(%ebp), %reg
+       { 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} },  // mov $imm(%eax-%edx), %reg
+       { 0x3, {0xFF, 0xCF, 0x00}, {0x8B, 0x4D, 0x00} },  // mov $imm(%rpb), %reg
+       { 0x3, {0xFF, 0x4F, 0x00}, {0x8A, 0x4D, 0x00} },  // mov $imm(%ebp), %cl
+       { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x8B, 0x4C, 0x24, 0x00} },                    // mov $imm(%esp), %ecx
+       { 0x4, {0xFF, 0x00, 0x00, 0x00}, {0x8B, 0x00, 0x00, 0x00} },                    // mov r16,r/m16 or r32,r/m32
+       { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB9, 0x00, 0x00, 0x00, 0x00} },        // mov $imm, %ecx
+       { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} },        // mov $imm, %eax
+       { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x66, 0x0F, 0xEF, 0x00} },                    // pxor xmm2/128, xmm1
+       { 0x2, {0xFF, 0xFF}, {0xDB, 0xE3} },                                            // fninit
+       { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE8, 0x00, 0x00, 0x00, 0x00} },        // call $imm
+       { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x0F, 0xBE, 0x55, 0x00} },                    // movsbl $imm(%ebp), %edx
+       { 0x0, {0x00}, {0x00} }
+};
+#elif defined(__x86_64__)
+// TODO(glider): disassembling the "0x48, 0x89" sequences is trickier than it's done below.
+// If it stops working, refer to http://ref.x86asm.net/geek.html#modrm_byte_32_64 to do it
+// more accurately.
+// Note: 0x48 is in fact the REX.W prefix, but it might be wrong to treat it as a separate
+// instruction.
+static AsmInstructionMatch possibleInstructions[] = {
+       { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} },        // jmp 0x????????
+       { 0x1, {0xFF}, {0x90} },                                                        // nop
+       { 0x1, {0xF8}, {0x50} },                                                        // push %rX
+       { 0x1, {0xFF}, {0x65} },                                                        // GS prefix
+       { 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, 0x07, 0x00}, {0x48, 0x89, 0x05, 0x00} },                    // move onto rbp
+       { 0x3, {0xFB, 0xFF, 0x00}, {0x48, 0x89, 0x00} },                                    // mov %reg, %reg
+       { 0x3, {0xFB, 0xFF, 0x00}, {0x49, 0x89, 0x00} },                                    // mov %reg, %reg (REX.WB)
+       { 0x2, {0xFF, 0x00}, {0x41, 0x00} },                                            // push %rXX
+       { 0x2, {0xFF, 0x00}, {0x84, 0x00} },                                            // test %rX8,%rX8
+       { 0x2, {0xFF, 0x00}, {0x85, 0x00} },                                            // test %rX,%rX
+       { 0x2, {0xFF, 0x00}, {0x77, 0x00} },                                            // ja $i8
+       { 0x2, {0xFF, 0x00}, {0x74, 0x00} },                                            // je $i8
+       { 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} },        // mov $imm, %reg
+       { 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} },                                // pushq $imm(%rdi)
+       { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },                                            // xor %eax, %eax
+       { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0x25, 0x00, 0x00, 0x00, 0x00} },        // and $imm, %eax
+       { 0x3, {0xFF, 0xFF, 0xFF}, {0x80, 0x3F, 0x00} },                                // cmpb $imm, (%rdi)
+
+  { 0x8, {0xFF, 0xFF, 0xCF, 0xFF, 0x00, 0x00, 0x00, 0x00},
+         {0x48, 0x8B, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00}, },                     // mov $imm, %{rax,rdx,rsp,rsi}
+  { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xFA, 0x00}, },   // cmp $i8, %rdx
+       { 0x4, {0xFF, 0xFF, 0x00, 0x00}, {0x83, 0x7f, 0x00, 0x00}, },                   // cmpl $imm, $imm(%rdi)
+       { 0xa, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               {0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },    // mov $imm, %rax
+        { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00},
+               {0x81, 0xE6, 0x00, 0x00, 0x00, 0x00} },                            // and $imm, %esi
+        { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00},
+               {0xFF, 0x25, 0x00, 0x00, 0x00, 0x00} },                            // jmpq *(%rip)
+        { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x66, 0x0F, 0xEF, 0x00} },              // pxor xmm2/128, xmm1
+        { 0x2, {0xFF, 0x00}, {0x89, 0x00} },                               // mov r/m32,r32 or r/m16,r16
+        { 0x3, {0xFF, 0xFF, 0xFF}, {0x49, 0x89, 0xF8} },                   // mov %rdi,%r8
+        { 0x4, {0xFF, 0xFF, 0xFF, 0xFF}, {0x40, 0x0F, 0xBE, 0xCE} },       // movsbl %sil,%ecx
+        { 0x7, {0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00},
+               {0x48, 0x8D, 0x05, 0x00, 0x00, 0x00, 0x00} },  // lea $imm(%rip),%rax
+        { 0x3, {0xFF, 0xFF, 0xFF}, {0x0F, 0xBE, 0xCE} },  // movsbl, %dh, %ecx
+        { 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} },  // pushq $imm(%rdi)
+        { 0x2, {0xFF, 0xFF}, {0xDB, 0xE3} }, // fninit
+        { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x85, 0xD2} },  // test %rdx,%rdx
+       { 0x0, {0x00}, {0x00} }
+};
+#endif
+
+static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch* instruction) 
+{
+       Boolean match = true;
+       
+       size_t i;
+  assert(instruction);
+#ifdef DEBUG_DISASM
+       fprintf(stderr, "Matching: ");
+#endif  
+       for (i=0; i<instruction->length; i++) {
+               unsigned char mask = instruction->mask[i];
+               unsigned char constraint = instruction->constraint[i];
+               unsigned char codeValue = code[i];
+#ifdef DEBUG_DISASM
+               fprintf(stderr, "%x ", (unsigned)codeValue);
+#endif    
+               match = ((codeValue & mask) == constraint);
+               if (!match) break;
+       }
+#ifdef DEBUG_DISASM
+       if (match) {
+               fprintf(stderr, " OK\n");
+       } else {
+               fprintf(stderr, " FAIL\n");
+       }
+#endif  
+       return match;
+}
+
+#if defined(__i386__) || defined(__x86_64__)
+       static Boolean 
+eatKnownInstructions( 
+       unsigned char   *code, 
+       uint64_t                *newInstruction,
+       int                             *howManyEaten, 
+       char                    *originalInstructions,
+       int                             *originalInstructionCount, 
+       uint8_t                 *originalInstructionSizes )
+{
+       Boolean allInstructionsKnown = true;
+       int totalEaten = 0;
+       unsigned char* ptr = code;
+       int remainsToEat = 5; // a JMP instruction takes 5 bytes
+       int instructionIndex = 0;
+       
+       if (howManyEaten) *howManyEaten = 0;
+       if (originalInstructionCount) *originalInstructionCount = 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;
+                       fprintf(stderr, "mach_override: some instructions unknown! Need to update mach_override.c\n");
+                       break;
+               }
+               
+               // At this point, we've matched curInstr
+               int eaten = curInstr->length;
+               ptr += eaten;
+               remainsToEat -= eaten;
+               totalEaten += eaten;
+               
+               if (originalInstructionSizes) originalInstructionSizes[instructionIndex] = eaten;
+               instructionIndex += 1;
+               if (originalInstructionCount) *originalInstructionCount = instructionIndex;
+       }
+
+
+       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 {
+#ifdef DEBUG_DISASM
+                       fprintf(stderr, "Not enough space in island to store original instructions. Adapt the island definition and kOriginalInstructionsSize\n");
+#endif      
+                       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;
+}
+
+       static void
+fixupInstructions(
+    void               *originalFunction,
+    void               *escapeIsland,
+    void               *instructionsToFix,
+       int                     instructionCount,
+       uint8_t         *instructionSizes )
+{
+       void *initialOriginalFunction = originalFunction;
+       int     index, fixed_size, code_size = 0;
+       for (index = 0;index < instructionCount;index += 1)
+               code_size += instructionSizes[index];
+
+#ifdef DEBUG_DISASM
+       void *initialInstructionsToFix = instructionsToFix;
+       fprintf(stderr, "BEFORE FIXING:\n");
+       dump16Bytes(initialOriginalFunction);
+       dump16Bytes(initialInstructionsToFix);
+#endif  // DEBUG_DISASM
+
+       for (index = 0;index < instructionCount;index += 1)
+       {
+                fixed_size = instructionSizes[index];
+               if ((*(uint8_t*)instructionsToFix == 0xE9) || // 32-bit jump relative
+                   (*(uint8_t*)instructionsToFix == 0xE8))   // 32-bit call relative
+               {
+                       uint32_t offset = (uintptr_t)originalFunction - (uintptr_t)escapeIsland;
+                       uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 1);
+                       *jumpOffsetPtr += offset;
+               }
+               if ((*(uint8_t*)instructionsToFix == 0x74) ||  // Near jump if equal (je), 2 bytes.
+                   (*(uint8_t*)instructionsToFix == 0x77))    // Near jump if above (ja), 2 bytes.
+               {
+                       // We replace a near je/ja instruction, "7P JJ", with a 32-bit je/ja, "0F 8P WW XX YY ZZ".
+                       // This is critical, otherwise a near jump will likely fall outside the original function.
+                       uint32_t offset = (uintptr_t)initialOriginalFunction - (uintptr_t)escapeIsland;
+                       uint32_t jumpOffset = *(uint8_t*)((uintptr_t)instructionsToFix + 1);
+                       *((uint8_t*)instructionsToFix + 1) = *(uint8_t*)instructionsToFix + 0x10;
+                       *(uint8_t*)instructionsToFix = 0x0F;
+                       uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 2 );
+                       *jumpOffsetPtr = offset + jumpOffset;
+                       fixed_size = 6;
+                }
+               
+               originalFunction = (void*)((uintptr_t)originalFunction + instructionSizes[index]);
+               escapeIsland = (void*)((uintptr_t)escapeIsland + instructionSizes[index]);
+               instructionsToFix = (void*)((uintptr_t)instructionsToFix + fixed_size);
+
+               // Expanding short instructions into longer ones may overwrite the next instructions,
+               // so we must restore them.
+               code_size -= fixed_size;
+               if ((code_size > 0) && (fixed_size != instructionSizes[index])) {
+                       bcopy(originalFunction, instructionsToFix, code_size);
+               }
+       }
+#ifdef DEBUG_DISASM
+       fprintf(stderr, "AFTER_FIXING:\n");
+       dump16Bytes(initialOriginalFunction);
+       dump16Bytes(initialInstructionsToFix);
+#endif  // DEBUG_DISASM
+}
+
+#ifdef DEBUG_DISASM
+#define HEX_DIGIT(x) ((((x) % 16) < 10) ? ('0' + ((x) % 16)) : ('A' + ((x) % 16 - 10)))
+
+       static void
+dump16Bytes(
+       void    *ptr) {
+       int i;
+       char buf[3];
+       uint8_t *bytes = (uint8_t*)ptr;
+       for (i = 0; i < 16; i++) {
+               buf[0] = HEX_DIGIT(bytes[i] / 16);
+               buf[1] = HEX_DIGIT(bytes[i] % 16);
+               buf[2] = ' ';
+               write(2, buf, 3);
+       }
+       write(2, "\n", 1);
+}
+#endif  // DEBUG_DISASM
+#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
+#endif  // __APPLE__
diff --git a/libsanitizer/interception/mach_override/mach_override.h b/libsanitizer/interception/mach_override/mach_override.h
new file mode 100644 (file)
index 0000000..7e60cdc
--- /dev/null
@@ -0,0 +1,140 @@
+/*******************************************************************************
+       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.
+
+       ***************************************************************************/
+
+#ifdef __APPLE__
+
+#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.
+
+       ************************************************************************************/
+
+// We're prefixing mach_override_ptr() with "__asan_" to avoid name conflicts with other
+// mach_override_ptr() implementations that may appear in the client program.
+    mach_error_t
+__asan_mach_override_ptr(
+       void *originalFunctionAddress,
+    const void *overrideFunctionAddress,
+    void **originalFunctionReentryIsland );
+
+// Allow to use custom allocation and deallocation routines with mach_override_ptr().
+// This should help to speed up the things on x86_64.
+typedef mach_error_t island_malloc( void **ptr, size_t size, void *hint );
+typedef mach_error_t island_free( void *ptr );
+
+    mach_error_t
+__asan_mach_override_ptr_custom(
+       void *originalFunctionAddress,
+    const void *overrideFunctionAddress,
+    void **originalFunctionReentryIsland,
+    island_malloc *alloc,
+    island_free *dealloc );
+
+/************************************************************************************//**
+       
+
+       ************************************************************************************/
+#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_
+
+#endif  // __APPLE__