| OLD | NEW | 
|---|
| 1 /* Copyright (c) 2007, Google Inc. | 1 /* Copyright (c) 2007, Google Inc. | 
| 2  * All rights reserved. | 2  * All rights reserved. | 
| 3  * | 3  * | 
| 4  * Redistribution and use in source and binary forms, with or without | 4  * Redistribution and use in source and binary forms, with or without | 
| 5  * modification, are permitted provided that the following conditions are | 5  * modification, are permitted provided that the following conditions are | 
| 6  * met: | 6  * met: | 
| 7  * | 7  * | 
| 8  *     * Redistributions of source code must retain the above copyright | 8  *     * Redistributions of source code must retain the above copyright | 
| 9  * notice, this list of conditions and the following disclaimer. | 9  * notice, this list of conditions and the following disclaimer. | 
| 10  *     * Redistributions in binary form must reproduce the above | 10  *     * Redistributions in binary form must reproduce the above | 
| (...skipping 11 matching lines...) Expand all  Loading... | 
| 22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
| 23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
| 24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
| 25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
| 26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
| 27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
| 28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
| 29  * | 29  * | 
| 30  * --- | 30  * --- | 
| 31  * Author: Joi Sigurdsson | 31  * Author: Joi Sigurdsson | 
| 32  * Author: Scott Francis |  | 
| 33  * | 32  * | 
| 34  * Implementation of PreamblePatcher | 33  * Implementation of PreamblePatcher | 
| 35  */ | 34  */ | 
| 36 | 35 | 
| 37 #include "preamble_patcher.h" | 36 #include "preamble_patcher.h" | 
| 38 | 37 | 
| 39 #include "mini_disassembler.h" | 38 #include "mini_disassembler.h" | 
| 40 | 39 | 
| 41 // Definitions of assembly statements we need | 40 // Definitions of assembly statements we need | 
| 42 #define ASM_JMP32REL 0xE9 | 41 #define ASM_JMP32REL 0xE9 | 
| 43 #define ASM_INT3 0xCC | 42 #define ASM_INT3 0xCC | 
| 44 #define ASM_NOP 0x90 |  | 
| 45 // X64 opcodes |  | 
| 46 #define ASM_MOVRAX_IMM 0xB8 |  | 
| 47 #define ASM_REXW 0x48 |  | 
| 48 #define ASM_JMP 0xFF |  | 
| 49 #define ASM_JMP_RAX 0xE0 |  | 
| 50 #define ASM_PUSH 0x68 |  | 
| 51 #define ASM_RET 0xC3 |  | 
| 52 | 43 | 
| 53 namespace sidestep { | 44 namespace sidestep { | 
| 54 | 45 | 
| 55 SideStepError PreamblePatcher::RawPatchWithStub( | 46 SideStepError PreamblePatcher::RawPatchWithStub( | 
| 56     void* target_function, | 47     void* target_function, | 
| 57     void* replacement_function, | 48     void *replacement_function, | 
| 58     unsigned char* preamble_stub, | 49     unsigned char* preamble_stub, | 
| 59     unsigned long stub_size, | 50     unsigned long stub_size, | 
| 60     unsigned long* bytes_needed) { | 51     unsigned long* bytes_needed) { | 
| 61   if ((NULL == target_function) || | 52   if ((NULL == target_function) || | 
| 62       (NULL == replacement_function) || | 53       (NULL == replacement_function) || | 
| 63       (NULL == preamble_stub)) { | 54       (NULL == preamble_stub)) { | 
| 64     SIDESTEP_ASSERT(false && | 55     SIDESTEP_ASSERT(false && | 
| 65                     "Invalid parameters - either pTargetFunction or " | 56                     "Invalid parameters - either pTargetFunction or " | 
| 66                     "pReplacementFunction or pPreambleStub were NULL."); | 57                     "pReplacementFunction or pPreambleStub were NULL."); | 
| 67     return SIDESTEP_INVALID_PARAMETER; | 58     return SIDESTEP_INVALID_PARAMETER; | 
| 68   } | 59   } | 
| 69 | 60 | 
| 70   // TODO(V7:joi) Siggi and I just had a discussion and decided that both | 61   // TODO(V7:joi) Siggi and I just had a discussion and decided that both | 
| 71   // patching and unpatching are actually unsafe.  We also discussed a | 62   // patching and unpatching are actually unsafe.  We also discussed a | 
| 72   // method of making it safe, which is to freeze all other threads in the | 63   // method of making it safe, which is to freeze all other threads in the | 
| 73   // process, check their thread context to see if their eip is currently | 64   // process, check their thread context to see if their eip is currently | 
| 74   // inside the block of instructions we need to copy to the stub, and if so | 65   // inside the block of instructions we need to copy to the stub, and if so | 
| 75   // wait a bit and try again, then unfreeze all threads once we've patched. | 66   // wait a bit and try again, then unfreeze all threads once we've patched. | 
| 76   // Not implementing this for now since we're only using SideStep for unit | 67   // Not implementing this for now since we're only using SideStep for unit | 
| 77   // testing, but if we ever use it for production code this is what we | 68   // testing, but if we ever use it for production code this is what we | 
| 78   // should do. | 69   // should do. | 
| 79   // | 70   // | 
| 80   // NOTE: Stoyan suggests we can write 8 or even 10 bytes atomically using | 71   // NOTE: Stoyan suggests we can write 8 or even 10 bytes atomically using | 
| 81   // FPU instructions, and on newer processors we could use cmpxchg8b or | 72   // FPU instructions, and on newer processors we could use cmpxchg8b or | 
| 82   // cmpxchg16b. So it might be possible to do the patching/unpatching | 73   // cmpxchg16b. So it might be possible to do the patching/unpatching | 
| 83   // atomically and avoid having to freeze other threads.  Note though, that | 74   // atomically and avoid having to freeze other threads.  Note though, that | 
| 84   // doing it atomically does not help if one of the other threads happens | 75   // doing it atomically does not help if one of the other threads happens | 
| 85   // to have its eip in the middle of the bytes you change while you change | 76   // to have its eip in the middle of the bytes you change while you change | 
| 86   // them. | 77   // them. | 
| 87   unsigned char* target = reinterpret_cast<unsigned char*>(target_function); |  | 
| 88   unsigned int required_trampoline_bytes = 0; |  | 
| 89   const unsigned int kRequiredStubJumpBytes = 5; |  | 
| 90   const unsigned int kRequiredTargetPatchBytes = 5; |  | 
| 91 | 78 | 
| 92   // Initialize the stub with INT3's just in case. | 79   // First, deal with a special case that we see with functions that | 
| 93   if (stub_size) { | 80   // point into an IAT table (including functions linked statically | 
| 94     memset(preamble_stub, 0xcc, stub_size); | 81   // into the application): these function already starts with | 
|  | 82   // ASM_JMP32REL.  For instance, malloc() might be implemented as a | 
|  | 83   // JMP to __malloc().  In that case, we replace the destination of | 
|  | 84   // the JMP (__malloc), rather than the JMP itself (malloc).  This | 
|  | 85   // way we get the correct behavior no matter how malloc gets called. | 
|  | 86   void *new_target = ResolveTarget(target_function); | 
|  | 87   if (new_target != target_function) {   // we're in the IAT case | 
|  | 88     // I'd like to just say "target = new_target", but I can't, | 
|  | 89     // because the new target will need to have its protections set. | 
|  | 90     return RawPatchWithStubAndProtections(new_target, replacement_function, | 
|  | 91                                           preamble_stub, stub_size, | 
|  | 92                                           bytes_needed); | 
| 95   } | 93   } | 
| 96   if (kIs64BitBinary) { | 94   unsigned char* target = reinterpret_cast<unsigned char*>(new_target); | 
| 97     // In 64-bit mode JMP instructions are always relative to RIP.  If the |  | 
| 98     // replacement - target offset is > 2GB, we can't JMP to the replacement |  | 
| 99     // function.  In this case, we're going to use a trampoline - that is, |  | 
| 100     // we're going to do a relative jump to a small chunk of code in the stub |  | 
| 101     // that will then do the absolute jump to the replacement function.  By |  | 
| 102     // doing this, we only need to patch 5 bytes in the target function, as |  | 
| 103     // opposed to patching 12 bytes if we were to do an absolute jump. |  | 
| 104     // |  | 
| 105     // Note that the first byte of the trampoline is a NOP instruction.  This |  | 
| 106     // is used as a trampoline signature that will be detected when unpatching |  | 
| 107     // the function. |  | 
| 108     // |  | 
| 109     // jmp <trampoline> |  | 
| 110     // |  | 
| 111     // trampoline: |  | 
| 112     //    nop |  | 
| 113     //    mov rax, <replacement_function> |  | 
| 114     //    jmp rax |  | 
| 115     // |  | 
| 116     __int64 replacement_target_offset = reinterpret_cast<__int64>( |  | 
| 117         replacement_function) - reinterpret_cast<__int64>(target) - 5; |  | 
| 118     if (replacement_target_offset > INT_MAX |  | 
| 119         || replacement_target_offset < INT_MIN) { |  | 
| 120       // The stub needs to be within 2GB of the target for the trampoline to |  | 
| 121       // work! |  | 
| 122       __int64 trampoline_offset = reinterpret_cast<__int64>(preamble_stub) |  | 
| 123           - reinterpret_cast<__int64>(target) - 5; |  | 
| 124       if (trampoline_offset > INT_MAX || trampoline_offset < INT_MIN) { |  | 
| 125         // We're screwed. |  | 
| 126         SIDESTEP_ASSERT(false |  | 
| 127                        && "Preamble stub is too far from target to patch."); |  | 
| 128         return SIDESTEP_UNEXPECTED; |  | 
| 129       } |  | 
| 130       required_trampoline_bytes = 13; |  | 
| 131     } |  | 
| 132   } |  | 
| 133 | 95 | 
| 134   // Let's disassemble the preamble of the target function to see if we can | 96   // Let's disassemble the preamble of the target function to see if we can | 
| 135   // patch, and to see how much of the preamble we need to take.  We need 5 | 97   // patch, and to see how much of the preamble we need to take.  We need 5 | 
| 136   // bytes for our jmp instruction, so let's find the minimum number of | 98   // bytes for our jmp instruction, so let's find the minimum number of | 
| 137   // instructions to get 5 bytes. | 99   // instructions to get 5 bytes. | 
| 138   MiniDisassembler disassembler; | 100   MiniDisassembler disassembler; | 
| 139   unsigned int preamble_bytes = 0; | 101   unsigned int preamble_bytes = 0; | 
| 140   unsigned int stub_bytes = 0; | 102   while (preamble_bytes < 5) { | 
| 141   while (preamble_bytes < kRequiredTargetPatchBytes) { |  | 
| 142     unsigned int cur_bytes = 0; |  | 
| 143     InstructionType instruction_type = | 103     InstructionType instruction_type = | 
| 144         disassembler.Disassemble(target + preamble_bytes, cur_bytes); | 104         disassembler.Disassemble(target + preamble_bytes, preamble_bytes); | 
| 145     if (IT_JUMP == instruction_type) { | 105     if (IT_JUMP == instruction_type) { | 
| 146       unsigned int jump_bytes = 0; | 106       SIDESTEP_ASSERT(false && | 
| 147       SideStepError jump_ret = SIDESTEP_JUMP_INSTRUCTION; | 107                       "Unable to patch because there is a jump instruction " | 
| 148       if (IsShortConditionalJump(target + preamble_bytes, cur_bytes)) { | 108                       "in the first 5 bytes."); | 
| 149         jump_ret = PatchShortConditionalJump(target + preamble_bytes, cur_bytes, | 109       return SIDESTEP_JUMP_INSTRUCTION; | 
| 150                                              preamble_stub + stub_bytes, |  | 
| 151                                              &jump_bytes, |  | 
| 152                                              stub_size - stub_bytes); |  | 
| 153       } else if (IsNearConditionalJump(target + preamble_bytes, cur_bytes) || |  | 
| 154                  IsNearRelativeJump(target + preamble_bytes, cur_bytes) || |  | 
| 155                  IsNearAbsoluteCall(target + preamble_bytes, cur_bytes) || |  | 
| 156                  IsNearRelativeCall(target + preamble_bytes, cur_bytes)) { |  | 
| 157          jump_ret = PatchNearJumpOrCall(target + preamble_bytes, cur_bytes, |  | 
| 158                                         preamble_stub + stub_bytes, &jump_bytes, |  | 
| 159                                         stub_size - stub_bytes); |  | 
| 160       } |  | 
| 161       if (jump_ret != SIDESTEP_SUCCESS) { |  | 
| 162         SIDESTEP_ASSERT(false && |  | 
| 163                         "Unable to patch because there is an unhandled branch " |  | 
| 164                         "instruction in the initial preamble bytes."); |  | 
| 165         return SIDESTEP_JUMP_INSTRUCTION; |  | 
| 166       } |  | 
| 167       stub_bytes += jump_bytes; |  | 
| 168     } else if (IT_RETURN == instruction_type) { | 110     } else if (IT_RETURN == instruction_type) { | 
| 169       SIDESTEP_ASSERT(false && | 111       SIDESTEP_ASSERT(false && | 
| 170                       "Unable to patch because function is too short"); | 112                       "Unable to patch because function is too short"); | 
| 171       return SIDESTEP_FUNCTION_TOO_SMALL; | 113       return SIDESTEP_FUNCTION_TOO_SMALL; | 
| 172     } else if (IT_GENERIC == instruction_type) { | 114     } else if (IT_GENERIC != instruction_type) { | 
| 173       if (IsMovWithDisplacement(target + preamble_bytes, cur_bytes)) { |  | 
| 174         unsigned int mov_bytes = 0; |  | 
| 175         if (PatchMovWithDisplacement(target + preamble_bytes, cur_bytes, |  | 
| 176                                      preamble_stub + stub_bytes, &mov_bytes, |  | 
| 177                                      stub_size - stub_bytes) |  | 
| 178             != SIDESTEP_SUCCESS) { |  | 
| 179           return SIDESTEP_UNSUPPORTED_INSTRUCTION; |  | 
| 180         } |  | 
| 181         stub_bytes += mov_bytes; |  | 
| 182       } else { |  | 
| 183         memcpy(reinterpret_cast<void*>(preamble_stub + stub_bytes), |  | 
| 184                reinterpret_cast<void*>(target + preamble_bytes), cur_bytes); |  | 
| 185         stub_bytes += cur_bytes; |  | 
| 186       } |  | 
| 187     } else { |  | 
| 188       SIDESTEP_ASSERT(false && | 115       SIDESTEP_ASSERT(false && | 
| 189                       "Disassembler encountered unsupported instruction " | 116                       "Disassembler encountered unsupported instruction " | 
| 190                       "(either unused or unknown"); | 117                       "(either unused or unknown"); | 
| 191       return SIDESTEP_UNSUPPORTED_INSTRUCTION; | 118       return SIDESTEP_UNSUPPORTED_INSTRUCTION; | 
| 192     } | 119     } | 
| 193     preamble_bytes += cur_bytes; |  | 
| 194   } | 120   } | 
| 195 | 121 | 
| 196   if (NULL != bytes_needed) | 122   if (NULL != bytes_needed) | 
| 197     *bytes_needed = stub_bytes + kRequiredStubJumpBytes | 123     *bytes_needed = preamble_bytes + 5; | 
| 198         + required_trampoline_bytes; |  | 
| 199 | 124 | 
| 200   // Inv: cbPreamble is the number of bytes (at least 5) that we need to take | 125   // Inv: cbPreamble is the number of bytes (at least 5) that we need to take | 
| 201   // from the preamble to have whole instructions that are 5 bytes or more | 126   // from the preamble to have whole instructions that are 5 bytes or more | 
| 202   // in size total. The size of the stub required is cbPreamble + | 127   // in size total. The size of the stub required is cbPreamble + size of | 
| 203   // kRequiredStubJumpBytes (5) + required_trampoline_bytes (0 or 13) | 128   // jmp (5) | 
| 204   if (stub_bytes + kRequiredStubJumpBytes + required_trampoline_bytes | 129   if (preamble_bytes + 5 > stub_size) { | 
| 205       > stub_size) { |  | 
| 206     SIDESTEP_ASSERT(false); | 130     SIDESTEP_ASSERT(false); | 
| 207     return SIDESTEP_INSUFFICIENT_BUFFER; | 131     return SIDESTEP_INSUFFICIENT_BUFFER; | 
| 208   } | 132   } | 
| 209 | 133 | 
|  | 134   // First, copy the preamble that we will overwrite. | 
|  | 135   memcpy(reinterpret_cast<void*>(preamble_stub), | 
|  | 136          reinterpret_cast<void*>(target), preamble_bytes); | 
|  | 137 | 
| 210   // Now, make a jmp instruction to the rest of the target function (minus the | 138   // Now, make a jmp instruction to the rest of the target function (minus the | 
| 211   // preamble bytes we moved into the stub) and copy it into our preamble-stub. | 139   // preamble bytes we moved into the stub) and copy it into our preamble-stub. | 
| 212   // find address to jump to, relative to next address after jmp instruction | 140   // find address to jump to, relative to next address after jmp instruction | 
| 213 #ifdef _MSC_VER | 141 #ifdef _MSC_VER | 
| 214 #pragma warning(push) | 142 #pragma warning(push) | 
| 215 #pragma warning(disable:4244) | 143 #pragma warning(disable:4244) | 
| 216 #endif | 144 #endif | 
| 217   int relative_offset_to_target_rest | 145   int relative_offset_to_target_rest | 
| 218       = ((reinterpret_cast<unsigned char*>(target) + preamble_bytes) - | 146       = ((reinterpret_cast<unsigned char*>(target) + preamble_bytes) - | 
| 219          (preamble_stub + stub_bytes + kRequiredStubJumpBytes)); | 147          (preamble_stub + preamble_bytes + 5)); | 
| 220 #ifdef _MSC_VER | 148 #ifdef _MSC_VER | 
| 221 #pragma warning(pop) | 149 #pragma warning(pop) | 
| 222 #endif | 150 #endif | 
| 223   // jmp (Jump near, relative, displacement relative to next instruction) | 151   // jmp (Jump near, relative, displacement relative to next instruction) | 
| 224   preamble_stub[stub_bytes] = ASM_JMP32REL; | 152   preamble_stub[preamble_bytes] = ASM_JMP32REL; | 
| 225   // copy the address | 153   // copy the address | 
| 226   memcpy(reinterpret_cast<void*>(preamble_stub + stub_bytes + 1), | 154   memcpy(reinterpret_cast<void*>(preamble_stub + preamble_bytes + 1), | 
| 227          reinterpret_cast<void*>(&relative_offset_to_target_rest), 4); | 155          reinterpret_cast<void*>(&relative_offset_to_target_rest), 4); | 
| 228 | 156 | 
| 229   if (kIs64BitBinary && required_trampoline_bytes != 0) { |  | 
| 230     // Construct the trampoline |  | 
| 231     unsigned int trampoline_pos = stub_bytes + kRequiredStubJumpBytes; |  | 
| 232     preamble_stub[trampoline_pos] = ASM_NOP; |  | 
| 233     preamble_stub[trampoline_pos + 1] = ASM_REXW; |  | 
| 234     preamble_stub[trampoline_pos + 2] = ASM_MOVRAX_IMM; |  | 
| 235     memcpy(reinterpret_cast<void*>(preamble_stub + trampoline_pos + 3), |  | 
| 236            reinterpret_cast<void*>(&replacement_function), |  | 
| 237            sizeof(void *)); |  | 
| 238     preamble_stub[trampoline_pos + 11] = ASM_JMP; |  | 
| 239     preamble_stub[trampoline_pos + 12] = ASM_JMP_RAX; |  | 
| 240 |  | 
| 241     // Now update replacement_function to point to the trampoline |  | 
| 242     replacement_function = preamble_stub + trampoline_pos; |  | 
| 243   } |  | 
| 244 |  | 
| 245   // Inv: preamble_stub points to assembly code that will execute the | 157   // Inv: preamble_stub points to assembly code that will execute the | 
| 246   // original function by first executing the first cbPreamble bytes of the | 158   // original function by first executing the first cbPreamble bytes of the | 
| 247   // preamble, then jumping to the rest of the function. | 159   // preamble, then jumping to the rest of the function. | 
| 248 | 160 | 
| 249   // Overwrite the first 5 bytes of the target function with a jump to our | 161   // Overwrite the first 5 bytes of the target function with a jump to our | 
| 250   // replacement function. | 162   // replacement function. | 
| 251   // (Jump near, relative, displacement relative to next instruction) | 163   // (Jump near, relative, displacement relative to next instruction) | 
| 252   target[0] = ASM_JMP32REL; | 164   target[0] = ASM_JMP32REL; | 
| 253 | 165 | 
| 254   // Find offset from instruction after jmp, to the replacement function. | 166   // Find offset from instruction after jmp, to the replacement function. | 
| 255 #ifdef _MSC_VER | 167 #ifdef _MSC_VER | 
| 256 #pragma warning(push) | 168 #pragma warning(push) | 
| 257 #pragma warning(disable:4244) | 169 #pragma warning(disable:4244) | 
| 258 #endif | 170 #endif | 
| 259   int offset_to_replacement_function = | 171   int offset_to_replacement_function = | 
| 260       reinterpret_cast<unsigned char*>(replacement_function) - | 172       reinterpret_cast<unsigned char*>(replacement_function) - | 
| 261       reinterpret_cast<unsigned char*>(target) - 5; | 173       reinterpret_cast<unsigned char*>(target) - 5; | 
| 262 #ifdef _MSC_VER | 174 #ifdef _MSC_VER | 
| 263 #pragma warning(pop) | 175 #pragma warning(pop) | 
| 264 #endif | 176 #endif | 
| 265   // complete the jmp instruction | 177   // complete the jmp instruction | 
| 266   memcpy(reinterpret_cast<void*>(target + 1), | 178   memcpy(reinterpret_cast<void*>(target + 1), | 
| 267          reinterpret_cast<void*>(&offset_to_replacement_function), 4); | 179          reinterpret_cast<void*>(&offset_to_replacement_function), 4); | 
| 268 |  | 
| 269   // Set any remaining bytes that were moved to the preamble-stub to INT3 so | 180   // Set any remaining bytes that were moved to the preamble-stub to INT3 so | 
| 270   // as not to cause confusion (otherwise you might see some strange | 181   // as not to cause confusion (otherwise you might see some strange | 
| 271   // instructions if you look at the disassembly, or even invalid | 182   // instructions if you look at the disassembly, or even invalid | 
| 272   // instructions). Also, by doing this, we will break into the debugger if | 183   // instructions). Also, by doing this, we will break into the debugger if | 
| 273   // some code calls into this portion of the code.  If this happens, it | 184   // some code calls into this portion of the code.  If this happens, it | 
| 274   // means that this function cannot be patched using this patcher without | 185   // means that this function cannot be patched using this patcher without | 
| 275   // further thought. | 186   // further thought. | 
| 276   if (preamble_bytes > kRequiredTargetPatchBytes) { | 187   if (preamble_bytes > 5) { | 
| 277     memset(reinterpret_cast<void*>(target + kRequiredTargetPatchBytes), | 188     memset(reinterpret_cast<void*>(target + 5), ASM_INT3, preamble_bytes - 5); | 
| 278            ASM_INT3, preamble_bytes - kRequiredTargetPatchBytes); |  | 
| 279   } | 189   } | 
| 280 | 190 | 
| 281   // Inv: The memory pointed to by target_function now points to a relative | 191   // Inv: The memory pointed to by target_function now points to a relative | 
| 282   // jump instruction that jumps over to the preamble_stub.  The preamble | 192   // jump instruction that jumps over to the preamble_stub.  The preamble | 
| 283   // stub contains the first stub_size bytes of the original target | 193   // stub contains the first stub_size bytes of the original target | 
| 284   // function's preamble code, followed by a relative jump back to the next | 194   // function's preamble code, followed by a relative jump back to the next | 
| 285   // instruction after the first cbPreamble bytes. | 195   // instruction after the first cbPreamble bytes. | 
| 286   // | 196 | 
| 287   // In 64-bit mode the memory pointed to by target_function *may* point to a |  | 
| 288   // relative jump instruction that jumps to a trampoline which will then |  | 
| 289   // perform an absolute jump to the replacement function.  The preamble stub |  | 
| 290   // still contains the original target function's preamble code, followed by a |  | 
| 291   // jump back to the instructions after the first preamble bytes. |  | 
| 292   // |  | 
| 293   return SIDESTEP_SUCCESS; | 197   return SIDESTEP_SUCCESS; | 
| 294 } | 198 } | 
| 295 | 199 | 
| 296 };  // namespace sidestep | 200 };  // namespace sidestep | 
| OLD | NEW | 
|---|