Index: tools/memory_watcher/preamble_patcher.cc |
diff --git a/tools/memory_watcher/preamble_patcher.cc b/tools/memory_watcher/preamble_patcher.cc |
deleted file mode 100644 |
index 846d88141be32b8a3602f120b9d8199f67dc4e93..0000000000000000000000000000000000000000 |
--- a/tools/memory_watcher/preamble_patcher.cc |
+++ /dev/null |
@@ -1,228 +0,0 @@ |
-// Copyright (c) 2010 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. |
- |
-#include "preamble_patcher.h" |
-#include "memory_hook.h" |
-#include "mini_disassembler.h" |
- |
-// compatibility shims |
-#include "base/logging.h" |
- |
-// Definitions of assembly statements we need |
-#define ASM_JMP32REL 0xE9 |
-#define ASM_INT3 0xCC |
- |
-namespace sidestep { |
- |
-SideStepError PreamblePatcher::RawPatchWithStubAndProtections( |
- void* target_function, void *replacement_function, |
- unsigned char* preamble_stub, unsigned long stub_size, |
- unsigned long* bytes_needed) { |
- // We need to be able to write to a process-local copy of the first |
- // MAX_PREAMBLE_STUB_SIZE bytes of target_function. We may be giving execute |
- // privilege to something that doesn't have it, but that's the price to pay |
- // for tools. |
- DWORD old_target_function_protect = 0; |
- BOOL succeeded = ::VirtualProtect(reinterpret_cast<void*>(target_function), |
- MAX_PREAMBLE_STUB_SIZE, |
- PAGE_EXECUTE_READWRITE, |
- &old_target_function_protect); |
- if (!succeeded) { |
- ASSERT(false, "Failed to make page containing target function " |
- "copy-on-write."); |
- return SIDESTEP_ACCESS_DENIED; |
- } |
- |
- SideStepError error_code = RawPatchWithStub(target_function, |
- replacement_function, |
- preamble_stub, |
- stub_size, |
- bytes_needed); |
- if (SIDESTEP_SUCCESS != error_code) { |
- ASSERT1(false); |
- return error_code; |
- } |
- |
- // Restore the protection of the first MAX_PREAMBLE_STUB_SIZE bytes of |
- // pTargetFunction to what they were before we started goofing around. |
- succeeded = ::VirtualProtect(reinterpret_cast<void*>(target_function), |
- MAX_PREAMBLE_STUB_SIZE, |
- old_target_function_protect, |
- &old_target_function_protect); |
- if (!succeeded) { |
- ASSERT(false, "Failed to restore protection to target function."); |
- // We must not return an error here because the function has actually |
- // been patched, and returning an error would likely cause our client |
- // code not to unpatch it. So we just keep going. |
- } |
- |
- // Flush the instruction cache to make sure the processor doesn't execute the |
- // old version of the instructions (before our patch). |
- // |
- // FlushInstructionCache is actually a no-op at least on single-processor |
- // XP machines. I'm not sure why this is so, but it is, yet I want to keep |
- // the call to the API here for correctness in case there is a difference in |
- // some variants of Windows/hardware. |
- succeeded = ::FlushInstructionCache(::GetCurrentProcess(), |
- target_function, |
- MAX_PREAMBLE_STUB_SIZE); |
- if (!succeeded) { |
- ASSERT(false, "Failed to flush instruction cache."); |
- // We must not return an error here because the function has actually |
- // been patched, and returning an error would likely cause our client |
- // code not to unpatch it. So we just keep going. |
- } |
- |
- return SIDESTEP_SUCCESS; |
-} |
- |
-SideStepError PreamblePatcher::RawPatch(void* target_function, |
- void* replacement_function, |
- void** original_function_stub) { |
- if (!target_function || !replacement_function || !original_function_stub || |
- (*original_function_stub) || target_function == replacement_function) { |
- ASSERT(false, "Preconditions not met"); |
- return SIDESTEP_INVALID_PARAMETER; |
- } |
- |
- // @see MAX_PREAMBLE_STUB_SIZE for an explanation of how we arrives at |
- // this size |
- unsigned char* preamble_stub = |
- reinterpret_cast<unsigned char*>( |
- MemoryHook::Alloc(sizeof(unsigned char) * MAX_PREAMBLE_STUB_SIZE)); |
- if (!preamble_stub) { |
- ASSERT(false, "Unable to allocate preamble-stub."); |
- return SIDESTEP_INSUFFICIENT_BUFFER; |
- } |
- |
- // Change the protection of the newly allocated preamble stub to |
- // PAGE_EXECUTE_READWRITE. This is required to work with DEP (Data |
- // Execution Prevention) which will cause an exception if code is executed |
- // from a page on which you do not have read access. |
- DWORD old_stub_protect = 0; |
- BOOL succeeded = VirtualProtect(preamble_stub, MAX_PREAMBLE_STUB_SIZE, |
- PAGE_EXECUTE_READWRITE, &old_stub_protect); |
- if (!succeeded) { |
- ASSERT(false, "Failed to make page preamble stub read-write-execute."); |
- delete[] preamble_stub; |
- return SIDESTEP_ACCESS_DENIED; |
- } |
- |
- SideStepError error_code = RawPatchWithStubAndProtections(target_function, |
- replacement_function, |
- preamble_stub, |
- MAX_PREAMBLE_STUB_SIZE, |
- NULL); |
- if (SIDESTEP_SUCCESS != error_code) { |
- ASSERT1(false); |
- delete[] preamble_stub; |
- return error_code; |
- } |
- |
- *original_function_stub = reinterpret_cast<void*>(preamble_stub); |
- |
- // NOTE: For hooking malloc/free, we don't want to use streams which |
- // allocate. Basically, we've hooked malloc, but not necessarily |
- // hooked free yet. To do anything which uses the heap could crash |
- // with a mismatched malloc/free! |
- //VLOG(1) << "PreamblePatcher::RawPatch successfully patched 0x" |
- // << target_function; |
- |
- return SIDESTEP_SUCCESS; |
-} |
- |
-SideStepError PreamblePatcher::Unpatch(void* target_function, |
- void* replacement_function, |
- void* original_function_stub) { |
- ASSERT1(target_function && original_function_stub); |
- if (!target_function || !original_function_stub) { |
- return SIDESTEP_INVALID_PARAMETER; |
- } |
- |
- // We disassemble the preamble of the _stub_ to see how many bytes we |
- // originally copied to the stub. |
- MiniDisassembler disassembler; |
- unsigned int preamble_bytes = 0; |
- while (preamble_bytes < 5) { |
- InstructionType instruction_type = disassembler.Disassemble( |
- reinterpret_cast<unsigned char*>(original_function_stub) + |
- preamble_bytes, preamble_bytes); |
- if (IT_GENERIC != instruction_type) { |
- ASSERT(false, "Should only have generic instructions in stub!!"); |
- return SIDESTEP_UNSUPPORTED_INSTRUCTION; |
- } |
- } |
- |
- // Before unpatching, target_function should be a JMP to |
- // replacement_function. If it's not, then either it's an error, or |
- // we're falling into the case where the original instruction was a |
- // JMP, and we patched the jumped_to address rather than the JMP |
- // itself. (For instance, if malloc() is just a JMP to __malloc(), |
- // we patched __malloc() and not malloc().) |
- unsigned char* target = reinterpret_cast<unsigned char*>(target_function); |
- while (1) { // we stop when target is a JMP to replacement_function |
- if (target[0] != ASM_JMP32REL) { |
- ASSERT(false, "target_function does not look like it was patched."); |
- return SIDESTEP_INVALID_PARAMETER; |
- } |
- int relative_offset; // Windows guarantees int is 4 bytes |
- ASSERT1(sizeof(relative_offset) == 4); |
- memcpy(reinterpret_cast<void*>(&relative_offset), |
- reinterpret_cast<void*>(target + 1), 4); |
- unsigned char* jump_to = target + 5 + relative_offset; |
- if (jump_to == replacement_function) |
- break; |
- target = jump_to; // follow the jmp |
- } |
- |
- // We need to be able to write to a process-local copy of the first |
- // MAX_PREAMBLE_STUB_SIZE bytes of target_function. We may be giving execute |
- // privilege to something that doesn't have it, but that's the price to pay |
- // for tools. |
- DWORD old_target_function_protect = 0; |
- BOOL succeeded = ::VirtualProtect(reinterpret_cast<void*>(target), |
- MAX_PREAMBLE_STUB_SIZE, |
- PAGE_EXECUTE_READWRITE, |
- &old_target_function_protect); |
- if (!succeeded) { |
- ASSERT(false, "Failed to make page containing target function " |
- "copy-on-write."); |
- return SIDESTEP_ACCESS_DENIED; |
- } |
- |
- // Replace the first few bytes of the original function with the bytes we |
- // previously moved to the preamble stub. |
- memcpy(reinterpret_cast<void*>(target), |
- original_function_stub, preamble_bytes); |
- |
- // Stub is now useless so delete it. |
- // [csilvers: Commented out for perftools because it causes big problems |
- // when we're unpatching malloc. We just let this live on as a leak.] |
- //delete original_function_stub; |
- |
- // Restore the protection of the first MAX_PREAMBLE_STUB_SIZE bytes of |
- // target to what they were before we started goofing around. |
- succeeded = ::VirtualProtect(reinterpret_cast<void*>(target), |
- MAX_PREAMBLE_STUB_SIZE, |
- old_target_function_protect, |
- &old_target_function_protect); |
- |
- // Flush the instruction cache to make sure the processor doesn't execute the |
- // old version of the instructions (before our patch). |
- // |
- // See comment on FlushInstructionCache elsewhere in this file. |
- succeeded = ::FlushInstructionCache(::GetCurrentProcess(), |
- target, |
- MAX_PREAMBLE_STUB_SIZE); |
- if (!succeeded) { |
- ASSERT(false, "Failed to flush instruction cache."); |
- return SIDESTEP_UNEXPECTED; |
- } |
- |
- VLOG(1) << "PreamblePatcher::Unpatch successfully unpatched 0x" |
- << target_function; |
- return SIDESTEP_SUCCESS; |
-} |
- |
-}; // namespace sidestep |