1+ /* *
2+ * =============================================================================
3+ * Source Python
4+ * Copyright (C) 2012 Source Python Development Team. All rights reserved.
5+ * =============================================================================
6+ *
7+ * This program is free software; you can redistribute it and/or modify it under
8+ * the terms of the GNU General Public License, version 3.0, as published by the
9+ * Free Software Foundation.
10+ *
11+ * This program is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14+ * details.
15+ *
16+ * You should have received a copy of the GNU General Public License along with
17+ * this program. If not, see <http://www.gnu.org/licenses/>.
18+ *
19+ * As a special exception, the Source Python Team gives you permission
20+ * to link the code of this program (as well as its derivative works) to
21+ * "Half-Life 2," the "Source Engine," and any Game MODs that run on software
22+ * by the Valve Corporation. You must obey the GNU General Public License in
23+ * all respects for all other code used. Additionally, the Source.Python
24+ * Development Team grants this exception to all derivative works.
25+ */
26+
27+ // ============================================================================
28+ // >> INCLUDES
29+ // ============================================================================
30+ #include " memory_callback.h"
31+ #include " utility/wrap_macros.h"
32+
33+ #include " AsmJit.h"
34+ using namespace AsmJit ;
35+
36+ #include " utilities.h"
37+ #include " DynamicHooks.h"
38+ using namespace DynamicHooks ;
39+
40+
41+ // ============================================================================
42+ // >> CLASSES
43+ // ============================================================================
44+ #define GET_CALLBACK_CALLER (type ) \
45+ GET_FUNCTION (type, CallbackCaller<type>, CCallback*, unsigned long , unsigned long )
46+
47+ CCallback::CCallback(object oCallback, Convention_t eConv, char * szParams)
48+ : CFunction(NULL , eConv, szParams)
49+ {
50+ m_eConv = eConv;
51+ m_oCallback = oCallback;
52+
53+ // Parse the parameter string
54+ m_pParams = new Param_t;
55+ m_pRetParam = new Param_t;
56+ ParseParams (eConv, szParams, m_pParams, m_pRetParam);
57+
58+ // Find the proper callback caller function
59+ void * pCallCallbackFunc = NULL ;
60+ switch (m_pRetParam->m_cParam )
61+ {
62+ case SIGCHAR_VOID: pCallCallbackFunc = GET_CALLBACK_CALLER (void ); break ;
63+ case SIGCHAR_BOOL: pCallCallbackFunc = GET_CALLBACK_CALLER (bool ); break ;
64+ case SIGCHAR_CHAR: pCallCallbackFunc = GET_CALLBACK_CALLER (char ); break ;
65+ case SIGCHAR_UCHAR: pCallCallbackFunc = GET_CALLBACK_CALLER (unsigned char ); break ;
66+ case SIGCHAR_SHORT: pCallCallbackFunc = GET_CALLBACK_CALLER (short ); break ;
67+ case SIGCHAR_USHORT: pCallCallbackFunc = GET_CALLBACK_CALLER (unsigned short ); break ;
68+ case SIGCHAR_INT: pCallCallbackFunc = GET_CALLBACK_CALLER (int ); break ;
69+ case SIGCHAR_UINT: pCallCallbackFunc = GET_CALLBACK_CALLER (unsigned int ); break ;
70+ case SIGCHAR_LONG: pCallCallbackFunc = GET_CALLBACK_CALLER (long ); break ;
71+ case SIGCHAR_ULONG: pCallCallbackFunc = GET_CALLBACK_CALLER (unsigned long ); break ;
72+ case SIGCHAR_LONGLONG: pCallCallbackFunc = GET_CALLBACK_CALLER (long long ); break ;
73+ case SIGCHAR_ULONGLONG: pCallCallbackFunc = GET_CALLBACK_CALLER (unsigned long long ); break ;
74+ case SIGCHAR_FLOAT: pCallCallbackFunc = GET_CALLBACK_CALLER (float ); break ;
75+ case SIGCHAR_DOUBLE: pCallCallbackFunc = GET_CALLBACK_CALLER (double ); break ;
76+ case SIGCHAR_POINTER: pCallCallbackFunc = GET_CALLBACK_CALLER (void *); break ;
77+ case SIGCHAR_STRING: pCallCallbackFunc = GET_CALLBACK_CALLER (char *); break ;
78+ default : BOOST_RAISE_EXCEPTION (PyExc_ValueError, " Unknown return type." );
79+ }
80+
81+ // Generate the function
82+ Assembler a;
83+
84+ // Epilog
85+ a.push (ebp);
86+ a.mov (ebp, esp);
87+
88+ // Call callback caller
89+ a.push (ecx);
90+ a.push (ebp);
91+ a.push (imm ((sysint_t ) this ));
92+ a.call (pCallCallbackFunc);
93+ a.add (esp, imm (12 ));
94+
95+ // Prolog
96+ a.mov (esp, ebp);
97+ a.pop (ebp);
98+
99+ // Return
100+ a.ret (imm (GetPopSize ()));
101+
102+ m_ulAddr = (unsigned long ) a.make ();
103+ }
104+
105+ CCallback::~CCallback ()
106+ {
107+ delete m_pParams;
108+ delete m_pRetParam;
109+ }
110+
111+ int CCallback::GetPopSize ()
112+ {
113+ #ifdef _WIN32
114+ if (m_eConv == CONV_THISCALL || m_eConv == CONV_STDCALL)
115+ {
116+ Param_t* pParam = GetArgument (GetArgumentCount () - 1 );
117+ return pParam->m_iOffset + pParam->m_iSize ;
118+ }
119+ #endif
120+ return 0 ;
121+ }
122+
123+ int CCallback::GetArgumentCount ()
124+ {
125+ int count = 0 ;
126+ Param_t* temp = m_pParams;
127+ while (temp)
128+ {
129+ count++;
130+ temp = temp->m_pNext ;
131+ }
132+ return count - 1 ;
133+ }
134+
135+ Param_t* CCallback::GetArgument (int iIndex)
136+ {
137+ Param_t* temp = m_pParams;
138+ while (temp && iIndex > 0 )
139+ {
140+ iIndex--;
141+ temp = temp->m_pNext ;
142+ }
143+ return temp;
144+ }
145+
146+ void CCallback::Free ()
147+ {
148+ // TODO: Figure out how to use std::free() on the generated code, so we can
149+ // use Dealloc().
150+ MemoryManager::getGlobal ()->free ((void *) m_ulAddr);
151+ m_ulAddr = 0 ;
152+ }
153+
154+
155+ // ============================================================================
156+ // >> FUNCTIONS
157+ // ============================================================================
158+ template <class T >
159+ T GetArgument (CCallback* pCallback, unsigned long ulEBP, unsigned long ulECX, int iIndex)
160+ {
161+ #ifdef _WIN32
162+ if (pCallback->m_eConv == CONV_THISCALL && iIndex == 0 )
163+ return *(T *) &ulECX;
164+ #endif
165+
166+ return *(T *) (ulEBP + pCallback->GetArgument (iIndex)->m_iOffset + 8 );
167+ }
168+
169+ object CallCallback (CCallback* pCallback, unsigned long ulEBP, unsigned long ulECX)
170+ {
171+ BEGIN_BOOST_PY ()
172+
173+ list arg_list;
174+ for (int i=0 ; i < pCallback->GetArgumentCount (); i++)
175+ {
176+ object val;
177+ switch (pCallback->GetArgument (i)->m_cParam )
178+ {
179+ case SIGCHAR_BOOL: val = object (GetArgument<bool >(pCallback, ulEBP, ulECX, i)); break ;
180+ case SIGCHAR_CHAR: val = object (GetArgument<char >(pCallback, ulEBP, ulECX, i)); break ;
181+ case SIGCHAR_UCHAR: val = object (GetArgument<unsigned char >(pCallback, ulEBP, ulECX, i)); break ;
182+ case SIGCHAR_SHORT: val = object (GetArgument<short >(pCallback, ulEBP, ulECX, i)); break ;
183+ case SIGCHAR_USHORT: val = object (GetArgument<unsigned short >(pCallback, ulEBP, ulECX, i)); break ;
184+ case SIGCHAR_INT: val = object (GetArgument<int >(pCallback, ulEBP, ulECX, i)); break ;
185+ case SIGCHAR_UINT: val = object (GetArgument<unsigned int >(pCallback, ulEBP, ulECX, i)); break ;
186+ case SIGCHAR_LONG: val = object (GetArgument<long >(pCallback, ulEBP, ulECX, i)); break ;
187+ case SIGCHAR_ULONG: val = object (GetArgument<unsigned long >(pCallback, ulEBP, ulECX, i)); break ;
188+ case SIGCHAR_LONGLONG: val = object (GetArgument<long long >(pCallback, ulEBP, ulECX, i)); break ;
189+ case SIGCHAR_ULONGLONG: val = object (GetArgument<unsigned long long >(pCallback, ulEBP, ulECX, i)); break ;
190+ case SIGCHAR_FLOAT: val = object (GetArgument<float >(pCallback, ulEBP, ulECX, i)); break ;
191+ case SIGCHAR_DOUBLE: val = object (GetArgument<double >(pCallback, ulEBP, ulECX, i)); break ;
192+ case SIGCHAR_POINTER: val = object (CPointer (GetArgument<unsigned long >(pCallback, ulEBP, ulECX, i))); break ;
193+ case SIGCHAR_STRING: val = object (GetArgument<const char *>(pCallback, ulEBP, ulECX, i)); break ;
194+ default : BOOST_RAISE_EXCEPTION (PyExc_TypeError, " Unknown type." ); break ;
195+ }
196+ arg_list.append (val);
197+ }
198+ arg_list.append (CPointer ((unsigned long ) ulEBP));
199+ return eval (" lambda func, args: func(*args)" )(pCallback->m_oCallback , arg_list);
200+
201+ END_BOOST_PY_NORET ()
202+
203+ // Throw an exception. We will crash now :(
204+ throw ;
205+ }
0 commit comments