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"
8 #include "base/logging.h"
11 #error Only x86 supported right now.
15 typedef enum AsmConstants
{
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
{
26 ExecutableHeap() : heap_(NULL
) {
31 BOOL ret
= ::HeapDestroy(heap_
);
36 void* Allocate(size_t size
) {
42 return ::HeapAlloc(heap_
, 0, size
);
45 void Free(void* ptr
) {
46 DCHECK(heap_
!= NULL
);
47 ::HeapFree(heap_
, 0, ptr
);
51 AutoLock
lock(init_lock_
);
54 heap_
= ::HeapCreate(HEAP_CREATE_ENABLE_EXECUTE
, 0, 0);
62 // Our executable heap instance, all stubs are allocated from here.
67 extern "C" IMAGE_DOS_HEADER __ImageBase
;
69 bool FunctionStub::is_valid() const {
70 return signature_
== reinterpret_cast<HMODULE
>(&__ImageBase
) &&
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_
);
82 FunctionStub::~FunctionStub() {
85 void FunctionStub::Init(FunctionStubAsm
* stub
) {
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_
);
97 // Flush the instruction cache for the newly written code.
98 BOOL ret
= ::FlushInstructionCache(::GetCurrentProcess(),
103 void FunctionStub::BypassStub(void* new_target
) {
104 set_bypass_address(reinterpret_cast<uintptr_t>(new_target
));
107 FunctionStub
* FunctionStub::Create(uintptr_t extra_argument
, void* dest
) {
110 reinterpret_cast<FunctionStub
*>(heap_
.Allocate(sizeof(FunctionStub
)));
113 new (stub
) FunctionStub(extra_argument
, dest
);
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
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
)) {
131 } __except(EXCEPTION_EXECUTE_HANDLER
) {
137 bool FunctionStub::Destroy(FunctionStub
* stub
) {