Index: chrome_frame/function_stub.cc |
=================================================================== |
--- chrome_frame/function_stub.cc (revision 0) |
+++ chrome_frame/function_stub.cc (revision 0) |
@@ -0,0 +1,141 @@ |
+// 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/function_stub.h" |
+ |
+#include <new> |
+#include "base/lock.h" |
+#include "base/logging.h" |
+ |
+#ifndef _M_IX86 |
+#error Only x86 supported right now. |
+#endif |
+ |
+namespace { |
+typedef enum AsmConstants { |
+ POP_EAX = 0x58, |
+ PUSH_IND = 0x35ff, |
+ PUSH_EAX = 0x50, |
+ JUMP_IND = 0x25ff, |
+}; |
+ |
+// A quick and dirty wrapper class that allows us to defer allocating |
+// the executable heap until first use, and to release it teardown. |
+class ExecutableHeap { |
+ public: |
+ ExecutableHeap() : heap_(NULL) { |
+ } |
+ |
+ ~ExecutableHeap() { |
+ if (heap_ != NULL) { |
+ BOOL ret = ::HeapDestroy(heap_); |
+ heap_ = NULL; |
+ } |
+ } |
+ |
+ void* Allocate(size_t size) { |
+ if (!heap_) |
+ CreateHeap(); |
+ |
+ DCHECK(heap_); |
+ |
+ return ::HeapAlloc(heap_, 0, size); |
+ } |
+ |
+ void Free(void* ptr) { |
+ DCHECK(heap_ != NULL); |
+ ::HeapFree(heap_, 0, ptr); |
+ } |
+ |
+ void CreateHeap() { |
+ AutoLock lock(init_lock_); |
+ |
+ if (heap_ == NULL) |
+ heap_ = ::HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0); |
+ } |
+ |
+ private: |
+ Lock init_lock_; |
+ HANDLE heap_; |
+}; |
+ |
+// Our executable heap instance, all stubs are allocated from here. |
+ExecutableHeap heap_; |
+ |
+} // namespace |
+ |
+extern "C" IMAGE_DOS_HEADER __ImageBase; |
+ |
+bool FunctionStub::is_valid() const { |
+ return signature_ == reinterpret_cast<HMODULE>(&__ImageBase) && |
+ !is_bypassed(); |
+} |
+ |
+FunctionStub::FunctionStub(uintptr_t extra_argument, void* dest) |
+ : signature_(reinterpret_cast<HMODULE>(&__ImageBase)), |
+ argument_(extra_argument), |
+ destination_function_(reinterpret_cast<uintptr_t>(dest)) { |
+ bypass_address_ = reinterpret_cast<uintptr_t>(&stub_.pop_return_addr_); |
+ Init(&stub_); |
+} |
+ |
+FunctionStub::~FunctionStub() { |
+} |
+ |
+void FunctionStub::Init(FunctionStubAsm* stub) { |
+ DCHECK(stub != NULL); |
+ |
+ stub->jump_to_bypass_ = JUMP_IND; |
+ stub->bypass_target_addr_ = reinterpret_cast<uintptr_t>(&bypass_address_); |
+ stub->pop_return_addr_ = POP_EAX; |
+ stub->push_ = PUSH_IND; |
+ stub->arg_addr_ = reinterpret_cast<uintptr_t>(&argument_); |
+ stub->push_return_addr_ = PUSH_EAX; |
+ stub->jump_to_target = JUMP_IND; |
+ stub->target_addr_ = reinterpret_cast<uintptr_t>(&destination_function_); |
+ |
+ // Flush the instruction cache for the newly written code. |
+ BOOL ret = ::FlushInstructionCache(::GetCurrentProcess(), |
+ stub, |
+ sizeof(*stub)); |
+} |
+ |
+void FunctionStub::BypassStub(void* new_target) { |
+ set_bypass_address(reinterpret_cast<uintptr_t>(new_target)); |
+} |
+ |
+FunctionStub* FunctionStub::Create(uintptr_t extra_argument, void* dest) { |
+ DCHECK(dest); |
+ FunctionStub* stub = |
+ reinterpret_cast<FunctionStub*>(heap_.Allocate(sizeof(FunctionStub))); |
+ |
+ if (stub != NULL) |
+ new (stub) FunctionStub(extra_argument, dest); |
+ |
+ return stub; |
+} |
+ |
+FunctionStub* FunctionStub::FromCode(void* address) { |
+ // Address points to arbitrary code here, which may e.g. |
+ // lie at the end of an executable segment, which in turn |
+ // may terminate earlier than the last address we probe. |
+ // We therefore execute under an SEH, so as not to crash |
+ // on failed probes. |
+ __try { |
+ // Retrieve the candidata function stub. |
+ FunctionStub* candidate = CONTAINING_RECORD(address, FunctionStub, stub_); |
+ if (candidate->stub_.jump_to_bypass_ == JUMP_IND && |
+ candidate->signature_ == reinterpret_cast<HMODULE>(&__ImageBase)) { |
+ return candidate; |
+ } |
+ } __except(EXCEPTION_EXECUTE_HANDLER) { |
+ } |
+ |
+ return NULL; |
+} |
+ |
+bool FunctionStub::Destroy(FunctionStub* stub) { |
+ heap_.Free(stub); |
+ |
+ return true; |
+} |
Property changes on: chrome_frame\function_stub.cc |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |