summaryrefslogtreecommitdiffstats
path: root/chrome_frame/vtable_patch_manager.cc
diff options
context:
space:
mode:
authorslightlyoff@chromium.org <slightlyoff@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-24 05:11:58 +0000
committerslightlyoff@chromium.org <slightlyoff@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-24 05:11:58 +0000
commitf781782dd67077478e117c61dca4ea5eefce3544 (patch)
tree4801f724123cfdcbb69c4e7fe40a565b331723ae /chrome_frame/vtable_patch_manager.cc
parent63cf4759efa2373e33436fb5df6849f930081226 (diff)
downloadchromium_src-f781782dd67077478e117c61dca4ea5eefce3544.zip
chromium_src-f781782dd67077478e117c61dca4ea5eefce3544.tar.gz
chromium_src-f781782dd67077478e117c61dca4ea5eefce3544.tar.bz2
Initial import of the Chrome Frame codebase. Integration in chrome.gyp coming in a separate CL.
BUG=None TEST=None Review URL: http://codereview.chromium.org/218019 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@27042 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame/vtable_patch_manager.cc')
-rw-r--r--chrome_frame/vtable_patch_manager.cc82
1 files changed, 82 insertions, 0 deletions
diff --git a/chrome_frame/vtable_patch_manager.cc b/chrome_frame/vtable_patch_manager.cc
new file mode 100644
index 0000000..5f15158
--- /dev/null
+++ b/chrome_frame/vtable_patch_manager.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2009 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 "chrome_frame/vtable_patch_manager.h"
+
+#include "base/logging.h"
+
+#include "chrome_frame/function_stub.h"
+
+namespace vtable_patch {
+
+// Convenient definition of a VTABLE
+typedef PROC* Vtable;
+
+// Returns a pointer to the VTable of a COM interface.
+// @param unknown [in] The pointer of the COM interface.
+inline Vtable GetIFVTable(void* unknown) {
+ return reinterpret_cast<Vtable>(*reinterpret_cast<void**>(unknown));
+}
+
+HRESULT PatchInterfaceMethods(void* unknown, MethodPatchInfo* patches) {
+ // Do some sanity checking of the input arguments.
+ if (NULL == unknown || NULL == patches) {
+ NOTREACHED();
+ return E_INVALIDARG;
+ }
+
+ Vtable vtable = GetIFVTable(unknown);
+ DCHECK(vtable);
+
+ for (MethodPatchInfo* it = patches; it->index_ != -1; ++it) {
+ PROC original_fn = vtable[it->index_];
+ FunctionStub* stub = FunctionStub::FromCode(original_fn);
+ if (stub != NULL) {
+ DLOG(ERROR) << "attempt to patch a function that's already patched";
+ DCHECK(stub->absolute_target() ==
+ reinterpret_cast<uintptr_t>(it->method_)) <<
+ "patching the same method multiple times with different hooks?";
+ continue;
+ }
+
+ stub = FunctionStub::Create(reinterpret_cast<uintptr_t>(original_fn),
+ it->method_);
+ if (!stub) {
+ NOTREACHED();
+ return E_OUTOFMEMORY;
+ } else {
+ DWORD protect = 0;
+ if (::VirtualProtect(&vtable[it->index_], sizeof(PROC),
+ PAGE_EXECUTE_READWRITE, &protect)) {
+ it->stub_ = stub; // save the stub
+ vtable[it->index_] = stub->code();
+ ::VirtualProtect(&vtable[it->index_], sizeof(PROC), protect,
+ &protect);
+ } else {
+ NOTREACHED();
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT UnpatchInterfaceMethods(MethodPatchInfo* patches) {
+ for (MethodPatchInfo* it = patches; it->index_ != -1; ++it) {
+ if (it->stub_) {
+ DCHECK(it->stub_->absolute_target() ==
+ reinterpret_cast<uintptr_t>(it->method_));
+ // Modify the stub to just jump directly to the original function.
+ it->stub_->BypassStub(reinterpret_cast<void*>(it->stub_->argument()));
+ it->stub_ = NULL;
+ // Leave the stub in memory so that we won't break any possible chains.
+ } else {
+ DLOG(WARNING) << "attempt to unpatch a function that wasn't patched";
+ }
+ }
+
+ return S_OK;
+}
+
+} // namespace vtable_patch