Framework for the doppler effect.
[wine] / relay32 / relay386.c
1 /*
2  * 386-specific Win32 relay functions
3  *
4  * Copyright 1997 Alexandre Julliard
5  *
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
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <string.h>
26 #include <stdio.h>
27
28 #include "winternl.h"
29 #include "stackframe.h"
30 #include "module.h"
31 #include "wine/unicode.h"
32 #include "wine/debug.h"
33 #include "ntdll_misc.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(relay);
36 WINE_DECLARE_DEBUG_CHANNEL(snoop);
37
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;
42
43 /***********************************************************************
44  *           build_list
45  *
46  * Build a function list from a ';'-separated string.
47  */
48 static const char **build_list( const WCHAR *bufferW )
49 {
50     int count = 1;
51     char buffer[1024];
52     const char *p = buffer;
53     const char **ret;
54
55     RtlUnicodeToMultiByteN( buffer, sizeof(buffer), NULL,
56                             bufferW, (strlenW(bufferW)+1) * sizeof(WCHAR) );
57
58     while ((p = strchr( p, ';' )))
59     {
60          count++;
61         p++;
62     }
63     /* allocate count+1 pointers, plus the space for a copy of the string */
64     if ((ret = RtlAllocateHeap( ntdll_get_process_heap(), 0, (count+1) * sizeof(char*) + strlen(buffer) + 1 )))
65     {
66         char *str = (char *)(ret + count + 1);
67         char *p = str;
68
69         strcpy( str, buffer );
70         count = 0;
71         for (;;)
72         {
73             ret[count++] = p;
74             if (!(p = strchr( p, ';' ))) break;
75             *p++ = 0;
76         }
77         ret[count++] = NULL;
78     }
79     return ret;
80 }
81
82
83 /***********************************************************************
84  *           RELAY_InitDebugLists
85  *
86  * Build the relay include/exclude function lists.
87  */
88 void RELAY_InitDebugLists(void)
89 {
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};
106
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 );
114
115     if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return;
116
117     str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)buffer)->Data;
118     RtlInitUnicodeString( &name, RelayIncludeW );
119     if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
120     {
121         TRACE("RelayInclude = %s\n", debugstr_w(str) );
122         debug_relay_includelist = build_list( str );
123     }
124
125     RtlInitUnicodeString( &name, RelayExcludeW );
126     if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
127     {
128         TRACE( "RelayExclude = %s\n", debugstr_w(str) );
129         debug_relay_excludelist = build_list( str );
130     }
131
132     RtlInitUnicodeString( &name, SnoopIncludeW );
133     if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
134     {
135         TRACE_(snoop)( "SnoopInclude = %s\n", debugstr_w(str) );
136         debug_snoop_includelist = build_list( str );
137     }
138
139     RtlInitUnicodeString( &name, SnoopExcludeW );
140     if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
141     {
142         TRACE_(snoop)( "SnoopExclude = %s\n", debugstr_w(str) );
143         debug_snoop_excludelist = build_list( str );
144     }
145
146     NtClose( hkey );
147 }
148
149
150 #ifdef __i386__
151
152 typedef struct
153 {
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;
161
162
163 /***********************************************************************
164  *           check_relay_include
165  *
166  * Check if a given function must be included in the relay output.
167  */
168 static BOOL check_relay_include( const char *module, const char *func )
169 {
170     const char **listitem;
171     BOOL show;
172
173     if (!debug_relay_excludelist && !debug_relay_includelist) return TRUE;
174     if (debug_relay_excludelist)
175     {
176         show = TRUE;
177         listitem = debug_relay_excludelist;
178     }
179     else
180     {
181         show = FALSE;
182         listitem = debug_relay_includelist;
183     }
184     for(; *listitem; listitem++)
185     {
186         char *p = strrchr( *listitem, '.' );
187         if (p && p > *listitem)  /* check module and function */
188         {
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;
192         }
193         else  /* function only */
194         {
195             if (!strcmp( *listitem, func )) return !show;
196         }
197     }
198     return show;
199 }
200
201
202 /***********************************************************************
203  *           find_exported_name
204  *
205  * Find the name of an exported function.
206  */
207 static const char *find_exported_name( const char *module,
208                                        IMAGE_EXPORT_DIRECTORY *exp, int ordinal )
209 {
210     int i;
211     const char *ret = NULL;
212
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;
219 }
220
221
222 /***********************************************************************
223  *           get_entry_point
224  *
225  * Get the name of the DLL entry point corresponding to a relay address.
226  */
227 static void get_entry_point( char *buffer, DEBUG_ENTRY_POINT *relay )
228 {
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;
236
237     /* First find the module */
238
239     for (wm = MODULE_modref_list; wm; wm = wm->next)
240     {
241         if (!(wm->ldr.Flags & LDR_WINE_INTERNAL)) continue;
242         exp = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, 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)
246         {
247             ordinal = relay - debug;
248             break;
249         }
250     }
251
252     /* Now find the function */
253
254     base = (char *)wm->ldr.BaseAddress;
255     strcpy( buffer, base + exp->Name );
256     p = buffer + strlen(buffer);
257     if (p > buffer + 4 && !strcasecmp( p - 4, ".dll" )) p -= 4;
258
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 );
263 }
264
265
266 /***********************************************************************
267  *           RELAY_PrintArgs
268  */
269 static inline void RELAY_PrintArgs( int *args, int nb_args, unsigned int typemask )
270 {
271     while (nb_args--)
272     {
273         if ((typemask & 3) && HIWORD(*args))
274         {
275             if (typemask & 2)
276                 DPRINTF( "%08x %s", *args, debugstr_w((LPWSTR)*args) );
277             else
278                 DPRINTF( "%08x %s", *args, debugstr_a((LPCSTR)*args) );
279         }
280         else DPRINTF( "%08x", *args );
281         if (nb_args) DPRINTF( "," );
282         args++;
283         typemask >>= 2;
284     }
285 }
286
287
288 typedef LONGLONG (*LONGLONG_CPROC)();
289 typedef LONGLONG (WINAPI *LONGLONG_FARPROC)();
290
291
292 /***********************************************************************
293  *           call_cdecl_function
294  */
295 static LONGLONG call_cdecl_function( LONGLONG_CPROC func, int nb_args, const int *args )
296 {
297     LONGLONG ret;
298     switch(nb_args)
299     {
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;
338     }
339     return ret;
340 }
341
342
343 /***********************************************************************
344  *           call_stdcall_function
345  */
346 static LONGLONG call_stdcall_function( LONGLONG_FARPROC func, int nb_args, const int *args )
347 {
348     LONGLONG ret;
349     switch(nb_args)
350     {
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;
389     }
390     return ret;
391 }
392
393
394 /***********************************************************************
395  *           RELAY_CallFrom32
396  *
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
403  */
404 static LONGLONG RELAY_CallFrom32( int ret_addr, ... )
405 {
406     LONGLONG ret;
407     char buffer[80];
408
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);
414
415     if (TRACE_ON(relay))
416     {
417         get_entry_point( buffer, relay );
418
419         DPRINTF( "%04lx:Call %s(", GetCurrentThreadId(), buffer );
420         RELAY_PrintArgs( args, nb_args, relay->argtypes );
421         DPRINTF( ") ret=%08x\n", ret_addr );
422     }
423
424     if (relay->ret == 0xc3) /* cdecl */
425     {
426         ret = call_cdecl_function( (LONGLONG_CPROC)relay->orig, nb_args, args );
427     }
428     else  /* stdcall */
429     {
430         ret = call_stdcall_function( (LONGLONG_FARPROC)relay->orig, nb_args, args );
431     }
432
433     if (TRACE_ON(relay))
434     {
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 );
444     }
445     return ret;
446 }
447
448
449 /***********************************************************************
450  *           RELAY_CallFrom32Regs
451  *
452  * Stack layout (esp is context->Esp, not the current %esp):
453  *
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)
460  */
461 void WINAPI RELAY_DoCallFrom32Regs( CONTEXT86 *context )
462 {
463     char buffer[80];
464     int* args;
465     int args_copy[17];
466     BYTE *entry_point;
467
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);
471
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);
477
478     entry_point = (BYTE *)relay->orig;
479     assert( *entry_point == 0xe8 /* lcall */ );
480
481     if (TRACE_ON(relay))
482     {
483         get_entry_point( buffer, relay );
484
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 );
488
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 );
495     }
496
497     /* Now call the real function */
498
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 */
502     {
503         call_cdecl_function( *(LONGLONG_CPROC *)(entry_point + 5), nb_args+1, args_copy );
504     }
505     else  /* stdcall */
506     {
507         call_stdcall_function( *(LONGLONG_FARPROC *)(entry_point + 5), nb_args+1, args_copy );
508     }
509
510     if (TRACE_ON(relay))
511     {
512         DPRINTF( "%04lx:Ret  %s() retval=%08lx ret=%08lx fs=%04lx\n",
513                  GetCurrentThreadId(),
514                  buffer, context->Eax, context->Eip, context->SegFs );
515
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 );
522     }
523 }
524
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" );
529
530
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 )
533 {
534     extern void __wine_call_from_32_regs();
535     int *offset;
536     void *ptr;
537
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);
547 }
548
549
550 /***********************************************************************
551  *           RELAY_SetupDLL
552  *
553  * Setup relay debugging for a built-in dll.
554  */
555 void RELAY_SetupDLL( const char *module )
556 {
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;
564
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;
573
574     for (i = 0; i < exports->NumberOfFunctions; i++, funcs++, debug++)
575     {
576         int on = 1;
577
578         if (!debug->call) continue;  /* not a normal function */
579         if (debug->call != 0xe8 && debug->call != 0xe9) break; /* not a debug thunk at all */
580
581         if ((name = find_exported_name( module, exports, i + exports->Base )))
582             on = check_relay_include( dllname, name );
583
584         if (on)
585         {
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;
591         }
592         else
593         {
594             debug->call = 0xe9;  /* jmp relative */
595             debug->callfrom32 = (char *)debug->orig - (char *)&debug->ret;
596         }
597
598         debug->orig = (FARPROC)(module + (DWORD)*funcs);
599         *funcs = (char *)debug - module;
600     }
601 }
602
603 #else  /* __i386__ */
604
605 void RELAY_SetupDLL( const char *module )
606 {
607 }
608
609 #endif /* __i386__ */