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 |