root/third_party/tcmalloc/chromium/src/windows/preamble_patcher.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


/* 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);

  // 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);

  // 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_

/* [<][>][^][v][top][bottom][index][help] */