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