diff options
Diffstat (limited to 'src/third_party/gperftools-2.5/src/windows/preamble_patcher.h')
-rw-r--r-- | src/third_party/gperftools-2.5/src/windows/preamble_patcher.h | 620 |
1 files changed, 0 insertions, 620 deletions
diff --git a/src/third_party/gperftools-2.5/src/windows/preamble_patcher.h b/src/third_party/gperftools-2.5/src/windows/preamble_patcher.h deleted file mode 100644 index 76f158a19a1..00000000000 --- a/src/third_party/gperftools-2.5/src/windows/preamble_patcher.h +++ /dev/null @@ -1,620 +0,0 @@ -// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- -/* Copyright (c) 2007, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * --- - * Author: Joi Sigurdsson - * Author: Scott Francis - * - * Definition of PreamblePatcher - */ - -#ifndef GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_ -#define GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_ - -#include "config.h" -#include <windows.h> - -// compatibility shim -#include "base/logging.h" -#define SIDESTEP_ASSERT(cond) RAW_DCHECK(cond, #cond) -#define SIDESTEP_LOG(msg) RAW_VLOG(1, msg) - -// Maximum size of the preamble stub. We overwrite at least the first 5 -// bytes of the function. Considering the worst case scenario, we need 4 -// bytes + the max instruction size + 5 more bytes for our jump back to -// the original code. With that in mind, 32 is a good number :) -#ifdef _M_X64 -// In 64-bit mode we may need more room. In 64-bit mode all jumps must be -// within +/-2GB of RIP. Because of this limitation we may need to use a -// trampoline to jump to the replacement function if it is further than 2GB -// away from the target. The trampoline is 14 bytes. -// -// So 4 bytes + max instruction size (17 bytes) + 5 bytes to jump back to the -// original code + trampoline size. 64 bytes is a nice number :-) -#define MAX_PREAMBLE_STUB_SIZE (64) -#else -#define MAX_PREAMBLE_STUB_SIZE (32) -#endif - -// Determines if this is a 64-bit binary. -#ifdef _M_X64 -static const bool kIs64BitBinary = true; -#else -static const bool kIs64BitBinary = false; -#endif - -namespace sidestep { - -// Possible results of patching/unpatching -enum SideStepError { - SIDESTEP_SUCCESS = 0, - SIDESTEP_INVALID_PARAMETER, - SIDESTEP_INSUFFICIENT_BUFFER, - SIDESTEP_JUMP_INSTRUCTION, - SIDESTEP_FUNCTION_TOO_SMALL, - SIDESTEP_UNSUPPORTED_INSTRUCTION, - SIDESTEP_NO_SUCH_MODULE, - SIDESTEP_NO_SUCH_FUNCTION, - SIDESTEP_ACCESS_DENIED, - SIDESTEP_UNEXPECTED, -}; - -#define SIDESTEP_TO_HRESULT(error) \ - MAKE_HRESULT(SEVERITY_ERROR, FACILITY_NULL, error) - -class DeleteUnsignedCharArray; - -// Implements a patching mechanism that overwrites the first few bytes of -// a function preamble with a jump to our hook function, which is then -// able to call the original function via a specially-made preamble-stub -// that imitates the action of the original preamble. -// -// NOTE: This patching mechanism should currently only be used for -// non-production code, e.g. unit tests, because it is not threadsafe. -// See the TODO in preamble_patcher_with_stub.cc for instructions on what -// we need to do before using it in production code; it's fairly simple -// but unnecessary for now since we only intend to use it in unit tests. -// -// To patch a function, use either of the typesafe Patch() methods. You -// can unpatch a function using Unpatch(). -// -// Typical usage goes something like this: -// @code -// typedef int (*MyTypesafeFuncPtr)(int x); -// MyTypesafeFuncPtr original_func_stub; -// int MyTypesafeFunc(int x) { return x + 1; } -// int HookMyTypesafeFunc(int x) { return 1 + original_func_stub(x); } -// -// void MyPatchInitializingFunction() { -// original_func_stub = PreamblePatcher::Patch( -// MyTypesafeFunc, HookMyTypesafeFunc); -// if (!original_func_stub) { -// // ... error handling ... -// } -// -// // ... continue - you have patched the function successfully ... -// } -// @endcode -// -// Note that there are a number of ways that this method of patching can -// fail. The most common are: -// - If there is a jump (jxx) instruction in the first 5 bytes of -// the function being patched, we cannot patch it because in the -// current implementation we do not know how to rewrite relative -// jumps after relocating them to the preamble-stub. Note that -// if you really really need to patch a function like this, it -// would be possible to add this functionality (but at some cost). -// - If there is a return (ret) instruction in the first 5 bytes -// we cannot patch the function because it may not be long enough -// for the jmp instruction we use to inject our patch. -// - If there is another thread currently executing within the bytes -// that are copied to the preamble stub, it will crash in an undefined -// way. -// -// If you get any other error than the above, you're either pointing the -// patcher at an invalid instruction (e.g. into the middle of a multi- -// byte instruction, or not at memory containing executable instructions) -// or, there may be a bug in the disassembler we use to find -// instruction boundaries. -// -// NOTE: In optimized builds, when you have very trivial functions that -// the compiler can reason do not have side effects, the compiler may -// reuse the result of calling the function with a given parameter, which -// may mean if you patch the function in between your patch will never get -// invoked. See preamble_patcher_test.cc for an example. -class PERFTOOLS_DLL_DECL PreamblePatcher { - public: - - // This is a typesafe version of RawPatch(), identical in all other - // ways than it takes a template parameter indicating the type of the - // function being patched. - // - // @param T The type of the function you are patching. Usually - // you will establish this type using a typedef, as in the following - // example: - // @code - // typedef BOOL (WINAPI *MessageBoxPtr)(HWND, LPCTSTR, LPCTSTR, UINT); - // MessageBoxPtr original = NULL; - // PreamblePatcher::Patch(MessageBox, Hook_MessageBox, &original); - // @endcode - template <class T> - static SideStepError Patch(T target_function, - T replacement_function, - T* original_function_stub) { - // NOTE: casting from a function to a pointer is contra the C++ - // spec. It's not safe on IA64, but is on i386. We use - // a C-style cast here to emphasize this is not legal C++. - return RawPatch((void*)(target_function), - (void*)(replacement_function), - (void**)(original_function_stub)); - } - - // Patches a named function imported from the named module using - // preamble patching. Uses RawPatch() to do the actual patching - // work. - // - // @param T The type of the function you are patching. Must - // exactly match the function you specify using module_name and - // function_name. - // - // @param module_name The name of the module from which the function - // is being imported. Note that the patch will fail if this module - // has not already been loaded into the current process. - // - // @param function_name The name of the function you wish to patch. - // - // @param replacement_function Your replacement function which - // will be called whenever code tries to call the original function. - // - // @param original_function_stub Pointer to memory that should receive a - // pointer that can be used (e.g. in the replacement function) to call the - // original function, or NULL to indicate failure. - // - // @return One of the EnSideStepError error codes; only SIDESTEP_SUCCESS - // indicates success. - template <class T> - static SideStepError Patch(LPCTSTR module_name, - LPCSTR function_name, - T replacement_function, - T* original_function_stub) { - SIDESTEP_ASSERT(module_name && function_name); - if (!module_name || !function_name) { - SIDESTEP_ASSERT(false && - "You must specify a module name and function name."); - return SIDESTEP_INVALID_PARAMETER; - } - HMODULE module = ::GetModuleHandle(module_name); - SIDESTEP_ASSERT(module != NULL); - if (!module) { - SIDESTEP_ASSERT(false && "Invalid module name."); - return SIDESTEP_NO_SUCH_MODULE; - } - FARPROC existing_function = ::GetProcAddress(module, function_name); - if (!existing_function) { - SIDESTEP_ASSERT( - false && "Did not find any function with that name in the module."); - return SIDESTEP_NO_SUCH_FUNCTION; - } - // NOTE: casting from a function to a pointer is contra the C++ - // spec. It's not safe on IA64, but is on i386. We use - // a C-style cast here to emphasize this is not legal C++. - return RawPatch((void*)existing_function, (void*)replacement_function, - (void**)(original_function_stub)); - } - - // Patches a function by overwriting its first few bytes with - // a jump to a different function. This is the "worker" function - // for each of the typesafe Patch() functions. In most cases, - // it is preferable to use the Patch() functions rather than - // this one as they do more checking at compile time. - // - // @param target_function A pointer to the function that should be - // patched. - // - // @param replacement_function A pointer to the function that should - // replace the target function. The replacement function must have - // exactly the same calling convention and parameters as the original - // function. - // - // @param original_function_stub Pointer to memory that should receive a - // pointer that can be used (e.g. in the replacement function) to call the - // original function, or NULL to indicate failure. - // - // @param original_function_stub Pointer to memory that should receive a - // pointer that can be used (e.g. in the replacement function) to call the - // original function, or NULL to indicate failure. - // - // @return One of the EnSideStepError error codes; only SIDESTEP_SUCCESS - // indicates success. - // - // @note The preamble-stub (the memory pointed to by - // *original_function_stub) is allocated on the heap, and (in - // production binaries) never destroyed, resulting in a memory leak. This - // will be the case until we implement safe unpatching of a method. - // However, it is quite difficult to unpatch a method (because other - // threads in the process may be using it) so we are leaving it for now. - // See however UnsafeUnpatch, which can be used for binaries where you - // know only one thread is running, e.g. unit tests. - static SideStepError RawPatch(void* target_function, - void* replacement_function, - void** original_function_stub); - - // Unpatches target_function and deletes the stub that previously could be - // used to call the original version of the function. - // - // DELETES the stub that is passed to the function. - // - // @param target_function Pointer to the target function which was - // previously patched, i.e. a pointer which value should match the value - // of the symbol prior to patching it. - // - // @param replacement_function Pointer to the function target_function - // was patched to. - // - // @param original_function_stub Pointer to the stub returned when - // patching, that could be used to call the original version of the - // patched function. This function will also delete the stub, which after - // unpatching is useless. - // - // If your original call was - // Patch(VirtualAlloc, MyVirtualAlloc, &origptr) - // then to undo it you would call - // Unpatch(VirtualAlloc, MyVirtualAlloc, origptr); - // - // @return One of the EnSideStepError error codes; only SIDESTEP_SUCCESS - // indicates success. - static SideStepError Unpatch(void* target_function, - void* replacement_function, - void* original_function_stub); - - // A helper routine when patching, which follows jmp instructions at - // function addresses, to get to the "actual" function contents. - // This allows us to identify two functions that are at different - // addresses but actually resolve to the same code. - // - // @param target_function Pointer to a function. - // - // @return Either target_function (the input parameter), or if - // target_function's body consists entirely of a JMP instruction, - // the address it JMPs to (or more precisely, the address at the end - // of a chain of JMPs). - template <class T> - static T ResolveTarget(T target_function) { - return (T)ResolveTargetImpl((unsigned char*)target_function, NULL); - } - - // Allocates a block of memory of size MAX_PREAMBLE_STUB_SIZE that is as - // close (within 2GB) as possible to target. This is done to ensure that - // we can perform a relative jump from target to a trampoline if the - // replacement function is > +-2GB from target. This means that we only need - // to patch 5 bytes in the target function. - // - // @param target Pointer to target function. - // - // @return Returns a block of memory of size MAX_PREAMBLE_STUB_SIZE that can - // be used to store a function preamble block. - static unsigned char* AllocPreambleBlockNear(void* target); - - // Frees a block allocated by AllocPreambleBlockNear. - // - // @param block Block that was returned by AllocPreambleBlockNear. - static void FreePreambleBlock(unsigned char* block); - - private: - friend class DeleteUnsignedCharArray; - - // Used to store data allocated for preamble stubs - struct PreamblePage { - unsigned int magic_; - PreamblePage* next_; - // This member points to a linked list of free blocks within the page - // or NULL if at the end - void* free_; - }; - - // In 64-bit mode, the replacement function must be within 2GB of the original - // target in order to only require 5 bytes for the function patch. To meet - // this requirement we're creating an allocator within this class to - // allocate blocks that are within 2GB of a given target. This member is the - // head of a linked list of pages used to allocate blocks that are within - // 2GB of the target. - static PreamblePage* preamble_pages_; - - // Page granularity - static long granularity_; - - // Page size - static long pagesize_; - - // Determines if the patcher has been initialized. - static bool initialized_; - - // Used to initialize static members. - static void Initialize(); - - // Patches a function by overwriting its first few bytes with - // a jump to a different function. This is similar to the RawPatch - // function except that it uses the stub allocated by the caller - // instead of allocating it. - // - // We call VirtualProtect to make the - // target function writable at least for the duration of the call. - // - // @param target_function A pointer to the function that should be - // patched. - // - // @param replacement_function A pointer to the function that should - // replace the target function. The replacement function must have - // exactly the same calling convention and parameters as the original - // function. - // - // @param preamble_stub A pointer to a buffer where the preamble stub - // should be copied. The size of the buffer should be sufficient to - // hold the preamble bytes. - // - // @param stub_size Size in bytes of the buffer allocated for the - // preamble_stub - // - // @param bytes_needed Pointer to a variable that receives the minimum - // number of bytes required for the stub. Can be set to NULL if you're - // not interested. - // - // @return An error code indicating the result of patching. - static SideStepError RawPatchWithStubAndProtections( - void* target_function, - void* replacement_function, - unsigned char* preamble_stub, - unsigned long stub_size, - unsigned long* bytes_needed); - - // A helper function used by RawPatchWithStubAndProtections -- it - // does everything but the VirtualProtect work. Defined in - // preamble_patcher_with_stub.cc. - // - // @param target_function A pointer to the function that should be - // patched. - // - // @param replacement_function A pointer to the function that should - // replace the target function. The replacement function must have - // exactly the same calling convention and parameters as the original - // function. - // - // @param preamble_stub A pointer to a buffer where the preamble stub - // should be copied. The size of the buffer should be sufficient to - // hold the preamble bytes. - // - // @param stub_size Size in bytes of the buffer allocated for the - // preamble_stub - // - // @param bytes_needed Pointer to a variable that receives the minimum - // number of bytes required for the stub. Can be set to NULL if you're - // not interested. - // - // @return An error code indicating the result of patching. - static SideStepError RawPatchWithStub(void* target_function, - void* replacement_function, - unsigned char* preamble_stub, - unsigned long stub_size, - unsigned long* bytes_needed); - - - // A helper routine when patching, which follows jmp instructions at - // function addresses, to get to the "actual" function contents. - // This allows us to identify two functions that are at different - // addresses but actually resolve to the same code. - // - // @param target_function Pointer to a function. - // - // @param stop_before If, when following JMP instructions from - // target_function, we get to the address stop, we return - // immediately, the address that jumps to stop_before. - // - // @param stop_before_trampoline When following JMP instructions from - // target_function, stop before a trampoline is detected. See comment in - // PreamblePatcher::RawPatchWithStub for more information. This parameter - // has no effect in 32-bit mode. - // - // @return Either target_function (the input parameter), or if - // target_function's body consists entirely of a JMP instruction, - // the address it JMPs to (or more precisely, the address at the end - // of a chain of JMPs). - static void* ResolveTargetImpl(unsigned char* target_function, - unsigned char* stop_before, - bool stop_before_trampoline = false); - - // Helper routine that attempts to allocate a page as close (within 2GB) - // as possible to target. - // - // @param target Pointer to target function. - // - // @return Returns an address that is within 2GB of target. - static void* AllocPageNear(void* target); - - // Helper routine that determines if a target instruction is a short - // conditional jump. - // - // @param target Pointer to instruction. - // - // @param instruction_size Size of the instruction in bytes. - // - // @return Returns true if the instruction is a short conditional jump. - static bool IsShortConditionalJump(unsigned char* target, - unsigned int instruction_size); - - static bool IsShortJump(unsigned char *target, unsigned int instruction_size); - - // Helper routine that determines if a target instruction is a near - // conditional jump. - // - // @param target Pointer to instruction. - // - // @param instruction_size Size of the instruction in bytes. - // - // @return Returns true if the instruction is a near conditional jump. - static bool IsNearConditionalJump(unsigned char* target, - unsigned int instruction_size); - - // Helper routine that determines if a target instruction is a near - // relative jump. - // - // @param target Pointer to instruction. - // - // @param instruction_size Size of the instruction in bytes. - // - // @return Returns true if the instruction is a near absolute jump. - static bool IsNearRelativeJump(unsigned char* target, - unsigned int instruction_size); - - // Helper routine that determines if a target instruction is a near - // absolute call. - // - // @param target Pointer to instruction. - // - // @param instruction_size Size of the instruction in bytes. - // - // @return Returns true if the instruction is a near absolute call. - static bool IsNearAbsoluteCall(unsigned char* target, - unsigned int instruction_size); - - // Helper routine that determines if a target instruction is a near - // absolute call. - // - // @param target Pointer to instruction. - // - // @param instruction_size Size of the instruction in bytes. - // - // @return Returns true if the instruction is a near absolute call. - static bool IsNearRelativeCall(unsigned char* target, - unsigned int instruction_size); - - // Helper routine that determines if a target instruction is a 64-bit MOV - // that uses a RIP-relative displacement. - // - // @param target Pointer to instruction. - // - // @param instruction_size Size of the instruction in bytes. - // - // @return Returns true if the instruction is a MOV with displacement. - static bool IsMovWithDisplacement(unsigned char* target, - unsigned int instruction_size); - - // Helper routine that converts a short conditional jump instruction - // to a near conditional jump in a target buffer. Note that the target - // buffer must be within 2GB of the source for the near jump to work. - // - // A short conditional jump instruction is in the format: - // 7x xx = Jcc rel8off - // - // @param source Pointer to instruction. - // - // @param instruction_size Size of the instruction. - // - // @param target Target buffer to write the new instruction. - // - // @param target_bytes Pointer to a buffer that contains the size - // of the target instruction, in bytes. - // - // @param target_size Size of the target buffer. - // - // @return Returns SIDESTEP_SUCCESS if successful, otherwise an error. - static SideStepError PatchShortConditionalJump(unsigned char* source, - unsigned int instruction_size, - unsigned char* target, - unsigned int* target_bytes, - unsigned int target_size); - - static SideStepError PatchShortJump(unsigned char* source, - unsigned int instruction_size, - unsigned char* target, - unsigned int* target_bytes, - unsigned int target_size); - - // Helper routine that converts an instruction that will convert various - // jump-like instructions to corresponding instructions in the target buffer. - // What this routine does is fix up the relative offsets contained in jump - // instructions to point back to the original target routine. Like with - // PatchShortConditionalJump, the target buffer must be within 2GB of the - // source. - // - // We currently handle the following instructions: - // - // E9 xx xx xx xx = JMP rel32off - // 0F 8x xx xx xx xx = Jcc rel32off - // FF /2 xx xx xx xx = CALL reg/mem32/mem64 - // E8 xx xx xx xx = CALL rel32off - // - // It should not be hard to update this function to support other - // instructions that jump to relative targets. - // - // @param source Pointer to instruction. - // - // @param instruction_size Size of the instruction. - // - // @param target Target buffer to write the new instruction. - // - // @param target_bytes Pointer to a buffer that contains the size - // of the target instruction, in bytes. - // - // @param target_size Size of the target buffer. - // - // @return Returns SIDESTEP_SUCCESS if successful, otherwise an error. - static SideStepError PatchNearJumpOrCall(unsigned char* source, - unsigned int instruction_size, - unsigned char* target, - unsigned int* target_bytes, - unsigned int target_size); - - // Helper routine that patches a 64-bit MOV instruction with a RIP-relative - // displacement. The target buffer must be within 2GB of the source. - // - // 48 8B 0D XX XX XX XX = MOV rel32off - // - // @param source Pointer to instruction. - // - // @param instruction_size Size of the instruction. - // - // @param target Target buffer to write the new instruction. - // - // @param target_bytes Pointer to a buffer that contains the size - // of the target instruction, in bytes. - // - // @param target_size Size of the target buffer. - // - // @return Returns SIDESTEP_SUCCESS if successful, otherwise an error. - static SideStepError PatchMovWithDisplacement(unsigned char* source, - unsigned int instruction_size, - unsigned char* target, - unsigned int* target_bytes, - unsigned int target_size); -}; - -}; // namespace sidestep - -#endif // GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_ |