• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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