Introduce the -J, --input-format options for compatibility with
[wine/multimedia.git] / relay32 / relay386.c
blob543da943d61f65d6270db96cc805fda8fbee640b
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 "windef.h"
29 #include "winternl.h"
30 #include "stackframe.h"
31 #include "module.h"
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(relay);
36 WINE_DECLARE_DEBUG_CHANNEL(snoop);
38 const char **debug_relay_excludelist = NULL;
39 const char **debug_relay_includelist = NULL;
40 const char **debug_snoop_excludelist = NULL;
41 const char **debug_snoop_includelist = NULL;
43 /***********************************************************************
44 * build_list
46 * Build a function list from a ';'-separated string.
48 static const char **build_list( const WCHAR *bufferW )
50 int count = 1;
51 char buffer[1024];
52 const char *p = buffer;
53 const char **ret;
55 RtlUnicodeToMultiByteN( buffer, sizeof(buffer), NULL,
56 bufferW, (strlenW(bufferW)+1) * sizeof(WCHAR) );
58 while ((p = strchr( p, ';' )))
60 count++;
61 p++;
63 /* allocate count+1 pointers, plus the space for a copy of the string */
64 if ((ret = HeapAlloc( GetProcessHeap(), 0, (count+1) * sizeof(char*) + strlen(buffer) + 1 )))
66 char *str = (char *)(ret + count + 1);
67 char *p = str;
69 strcpy( str, buffer );
70 count = 0;
71 for (;;)
73 ret[count++] = p;
74 if (!(p = strchr( p, ';' ))) break;
75 *p++ = 0;
77 ret[count++] = NULL;
79 return ret;
83 /***********************************************************************
84 * RELAY_InitDebugLists
86 * Build the relay include/exclude function lists.
88 void RELAY_InitDebugLists(void)
90 OBJECT_ATTRIBUTES attr;
91 UNICODE_STRING name;
92 char buffer[1024];
93 HKEY hkey;
94 DWORD count;
95 WCHAR *str;
96 static const WCHAR configW[] = {'M','a','c','h','i','n','e','\\',
97 'S','o','f','t','w','a','r','e','\\',
98 'W','i','n','e','\\',
99 'W','i','n','e','\\',
100 'C','o','n','f','i','g','\\',
101 'D','e','b','u','g',0};
102 static const WCHAR RelayIncludeW[] = {'R','e','l','a','y','I','n','c','l','u','d','e',0};
103 static const WCHAR RelayExcludeW[] = {'R','e','l','a','y','E','x','c','l','u','d','e',0};
104 static const WCHAR SnoopIncludeW[] = {'S','n','o','o','p','I','n','c','l','u','d','e',0};
105 static const WCHAR SnoopExcludeW[] = {'S','n','o','o','p','E','x','c','l','u','d','e',0};
107 attr.Length = sizeof(attr);
108 attr.RootDirectory = 0;
109 attr.ObjectName = &name;
110 attr.Attributes = 0;
111 attr.SecurityDescriptor = NULL;
112 attr.SecurityQualityOfService = NULL;
113 RtlInitUnicodeString( &name, configW );
115 if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return;
117 str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)buffer)->Data;
118 RtlInitUnicodeString( &name, RelayIncludeW );
119 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
121 TRACE("RelayInclude = %s\n", debugstr_w(str) );
122 debug_relay_includelist = build_list( str );
125 RtlInitUnicodeString( &name, RelayExcludeW );
126 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
128 TRACE( "RelayExclude = %s\n", debugstr_w(str) );
129 debug_relay_excludelist = build_list( str );
132 RtlInitUnicodeString( &name, SnoopIncludeW );
133 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
135 TRACE_(snoop)( "SnoopInclude = %s\n", debugstr_w(str) );
136 debug_snoop_includelist = build_list( str );
139 RtlInitUnicodeString( &name, SnoopExcludeW );
140 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
142 TRACE_(snoop)( "SnoopExclude = %s\n", debugstr_w(str) );
143 debug_snoop_excludelist = build_list( str );
146 NtClose( hkey );
150 #ifdef __i386__
152 typedef struct
154 BYTE call; /* 0xe8 call callfrom32 (relative) */
155 DWORD callfrom32 WINE_PACKED; /* RELAY_CallFrom32 relative addr */
156 BYTE ret; /* 0xc2 ret $n or 0xc3 ret */
157 WORD args; /* nb of args to remove from the stack */
158 void *orig; /* original entry point */
159 DWORD argtypes; /* argument types */
160 } DEBUG_ENTRY_POINT;
163 /***********************************************************************
164 * check_relay_include
166 * Check if a given function must be included in the relay output.
168 static BOOL check_relay_include( const char *module, const char *func )
170 const char **listitem;
171 BOOL show;
173 if (!debug_relay_excludelist && !debug_relay_includelist) return TRUE;
174 if (debug_relay_excludelist)
176 show = TRUE;
177 listitem = debug_relay_excludelist;
179 else
181 show = FALSE;
182 listitem = debug_relay_includelist;
184 for(; *listitem; listitem++)
186 char *p = strrchr( *listitem, '.' );
187 if (p && p > *listitem) /* check module and function */
189 int len = p - *listitem;
190 if (strncasecmp( *listitem, module, len-1 ) || module[len]) continue;
191 if (!strcmp( p + 1, func ) || !strcmp( p + 1, "*" )) return !show;
193 else /* function only */
195 if (!strcmp( *listitem, func )) return !show;
198 return show;
202 /***********************************************************************
203 * find_exported_name
205 * Find the name of an exported function.
207 static const char *find_exported_name( const char *module,
208 IMAGE_EXPORT_DIRECTORY *exp, int ordinal )
210 int i;
211 const char *ret = NULL;
213 WORD *ordptr = (WORD *)(module + exp->AddressOfNameOrdinals);
214 for (i = 0; i < exp->NumberOfNames; i++, ordptr++)
215 if (*ordptr + exp->Base == ordinal) break;
216 if (i < exp->NumberOfNames)
217 ret = module + ((DWORD*)(module + exp->AddressOfNames))[i];
218 return ret;
222 /***********************************************************************
223 * get_entry_point
225 * Get the name of the DLL entry point corresponding to a relay address.
227 static void get_entry_point( char *buffer, DEBUG_ENTRY_POINT *relay )
229 IMAGE_EXPORT_DIRECTORY *exp = NULL;
230 DEBUG_ENTRY_POINT *debug;
231 char *p, *base = NULL;
232 const char *name;
233 int ordinal = 0;
234 WINE_MODREF *wm;
235 DWORD size;
237 /* First find the module */
239 for (wm = MODULE_modref_list; wm; wm = wm->next)
241 if (!(wm->flags & WINE_MODREF_INTERNAL)) continue;
242 exp = RtlImageDirectoryEntryToData( wm->module, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size );
243 if (!exp) continue;
244 debug = (DEBUG_ENTRY_POINT *)((char *)exp + size);
245 if (debug <= relay && relay < debug + exp->NumberOfFunctions)
247 ordinal = relay - debug;
248 break;
252 /* Now find the function */
254 base = (char *)wm->module;
255 strcpy( buffer, base + exp->Name );
256 p = buffer + strlen(buffer);
257 if (p > buffer + 4 && !strcasecmp( p - 4, ".dll" )) p -= 4;
259 if ((name = find_exported_name( base, exp, ordinal + exp->Base )))
260 sprintf( p, ".%s", name );
261 else
262 sprintf( p, ".%ld", ordinal + exp->Base );
266 /***********************************************************************
267 * RELAY_PrintArgs
269 static inline void RELAY_PrintArgs( int *args, int nb_args, unsigned int typemask )
271 while (nb_args--)
273 if ((typemask & 3) && HIWORD(*args))
275 if (typemask & 2)
276 DPRINTF( "%08x %s", *args, debugstr_w((LPWSTR)*args) );
277 else
278 DPRINTF( "%08x %s", *args, debugstr_a((LPCSTR)*args) );
280 else DPRINTF( "%08x", *args );
281 if (nb_args) DPRINTF( "," );
282 args++;
283 typemask >>= 2;
288 typedef LONGLONG (*LONGLONG_CPROC)();
289 typedef LONGLONG (WINAPI *LONGLONG_FARPROC)();
292 /***********************************************************************
293 * call_cdecl_function
295 static LONGLONG call_cdecl_function( LONGLONG_CPROC func, int nb_args, const int *args )
297 LONGLONG ret;
298 switch(nb_args)
300 case 0: ret = func(); break;
301 case 1: ret = func(args[0]); break;
302 case 2: ret = func(args[0],args[1]); break;
303 case 3: ret = func(args[0],args[1],args[2]); break;
304 case 4: ret = func(args[0],args[1],args[2],args[3]); break;
305 case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
306 case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
307 args[5]); break;
308 case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
309 args[6]); break;
310 case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
311 args[6],args[7]); break;
312 case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
313 args[6],args[7],args[8]); break;
314 case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
315 args[6],args[7],args[8],args[9]); break;
316 case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
317 args[6],args[7],args[8],args[9],args[10]); break;
318 case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
319 args[6],args[7],args[8],args[9],args[10],
320 args[11]); break;
321 case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
322 args[6],args[7],args[8],args[9],args[10],args[11],
323 args[12]); break;
324 case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
325 args[6],args[7],args[8],args[9],args[10],args[11],
326 args[12],args[13]); break;
327 case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
328 args[6],args[7],args[8],args[9],args[10],args[11],
329 args[12],args[13],args[14]); break;
330 case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
331 args[6],args[7],args[8],args[9],args[10],args[11],
332 args[12],args[13],args[14],args[15]); break;
333 default:
334 ERR( "Unsupported nb of args %d\n", nb_args );
335 assert(FALSE);
336 ret = 0;
337 break;
339 return ret;
343 /***********************************************************************
344 * call_stdcall_function
346 static LONGLONG call_stdcall_function( LONGLONG_FARPROC func, int nb_args, const int *args )
348 LONGLONG ret;
349 switch(nb_args)
351 case 0: ret = func(); break;
352 case 1: ret = func(args[0]); break;
353 case 2: ret = func(args[0],args[1]); break;
354 case 3: ret = func(args[0],args[1],args[2]); break;
355 case 4: ret = func(args[0],args[1],args[2],args[3]); break;
356 case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
357 case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
358 args[5]); break;
359 case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
360 args[6]); break;
361 case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
362 args[6],args[7]); break;
363 case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
364 args[6],args[7],args[8]); break;
365 case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
366 args[6],args[7],args[8],args[9]); break;
367 case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
368 args[6],args[7],args[8],args[9],args[10]); break;
369 case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
370 args[6],args[7],args[8],args[9],args[10],
371 args[11]); break;
372 case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
373 args[6],args[7],args[8],args[9],args[10],args[11],
374 args[12]); break;
375 case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
376 args[6],args[7],args[8],args[9],args[10],args[11],
377 args[12],args[13]); break;
378 case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
379 args[6],args[7],args[8],args[9],args[10],args[11],
380 args[12],args[13],args[14]); break;
381 case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
382 args[6],args[7],args[8],args[9],args[10],args[11],
383 args[12],args[13],args[14],args[15]); break;
384 default:
385 ERR( "Unsupported nb of args %d\n", nb_args );
386 assert(FALSE);
387 ret = 0;
388 break;
390 return ret;
394 /***********************************************************************
395 * RELAY_CallFrom32
397 * Stack layout on entry to this function:
398 * ... ...
399 * (esp+12) arg2
400 * (esp+8) arg1
401 * (esp+4) ret_addr
402 * (esp) return addr to relay code
404 static LONGLONG RELAY_CallFrom32( int ret_addr, ... )
406 LONGLONG ret;
407 char buffer[80];
409 int *args = &ret_addr + 1;
410 /* Relay addr is the return address for this function */
411 BYTE *relay_addr = (BYTE *)__builtin_return_address(0);
412 DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
413 WORD nb_args = relay->args / sizeof(int);
415 if (TRACE_ON(relay))
417 get_entry_point( buffer, relay );
419 DPRINTF( "%04lx:Call %s(", GetCurrentThreadId(), buffer );
420 RELAY_PrintArgs( args, nb_args, relay->argtypes );
421 DPRINTF( ") ret=%08x\n", ret_addr );
424 if (relay->ret == 0xc3) /* cdecl */
426 ret = call_cdecl_function( (LONGLONG_CPROC)relay->orig, nb_args, args );
428 else /* stdcall */
430 ret = call_stdcall_function( (LONGLONG_FARPROC)relay->orig, nb_args, args );
433 if (TRACE_ON(relay))
435 BOOL ret64 = (relay->argtypes & 0x80000000) && (nb_args < 16);
436 if (ret64)
437 DPRINTF( "%04lx:Ret %s() retval=%08x%08x ret=%08x\n",
438 GetCurrentThreadId(),
439 buffer, (UINT)(ret >> 32), (UINT)ret, ret_addr );
440 else
441 DPRINTF( "%04lx:Ret %s() retval=%08x ret=%08x\n",
442 GetCurrentThreadId(),
443 buffer, (UINT)ret, ret_addr );
445 return ret;
449 /***********************************************************************
450 * RELAY_CallFrom32Regs
452 * Stack layout (esp is context->Esp, not the current %esp):
454 * ...
455 * (esp+4) first arg
456 * (esp) return addr to caller
457 * (esp-4) return addr to DEBUG_ENTRY_POINT
458 * (esp-8) ptr to relay entry code for RELAY_CallFrom32Regs
459 * ... >128 bytes space free to be modified (ensured by the assembly glue)
461 void WINAPI RELAY_DoCallFrom32Regs( CONTEXT86 *context )
463 char buffer[80];
464 int* args;
465 int args_copy[17];
466 BYTE *entry_point;
468 BYTE *relay_addr = *((BYTE **)context->Esp - 1);
469 DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
470 WORD nb_args = relay->args / sizeof(int);
472 /* remove extra stuff from the stack */
473 context->Eip = stack32_pop(context);
474 args = (int *)context->Esp;
475 if (relay->ret == 0xc2) /* stdcall */
476 context->Esp += nb_args * sizeof(int);
478 entry_point = (BYTE *)relay->orig;
479 assert( *entry_point == 0xe8 /* lcall */ );
481 if (TRACE_ON(relay))
483 get_entry_point( buffer, relay );
485 DPRINTF( "%04lx:Call %s(", GetCurrentThreadId(), buffer );
486 RELAY_PrintArgs( args, nb_args, relay->argtypes );
487 DPRINTF( ") ret=%08lx fs=%04lx\n", context->Eip, context->SegFs );
489 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
490 context->Eax, context->Ebx, context->Ecx,
491 context->Edx, context->Esi, context->Edi );
492 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
493 context->Ebp, context->Esp, context->SegDs,
494 context->SegEs, context->SegGs, context->EFlags );
497 /* Now call the real function */
499 memcpy( args_copy, args, nb_args * sizeof(args[0]) );
500 args_copy[nb_args] = (int)context; /* append context argument */
501 if (relay->ret == 0xc3) /* cdecl */
503 call_cdecl_function( *(LONGLONG_CPROC *)(entry_point + 5), nb_args+1, args_copy );
505 else /* stdcall */
507 call_stdcall_function( *(LONGLONG_FARPROC *)(entry_point + 5), nb_args+1, args_copy );
510 if (TRACE_ON(relay))
512 DPRINTF( "%04lx:Ret %s() retval=%08lx ret=%08lx fs=%04lx\n",
513 GetCurrentThreadId(),
514 buffer, context->Eax, context->Eip, context->SegFs );
516 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
517 context->Eax, context->Ebx, context->Ecx,
518 context->Edx, context->Esi, context->Edi );
519 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
520 context->Ebp, context->Esp, context->SegDs,
521 context->SegEs, context->SegGs, context->EFlags );
525 void WINAPI RELAY_CallFrom32Regs(void);
526 __ASM_GLOBAL_FUNC( RELAY_CallFrom32Regs,
527 "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
528 ".long " __ASM_NAME("RELAY_DoCallFrom32Regs") ",0" );
531 /* check whether the function at addr starts with a call to __wine_call_from_32_regs */
532 static BOOL is_register_entry_point( const BYTE *addr )
534 extern void __wine_call_from_32_regs();
535 int *offset;
536 void *ptr;
538 if (*addr != 0xe8) return FALSE; /* not a call */
539 /* check if call target is __wine_call_from_32_regs */
540 offset = (int *)(addr + 1);
541 if (*offset == (char *)__wine_call_from_32_regs - (char *)(offset + 1)) return TRUE;
542 /* now check if call target is an import table jump to __wine_call_from_32_regs */
543 addr = (BYTE *)(offset + 1) + *offset;
544 if (addr[0] != 0xff || addr[1] != 0x25) return FALSE; /* not an indirect jmp */
545 ptr = *(void **)(addr + 2); /* get indirect jmp target address */
546 return (*(char **)ptr == (char *)__wine_call_from_32_regs);
550 /***********************************************************************
551 * RELAY_SetupDLL
553 * Setup relay debugging for a built-in dll.
555 void RELAY_SetupDLL( const char *module )
557 IMAGE_EXPORT_DIRECTORY *exports;
558 DEBUG_ENTRY_POINT *debug;
559 DWORD *funcs;
560 int i;
561 const char *name;
562 char *p, dllname[80];
563 DWORD size;
565 exports = RtlImageDirectoryEntryToData( (HMODULE)module, TRUE,
566 IMAGE_DIRECTORY_ENTRY_EXPORT, &size );
567 if (!exports) return;
568 debug = (DEBUG_ENTRY_POINT *)((char *)exports + size);
569 funcs = (DWORD *)(module + exports->AddressOfFunctions);
570 strcpy( dllname, module + exports->Name );
571 p = dllname + strlen(dllname) - 4;
572 if (p > dllname && !strcasecmp( p, ".dll" )) *p = 0;
574 for (i = 0; i < exports->NumberOfFunctions; i++, funcs++, debug++)
576 int on = 1;
578 if (!debug->call) continue; /* not a normal function */
579 if (debug->call != 0xe8 && debug->call != 0xe9) break; /* not a debug thunk at all */
581 if ((name = find_exported_name( module, exports, i + exports->Base )))
582 on = check_relay_include( dllname, name );
584 if (on)
586 debug->call = 0xe8; /* call relative */
587 if (is_register_entry_point( debug->orig ))
588 debug->callfrom32 = (char *)RELAY_CallFrom32Regs - (char *)&debug->ret;
589 else
590 debug->callfrom32 = (char *)RELAY_CallFrom32 - (char *)&debug->ret;
592 else
594 debug->call = 0xe9; /* jmp relative */
595 debug->callfrom32 = (char *)debug->orig - (char *)&debug->ret;
598 debug->orig = (FARPROC)(module + (DWORD)*funcs);
599 *funcs = (char *)debug - module;
603 #else /* __i386__ */
605 void RELAY_SetupDLL( const char *module )
609 #endif /* __i386__ */