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"
30 #include "stackframe.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(relay
);
35 WINE_DECLARE_DEBUG_CHANNEL(snoop
);
37 const char **debug_relay_excludelist
= NULL
;
38 const char **debug_relay_includelist
= NULL
;
39 const char **debug_snoop_excludelist
= NULL
;
40 const char **debug_snoop_includelist
= NULL
;
42 /***********************************************************************
45 * Build a function list from a ';'-separated string.
47 static const char **build_list( const char *buffer
)
50 const char *p
= buffer
;
53 while ((p
= strchr( p
, ';' )))
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 )))
61 char *str
= (char *)(ret
+ count
+ 1);
64 strcpy( str
, buffer
);
69 if (!(p
= strchr( p
, ';' ))) break;
78 /***********************************************************************
79 * RELAY_InitDebugLists
81 * Build the relay include/exclude function lists.
83 void RELAY_InitDebugLists(void)
89 if (RegOpenKeyA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\Debug", &hkey
)) return;
91 count
= sizeof(buffer
);
92 if (!RegQueryValueExA( hkey
, "RelayInclude", NULL
, &type
, buffer
, &count
))
94 TRACE("RelayInclude = %s\n", buffer
);
95 debug_relay_includelist
= build_list( buffer
);
98 count
= sizeof(buffer
);
99 if (!RegQueryValueExA( hkey
, "RelayExclude", NULL
, &type
, buffer
, &count
))
101 TRACE( "RelayExclude = %s\n", buffer
);
102 debug_relay_excludelist
= build_list( buffer
);
105 count
= sizeof(buffer
);
106 if (!RegQueryValueExA( hkey
, "SnoopInclude", NULL
, &type
, buffer
, &count
))
108 TRACE_(snoop
)( "SnoopInclude = %s\n", buffer
);
109 debug_snoop_includelist
= build_list( buffer
);
112 count
= sizeof(buffer
);
113 if (!RegQueryValueExA( hkey
, "SnoopExclude", NULL
, &type
, buffer
, &count
))
115 TRACE_(snoop
)( "SnoopExclude = %s\n", buffer
);
116 debug_snoop_excludelist
= build_list( buffer
);
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 */
131 void *orig
; /* original entry point */
132 DWORD argtypes
; /* argument types */
136 /***********************************************************************
137 * check_relay_include
139 * Check if a given function must be included in the relay output.
141 static BOOL
check_relay_include( const char *module
, const char *func
)
143 const char **listitem
;
146 if (!debug_relay_excludelist
&& !debug_relay_includelist
) return TRUE
;
147 if (debug_relay_excludelist
)
150 listitem
= debug_relay_excludelist
;
155 listitem
= debug_relay_includelist
;
157 for(; *listitem
; listitem
++)
159 char *p
= strchr( *listitem
, '.' );
160 if (p
&& p
> *listitem
) /* check module and function */
162 int len
= p
- *listitem
;
163 if (strncasecmp( *listitem
, module
, len
-1 ) || module
[len
]) continue;
164 if (!strcmp( p
+ 1, func
)) return !show
;
166 else /* function only */
168 if (!strcmp( *listitem
, func
)) return !show
;
175 /***********************************************************************
178 * Find the name of an exported function.
180 static const char *find_exported_name( const char *module
,
181 IMAGE_EXPORT_DIRECTORY
*exp
, int ordinal
)
184 const char *ret
= NULL
;
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
];
195 /***********************************************************************
198 * Get the name of the DLL entry point corresponding to a relay address.
200 static void get_entry_point( char *buffer
, DEBUG_ENTRY_POINT
*relay
)
202 IMAGE_DATA_DIRECTORY
*dir
;
203 IMAGE_EXPORT_DIRECTORY
*exp
= NULL
;
204 DEBUG_ENTRY_POINT
*debug
;
210 /* First find the module */
212 for (wm
= MODULE_modref_list
; wm
; wm
= wm
->next
)
214 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
)
222 ordinal
= relay
- debug
;
227 /* Now find the function */
229 if ((name
= find_exported_name( base
, exp
, ordinal
+ exp
->Base
)))
230 sprintf( buffer
, "%s.%s", base
+ exp
->Name
, name
);
232 sprintf( buffer
, "%s.%ld", base
+ exp
->Name
, ordinal
+ exp
->Base
);
236 /***********************************************************************
239 static inline void RELAY_PrintArgs( int *args
, int nb_args
, unsigned int typemask
)
243 if ((typemask
& 3) && HIWORD(*args
))
246 DPRINTF( "%08x %s", *args
, debugstr_w((LPWSTR
)*args
) );
248 DPRINTF( "%08x %s", *args
, debugstr_a((LPCSTR
)*args
) );
250 else DPRINTF( "%08x", *args
);
251 if (nb_args
) DPRINTF( "," );
258 typedef LONGLONG (*LONGLONG_CPROC
)();
259 typedef LONGLONG (WINAPI
*LONGLONG_FARPROC
)();
262 /***********************************************************************
263 * call_cdecl_function
265 static LONGLONG
call_cdecl_function( LONGLONG_CPROC func
, int nb_args
, const int *args
)
270 case 0: ret
= func(); break;
271 case 1: ret
= func(args
[0]); break;
272 case 2: ret
= func(args
[0],args
[1]); break;
273 case 3: ret
= func(args
[0],args
[1],args
[2]); break;
274 case 4: ret
= func(args
[0],args
[1],args
[2],args
[3]); break;
275 case 5: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4]); break;
276 case 6: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],
278 case 7: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
280 case 8: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
281 args
[6],args
[7]); break;
282 case 9: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
283 args
[6],args
[7],args
[8]); break;
284 case 10: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
285 args
[6],args
[7],args
[8],args
[9]); break;
286 case 11: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
287 args
[6],args
[7],args
[8],args
[9],args
[10]); break;
288 case 12: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
289 args
[6],args
[7],args
[8],args
[9],args
[10],
291 case 13: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
292 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
294 case 14: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
295 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
296 args
[12],args
[13]); break;
297 case 15: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
298 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
299 args
[12],args
[13],args
[14]); break;
300 case 16: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
301 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
302 args
[12],args
[13],args
[14],args
[15]); break;
304 ERR( "Unsupported nb of args %d\n", nb_args
);
311 /***********************************************************************
312 * call_stdcall_function
314 static LONGLONG
call_stdcall_function( LONGLONG_FARPROC func
, int nb_args
, const int *args
)
319 case 0: ret
= func(); break;
320 case 1: ret
= func(args
[0]); break;
321 case 2: ret
= func(args
[0],args
[1]); break;
322 case 3: ret
= func(args
[0],args
[1],args
[2]); break;
323 case 4: ret
= func(args
[0],args
[1],args
[2],args
[3]); break;
324 case 5: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4]); break;
325 case 6: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],
327 case 7: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
329 case 8: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
330 args
[6],args
[7]); break;
331 case 9: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
332 args
[6],args
[7],args
[8]); break;
333 case 10: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
334 args
[6],args
[7],args
[8],args
[9]); break;
335 case 11: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
336 args
[6],args
[7],args
[8],args
[9],args
[10]); break;
337 case 12: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
338 args
[6],args
[7],args
[8],args
[9],args
[10],
340 case 13: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
341 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
343 case 14: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
344 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
345 args
[12],args
[13]); break;
346 case 15: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
347 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
348 args
[12],args
[13],args
[14]); break;
349 case 16: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
350 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
351 args
[12],args
[13],args
[14],args
[15]); break;
353 ERR( "Unsupported nb of args %d\n", nb_args
);
360 /***********************************************************************
363 * Stack layout on entry to this function:
368 * (esp) return addr to relay code
370 static LONGLONG
RELAY_CallFrom32( int ret_addr
, ... )
375 int *args
= &ret_addr
+ 1;
376 /* Relay addr is the return address for this function */
377 BYTE
*relay_addr
= (BYTE
*)__builtin_return_address(0);
378 DEBUG_ENTRY_POINT
*relay
= (DEBUG_ENTRY_POINT
*)(relay_addr
- 5);
379 WORD nb_args
= relay
->args
/ sizeof(int);
383 get_entry_point( buffer
, relay
);
385 DPRINTF( "%08lx:Call %s(", GetCurrentThreadId(), buffer
);
386 RELAY_PrintArgs( args
, nb_args
, relay
->argtypes
);
387 DPRINTF( ") ret=%08x\n", ret_addr
);
390 if (relay
->ret
== 0xc3) /* cdecl */
392 ret
= call_cdecl_function( (LONGLONG_CPROC
)relay
->orig
, nb_args
, args
);
396 ret
= call_stdcall_function( (LONGLONG_FARPROC
)relay
->orig
, nb_args
, args
);
401 BOOL ret64
= (relay
->argtypes
& 0x80000000) && (nb_args
< 16);
403 DPRINTF( "%08lx:Ret %s() retval=%08x%08x ret=%08x\n",
404 GetCurrentThreadId(),
405 buffer
, (UINT
)(ret
>> 32), (UINT
)ret
, ret_addr
);
407 DPRINTF( "%08lx:Ret %s() retval=%08x ret=%08x\n",
408 GetCurrentThreadId(),
409 buffer
, (UINT
)ret
, ret_addr
);
415 /***********************************************************************
416 * RELAY_CallFrom32Regs
418 * Stack layout (esp is context->Esp, not the current %esp):
422 * (esp) return addr to caller
423 * (esp-4) return addr to DEBUG_ENTRY_POINT
424 * (esp-8) ptr to relay entry code for RELAY_CallFrom32Regs
425 * ... >128 bytes space free to be modified (ensured by the assembly glue)
427 void WINAPI
RELAY_DoCallFrom32Regs( CONTEXT86
*context
)
434 BYTE
*relay_addr
= *((BYTE
**)context
->Esp
- 1);
435 DEBUG_ENTRY_POINT
*relay
= (DEBUG_ENTRY_POINT
*)(relay_addr
- 5);
436 WORD nb_args
= (relay
->args
& ~0x8000) / sizeof(int);
438 /* remove extra stuff from the stack */
439 context
->Eip
= stack32_pop(context
);
440 args
= (int *)context
->Esp
;
441 if (relay
->ret
== 0xc2) /* stdcall */
442 context
->Esp
+= nb_args
* sizeof(int);
444 entry_point
= (BYTE
*)relay
->orig
;
445 assert( *entry_point
== 0xe8 /* lcall */ );
449 get_entry_point( buffer
, relay
);
451 DPRINTF( "%08lx:Call %s(", GetCurrentThreadId(), buffer
);
452 RELAY_PrintArgs( args
, nb_args
, relay
->argtypes
);
453 DPRINTF( ") ret=%08lx fs=%04lx\n", context
->Eip
, context
->SegFs
);
455 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
456 context
->Eax
, context
->Ebx
, context
->Ecx
,
457 context
->Edx
, context
->Esi
, context
->Edi
);
458 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
459 context
->Ebp
, context
->Esp
, context
->SegDs
,
460 context
->SegEs
, context
->SegGs
, context
->EFlags
);
463 /* Now call the real function */
465 memcpy( args_copy
, args
, nb_args
* sizeof(args
[0]) );
466 args_copy
[nb_args
] = (int)context
; /* append context argument */
467 if (relay
->ret
== 0xc3) /* cdecl */
469 call_cdecl_function( *(LONGLONG_CPROC
*)(entry_point
+ 5), nb_args
+1, args_copy
);
473 call_stdcall_function( *(LONGLONG_FARPROC
*)(entry_point
+ 5), nb_args
+1, args_copy
);
478 DPRINTF( "%08lx:Ret %s() retval=%08lx ret=%08lx fs=%04lx\n",
479 GetCurrentThreadId(),
480 buffer
, context
->Eax
, context
->Eip
, context
->SegFs
);
482 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
483 context
->Eax
, context
->Ebx
, context
->Ecx
,
484 context
->Edx
, context
->Esi
, context
->Edi
);
485 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
486 context
->Ebp
, context
->Esp
, context
->SegDs
,
487 context
->SegEs
, context
->SegGs
, context
->EFlags
);
491 void WINAPI
RELAY_CallFrom32Regs(void);
492 __ASM_GLOBAL_FUNC( RELAY_CallFrom32Regs
,
493 "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
494 ".long " __ASM_NAME("RELAY_DoCallFrom32Regs") ",0" );
496 /***********************************************************************
499 * Setup relay debugging for a built-in dll.
501 void RELAY_SetupDLL( const char *module
)
503 IMAGE_DATA_DIRECTORY
*dir
;
504 IMAGE_EXPORT_DIRECTORY
*exports
;
505 DEBUG_ENTRY_POINT
*debug
;
508 const char *name
, *dllname
;
510 dir
= &PE_HEADER(module
)->OptionalHeader
.DataDirectory
[IMAGE_FILE_EXPORT_DIRECTORY
];
511 if (!dir
->Size
) return;
512 exports
= (IMAGE_EXPORT_DIRECTORY
*)(module
+ dir
->VirtualAddress
);
513 debug
= (DEBUG_ENTRY_POINT
*)((char *)exports
+ dir
->Size
);
514 funcs
= (DWORD
*)(module
+ exports
->AddressOfFunctions
);
515 dllname
= module
+ exports
->Name
;
517 for (i
= 0; i
< exports
->NumberOfFunctions
; i
++, funcs
++, debug
++)
521 if (!debug
->call
) continue; /* not a normal function */
522 if (debug
->call
!= 0xe8 && debug
->call
!= 0xe9) break; /* not a debug thunk at all */
524 if ((name
= find_exported_name( module
, exports
, i
+ exports
->Base
)))
525 on
= check_relay_include( dllname
, name
);
529 debug
->call
= 0xe8; /* call relative */
530 if (debug
->args
& 0x8000) /* register func */
531 debug
->callfrom32
= (char *)RELAY_CallFrom32Regs
- (char *)&debug
->ret
;
533 debug
->callfrom32
= (char *)RELAY_CallFrom32
- (char *)&debug
->ret
;
537 debug
->call
= 0xe9; /* jmp relative */
538 debug
->callfrom32
= (char *)debug
->orig
- (char *)&debug
->ret
;
541 debug
->orig
= (FARPROC
)(module
+ (DWORD
)*funcs
);
542 *funcs
= (char *)debug
- module
;
548 void RELAY_SetupDLL( const char *module
)
552 #endif /* __i386__ */