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.
5 #include "chrome_frame/function_stub.h"
9 #include "base/synchronization/lock.h"
10 #include "base/logging.h"
13 #error Only x86 supported right now.
17 typedef enum AsmConstants
{
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
{
28 ExecutableHeap() : heap_(NULL
) {
33 BOOL ret
= ::HeapDestroy(heap_
);
38 void* Allocate(size_t size
) {
44 return ::HeapAlloc(heap_
, 0, size
);
47 void Free(void* ptr
) {
48 DCHECK(heap_
!= NULL
);
49 ::HeapFree(heap_
, 0, ptr
);
53 base::AutoLock
lock(init_lock_
);
56 heap_
= ::HeapCreate(HEAP_CREATE_ENABLE_EXECUTE
, 0, 0);
60 base::Lock init_lock_
;
64 // Our executable heap instance, all stubs are allocated from here.
69 extern "C" IMAGE_DOS_HEADER __ImageBase
;
71 bool FunctionStub::is_valid() const {
72 return signature_
== reinterpret_cast<HMODULE
>(&__ImageBase
) &&
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_
);
84 FunctionStub::~FunctionStub() {
87 void FunctionStub::Init(FunctionStubAsm
* stub
) {
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_
);
99 // Flush the instruction cache for the newly written code.
100 BOOL ret
= ::FlushInstructionCache(::GetCurrentProcess(),
105 void FunctionStub::BypassStub(void* new_target
) {
106 set_bypass_address(reinterpret_cast<uintptr_t>(new_target
));
109 FunctionStub
* FunctionStub::Create(uintptr_t extra_argument
, void* dest
) {
112 reinterpret_cast<FunctionStub
*>(heap_
.Allocate(sizeof(FunctionStub
)));
115 new (stub
) FunctionStub(extra_argument
, dest
);
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
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
)) {
133 } __except(EXCEPTION_EXECUTE_HANDLER
) {
139 bool FunctionStub::Destroy(FunctionStub
* stub
) {