Correct the comparison of two files. Just because they are the same
[wine/hacks.git] / relay32 / relay386.c
blobb5eb97002e130fdd785a4bd313900990903929c5
1 /*
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <string.h>
26 #include <stdio.h>
28 #include "winnt.h"
29 #include "winreg.h"
30 #include "stackframe.h"
31 #include "module.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 /***********************************************************************
43 * build_list
45 * Build a function list from a ';'-separated string.
47 static const char **build_list( const char *buffer )
49 int count = 1;
50 const char *p = buffer;
51 const char **ret;
53 while ((p = strchr( p, ';' )))
55 count++;
56 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);
62 char *p = str;
64 strcpy( str, buffer );
65 count = 0;
66 for (;;)
68 ret[count++] = p;
69 if (!(p = strchr( p, ';' ))) break;
70 *p++ = 0;
72 ret[count++] = NULL;
74 return ret;
78 /***********************************************************************
79 * RELAY_InitDebugLists
81 * Build the relay include/exclude function lists.
83 void RELAY_InitDebugLists(void)
85 char buffer[1024];
86 HKEY hkey;
87 DWORD count, type;
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 );
119 RegCloseKey( hkey );
123 #ifdef __i386__
125 typedef struct
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 */
133 } DEBUG_ENTRY_POINT;
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;
144 BOOL show;
146 if (!debug_relay_excludelist && !debug_relay_includelist) return TRUE;
147 if (debug_relay_excludelist)
149 show = TRUE;
150 listitem = debug_relay_excludelist;
152 else
154 show = FALSE;
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;
171 return show;
175 /***********************************************************************
176 * find_exported_name
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 )
183 int i;
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];
191 return ret;
195 /***********************************************************************
196 * get_entry_point
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;
205 char *base = NULL;
206 const char *name;
207 int ordinal = 0;
208 WINE_MODREF *wm;
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;
223 break;
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 );
231 else
232 sprintf( buffer, "%s.%ld", base + exp->Name, ordinal + exp->Base );
236 /***********************************************************************
237 * RELAY_PrintArgs
239 static inline void RELAY_PrintArgs( int *args, int nb_args, unsigned int typemask )
241 while (nb_args--)
243 if ((typemask & 3) && HIWORD(*args))
245 if (typemask & 2)
246 DPRINTF( "%08x %s", *args, debugstr_w((LPWSTR)*args) );
247 else
248 DPRINTF( "%08x %s", *args, debugstr_a((LPCSTR)*args) );
250 else DPRINTF( "%08x", *args );
251 if (nb_args) DPRINTF( "," );
252 args++;
253 typemask >>= 2;
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 )
267 LONGLONG ret;
268 switch(nb_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],
277 args[5]); break;
278 case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
279 args[6]); break;
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],
290 args[11]); break;
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],
293 args[12]); break;
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;
303 default:
304 ERR( "Unsupported nb of args %d\n", nb_args );
305 assert(FALSE);
307 return ret;
311 /***********************************************************************
312 * call_stdcall_function
314 static LONGLONG call_stdcall_function( LONGLONG_FARPROC func, int nb_args, const int *args )
316 LONGLONG ret;
317 switch(nb_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],
326 args[5]); break;
327 case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
328 args[6]); break;
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],
339 args[11]); break;
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],
342 args[12]); break;
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;
352 default:
353 ERR( "Unsupported nb of args %d\n", nb_args );
354 assert(FALSE);
356 return ret;
360 /***********************************************************************
361 * RELAY_CallFrom32
363 * Stack layout on entry to this function:
364 * ... ...
365 * (esp+12) arg2
366 * (esp+8) arg1
367 * (esp+4) ret_addr
368 * (esp) return addr to relay code
370 static LONGLONG RELAY_CallFrom32( int ret_addr, ... )
372 LONGLONG ret;
373 char buffer[80];
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);
381 if (TRACE_ON(relay))
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 );
394 else /* stdcall */
396 ret = call_stdcall_function( (LONGLONG_FARPROC)relay->orig, nb_args, args );
399 if (TRACE_ON(relay))
401 BOOL ret64 = (relay->argtypes & 0x80000000) && (nb_args < 16);
402 if (ret64)
403 DPRINTF( "%08lx:Ret %s() retval=%08x%08x ret=%08x\n",
404 GetCurrentThreadId(),
405 buffer, (UINT)(ret >> 32), (UINT)ret, ret_addr );
406 else
407 DPRINTF( "%08lx:Ret %s() retval=%08x ret=%08x\n",
408 GetCurrentThreadId(),
409 buffer, (UINT)ret, ret_addr );
411 return ret;
415 /***********************************************************************
416 * RELAY_CallFrom32Regs
418 * Stack layout (esp is context->Esp, not the current %esp):
420 * ...
421 * (esp+4) first arg
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 )
429 char buffer[80];
430 int* args;
431 int args_copy[17];
432 BYTE *entry_point;
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 */ );
447 if (TRACE_ON(relay))
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 );
471 else /* stdcall */
473 call_stdcall_function( *(LONGLONG_FARPROC *)(entry_point + 5), nb_args+1, args_copy );
476 if (TRACE_ON(relay))
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 /***********************************************************************
497 * RELAY_SetupDLL
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;
506 DWORD *funcs;
507 int i;
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++)
519 int on = 1;
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 );
527 if (on)
529 debug->call = 0xe8; /* call relative */
530 if (debug->args & 0x8000) /* register func */
531 debug->callfrom32 = (char *)RELAY_CallFrom32Regs - (char *)&debug->ret;
532 else
533 debug->callfrom32 = (char *)RELAY_CallFrom32 - (char *)&debug->ret;
535 else
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;
546 #else /* __i386__ */
548 void RELAY_SetupDLL( const char *module )
552 #endif /* __i386__ */