|
pred@2504
|
1 |
/** |
|
pred@2504
|
2 |
* vim: set ts=4 : |
|
pred@2504
|
3 |
* ============================================================================= |
|
pred@2504
|
4 |
* SourceMod BinTools Extension |
|
ds@3104
|
5 |
* Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved. |
|
pred@2504
|
6 |
* ============================================================================= |
|
pred@2504
|
7 |
* |
|
pred@2504
|
8 |
* This program is free software; you can redistribute it and/or modify it under |
|
pred@2504
|
9 |
* the terms of the GNU General Public License, version 3.0, as published by the |
|
pred@2504
|
10 |
* Free Software Foundation. |
|
pred@2504
|
11 |
* |
|
pred@2504
|
12 |
* This program is distributed in the hope that it will be useful, but WITHOUT |
|
pred@2504
|
13 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|
pred@2504
|
14 |
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
|
pred@2504
|
15 |
* details. |
|
pred@2504
|
16 |
* |
|
pred@2504
|
17 |
* You should have received a copy of the GNU General Public License along with |
|
pred@2504
|
18 |
* this program. If not, see <http://www.gnu.org/licenses/>. |
|
pred@2504
|
19 |
* |
|
pred@2504
|
20 |
* As a special exception, AlliedModders LLC gives you permission to link the |
|
pred@2504
|
21 |
* code of this program (as well as its derivative works) to "Half-Life 2," the |
|
pred@2504
|
22 |
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software |
|
pred@2504
|
23 |
* by the Valve Corporation. You must obey the GNU General Public License in |
|
pred@2504
|
24 |
* all respects for all other code used. Additionally, AlliedModders LLC grants |
|
pred@2504
|
25 |
* this exception to all derivative works. AlliedModders LLC defines further |
|
pred@2504
|
26 |
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), |
|
pred@2504
|
27 |
* or <http://www.sourcemod.net/license.php>. |
|
pred@2504
|
28 |
* |
|
pred@2504
|
29 |
* Version: $Id: CallMaker.h 1964 2008-03-27 04:54:56Z damagedsoul $ |
|
pred@2504
|
30 |
*/ |
|
pred@2504
|
31 |
|
|
pred@2504
|
32 |
#if defined HOOKING_ENABLED |
|
pred@2504
|
33 |
|
|
pred@2504
|
34 |
#include "HookWrapper.h" |
|
pred@2504
|
35 |
#include "jit_compile.h" |
|
pred@2504
|
36 |
|
|
pred@2504
|
37 |
/****************************** |
|
pred@2504
|
38 |
* HookWrapper Implementation * |
|
pred@2504
|
39 |
******************************/ |
|
pred@2504
|
40 |
|
|
pred@2504
|
41 |
HookWrapper::HookWrapper(SourceHook::ISourceHook *pSH, |
|
pred@2504
|
42 |
const SourceHook::ProtoInfo *proto, |
|
pred@2504
|
43 |
SourceHook::MemFuncInfo *memfunc, |
|
pred@2504
|
44 |
void *addr) : m_ParamOffs(NULL), m_ParamSize(0), m_RetSize(0) |
|
pred@2504
|
45 |
{ |
|
pred@2504
|
46 |
unsigned int argnum = proto->numOfParams; |
|
pred@2504
|
47 |
|
|
pred@2504
|
48 |
m_pSH = pSH; |
|
pred@2504
|
49 |
m_ProtoInfo = *proto; |
|
pred@2504
|
50 |
m_ProtoInfo.paramsPassInfo = new SourceHook::PassInfo[argnum + 1]; |
|
pred@2504
|
51 |
memcpy((void *)m_ProtoInfo.paramsPassInfo, proto->paramsPassInfo, sizeof(SourceHook::PassInfo) * (argnum+1)); |
|
pred@2504
|
52 |
m_MemFuncInfo = *memfunc; |
|
pred@2504
|
53 |
m_FuncAddr = addr; |
|
pred@2504
|
54 |
m_HookWrapper = NULL; |
|
pred@2504
|
55 |
|
|
pred@2504
|
56 |
/* If the function has parameters calculate the parameter buffer size and offsets */ |
|
pred@2504
|
57 |
if (argnum > 0) |
|
pred@2504
|
58 |
{ |
|
pred@2504
|
59 |
const SourceHook::PassInfo *info = m_ProtoInfo.paramsPassInfo; |
|
pred@2504
|
60 |
m_ParamOffs = new unsigned int[argnum]; |
|
pred@2504
|
61 |
m_ParamOffs[0] = 0; |
|
pred@2504
|
62 |
|
|
pred@2504
|
63 |
for (unsigned int i=1; i<=argnum; i++) |
|
pred@2504
|
64 |
{ |
|
pred@2504
|
65 |
/* The stack should be at least aligned to a 4 byte boundary |
|
pred@2504
|
66 |
* and byref params have the size of pointers |
|
pred@2504
|
67 |
*/ |
|
pred@2504
|
68 |
if (((info[i].type == SourceHook::PassInfo::PassType_Basic) && |
|
pred@2504
|
69 |
(info[i].flags & SourceHook::PassInfo::PassFlag_ByVal) && |
|
pred@2504
|
70 |
(info[i].size < sizeof(void *))) || |
|
pred@2504
|
71 |
(info[i].flags & SourceHook::PassInfo::PassFlag_ByRef)) |
|
pred@2504
|
72 |
{ |
|
pred@2504
|
73 |
m_ParamSize += sizeof(void *); |
|
pred@2504
|
74 |
} |
|
pred@2504
|
75 |
else |
|
pred@2504
|
76 |
{ |
|
pred@2504
|
77 |
m_ParamSize += info[i].size; |
|
pred@2504
|
78 |
} |
|
pred@2504
|
79 |
|
|
pred@2504
|
80 |
//:TODO: fix this! |
|
pred@2504
|
81 |
if (i < argnum) |
|
pred@2504
|
82 |
{ |
|
pred@2504
|
83 |
m_ParamOffs[i] = m_ParamSize; |
|
pred@2504
|
84 |
} |
|
pred@2504
|
85 |
} |
|
pred@2504
|
86 |
} |
|
pred@2504
|
87 |
|
|
pred@2504
|
88 |
/* Finally calculate the retval size if any */ |
|
pred@2504
|
89 |
size_t retsize = m_ProtoInfo.retPassInfo.size; |
|
pred@2504
|
90 |
if (retsize != 0) |
|
pred@2504
|
91 |
{ |
|
pred@2504
|
92 |
if (m_ProtoInfo.retPassInfo.flags & SourceHook::PassInfo::PassFlag_ByRef) |
|
pred@2504
|
93 |
{ |
|
pred@2504
|
94 |
m_RetSize = sizeof(void *); |
|
pred@2504
|
95 |
} |
|
pred@2504
|
96 |
else |
|
pred@2504
|
97 |
{ |
|
pred@2504
|
98 |
m_RetSize = (retsize < sizeof(void *)) ? sizeof(void *) : retsize; |
|
pred@2504
|
99 |
} |
|
pred@2504
|
100 |
} |
|
pred@2504
|
101 |
} |
|
pred@2504
|
102 |
|
|
pred@2504
|
103 |
ISMDelegate *HookWrapper::CreateDelegate(void *data) |
|
pred@2504
|
104 |
{ |
|
pred@2504
|
105 |
SMDelegate *pDeleg = new SMDelegate(data); |
|
pred@2504
|
106 |
pDeleg->PatchVtable(m_HookWrapper); |
|
pred@2504
|
107 |
|
|
pred@2504
|
108 |
return pDeleg; |
|
pred@2504
|
109 |
} |
|
pred@2504
|
110 |
|
|
pred@2504
|
111 |
unsigned int HookWrapper::GetParamCount() |
|
pred@2504
|
112 |
{ |
|
pred@2504
|
113 |
return m_ProtoInfo.numOfParams; |
|
pred@2504
|
114 |
} |
|
pred@2504
|
115 |
|
|
pred@2504
|
116 |
unsigned int HookWrapper::GetParamOffset(unsigned int argnum, unsigned int *size) |
|
pred@2504
|
117 |
{ |
|
pred@2504
|
118 |
assert(m_ParamOffs && argnum < (unsigned int)m_ProtoInfo.numOfParams); |
|
pred@2504
|
119 |
|
|
pred@2504
|
120 |
if (size) |
|
pred@2504
|
121 |
{ |
|
pred@2504
|
122 |
*size = m_ProtoInfo.paramsPassInfo[argnum+1].size; |
|
pred@2504
|
123 |
} |
|
pred@2504
|
124 |
|
|
pred@2504
|
125 |
return m_ParamOffs[argnum]; |
|
pred@2504
|
126 |
} |
|
pred@2504
|
127 |
|
|
pred@2504
|
128 |
void HookWrapper::PerformRecall(void *params, void *retval) |
|
pred@2504
|
129 |
{ |
|
pred@2504
|
130 |
/* Notify SourceHook of the upcoming recall */ |
|
ds@3104
|
131 |
m_pSH->DoRecall(); |
|
pred@2504
|
132 |
|
|
pred@2504
|
133 |
/* Add thisptr into params buffer */ |
|
pred@2504
|
134 |
unsigned char *newparams = new unsigned char[sizeof(void *) + m_ParamSize]; |
|
ds@3104
|
135 |
*(void **)newparams = m_pSH->GetIfacePtr(); |
|
pred@2504
|
136 |
memcpy(newparams + sizeof(void *), params, m_ParamSize); |
|
pred@2504
|
137 |
|
|
pred@2504
|
138 |
/* Execute the call */ |
|
pred@2504
|
139 |
m_CallWrapper->Execute(newparams, retval); |
|
pred@2504
|
140 |
|
|
ds@3104
|
141 |
m_pSH->SetRes(MRES_SUPERCEDE); |
|
pred@2504
|
142 |
|
|
pred@2504
|
143 |
return; |
|
pred@2504
|
144 |
} |
|
pred@2504
|
145 |
|
|
pred@2504
|
146 |
void HookWrapper::Destroy() |
|
pred@2504
|
147 |
{ |
|
pred@2504
|
148 |
if (m_HookWrapper != NULL) |
|
pred@2504
|
149 |
{ |
|
pred@2504
|
150 |
JIT_FreeHook(m_HookWrapper); |
|
pred@2504
|
151 |
} |
|
pred@2504
|
152 |
|
|
pred@2504
|
153 |
if (m_CallWrapper != NULL) |
|
pred@2504
|
154 |
{ |
|
pred@2504
|
155 |
m_CallWrapper->Destroy(); |
|
pred@2504
|
156 |
} |
|
pred@2504
|
157 |
|
|
pred@2504
|
158 |
delete this; |
|
pred@2504
|
159 |
} |
|
pred@2504
|
160 |
|
|
pred@2504
|
161 |
unsigned int HookWrapper::GetParamSize() |
|
pred@2504
|
162 |
{ |
|
pred@2504
|
163 |
return m_ParamSize; |
|
pred@2504
|
164 |
} |
|
pred@2504
|
165 |
|
|
pred@2504
|
166 |
SourceHook::ProtoInfo * HookWrapper::GetProtoInfo() |
|
pred@2504
|
167 |
{ |
|
pred@2504
|
168 |
return &m_ProtoInfo; |
|
pred@2504
|
169 |
} |
|
pred@2504
|
170 |
|
|
pred@2504
|
171 |
unsigned int HookWrapper::GetRetSize() |
|
pred@2504
|
172 |
{ |
|
pred@2504
|
173 |
return m_RetSize; |
|
pred@2504
|
174 |
} |
|
pred@2504
|
175 |
|
|
pred@2504
|
176 |
void * HookWrapper::GetHandlerAddr() |
|
pred@2504
|
177 |
{ |
|
pred@2504
|
178 |
return m_FuncAddr; |
|
pred@2504
|
179 |
} |
|
pred@2504
|
180 |
|
|
pred@2504
|
181 |
void HookWrapper::SetCallWrapperAddr( ICallWrapper *wrap ) |
|
pred@2504
|
182 |
{ |
|
pred@2504
|
183 |
m_CallWrapper = wrap; |
|
pred@2504
|
184 |
} |
|
pred@2504
|
185 |
|
|
pred@2504
|
186 |
void HookWrapper::SetHookWrpAddr( void *addr ) |
|
pred@2504
|
187 |
{ |
|
pred@2504
|
188 |
m_HookWrapper = addr; |
|
pred@2504
|
189 |
} |
|
pred@2504
|
190 |
|
|
pred@2504
|
191 |
HookWrapper::~HookWrapper() |
|
pred@2504
|
192 |
{ |
|
pred@2504
|
193 |
delete [] m_ProtoInfo.paramsPassInfo; |
|
pred@2504
|
194 |
delete [] m_ParamOffs; |
|
pred@2504
|
195 |
} |
|
pred@2504
|
196 |
/***************************** |
|
pred@2504
|
197 |
* SMDelegate Implementation * |
|
pred@2504
|
198 |
*****************************/ |
|
pred@2504
|
199 |
|
|
pred@2504
|
200 |
SMDelegate::SMDelegate(void *data) |
|
pred@2504
|
201 |
{ |
|
pred@2504
|
202 |
m_Data = data; |
|
pred@2504
|
203 |
} |
|
pred@2504
|
204 |
|
|
pred@2504
|
205 |
bool SMDelegate::IsEqual(ISHDelegate *pOtherDeleg) |
|
pred@2504
|
206 |
{ |
|
pred@2504
|
207 |
return false; |
|
pred@2504
|
208 |
} |
|
pred@2504
|
209 |
|
|
pred@2504
|
210 |
void SMDelegate::DeleteThis() |
|
pred@2504
|
211 |
{ |
|
pred@2504
|
212 |
/* Remove our allocated vtable */ |
|
pred@2504
|
213 |
delete [] *reinterpret_cast<void ***>(this); |
|
pred@2504
|
214 |
|
|
pred@2504
|
215 |
delete this; |
|
pred@2504
|
216 |
} |
|
pred@2504
|
217 |
|
|
pred@2504
|
218 |
void SMDelegate::Call() |
|
pred@2504
|
219 |
{ |
|
pred@2504
|
220 |
} |
|
pred@2504
|
221 |
|
|
pred@2504
|
222 |
void *SMDelegate::GetUserData() |
|
pred@2504
|
223 |
{ |
|
pred@2504
|
224 |
return m_Data; |
|
pred@2504
|
225 |
} |
|
pred@2504
|
226 |
|
|
pred@2504
|
227 |
/** |
|
pred@2504
|
228 |
* This duplicates the vtable (so each instance has a unique table) and patches SMDelgate::Call to point to our allocated function |
|
pred@2504
|
229 |
*/ |
|
pred@2504
|
230 |
void SMDelegate::PatchVtable(void *addr) |
|
pred@2504
|
231 |
{ |
|
pred@2504
|
232 |
void **new_vtptr = new void *[4]; |
|
pred@2504
|
233 |
void **cur_vtptr = *reinterpret_cast<void ***>(this); |
|
pred@2504
|
234 |
memcpy(new_vtptr, cur_vtptr, sizeof(void *)*4); |
|
pred@2504
|
235 |
|
|
pred@2504
|
236 |
*reinterpret_cast<void ***>(this) = new_vtptr; |
|
pred@2504
|
237 |
|
|
pred@2504
|
238 |
void *cur_vfnptr = reinterpret_cast<void *>(new_vtptr + VTABLE_PATCH_OFFS); |
|
pred@2504
|
239 |
|
|
pred@2504
|
240 |
*reinterpret_cast<void **>(cur_vfnptr) = addr; |
|
pred@2504
|
241 |
} |
|
pred@2504
|
242 |
|
|
pred@2504
|
243 |
#endif |