blob: d9a4e9f725f3e23c93678c8766f55e1b2821e2ea [file] [log] [blame]
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001/*
2 * 386-specific Win32 relay functions
3 *
4 * Copyright 1997 Alexandre Julliard
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Alexandre Julliard44ed71f1997-12-21 19:17:50 +000019 */
20
Francois Gougete5ddd262001-10-14 16:18:52 +000021#include "config.h"
Alexandre Julliard894b1882002-04-25 21:40:56 +000022#include "wine/port.h"
Francois Gougete5ddd262001-10-14 16:18:52 +000023
Alexandre Julliard44ed71f1997-12-21 19:17:50 +000024#include <assert.h>
Alexandre Julliardf90efa91998-06-14 15:24:15 +000025#include <string.h>
Alexandre Julliard246c3602000-05-10 03:48:00 +000026#include <stdio.h>
Dimitrie O. Paun0b7a7bb2000-11-25 01:31:17 +000027
Alexandre Julliard44ed71f1997-12-21 19:17:50 +000028#include "winnt.h"
Alexandre Julliarda061b842002-06-04 17:48:41 +000029#include "winreg.h"
Alexandre Julliard06b97891999-05-13 16:13:17 +000030#include "stackframe.h"
Alexandre Julliard246c3602000-05-10 03:48:00 +000031#include "module.h"
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000032#include "wine/debug.h"
Alexandre Julliard44ed71f1997-12-21 19:17:50 +000033
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000034WINE_DEFAULT_DEBUG_CHANNEL(relay);
Alexandre Julliarda061b842002-06-04 17:48:41 +000035WINE_DECLARE_DEBUG_CHANNEL(snoop);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000036
Alexandre Julliarda061b842002-06-04 17:48:41 +000037const char **debug_relay_excludelist = NULL;
38const char **debug_relay_includelist = NULL;
39const char **debug_snoop_excludelist = NULL;
40const char **debug_snoop_includelist = NULL;
Alexandre Julliardf90efa91998-06-14 15:24:15 +000041
Alexandre Julliard44ed71f1997-12-21 19:17:50 +000042/***********************************************************************
Alexandre Julliarda061b842002-06-04 17:48:41 +000043 * build_list
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +000044 *
Alexandre Julliarda061b842002-06-04 17:48:41 +000045 * Build a function list from a ';'-separated string.
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +000046 */
Alexandre Julliarda061b842002-06-04 17:48:41 +000047static const char **build_list( const char *buffer )
48{
49 int count = 1;
50 const char *p = buffer;
51 const char **ret;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +000052
Alexandre Julliarda061b842002-06-04 17:48:41 +000053 while ((p = strchr( p, ';' )))
54 {
55 count++;
56 p++;
57 }
58 /* allocate count+1 pointers, plus the space for a copy of the string */
59 if ((ret = HeapAlloc( GetProcessHeap(), 0, (count+1) * sizeof(char*) + strlen(buffer) + 1 )))
60 {
61 char *str = (char *)(ret + count + 1);
62 char *p = str;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +000063
Alexandre Julliarda061b842002-06-04 17:48:41 +000064 strcpy( str, buffer );
65 count = 0;
66 for (;;)
67 {
68 ret[count++] = p;
69 if (!(p = strchr( p, ';' ))) break;
70 *p++ = 0;
71 }
72 ret[count++] = NULL;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +000073 }
Alexandre Julliarda061b842002-06-04 17:48:41 +000074 return ret;
75}
76
77
78/***********************************************************************
79 * RELAY_InitDebugLists
80 *
81 * Build the relay include/exclude function lists.
82 */
83void RELAY_InitDebugLists(void)
84{
85 char buffer[1024];
86 HKEY hkey;
87 DWORD count, type;
88
89 if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Debug", &hkey )) return;
90
91 count = sizeof(buffer);
92 if (!RegQueryValueExA( hkey, "RelayInclude", NULL, &type, buffer, &count ))
93 {
94 TRACE("RelayInclude = %s\n", buffer );
95 debug_relay_includelist = build_list( buffer );
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +000096 }
Alexandre Julliarda061b842002-06-04 17:48:41 +000097
98 count = sizeof(buffer);
99 if (!RegQueryValueExA( hkey, "RelayExclude", NULL, &type, buffer, &count ))
100 {
101 TRACE( "RelayExclude = %s\n", buffer );
102 debug_relay_excludelist = build_list( buffer );
103 }
104
105 count = sizeof(buffer);
106 if (!RegQueryValueExA( hkey, "SnoopInclude", NULL, &type, buffer, &count ))
107 {
108 TRACE_(snoop)( "SnoopInclude = %s\n", buffer );
109 debug_snoop_includelist = build_list( buffer );
110 }
111
112 count = sizeof(buffer);
113 if (!RegQueryValueExA( hkey, "SnoopExclude", NULL, &type, buffer, &count ))
114 {
115 TRACE_(snoop)( "SnoopExclude = %s\n", buffer );
116 debug_snoop_excludelist = build_list( buffer );
117 }
118
119 RegCloseKey( hkey );
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +0000120}
121
Alexandre Julliard06b97891999-05-13 16:13:17 +0000122
Ulrich Weigand6ca85a51999-11-14 21:28:57 +0000123#ifdef __i386__
124
Alexandre Julliard246c3602000-05-10 03:48:00 +0000125typedef struct
126{
127 BYTE call; /* 0xe8 call callfrom32 (relative) */
128 DWORD callfrom32 WINE_PACKED; /* RELAY_CallFrom32 relative addr */
129 BYTE ret; /* 0xc2 ret $n or 0xc3 ret */
130 WORD args; /* nb of args to remove from the stack */
Alexandre Julliarda8378492000-10-01 01:33:50 +0000131 void *orig; /* original entry point */
Alexandre Julliard246c3602000-05-10 03:48:00 +0000132 DWORD argtypes; /* argument types */
133} DEBUG_ENTRY_POINT;
134
135
136/***********************************************************************
Alexandre Julliarda061b842002-06-04 17:48:41 +0000137 * check_relay_include
138 *
139 * Check if a given function must be included in the relay output.
140 */
141static BOOL check_relay_include( const char *module, const char *func )
142{
143 const char **listitem;
144 BOOL show;
145
146 if (!debug_relay_excludelist && !debug_relay_includelist) return TRUE;
147 if (debug_relay_excludelist)
148 {
149 show = TRUE;
150 listitem = debug_relay_excludelist;
151 }
152 else
153 {
154 show = FALSE;
155 listitem = debug_relay_includelist;
156 }
157 for(; *listitem; listitem++)
158 {
Alexandre Julliard6da43662002-07-08 20:46:58 +0000159 char *p = strrchr( *listitem, '.' );
Alexandre Julliarda061b842002-06-04 17:48:41 +0000160 if (p && p > *listitem) /* check module and function */
161 {
162 int len = p - *listitem;
163 if (strncasecmp( *listitem, module, len-1 ) || module[len]) continue;
Alexandre Julliard6da43662002-07-08 20:46:58 +0000164 if (!strcmp( p + 1, func ) || !strcmp( p + 1, "*" )) return !show;
Alexandre Julliarda061b842002-06-04 17:48:41 +0000165 }
166 else /* function only */
167 {
168 if (!strcmp( *listitem, func )) return !show;
169 }
170 }
171 return show;
172}
173
174
175/***********************************************************************
Alexandre Julliard246c3602000-05-10 03:48:00 +0000176 * find_exported_name
177 *
178 * Find the name of an exported function.
179 */
180static const char *find_exported_name( const char *module,
181 IMAGE_EXPORT_DIRECTORY *exp, int ordinal )
182{
183 int i;
184 const char *ret = NULL;
185
186 WORD *ordptr = (WORD *)(module + exp->AddressOfNameOrdinals);
187 for (i = 0; i < exp->NumberOfNames; i++, ordptr++)
188 if (*ordptr + exp->Base == ordinal) break;
189 if (i < exp->NumberOfNames)
190 ret = module + ((DWORD*)(module + exp->AddressOfNames))[i];
191 return ret;
192}
193
194
195/***********************************************************************
196 * get_entry_point
197 *
198 * Get the name of the DLL entry point corresponding to a relay address.
199 */
200static void get_entry_point( char *buffer, DEBUG_ENTRY_POINT *relay )
201{
202 IMAGE_DATA_DIRECTORY *dir;
203 IMAGE_EXPORT_DIRECTORY *exp = NULL;
204 DEBUG_ENTRY_POINT *debug;
Alexandre Julliard6da43662002-07-08 20:46:58 +0000205 char *p, *base = NULL;
Alexandre Julliard246c3602000-05-10 03:48:00 +0000206 const char *name;
207 int ordinal = 0;
208 WINE_MODREF *wm;
209
210 /* First find the module */
211
Alexandre Julliardbecb9a32000-12-11 03:48:15 +0000212 for (wm = MODULE_modref_list; wm; wm = wm->next)
Alexandre Julliard246c3602000-05-10 03:48:00 +0000213 {
Alexandre Julliard246c3602000-05-10 03:48:00 +0000214 if (!(wm->flags & WINE_MODREF_INTERNAL)) continue;
215 base = (char *)wm->module;
216 dir = &PE_HEADER(base)->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
217 if (!dir->Size) continue;
218 exp = (IMAGE_EXPORT_DIRECTORY *)(base + dir->VirtualAddress);
219 debug = (DEBUG_ENTRY_POINT *)((char *)exp + dir->Size);
220 if (debug <= relay && relay < debug + exp->NumberOfFunctions)
221 {
222 ordinal = relay - debug;
223 break;
224 }
225 }
226
227 /* Now find the function */
228
Alexandre Julliard6da43662002-07-08 20:46:58 +0000229 strcpy( buffer, base + exp->Name );
230 p = buffer + strlen(buffer);
231 if (p > buffer + 4 && !strcasecmp( p - 4, ".dll" )) p -= 4;
232
Dmitry Timoshkov4ea3c262001-04-09 18:47:10 +0000233 if ((name = find_exported_name( base, exp, ordinal + exp->Base )))
Alexandre Julliard6da43662002-07-08 20:46:58 +0000234 sprintf( p, ".%s", name );
Dmitry Timoshkov4ea3c262001-04-09 18:47:10 +0000235 else
Alexandre Julliard6da43662002-07-08 20:46:58 +0000236 sprintf( p, ".%ld", ordinal + exp->Base );
Alexandre Julliard246c3602000-05-10 03:48:00 +0000237}
238
239
Alexandre Julliard06b97891999-05-13 16:13:17 +0000240/***********************************************************************
241 * RELAY_PrintArgs
242 */
243static inline void RELAY_PrintArgs( int *args, int nb_args, unsigned int typemask )
244{
245 while (nb_args--)
246 {
247 if ((typemask & 3) && HIWORD(*args))
248 {
249 if (typemask & 2)
Francois Gougete73b8b81999-12-26 00:40:37 +0000250 DPRINTF( "%08x %s", *args, debugstr_w((LPWSTR)*args) );
Alexandre Julliard06b97891999-05-13 16:13:17 +0000251 else
252 DPRINTF( "%08x %s", *args, debugstr_a((LPCSTR)*args) );
253 }
254 else DPRINTF( "%08x", *args );
255 if (nb_args) DPRINTF( "," );
256 args++;
257 typemask >>= 2;
258 }
259}
260
261
Alexandre Julliard7662ea12001-12-14 23:14:22 +0000262typedef LONGLONG (*LONGLONG_CPROC)();
Patrik Stridvall57e57842002-02-02 18:42:11 +0000263typedef LONGLONG (WINAPI *LONGLONG_FARPROC)();
Alexandre Julliard3f2b2d52000-10-12 20:55:26 +0000264
Alexandre Julliard7662ea12001-12-14 23:14:22 +0000265
266/***********************************************************************
267 * call_cdecl_function
268 */
269static LONGLONG call_cdecl_function( LONGLONG_CPROC func, int nb_args, const int *args )
270{
271 LONGLONG ret;
272 switch(nb_args)
273 {
274 case 0: ret = func(); break;
275 case 1: ret = func(args[0]); break;
276 case 2: ret = func(args[0],args[1]); break;
277 case 3: ret = func(args[0],args[1],args[2]); break;
278 case 4: ret = func(args[0],args[1],args[2],args[3]); break;
279 case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
280 case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
281 args[5]); break;
282 case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
283 args[6]); break;
284 case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
285 args[6],args[7]); break;
286 case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
287 args[6],args[7],args[8]); break;
288 case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
289 args[6],args[7],args[8],args[9]); break;
290 case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
291 args[6],args[7],args[8],args[9],args[10]); break;
292 case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
293 args[6],args[7],args[8],args[9],args[10],
294 args[11]); break;
295 case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
296 args[6],args[7],args[8],args[9],args[10],args[11],
297 args[12]); break;
298 case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
299 args[6],args[7],args[8],args[9],args[10],args[11],
300 args[12],args[13]); break;
301 case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
302 args[6],args[7],args[8],args[9],args[10],args[11],
303 args[12],args[13],args[14]); break;
304 case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
305 args[6],args[7],args[8],args[9],args[10],args[11],
306 args[12],args[13],args[14],args[15]); break;
307 default:
308 ERR( "Unsupported nb of args %d\n", nb_args );
309 assert(FALSE);
310 }
311 return ret;
312}
313
314
315/***********************************************************************
316 * call_stdcall_function
317 */
318static LONGLONG call_stdcall_function( LONGLONG_FARPROC func, int nb_args, const int *args )
319{
320 LONGLONG ret;
321 switch(nb_args)
322 {
323 case 0: ret = func(); break;
324 case 1: ret = func(args[0]); break;
325 case 2: ret = func(args[0],args[1]); break;
326 case 3: ret = func(args[0],args[1],args[2]); break;
327 case 4: ret = func(args[0],args[1],args[2],args[3]); break;
328 case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
329 case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
330 args[5]); break;
331 case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
332 args[6]); break;
333 case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
334 args[6],args[7]); break;
335 case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
336 args[6],args[7],args[8]); break;
337 case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
338 args[6],args[7],args[8],args[9]); break;
339 case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
340 args[6],args[7],args[8],args[9],args[10]); break;
341 case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
342 args[6],args[7],args[8],args[9],args[10],
343 args[11]); break;
344 case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
345 args[6],args[7],args[8],args[9],args[10],args[11],
346 args[12]); break;
347 case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
348 args[6],args[7],args[8],args[9],args[10],args[11],
349 args[12],args[13]); break;
350 case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
351 args[6],args[7],args[8],args[9],args[10],args[11],
352 args[12],args[13],args[14]); break;
353 case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
354 args[6],args[7],args[8],args[9],args[10],args[11],
355 args[12],args[13],args[14],args[15]); break;
356 default:
357 ERR( "Unsupported nb of args %d\n", nb_args );
358 assert(FALSE);
359 }
360 return ret;
361}
362
363
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +0000364/***********************************************************************
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000365 * RELAY_CallFrom32
366 *
367 * Stack layout on entry to this function:
368 * ... ...
369 * (esp+12) arg2
370 * (esp+8) arg1
371 * (esp+4) ret_addr
372 * (esp) return addr to relay code
373 */
Alexandre Julliarda8378492000-10-01 01:33:50 +0000374static LONGLONG RELAY_CallFrom32( int ret_addr, ... )
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000375{
Alexandre Julliarda8378492000-10-01 01:33:50 +0000376 LONGLONG ret;
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000377 char buffer[80];
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000378
Alexandre Julliard06b97891999-05-13 16:13:17 +0000379 int *args = &ret_addr + 1;
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000380 /* Relay addr is the return address for this function */
Alexandre Julliard06b97891999-05-13 16:13:17 +0000381 BYTE *relay_addr = (BYTE *)__builtin_return_address(0);
Alexandre Julliard246c3602000-05-10 03:48:00 +0000382 DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
383 WORD nb_args = relay->args / sizeof(int);
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000384
Alexandre Julliard1cf02612002-06-04 21:25:34 +0000385 if (TRACE_ON(relay))
386 {
387 get_entry_point( buffer, relay );
Alexandre Julliard246c3602000-05-10 03:48:00 +0000388
Alexandre Julliard1cf02612002-06-04 21:25:34 +0000389 DPRINTF( "%08lx:Call %s(", GetCurrentThreadId(), buffer );
390 RELAY_PrintArgs( args, nb_args, relay->argtypes );
391 DPRINTF( ") ret=%08x\n", ret_addr );
392 }
Marcus Meissner38980e41998-11-22 14:12:36 +0000393
Alexandre Julliard246c3602000-05-10 03:48:00 +0000394 if (relay->ret == 0xc3) /* cdecl */
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000395 {
Alexandre Julliard7662ea12001-12-14 23:14:22 +0000396 ret = call_cdecl_function( (LONGLONG_CPROC)relay->orig, nb_args, args );
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000397 }
398 else /* stdcall */
399 {
Alexandre Julliard7662ea12001-12-14 23:14:22 +0000400 ret = call_stdcall_function( (LONGLONG_FARPROC)relay->orig, nb_args, args );
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000401 }
Alexandre Julliard7662ea12001-12-14 23:14:22 +0000402
Alexandre Julliard1cf02612002-06-04 21:25:34 +0000403 if (TRACE_ON(relay))
404 {
405 BOOL ret64 = (relay->argtypes & 0x80000000) && (nb_args < 16);
406 if (ret64)
407 DPRINTF( "%08lx:Ret %s() retval=%08x%08x ret=%08x\n",
408 GetCurrentThreadId(),
409 buffer, (UINT)(ret >> 32), (UINT)ret, ret_addr );
410 else
411 DPRINTF( "%08lx:Ret %s() retval=%08x ret=%08x\n",
412 GetCurrentThreadId(),
413 buffer, (UINT)ret, ret_addr );
414 }
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000415 return ret;
416}
417
418
419/***********************************************************************
420 * RELAY_CallFrom32Regs
421 *
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000422 * Stack layout (esp is context->Esp, not the current %esp):
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000423 *
Alexandre Julliard06b97891999-05-13 16:13:17 +0000424 * ...
425 * (esp+4) first arg
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000426 * (esp) return addr to caller
Alexandre Julliard06b97891999-05-13 16:13:17 +0000427 * (esp-4) return addr to DEBUG_ENTRY_POINT
428 * (esp-8) ptr to relay entry code for RELAY_CallFrom32Regs
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000429 * ... >128 bytes space free to be modified (ensured by the assembly glue)
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000430 */
Ulrich Weigand6ca85a51999-11-14 21:28:57 +0000431void WINAPI RELAY_DoCallFrom32Regs( CONTEXT86 *context )
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000432{
Alexandre Julliard06b97891999-05-13 16:13:17 +0000433 char buffer[80];
434 int* args;
Alexandre Julliard7662ea12001-12-14 23:14:22 +0000435 int args_copy[17];
Alexandre Julliard06b97891999-05-13 16:13:17 +0000436 BYTE *entry_point;
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000437
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000438 BYTE *relay_addr = *((BYTE **)context->Esp - 1);
Alexandre Julliard246c3602000-05-10 03:48:00 +0000439 DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
440 WORD nb_args = (relay->args & ~0x8000) / sizeof(int);
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000441
Alexandre Julliard06b97891999-05-13 16:13:17 +0000442 /* remove extra stuff from the stack */
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000443 context->Eip = stack32_pop(context);
444 args = (int *)context->Esp;
Alexandre Julliard6a9325d2001-12-19 19:17:09 +0000445 if (relay->ret == 0xc2) /* stdcall */
446 context->Esp += nb_args * sizeof(int);
Alexandre Julliard06b97891999-05-13 16:13:17 +0000447
Alexandre Julliard246c3602000-05-10 03:48:00 +0000448 entry_point = (BYTE *)relay->orig;
Alexandre Julliard06b97891999-05-13 16:13:17 +0000449 assert( *entry_point == 0xe8 /* lcall */ );
Alexandre Julliard06b97891999-05-13 16:13:17 +0000450
Alexandre Julliard1cf02612002-06-04 21:25:34 +0000451 if (TRACE_ON(relay))
452 {
453 get_entry_point( buffer, relay );
Alexandre Julliard246c3602000-05-10 03:48:00 +0000454
Alexandre Julliard1cf02612002-06-04 21:25:34 +0000455 DPRINTF( "%08lx:Call %s(", GetCurrentThreadId(), buffer );
456 RELAY_PrintArgs( args, nb_args, relay->argtypes );
457 DPRINTF( ") ret=%08lx fs=%04lx\n", context->Eip, context->SegFs );
Alexandre Julliard06b97891999-05-13 16:13:17 +0000458
Alexandre Julliard1cf02612002-06-04 21:25:34 +0000459 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
460 context->Eax, context->Ebx, context->Ecx,
461 context->Edx, context->Esi, context->Edi );
462 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
463 context->Ebp, context->Esp, context->SegDs,
464 context->SegEs, context->SegGs, context->EFlags );
465 }
Alexandre Julliard06b97891999-05-13 16:13:17 +0000466
467 /* Now call the real function */
Alexandre Julliard7662ea12001-12-14 23:14:22 +0000468
469 memcpy( args_copy, args, nb_args * sizeof(args[0]) );
470 args_copy[nb_args] = (int)context; /* append context argument */
471 if (relay->ret == 0xc3) /* cdecl */
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000472 {
Alexandre Julliard7662ea12001-12-14 23:14:22 +0000473 call_cdecl_function( *(LONGLONG_CPROC *)(entry_point + 5), nb_args+1, args_copy );
474 }
475 else /* stdcall */
476 {
477 call_stdcall_function( *(LONGLONG_FARPROC *)(entry_point + 5), nb_args+1, args_copy );
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000478 }
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000479
Alexandre Julliard1cf02612002-06-04 21:25:34 +0000480 if (TRACE_ON(relay))
481 {
482 DPRINTF( "%08lx:Ret %s() retval=%08lx ret=%08lx fs=%04lx\n",
483 GetCurrentThreadId(),
484 buffer, context->Eax, context->Eip, context->SegFs );
Alexandre Julliardd8fab2e2000-09-25 23:53:07 +0000485
Alexandre Julliard1cf02612002-06-04 21:25:34 +0000486 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
487 context->Eax, context->Ebx, context->Ecx,
488 context->Edx, context->Esi, context->Edi );
489 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
490 context->Ebp, context->Esp, context->SegDs,
491 context->SegEs, context->SegGs, context->EFlags );
492 }
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000493}
Alexandre Julliard06b97891999-05-13 16:13:17 +0000494
Alexandre Julliard85d666a2000-12-12 00:49:45 +0000495void WINAPI RELAY_CallFrom32Regs(void);
496__ASM_GLOBAL_FUNC( RELAY_CallFrom32Regs,
Alexandre Julliardeb9a8632001-12-11 00:50:33 +0000497 "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
Alexandre Julliard85d666a2000-12-12 00:49:45 +0000498 ".long " __ASM_NAME("RELAY_DoCallFrom32Regs") ",0" );
Alexandre Julliard246c3602000-05-10 03:48:00 +0000499
500/***********************************************************************
501 * RELAY_SetupDLL
502 *
503 * Setup relay debugging for a built-in dll.
504 */
505void RELAY_SetupDLL( const char *module )
506{
507 IMAGE_DATA_DIRECTORY *dir;
508 IMAGE_EXPORT_DIRECTORY *exports;
509 DEBUG_ENTRY_POINT *debug;
510 DWORD *funcs;
511 int i;
Alexandre Julliard6da43662002-07-08 20:46:58 +0000512 const char *name;
513 char *p, dllname[80];
Alexandre Julliard246c3602000-05-10 03:48:00 +0000514
515 dir = &PE_HEADER(module)->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
516 if (!dir->Size) return;
517 exports = (IMAGE_EXPORT_DIRECTORY *)(module + dir->VirtualAddress);
518 debug = (DEBUG_ENTRY_POINT *)((char *)exports + dir->Size);
519 funcs = (DWORD *)(module + exports->AddressOfFunctions);
Alexandre Julliard6da43662002-07-08 20:46:58 +0000520 strcpy( dllname, module + exports->Name );
521 p = dllname + strlen(dllname) - 4;
522 if (p > dllname && !strcasecmp( p, ".dll" )) *p = 0;
Alexandre Julliard246c3602000-05-10 03:48:00 +0000523
524 for (i = 0; i < exports->NumberOfFunctions; i++, funcs++, debug++)
525 {
526 int on = 1;
527
528 if (!debug->call) continue; /* not a normal function */
Alexandre Julliard1a5e22f2000-11-27 23:48:08 +0000529 if (debug->call != 0xe8 && debug->call != 0xe9) break; /* not a debug thunk at all */
Alexandre Julliard246c3602000-05-10 03:48:00 +0000530
531 if ((name = find_exported_name( module, exports, i + exports->Base )))
Alexandre Julliarda061b842002-06-04 17:48:41 +0000532 on = check_relay_include( dllname, name );
Alexandre Julliard246c3602000-05-10 03:48:00 +0000533
534 if (on)
535 {
536 debug->call = 0xe8; /* call relative */
537 if (debug->args & 0x8000) /* register func */
538 debug->callfrom32 = (char *)RELAY_CallFrom32Regs - (char *)&debug->ret;
539 else
540 debug->callfrom32 = (char *)RELAY_CallFrom32 - (char *)&debug->ret;
541 }
542 else
543 {
544 debug->call = 0xe9; /* jmp relative */
545 debug->callfrom32 = (char *)debug->orig - (char *)&debug->ret;
546 }
547
548 debug->orig = (FARPROC)(module + (DWORD)*funcs);
549 *funcs = (char *)debug - module;
550 }
551}
552
553#else /* __i386__ */
554
555void RELAY_SetupDLL( const char *module )
556{
557}
558
559#endif /* __i386__ */