2 * 386-specific Win32 relay functions
4 * Copyright 1997 Alexandre Julliard
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.
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.
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
22 #include "wine/port.h"
29 #include "stackframe.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(relay
);
35 char **debug_relay_excludelist
= NULL
, **debug_relay_includelist
= NULL
;
37 /***********************************************************************
38 * RELAY_ShowDebugmsgRelay
40 * Simple function to decide if a particular debugging message is
41 * wanted. Called from RELAY_CallFrom32 and from in if1632/relay.c
43 int RELAY_ShowDebugmsgRelay(const char *func
) {
45 if(debug_relay_excludelist
|| debug_relay_includelist
) {
46 const char *term
= strchr(func
, ':');
48 int len
, len2
, itemlen
, show
;
50 if(debug_relay_excludelist
) {
52 listitem
= debug_relay_excludelist
;
55 listitem
= debug_relay_includelist
;
58 assert(strlen(term
) > 2);
60 len2
= strchr(func
, '.') - func
;
61 assert(len2
&& len2
> 0 && len2
< 64);
63 for(; *listitem
; listitem
++) {
64 itemlen
= strlen(*listitem
);
65 if((itemlen
== len
&& !strncasecmp(*listitem
, func
, len
)) ||
66 (itemlen
== len2
&& !strncasecmp(*listitem
, func
, len2
)) ||
67 !strcasecmp(*listitem
, term
)) {
82 BYTE call
; /* 0xe8 call callfrom32 (relative) */
83 DWORD callfrom32 WINE_PACKED
; /* RELAY_CallFrom32 relative addr */
84 BYTE ret
; /* 0xc2 ret $n or 0xc3 ret */
85 WORD args
; /* nb of args to remove from the stack */
86 void *orig
; /* original entry point */
87 DWORD argtypes
; /* argument types */
91 /***********************************************************************
94 * Find the name of an exported function.
96 static const char *find_exported_name( const char *module
,
97 IMAGE_EXPORT_DIRECTORY
*exp
, int ordinal
)
100 const char *ret
= NULL
;
102 WORD
*ordptr
= (WORD
*)(module
+ exp
->AddressOfNameOrdinals
);
103 for (i
= 0; i
< exp
->NumberOfNames
; i
++, ordptr
++)
104 if (*ordptr
+ exp
->Base
== ordinal
) break;
105 if (i
< exp
->NumberOfNames
)
106 ret
= module
+ ((DWORD
*)(module
+ exp
->AddressOfNames
))[i
];
111 /***********************************************************************
114 * Get the name of the DLL entry point corresponding to a relay address.
116 static void get_entry_point( char *buffer
, DEBUG_ENTRY_POINT
*relay
)
118 IMAGE_DATA_DIRECTORY
*dir
;
119 IMAGE_EXPORT_DIRECTORY
*exp
= NULL
;
120 DEBUG_ENTRY_POINT
*debug
;
126 /* First find the module */
128 for (wm
= MODULE_modref_list
; wm
; wm
= wm
->next
)
130 if (!(wm
->flags
& WINE_MODREF_INTERNAL
)) continue;
131 base
= (char *)wm
->module
;
132 dir
= &PE_HEADER(base
)->OptionalHeader
.DataDirectory
[IMAGE_FILE_EXPORT_DIRECTORY
];
133 if (!dir
->Size
) continue;
134 exp
= (IMAGE_EXPORT_DIRECTORY
*)(base
+ dir
->VirtualAddress
);
135 debug
= (DEBUG_ENTRY_POINT
*)((char *)exp
+ dir
->Size
);
136 if (debug
<= relay
&& relay
< debug
+ exp
->NumberOfFunctions
)
138 ordinal
= relay
- debug
;
143 /* Now find the function */
145 if ((name
= find_exported_name( base
, exp
, ordinal
+ exp
->Base
)))
146 sprintf( buffer
, "%s.%s", base
+ exp
->Name
, name
);
148 sprintf( buffer
, "%s.%ld", base
+ exp
->Name
, ordinal
+ exp
->Base
);
152 /***********************************************************************
155 static inline void RELAY_PrintArgs( int *args
, int nb_args
, unsigned int typemask
)
159 if ((typemask
& 3) && HIWORD(*args
))
162 DPRINTF( "%08x %s", *args
, debugstr_w((LPWSTR
)*args
) );
164 DPRINTF( "%08x %s", *args
, debugstr_a((LPCSTR
)*args
) );
166 else DPRINTF( "%08x", *args
);
167 if (nb_args
) DPRINTF( "," );
174 typedef LONGLONG (*LONGLONG_CPROC
)();
175 typedef LONGLONG (WINAPI
*LONGLONG_FARPROC
)();
178 /***********************************************************************
179 * call_cdecl_function
181 static LONGLONG
call_cdecl_function( LONGLONG_CPROC func
, int nb_args
, const int *args
)
186 case 0: ret
= func(); break;
187 case 1: ret
= func(args
[0]); break;
188 case 2: ret
= func(args
[0],args
[1]); break;
189 case 3: ret
= func(args
[0],args
[1],args
[2]); break;
190 case 4: ret
= func(args
[0],args
[1],args
[2],args
[3]); break;
191 case 5: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4]); break;
192 case 6: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],
194 case 7: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
196 case 8: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
197 args
[6],args
[7]); break;
198 case 9: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
199 args
[6],args
[7],args
[8]); break;
200 case 10: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
201 args
[6],args
[7],args
[8],args
[9]); break;
202 case 11: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
203 args
[6],args
[7],args
[8],args
[9],args
[10]); break;
204 case 12: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
205 args
[6],args
[7],args
[8],args
[9],args
[10],
207 case 13: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
208 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
210 case 14: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
211 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
212 args
[12],args
[13]); break;
213 case 15: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
214 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
215 args
[12],args
[13],args
[14]); break;
216 case 16: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
217 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
218 args
[12],args
[13],args
[14],args
[15]); break;
220 ERR( "Unsupported nb of args %d\n", nb_args
);
227 /***********************************************************************
228 * call_stdcall_function
230 static LONGLONG
call_stdcall_function( LONGLONG_FARPROC func
, int nb_args
, const int *args
)
235 case 0: ret
= func(); break;
236 case 1: ret
= func(args
[0]); break;
237 case 2: ret
= func(args
[0],args
[1]); break;
238 case 3: ret
= func(args
[0],args
[1],args
[2]); break;
239 case 4: ret
= func(args
[0],args
[1],args
[2],args
[3]); break;
240 case 5: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4]); break;
241 case 6: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],
243 case 7: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
245 case 8: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
246 args
[6],args
[7]); break;
247 case 9: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
248 args
[6],args
[7],args
[8]); break;
249 case 10: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
250 args
[6],args
[7],args
[8],args
[9]); break;
251 case 11: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
252 args
[6],args
[7],args
[8],args
[9],args
[10]); break;
253 case 12: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
254 args
[6],args
[7],args
[8],args
[9],args
[10],
256 case 13: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
257 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
259 case 14: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
260 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
261 args
[12],args
[13]); break;
262 case 15: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
263 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
264 args
[12],args
[13],args
[14]); break;
265 case 16: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
266 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
267 args
[12],args
[13],args
[14],args
[15]); break;
269 ERR( "Unsupported nb of args %d\n", nb_args
);
276 /***********************************************************************
279 * Stack layout on entry to this function:
284 * (esp) return addr to relay code
286 static LONGLONG
RELAY_CallFrom32( int ret_addr
, ... )
292 int *args
= &ret_addr
+ 1;
293 /* Relay addr is the return address for this function */
294 BYTE
*relay_addr
= (BYTE
*)__builtin_return_address(0);
295 DEBUG_ENTRY_POINT
*relay
= (DEBUG_ENTRY_POINT
*)(relay_addr
- 5);
296 WORD nb_args
= relay
->args
/ sizeof(int);
298 get_entry_point( buffer
, relay
);
300 DPRINTF( "%08lx:Call %s(", GetCurrentThreadId(), buffer
);
301 RELAY_PrintArgs( args
, nb_args
, relay
->argtypes
);
302 DPRINTF( ") ret=%08x\n", ret_addr
);
303 ret64
= (relay
->argtypes
& 0x80000000) && (nb_args
< 16);
305 if (relay
->ret
== 0xc3) /* cdecl */
307 ret
= call_cdecl_function( (LONGLONG_CPROC
)relay
->orig
, nb_args
, args
);
311 ret
= call_stdcall_function( (LONGLONG_FARPROC
)relay
->orig
, nb_args
, args
);
315 DPRINTF( "%08lx:Ret %s() retval=%08x%08x ret=%08x\n",
316 GetCurrentThreadId(),
317 buffer
, (UINT
)(ret
>> 32), (UINT
)ret
, ret_addr
);
319 DPRINTF( "%08lx:Ret %s() retval=%08x ret=%08x\n",
320 GetCurrentThreadId(),
321 buffer
, (UINT
)ret
, ret_addr
);
327 /***********************************************************************
328 * RELAY_CallFrom32Regs
330 * Stack layout (esp is context->Esp, not the current %esp):
334 * (esp) return addr to caller
335 * (esp-4) return addr to DEBUG_ENTRY_POINT
336 * (esp-8) ptr to relay entry code for RELAY_CallFrom32Regs
337 * ... >128 bytes space free to be modified (ensured by the assembly glue)
339 void WINAPI
RELAY_DoCallFrom32Regs( CONTEXT86
*context
)
346 BYTE
*relay_addr
= *((BYTE
**)context
->Esp
- 1);
347 DEBUG_ENTRY_POINT
*relay
= (DEBUG_ENTRY_POINT
*)(relay_addr
- 5);
348 WORD nb_args
= (relay
->args
& ~0x8000) / sizeof(int);
350 /* remove extra stuff from the stack */
351 context
->Eip
= stack32_pop(context
);
352 args
= (int *)context
->Esp
;
353 if (relay
->ret
== 0xc2) /* stdcall */
354 context
->Esp
+= nb_args
* sizeof(int);
356 assert(TRACE_ON(relay
));
358 entry_point
= (BYTE
*)relay
->orig
;
359 assert( *entry_point
== 0xe8 /* lcall */ );
361 get_entry_point( buffer
, relay
);
363 DPRINTF( "%08lx:Call %s(", GetCurrentThreadId(), buffer
);
364 RELAY_PrintArgs( args
, nb_args
, relay
->argtypes
);
365 DPRINTF( ") ret=%08lx fs=%04lx\n", context
->Eip
, context
->SegFs
);
367 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
368 context
->Eax
, context
->Ebx
, context
->Ecx
,
369 context
->Edx
, context
->Esi
, context
->Edi
);
370 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
371 context
->Ebp
, context
->Esp
, context
->SegDs
,
372 context
->SegEs
, context
->SegGs
, context
->EFlags
);
374 /* Now call the real function */
376 memcpy( args_copy
, args
, nb_args
* sizeof(args
[0]) );
377 args_copy
[nb_args
] = (int)context
; /* append context argument */
378 if (relay
->ret
== 0xc3) /* cdecl */
380 call_cdecl_function( *(LONGLONG_CPROC
*)(entry_point
+ 5), nb_args
+1, args_copy
);
384 call_stdcall_function( *(LONGLONG_FARPROC
*)(entry_point
+ 5), nb_args
+1, args_copy
);
387 DPRINTF( "%08lx:Ret %s() retval=%08lx ret=%08lx fs=%04lx\n",
388 GetCurrentThreadId(),
389 buffer
, context
->Eax
, context
->Eip
, context
->SegFs
);
391 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
392 context
->Eax
, context
->Ebx
, context
->Ecx
,
393 context
->Edx
, context
->Esi
, context
->Edi
);
394 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
395 context
->Ebp
, context
->Esp
, context
->SegDs
,
396 context
->SegEs
, context
->SegGs
, context
->EFlags
);
399 void WINAPI
RELAY_CallFrom32Regs(void);
400 __ASM_GLOBAL_FUNC( RELAY_CallFrom32Regs
,
401 "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
402 ".long " __ASM_NAME("RELAY_DoCallFrom32Regs") ",0" );
404 /***********************************************************************
407 * Setup relay debugging for a built-in dll.
409 void RELAY_SetupDLL( const char *module
)
411 IMAGE_DATA_DIRECTORY
*dir
;
412 IMAGE_EXPORT_DIRECTORY
*exports
;
413 DEBUG_ENTRY_POINT
*debug
;
416 const char *name
, *dllname
;
418 dir
= &PE_HEADER(module
)->OptionalHeader
.DataDirectory
[IMAGE_FILE_EXPORT_DIRECTORY
];
419 if (!dir
->Size
) return;
420 exports
= (IMAGE_EXPORT_DIRECTORY
*)(module
+ dir
->VirtualAddress
);
421 debug
= (DEBUG_ENTRY_POINT
*)((char *)exports
+ dir
->Size
);
422 funcs
= (DWORD
*)(module
+ exports
->AddressOfFunctions
);
423 dllname
= module
+ exports
->Name
;
425 for (i
= 0; i
< exports
->NumberOfFunctions
; i
++, funcs
++, debug
++)
429 if (!debug
->call
) continue; /* not a normal function */
430 if (debug
->call
!= 0xe8 && debug
->call
!= 0xe9) break; /* not a debug thunk at all */
432 if ((name
= find_exported_name( module
, exports
, i
+ exports
->Base
)))
435 sprintf( buffer
, "%s.%d: %s", dllname
, i
, name
);
436 on
= RELAY_ShowDebugmsgRelay(buffer
);
441 debug
->call
= 0xe8; /* call relative */
442 if (debug
->args
& 0x8000) /* register func */
443 debug
->callfrom32
= (char *)RELAY_CallFrom32Regs
- (char *)&debug
->ret
;
445 debug
->callfrom32
= (char *)RELAY_CallFrom32
- (char *)&debug
->ret
;
449 debug
->call
= 0xe9; /* jmp relative */
450 debug
->callfrom32
= (char *)debug
->orig
- (char *)&debug
->ret
;
453 debug
->orig
= (FARPROC
)(module
+ (DWORD
)*funcs
);
454 *funcs
= (char *)debug
- module
;
460 void RELAY_SetupDLL( const char *module
)
464 #endif /* __i386__ */