OLD | NEW |
(Empty) | |
| 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 #include "chrome_frame/function_stub.h" |
| 5 |
| 6 #include <new> |
| 7 #include "base/lock.h" |
| 8 #include "base/logging.h" |
| 9 |
| 10 #ifndef _M_IX86 |
| 11 #error Only x86 supported right now. |
| 12 #endif |
| 13 |
| 14 namespace { |
| 15 typedef enum AsmConstants { |
| 16 POP_EAX = 0x58, |
| 17 PUSH_IND = 0x35ff, |
| 18 PUSH_EAX = 0x50, |
| 19 JUMP_IND = 0x25ff, |
| 20 }; |
| 21 |
| 22 // A quick and dirty wrapper class that allows us to defer allocating |
| 23 // the executable heap until first use, and to release it teardown. |
| 24 class ExecutableHeap { |
| 25 public: |
| 26 ExecutableHeap() : heap_(NULL) { |
| 27 } |
| 28 |
| 29 ~ExecutableHeap() { |
| 30 if (heap_ != NULL) { |
| 31 BOOL ret = ::HeapDestroy(heap_); |
| 32 heap_ = NULL; |
| 33 } |
| 34 } |
| 35 |
| 36 void* Allocate(size_t size) { |
| 37 if (!heap_) |
| 38 CreateHeap(); |
| 39 |
| 40 DCHECK(heap_); |
| 41 |
| 42 return ::HeapAlloc(heap_, 0, size); |
| 43 } |
| 44 |
| 45 void Free(void* ptr) { |
| 46 DCHECK(heap_ != NULL); |
| 47 ::HeapFree(heap_, 0, ptr); |
| 48 } |
| 49 |
| 50 void CreateHeap() { |
| 51 AutoLock lock(init_lock_); |
| 52 |
| 53 if (heap_ == NULL) |
| 54 heap_ = ::HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0); |
| 55 } |
| 56 |
| 57 private: |
| 58 Lock init_lock_; |
| 59 HANDLE heap_; |
| 60 }; |
| 61 |
| 62 // Our executable heap instance, all stubs are allocated from here. |
| 63 ExecutableHeap heap_; |
| 64 |
| 65 } // namespace |
| 66 |
| 67 extern "C" IMAGE_DOS_HEADER __ImageBase; |
| 68 |
| 69 bool FunctionStub::is_valid() const { |
| 70 return signature_ == reinterpret_cast<HMODULE>(&__ImageBase) && |
| 71 !is_bypassed(); |
| 72 } |
| 73 |
| 74 FunctionStub::FunctionStub(uintptr_t extra_argument, void* dest) |
| 75 : signature_(reinterpret_cast<HMODULE>(&__ImageBase)), |
| 76 argument_(extra_argument), |
| 77 destination_function_(reinterpret_cast<uintptr_t>(dest)) { |
| 78 bypass_address_ = reinterpret_cast<uintptr_t>(&stub_.pop_return_addr_); |
| 79 Init(&stub_); |
| 80 } |
| 81 |
| 82 FunctionStub::~FunctionStub() { |
| 83 } |
| 84 |
| 85 void FunctionStub::Init(FunctionStubAsm* stub) { |
| 86 DCHECK(stub != NULL); |
| 87 |
| 88 stub->jump_to_bypass_ = JUMP_IND; |
| 89 stub->bypass_target_addr_ = reinterpret_cast<uintptr_t>(&bypass_address_); |
| 90 stub->pop_return_addr_ = POP_EAX; |
| 91 stub->push_ = PUSH_IND; |
| 92 stub->arg_addr_ = reinterpret_cast<uintptr_t>(&argument_); |
| 93 stub->push_return_addr_ = PUSH_EAX; |
| 94 stub->jump_to_target = JUMP_IND; |
| 95 stub->target_addr_ = reinterpret_cast<uintptr_t>(&destination_function_); |
| 96 |
| 97 // Flush the instruction cache for the newly written code. |
| 98 BOOL ret = ::FlushInstructionCache(::GetCurrentProcess(), |
| 99 stub, |
| 100 sizeof(*stub)); |
| 101 } |
| 102 |
| 103 void FunctionStub::BypassStub(void* new_target) { |
| 104 set_bypass_address(reinterpret_cast<uintptr_t>(new_target)); |
| 105 } |
| 106 |
| 107 FunctionStub* FunctionStub::Create(uintptr_t extra_argument, void* dest) { |
| 108 DCHECK(dest); |
| 109 FunctionStub* stub = |
| 110 reinterpret_cast<FunctionStub*>(heap_.Allocate(sizeof(FunctionStub))); |
| 111 |
| 112 if (stub != NULL) |
| 113 new (stub) FunctionStub(extra_argument, dest); |
| 114 |
| 115 return stub; |
| 116 } |
| 117 |
| 118 FunctionStub* FunctionStub::FromCode(void* address) { |
| 119 // Address points to arbitrary code here, which may e.g. |
| 120 // lie at the end of an executable segment, which in turn |
| 121 // may terminate earlier than the last address we probe. |
| 122 // We therefore execute under an SEH, so as not to crash |
| 123 // on failed probes. |
| 124 __try { |
| 125 // Retrieve the candidata function stub. |
| 126 FunctionStub* candidate = CONTAINING_RECORD(address, FunctionStub, stub_); |
| 127 if (candidate->stub_.jump_to_bypass_ == JUMP_IND && |
| 128 candidate->signature_ == reinterpret_cast<HMODULE>(&__ImageBase)) { |
| 129 return candidate; |
| 130 } |
| 131 } __except(EXCEPTION_EXECUTE_HANDLER) { |
| 132 } |
| 133 |
| 134 return NULL; |
| 135 } |
| 136 |
| 137 bool FunctionStub::Destroy(FunctionStub* stub) { |
| 138 heap_.Free(stub); |
| 139 |
| 140 return true; |
| 141 } |
OLD | NEW |