Home | History | Annotate | Download | only in chrome_frame
      1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef CHROME_FRAME_VTABLE_PATCH_MANAGER_H_
      6 #define CHROME_FRAME_VTABLE_PATCH_MANAGER_H_
      7 
      8 #include <windows.h>
      9 
     10 #include <list>
     11 
     12 #include "base/synchronization/lock.h"
     13 
     14 struct FunctionStub;
     15 
     16 // This namespace provides methods to patch VTable methods of COM interfaces.
     17 namespace vtable_patch {
     18 
     19 // Internal implementation, exposed only for testing.
     20 namespace internal {
     21 
     22 // Replaces *entry with new_proc iff *entry is curr_proc.
     23 // Returns true iff *entry was rewritten.
     24 // Note: does not crash on access violation.
     25 bool ReplaceFunctionPointer(void** entry, void* new_proc, void* curr_proc);
     26 
     27 }  // namespace internal
     28 
     29 // This structure represents information about one VTable method.
     30 // We allocate an array of these structures per VTable that we patch to
     31 // remember the original method. We also use this structure to actually
     32 // describe the VTable patch functions
     33 struct MethodPatchInfo {
     34   int index_;
     35   PROC method_;
     36   FunctionStub* stub_;
     37 };
     38 
     39 // Patches methods in the passed in COM interface. The indexes of the
     40 // methods to patch and the actual patch functions are described in the
     41 // array pointed to by patches.
     42 // @param[in] unknown  The pointer of the COM interface to patch
     43 // @param[in] patches  An array of MethodPatchInfo structures describing
     44 //  the methods to patch and the patch functions.
     45 //  The last entry of patches must have index_ set to -1.
     46 HRESULT PatchInterfaceMethods(void* unknown, MethodPatchInfo* patches);
     47 
     48 // Using the patch info provided in |patches| the function goes through the
     49 // list of patched methods and modifies thunks so that they no longer point
     50 // to a hook method but rather go straight through to the original target.
     51 // The thunk itself is not destroyed to support chaining.
     52 // @param[in] patches  An array of MethodPatchInfo structures describing
     53 //  the methods to patch and the patch functions.
     54 //  The last entry of patches must have index_ set to -1.
     55 HRESULT UnpatchInterfaceMethods(MethodPatchInfo* patches);
     56 
     57 // Disabled as we're not using it atm.
     58 #if 0
     59 // Used when dynamically patching zero or more (usually more than 1)
     60 // implementations of a particular interface.
     61 class DynamicPatchManager {
     62  public:
     63   explicit DynamicPatchManager(const MethodPatchInfo* patch_prototype);
     64   ~DynamicPatchManager();
     65 
     66   // Returns S_OK if the object was successfully patched, S_FALSE if it was
     67   // already patched or an error value if something bad happened.
     68   HRESULT PatchObject(void* unknown);
     69 
     70   bool UnpatchAll();
     71 
     72  protected:
     73   struct PatchedObject {
     74     void* vtable_;
     75     MethodPatchInfo patch_info_[1];
     76 
     77     // Used to match PatchedObject instances based on the vtable when
     78     // searching through the patch list.
     79     bool operator==(const PatchedObject& that) const {
     80       return vtable_ == that.vtable_;
     81     }
     82   };
     83 
     84   typedef std::list<PatchedObject*> PatchList;
     85   const MethodPatchInfo* patch_prototype_;
     86   mutable base::Lock patch_list_lock_;
     87   PatchList patch_list_;
     88 };
     89 #endif  // disable DynamicPatchManager
     90 
     91 }  // namespace vtable_patch
     92 
     93 // Begins the declaration of a VTable patch
     94 // @param IFName The name of the interface to patch
     95 #define BEGIN_VTABLE_PATCHES(IFName) \
     96     vtable_patch::MethodPatchInfo IFName##_PatchInfo[] = {
     97 // Defines a single method patch in a VTable
     98 // @param index The index of the method to patch
     99 // @param PatchFunction The patch function
    100 #define VTABLE_PATCH_ENTRY(index, PatchFunction) {\
    101       index, \
    102       reinterpret_cast<PROC>(PatchFunction), \
    103       NULL, \
    104     },
    105 
    106 #define DCHECK_IS_NOT_PATCHED(IFName) \
    107     for (vtable_patch::MethodPatchInfo* it = IFName##_PatchInfo; \
    108          it->index_ != -1; ++it) { \
    109       DCHECK(it->stub_ == NULL); \
    110     }
    111 
    112 #define DCHECK_IS_PATCHED(IFName) \
    113     for (vtable_patch::MethodPatchInfo* it = IFName##_PatchInfo; \
    114          it->index_ != -1; ++it) { \
    115       DCHECK(it->stub_ != NULL); \
    116     }
    117 
    118 // Checks if the interface is patched.  Note that only the first method
    119 // is checked and subsequent methods are assumed to have the same state.
    120 #define IS_PATCHED(IFName) \
    121   (IFName##_PatchInfo[0].stub_ != NULL)
    122 
    123 // Ends the declaration of a VTable patch by adding an entry with
    124 // index set to -1.
    125 #define END_VTABLE_PATCHES() \
    126       -1, NULL, NULL \
    127     };
    128 
    129 #endif  // CHROME_FRAME_VTABLE_PATCH_MANAGER_H_
    130