Get rid of the argv0 and full_argv0 global variables.
[wine] / dlls / ntdll / relay.c
1 /*
2  * Win32 relay and snoop functions
3  *
4  * Copyright 1997 Alexandre Julliard
5  * Copyright 1998 Marcus Meissner
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <assert.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winreg.h"
33 #include "winternl.h"
34 #include "excpt.h"
35 #include "wine/exception.h"
36 #include "ntdll_misc.h"
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(relay);
41 WINE_DECLARE_DEBUG_CHANNEL(snoop);
42 WINE_DECLARE_DEBUG_CHANNEL(seh);
43
44 const WCHAR **debug_relay_excludelist = NULL;
45 const WCHAR **debug_relay_includelist = NULL;
46 const WCHAR **debug_snoop_excludelist = NULL;
47 const WCHAR **debug_snoop_includelist = NULL;
48
49 static const WCHAR **debug_from_relay_excludelist;
50 static const WCHAR **debug_from_relay_includelist;
51
52 /* compare an ASCII and a Unicode string without depending on the current codepage */
53 inline static int strcmpAW( const char *strA, const WCHAR *strW )
54 {
55     while (*strA && ((unsigned char)*strA == *strW)) { strA++; strW++; }
56     return (unsigned char)*strA - *strW;
57 }
58
59 /* compare an ASCII and a Unicode string without depending on the current codepage */
60 inline static int strncmpiAW( const char *strA, const WCHAR *strW, int n )
61 {
62     int ret = 0;
63     for ( ; n > 0; n--, strA++, strW++)
64         if ((ret = toupperW((unsigned char)*strA) - toupperW(*strW)) || !*strA) break;
65     return ret;
66 }
67
68 /***********************************************************************
69  *           build_list
70  *
71  * Build a function list from a ';'-separated string.
72  */
73 static const WCHAR **build_list( const WCHAR *buffer )
74 {
75     int count = 1;
76     const WCHAR *p = buffer;
77     const WCHAR **ret;
78
79     while ((p = strchrW( p, ';' )))
80     {
81         count++;
82         p++;
83     }
84     /* allocate count+1 pointers, plus the space for a copy of the string */
85     if ((ret = RtlAllocateHeap( GetProcessHeap(), 0,
86                                 (count+1) * sizeof(WCHAR*) + (strlenW(buffer)+1) * sizeof(WCHAR) )))
87     {
88         WCHAR *str = (WCHAR *)(ret + count + 1);
89         WCHAR *p = str;
90
91         strcpyW( str, buffer );
92         count = 0;
93         for (;;)
94         {
95             ret[count++] = p;
96             if (!(p = strchrW( p, ';' ))) break;
97             *p++ = 0;
98         }
99         ret[count++] = NULL;
100     }
101     return ret;
102 }
103
104
105 /***********************************************************************
106  *           RELAY_InitDebugLists
107  *
108  * Build the relay include/exclude function lists.
109  */
110 void RELAY_InitDebugLists(void)
111 {
112     OBJECT_ATTRIBUTES attr;
113     UNICODE_STRING name;
114     char buffer[1024];
115     HKEY hkey;
116     DWORD count;
117     WCHAR *str;
118     static const WCHAR configW[] = {'M','a','c','h','i','n','e','\\',
119                                     'S','o','f','t','w','a','r','e','\\',
120                                     'W','i','n','e','\\',
121                                     'W','i','n','e','\\',
122                                     'C','o','n','f','i','g','\\',
123                                     'D','e','b','u','g',0};
124     static const WCHAR RelayIncludeW[] = {'R','e','l','a','y','I','n','c','l','u','d','e',0};
125     static const WCHAR RelayExcludeW[] = {'R','e','l','a','y','E','x','c','l','u','d','e',0};
126     static const WCHAR SnoopIncludeW[] = {'S','n','o','o','p','I','n','c','l','u','d','e',0};
127     static const WCHAR SnoopExcludeW[] = {'S','n','o','o','p','E','x','c','l','u','d','e',0};
128     static const WCHAR RelayFromIncludeW[] = {'R','e','l','a','y','F','r','o','m','I','n','c','l','u','d','e',0};
129     static const WCHAR RelayFromExcludeW[] = {'R','e','l','a','y','F','r','o','m','E','x','c','l','u','d','e',0};
130
131     attr.Length = sizeof(attr);
132     attr.RootDirectory = 0;
133     attr.ObjectName = &name;
134     attr.Attributes = 0;
135     attr.SecurityDescriptor = NULL;
136     attr.SecurityQualityOfService = NULL;
137     RtlInitUnicodeString( &name, configW );
138
139     if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return;
140
141     str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)buffer)->Data;
142     RtlInitUnicodeString( &name, RelayIncludeW );
143     if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
144     {
145         TRACE("RelayInclude = %s\n", debugstr_w(str) );
146         debug_relay_includelist = build_list( str );
147     }
148
149     RtlInitUnicodeString( &name, RelayExcludeW );
150     if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
151     {
152         TRACE( "RelayExclude = %s\n", debugstr_w(str) );
153         debug_relay_excludelist = build_list( str );
154     }
155
156     RtlInitUnicodeString( &name, SnoopIncludeW );
157     if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
158     {
159         TRACE_(snoop)( "SnoopInclude = %s\n", debugstr_w(str) );
160         debug_snoop_includelist = build_list( str );
161     }
162
163     RtlInitUnicodeString( &name, SnoopExcludeW );
164     if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
165     {
166         TRACE_(snoop)( "SnoopExclude = %s\n", debugstr_w(str) );
167         debug_snoop_excludelist = build_list( str );
168     }
169
170     RtlInitUnicodeString( &name, RelayFromIncludeW );
171     if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
172     {
173         TRACE("RelayFromInclude = %s\n", debugstr_w(str) );
174         debug_from_relay_includelist = build_list( str );
175     }
176
177     RtlInitUnicodeString( &name, RelayFromExcludeW );
178     if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
179     {
180         TRACE( "RelayFromExclude = %s\n", debugstr_w(str) );
181         debug_from_relay_excludelist = build_list( str );
182     }
183
184     NtClose( hkey );
185 }
186
187
188 #ifdef __i386__
189
190 #include "pshpack1.h"
191
192 typedef struct
193 {
194     BYTE          call;         /* 0xe8 call callfrom32 (relative) */
195     DWORD         callfrom32;   /* RELAY_CallFrom32 relative addr */
196     BYTE          ret;          /* 0xc2 ret $n  or  0xc3 ret */
197     WORD          args;         /* nb of args to remove from the stack */
198     void         *orig;         /* original entry point */
199     DWORD         argtypes;     /* argument types */
200 } DEBUG_ENTRY_POINT;
201
202 typedef struct
203 {
204         /* code part */
205         BYTE            lcall;          /* 0xe8 call snoopentry (relative) */
206         /* NOTE: If you move snoopentry OR nrofargs fix the relative offset
207          * calculation!
208          */
209         DWORD           snoopentry;     /* SNOOP_Entry relative */
210         /* unreached */
211         int             nrofargs;
212         FARPROC origfun;
213         const char *name;
214 } SNOOP_FUN;
215
216 typedef struct tagSNOOP_DLL {
217         HMODULE hmod;
218         SNOOP_FUN       *funs;
219         DWORD           ordbase;
220         DWORD           nrofordinals;
221         struct tagSNOOP_DLL     *next;
222         char name[1];
223 } SNOOP_DLL;
224
225 typedef struct
226 {
227         /* code part */
228         BYTE            lcall;          /* 0xe8 call snoopret relative*/
229         /* NOTE: If you move snoopret OR origreturn fix the relative offset
230          * calculation!
231          */
232         DWORD           snoopret;       /* SNOOP_Ret relative */
233         /* unreached */
234         FARPROC origreturn;
235         SNOOP_DLL       *dll;
236         DWORD           ordinal;
237         DWORD           origESP;
238         DWORD           *args;          /* saved args across a stdcall */
239 } SNOOP_RETURNENTRY;
240
241 typedef struct tagSNOOP_RETURNENTRIES {
242         SNOOP_RETURNENTRY entry[4092/sizeof(SNOOP_RETURNENTRY)];
243         struct tagSNOOP_RETURNENTRIES   *next;
244 } SNOOP_RETURNENTRIES;
245
246 #include "poppack.h"
247
248 extern void WINAPI SNOOP_Entry();
249 extern void WINAPI SNOOP_Return();
250
251 static SNOOP_DLL *firstdll;
252 static SNOOP_RETURNENTRIES *firstrets;
253
254 static WINE_EXCEPTION_FILTER(page_fault)
255 {
256     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ||
257         GetExceptionCode() == EXCEPTION_PRIV_INSTRUCTION)
258         return EXCEPTION_EXECUTE_HANDLER;
259     return EXCEPTION_CONTINUE_SEARCH;
260 }
261
262 /***********************************************************************
263  *           check_relay_include
264  *
265  * Check if a given function must be included in the relay output.
266  */
267 static BOOL check_relay_include( const char *module, const char *func )
268 {
269     const WCHAR **listitem;
270     BOOL show;
271
272     if (!debug_relay_excludelist && !debug_relay_includelist) return TRUE;
273     if (debug_relay_excludelist)
274     {
275         show = TRUE;
276         listitem = debug_relay_excludelist;
277     }
278     else
279     {
280         show = FALSE;
281         listitem = debug_relay_includelist;
282     }
283     for(; *listitem; listitem++)
284     {
285         WCHAR *p = strrchrW( *listitem, '.' );
286         if (p && p > *listitem)  /* check module and function */
287         {
288             int len = p - *listitem;
289             if (strncmpiAW( module, *listitem, len-1 ) || module[len]) continue;
290             if (p[1] == '*' && !p[2]) return !show;
291             if (!strcmpAW( func, p + 1 )) return !show;
292         }
293         else  /* function only */
294         {
295             if (!strcmpAW( func, *listitem )) return !show;
296         }
297     }
298     return show;
299 }
300
301
302 /***********************************************************************
303  *           check_relay_from_module
304  *
305  * Check if calls from a given module must be included in the relay output.
306  */
307 static BOOL check_relay_from_module( const WCHAR *module )
308 {
309     static const WCHAR dllW[] = {'.','d','l','l',0 };
310     const WCHAR **listitem;
311     BOOL show;
312
313     if (!debug_from_relay_excludelist && !debug_from_relay_includelist) return TRUE;
314     if (debug_from_relay_excludelist)
315     {
316         show = TRUE;
317         listitem = debug_from_relay_excludelist;
318     }
319     else
320     {
321         show = FALSE;
322         listitem = debug_from_relay_includelist;
323     }
324     for(; *listitem; listitem++)
325     {
326         int len;
327
328         if (!strcmpiW( *listitem, module )) return !show;
329         len = strlenW( *listitem );
330         if (!strncmpiW( *listitem, module, len ) && !strcmpiW( module + len, dllW ))
331             return !show;
332     }
333     return show;
334 }
335
336
337 /***********************************************************************
338  *           find_exported_name
339  *
340  * Find the name of an exported function.
341  */
342 static const char *find_exported_name( HMODULE module,
343                                        IMAGE_EXPORT_DIRECTORY *exp, int ordinal )
344 {
345     int i;
346     const char *ret = NULL;
347
348     WORD *ordptr = (WORD *)((char *)module + exp->AddressOfNameOrdinals);
349     for (i = 0; i < exp->NumberOfNames; i++, ordptr++)
350         if (*ordptr + exp->Base == ordinal) break;
351     if (i < exp->NumberOfNames)
352         ret = (char *)module + ((DWORD*)((char *)module + exp->AddressOfNames))[i];
353     return ret;
354 }
355
356
357 /***********************************************************************
358  *           get_entry_point
359  *
360  * Get the name of the DLL entry point corresponding to a relay address.
361  */
362 static void get_entry_point( char *buffer, DEBUG_ENTRY_POINT *relay )
363 {
364     IMAGE_EXPORT_DIRECTORY *exp = NULL;
365     DEBUG_ENTRY_POINT *debug;
366     char *p;
367     const char *name;
368     int ordinal = 0;
369     PLIST_ENTRY mark, entry;
370     PLDR_MODULE mod = NULL;
371     DWORD size;
372
373     /* First find the module */
374
375     mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
376     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
377     {
378         mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
379         if (!(mod->Flags & LDR_WINE_INTERNAL)) continue;
380         exp = RtlImageDirectoryEntryToData( mod->BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size );
381         if (!exp) continue;
382         debug = (DEBUG_ENTRY_POINT *)((char *)exp + size);
383         if (debug <= relay && relay < debug + exp->NumberOfFunctions)
384         {
385             ordinal = relay - debug;
386             break;
387         }
388     }
389
390     /* Now find the function */
391
392     strcpy( buffer, (char *)mod->BaseAddress + exp->Name );
393     p = buffer + strlen(buffer);
394     if (p > buffer + 4 && !strcasecmp( p - 4, ".dll" )) p -= 4;
395
396     if ((name = find_exported_name( mod->BaseAddress, exp, ordinal + exp->Base )))
397         sprintf( p, ".%s", name );
398     else
399         sprintf( p, ".%ld", ordinal + exp->Base );
400 }
401
402
403 /***********************************************************************
404  *           RELAY_PrintArgs
405  */
406 static inline void RELAY_PrintArgs( int *args, int nb_args, unsigned int typemask )
407 {
408     while (nb_args--)
409     {
410         if ((typemask & 3) && HIWORD(*args))
411         {
412             if (typemask & 2)
413                 DPRINTF( "%08x %s", *args, debugstr_w((LPWSTR)*args) );
414             else
415                 DPRINTF( "%08x %s", *args, debugstr_a((LPCSTR)*args) );
416         }
417         else DPRINTF( "%08x", *args );
418         if (nb_args) DPRINTF( "," );
419         args++;
420         typemask >>= 2;
421     }
422 }
423
424
425 typedef LONGLONG (*LONGLONG_CPROC)();
426 typedef LONGLONG (WINAPI *LONGLONG_FARPROC)();
427
428
429 /***********************************************************************
430  *           call_cdecl_function
431  */
432 static LONGLONG call_cdecl_function( LONGLONG_CPROC func, int nb_args, const int *args )
433 {
434     LONGLONG ret;
435     switch(nb_args)
436     {
437     case 0: ret = func(); break;
438     case 1: ret = func(args[0]); break;
439     case 2: ret = func(args[0],args[1]); break;
440     case 3: ret = func(args[0],args[1],args[2]); break;
441     case 4: ret = func(args[0],args[1],args[2],args[3]); break;
442     case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
443     case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
444                        args[5]); break;
445     case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
446                        args[6]); break;
447     case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
448                        args[6],args[7]); break;
449     case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
450                        args[6],args[7],args[8]); break;
451     case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
452                         args[6],args[7],args[8],args[9]); break;
453     case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
454                         args[6],args[7],args[8],args[9],args[10]); break;
455     case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
456                         args[6],args[7],args[8],args[9],args[10],
457                         args[11]); break;
458     case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
459                         args[6],args[7],args[8],args[9],args[10],args[11],
460                         args[12]); break;
461     case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
462                         args[6],args[7],args[8],args[9],args[10],args[11],
463                         args[12],args[13]); break;
464     case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
465                         args[6],args[7],args[8],args[9],args[10],args[11],
466                         args[12],args[13],args[14]); break;
467     case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
468                         args[6],args[7],args[8],args[9],args[10],args[11],
469                         args[12],args[13],args[14],args[15]); break;
470     default:
471         ERR( "Unsupported nb of args %d\n", nb_args );
472         assert(FALSE);
473         ret = 0;
474         break;
475     }
476     return ret;
477 }
478
479
480 /***********************************************************************
481  *           call_stdcall_function
482  */
483 static LONGLONG call_stdcall_function( LONGLONG_FARPROC func, int nb_args, const int *args )
484 {
485     LONGLONG ret;
486     switch(nb_args)
487     {
488     case 0: ret = func(); break;
489     case 1: ret = func(args[0]); break;
490     case 2: ret = func(args[0],args[1]); break;
491     case 3: ret = func(args[0],args[1],args[2]); break;
492     case 4: ret = func(args[0],args[1],args[2],args[3]); break;
493     case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
494     case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
495                        args[5]); break;
496     case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
497                        args[6]); break;
498     case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
499                        args[6],args[7]); break;
500     case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
501                        args[6],args[7],args[8]); break;
502     case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
503                         args[6],args[7],args[8],args[9]); break;
504     case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
505                         args[6],args[7],args[8],args[9],args[10]); break;
506     case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
507                         args[6],args[7],args[8],args[9],args[10],
508                         args[11]); break;
509     case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
510                         args[6],args[7],args[8],args[9],args[10],args[11],
511                         args[12]); break;
512     case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
513                         args[6],args[7],args[8],args[9],args[10],args[11],
514                         args[12],args[13]); break;
515     case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
516                         args[6],args[7],args[8],args[9],args[10],args[11],
517                         args[12],args[13],args[14]); break;
518     case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
519                         args[6],args[7],args[8],args[9],args[10],args[11],
520                         args[12],args[13],args[14],args[15]); break;
521     default:
522         ERR( "Unsupported nb of args %d\n", nb_args );
523         assert(FALSE);
524         ret = 0;
525         break;
526     }
527     return ret;
528 }
529
530
531 /***********************************************************************
532  *           RELAY_CallFrom32
533  *
534  * Stack layout on entry to this function:
535  *  ...      ...
536  * (esp+12)  arg2
537  * (esp+8)   arg1
538  * (esp+4)   ret_addr
539  * (esp)     return addr to relay code
540  */
541 static LONGLONG RELAY_CallFrom32( int ret_addr, ... )
542 {
543     LONGLONG ret;
544     char buffer[80];
545
546     int *args = &ret_addr + 1;
547     /* Relay addr is the return address for this function */
548     BYTE *relay_addr = (BYTE *)__builtin_return_address(0);
549     DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
550     WORD nb_args = relay->args / sizeof(int);
551
552     if (TRACE_ON(relay))
553     {
554         get_entry_point( buffer, relay );
555
556         DPRINTF( "%04lx:Call %s(", GetCurrentThreadId(), buffer );
557         RELAY_PrintArgs( args, nb_args, relay->argtypes );
558         DPRINTF( ") ret=%08x\n", ret_addr );
559     }
560
561     if (relay->ret == 0xc3) /* cdecl */
562     {
563         ret = call_cdecl_function( (LONGLONG_CPROC)relay->orig, nb_args, args );
564     }
565     else  /* stdcall */
566     {
567         ret = call_stdcall_function( (LONGLONG_FARPROC)relay->orig, nb_args, args );
568     }
569
570     if (TRACE_ON(relay))
571     {
572         BOOL ret64 = (relay->argtypes & 0x80000000) && (nb_args < 16);
573         if (ret64)
574             DPRINTF( "%04lx:Ret  %s() retval=%08x%08x ret=%08x\n",
575                      GetCurrentThreadId(),
576                      buffer, (UINT)(ret >> 32), (UINT)ret, ret_addr );
577         else
578             DPRINTF( "%04lx:Ret  %s() retval=%08x ret=%08x\n",
579                      GetCurrentThreadId(),
580                      buffer, (UINT)ret, ret_addr );
581     }
582     return ret;
583 }
584
585
586 /***********************************************************************
587  *           RELAY_CallFrom32Regs
588  *
589  * Stack layout (esp is context->Esp, not the current %esp):
590  *
591  * ...
592  * (esp+4) first arg
593  * (esp)   return addr to caller
594  * (esp-4) return addr to DEBUG_ENTRY_POINT
595  * (esp-8) ptr to relay entry code for RELAY_CallFrom32Regs
596  *  ...    >128 bytes space free to be modified (ensured by the assembly glue)
597  */
598 void WINAPI RELAY_DoCallFrom32Regs( CONTEXT86 *context )
599 {
600     char buffer[80];
601     int* args;
602     int args_copy[17];
603     BYTE *entry_point;
604
605     BYTE *relay_addr = *((BYTE **)context->Esp - 1);
606     DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
607     WORD nb_args = relay->args / sizeof(int);
608
609     /* remove extra stuff from the stack */
610     context->Eip = *(DWORD *)context->Esp;
611     context->Esp += sizeof(DWORD);
612     args = (int *)context->Esp;
613     if (relay->ret == 0xc2) /* stdcall */
614         context->Esp += nb_args * sizeof(int);
615
616     entry_point = (BYTE *)relay->orig;
617     assert( *entry_point == 0xe8 /* lcall */ );
618
619     if (TRACE_ON(relay))
620     {
621         get_entry_point( buffer, relay );
622
623         DPRINTF( "%04lx:Call %s(", GetCurrentThreadId(), buffer );
624         RELAY_PrintArgs( args, nb_args, relay->argtypes );
625         DPRINTF( ") ret=%08lx fs=%04lx\n", context->Eip, context->SegFs );
626
627         DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
628                 context->Eax, context->Ebx, context->Ecx,
629                 context->Edx, context->Esi, context->Edi );
630         DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
631                 context->Ebp, context->Esp, context->SegDs,
632                 context->SegEs, context->SegGs, context->EFlags );
633     }
634
635     /* Now call the real function */
636
637     memcpy( args_copy, args, nb_args * sizeof(args[0]) );
638     args_copy[nb_args] = (int)context;  /* append context argument */
639     if (relay->ret == 0xc3) /* cdecl */
640     {
641         call_cdecl_function( *(LONGLONG_CPROC *)(entry_point + 5), nb_args+1, args_copy );
642     }
643     else  /* stdcall */
644     {
645         call_stdcall_function( *(LONGLONG_FARPROC *)(entry_point + 5), nb_args+1, args_copy );
646     }
647
648     if (TRACE_ON(relay))
649     {
650         DPRINTF( "%04lx:Ret  %s() retval=%08lx ret=%08lx fs=%04lx\n",
651                  GetCurrentThreadId(),
652                  buffer, context->Eax, context->Eip, context->SegFs );
653
654         DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
655                 context->Eax, context->Ebx, context->Ecx,
656                 context->Edx, context->Esi, context->Edi );
657         DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
658                 context->Ebp, context->Esp, context->SegDs,
659                 context->SegEs, context->SegGs, context->EFlags );
660     }
661 }
662
663 void WINAPI RELAY_CallFrom32Regs(void);
664 __ASM_GLOBAL_FUNC( RELAY_CallFrom32Regs,
665                    "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
666                    ".long " __ASM_NAME("RELAY_DoCallFrom32Regs") ",0" );
667
668
669 /* check whether the function at addr starts with a call to __wine_call_from_32_regs */
670 static BOOL is_register_entry_point( const BYTE *addr )
671 {
672     extern void __wine_call_from_32_regs();
673     int *offset;
674     void *ptr;
675
676     if (*addr != 0xe8) return FALSE;  /* not a call */
677     /* check if call target is __wine_call_from_32_regs */
678     offset = (int *)(addr + 1);
679     if (*offset == (char *)__wine_call_from_32_regs - (char *)(offset + 1)) return TRUE;
680     /* now check if call target is an import table jump to __wine_call_from_32_regs */
681     addr = (BYTE *)(offset + 1) + *offset;
682     if (addr[0] != 0xff || addr[1] != 0x25) return FALSE;  /* not an indirect jmp */
683     ptr = *(void **)(addr + 2);  /* get indirect jmp target address */
684     return (*(char **)ptr == (char *)__wine_call_from_32_regs);
685 }
686
687
688 /***********************************************************************
689  *           RELAY_GetProcAddress
690  *
691  * Return the proc address to use for a given function.
692  */
693 FARPROC RELAY_GetProcAddress( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
694                               DWORD exp_size, FARPROC proc, const WCHAR *user )
695 {
696     DEBUG_ENTRY_POINT *debug = (DEBUG_ENTRY_POINT *)proc;
697     DEBUG_ENTRY_POINT *list = (DEBUG_ENTRY_POINT *)((char *)exports + exp_size);
698
699     if (debug < list || debug >= list + exports->NumberOfFunctions) return proc;
700     if (list + (debug - list) != debug) return proc;  /* not a valid address */
701     if (check_relay_from_module( user )) return proc;  /* we want to relay it */
702     if (!debug->call) return proc;  /* not a normal function */
703     if (debug->call != 0xe8 && debug->call != 0xe9) return proc; /* not a debug thunk at all */
704     return debug->orig;
705 }
706
707
708 /***********************************************************************
709  *           RELAY_SetupDLL
710  *
711  * Setup relay debugging for a built-in dll.
712  */
713 void RELAY_SetupDLL( HMODULE module )
714 {
715     IMAGE_EXPORT_DIRECTORY *exports;
716     DEBUG_ENTRY_POINT *debug;
717     DWORD *funcs;
718     int i;
719     const char *name;
720     char *p, dllname[80];
721     DWORD size;
722
723     exports = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size );
724     if (!exports) return;
725     debug = (DEBUG_ENTRY_POINT *)((char *)exports + size);
726     funcs = (DWORD *)((char *)module + exports->AddressOfFunctions);
727     strcpy( dllname, (char *)module + exports->Name );
728     p = dllname + strlen(dllname) - 4;
729     if (p > dllname && !strcasecmp( p, ".dll" )) *p = 0;
730
731     for (i = 0; i < exports->NumberOfFunctions; i++, funcs++, debug++)
732     {
733         int on = 1;
734
735         if (!debug->call) continue;  /* not a normal function */
736         if (debug->call != 0xe8 && debug->call != 0xe9) break; /* not a debug thunk at all */
737
738         if ((name = find_exported_name( module, exports, i + exports->Base )))
739             on = check_relay_include( dllname, name );
740
741         if (on)
742         {
743             debug->call = 0xe8;  /* call relative */
744             if (is_register_entry_point( debug->orig ))
745                 debug->callfrom32 = (char *)RELAY_CallFrom32Regs - (char *)&debug->ret;
746             else
747                 debug->callfrom32 = (char *)RELAY_CallFrom32 - (char *)&debug->ret;
748         }
749         else
750         {
751             debug->call = 0xe9;  /* jmp relative */
752             debug->callfrom32 = (char *)debug->orig - (char *)&debug->ret;
753         }
754
755         debug->orig = (FARPROC)((char *)module + (DWORD)*funcs);
756         *funcs = (char *)debug - (char *)module;
757     }
758 }
759
760
761 /***********************************************************************
762  *          SNOOP_ShowDebugmsgSnoop
763  *
764  * Simple function to decide if a particular debugging message is
765  * wanted.
766  */
767 int SNOOP_ShowDebugmsgSnoop(const char *dll, int ord, const char *fname)
768 {
769   if(debug_snoop_excludelist || debug_snoop_includelist) {
770     const WCHAR **listitem;
771     char buf[80];
772     int len, len2, itemlen, show;
773
774     if(debug_snoop_excludelist) {
775       show = 1;
776       listitem = debug_snoop_excludelist;
777     } else {
778       show = 0;
779       listitem = debug_snoop_includelist;
780     }
781     len = strlen(dll);
782     assert(len < 64);
783     sprintf(buf, "%s.%d", dll, ord);
784     len2 = strlen(buf);
785     for(; *listitem; listitem++)
786     {
787         itemlen = strlenW(*listitem);
788         if((itemlen == len && !strncmpiAW( buf, *listitem, len)) ||
789            (itemlen == len2 && !strncmpiAW(buf, *listitem, len2)) ||
790            (fname && !strcmpAW(fname, *listitem)))
791             return !show;
792     }
793     return show;
794   }
795   return 1;
796 }
797
798
799 /***********************************************************************
800  *           SNOOP_SetupDLL
801  *
802  * Setup snoop debugging for a native dll.
803  */
804 void SNOOP_SetupDLL(HMODULE hmod)
805 {
806     SNOOP_DLL **dll = &firstdll;
807     char *p, *name;
808     void *addr;
809     SIZE_T size;
810     IMAGE_EXPORT_DIRECTORY *exports;
811
812     exports = RtlImageDirectoryEntryToData( hmod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size );
813     if (!exports) return;
814     name = (char *)hmod + exports->Name;
815
816     TRACE("hmod=%p, name=%s\n", hmod, name);
817
818     while (*dll) {
819         if ((*dll)->hmod == hmod)
820         {
821             /* another dll, loaded at the same address */
822             addr = (*dll)->funs;
823             size = (*dll)->nrofordinals * sizeof(SNOOP_FUN);
824             NtFreeVirtualMemory(GetCurrentProcess(), &addr, &size, MEM_RELEASE);
825             break;
826         }
827         dll = &((*dll)->next);
828     }
829     *dll = RtlReAllocateHeap(ntdll_get_process_heap(),
830                              HEAP_ZERO_MEMORY, *dll,
831                              sizeof(SNOOP_DLL) + strlen(name));
832     (*dll)->hmod        = hmod;
833     (*dll)->ordbase = exports->Base;
834     (*dll)->nrofordinals = exports->NumberOfFunctions;
835     strcpy( (*dll)->name, name );
836     p = (*dll)->name + strlen((*dll)->name) - 4;
837     if (p > (*dll)->name && !strcasecmp( p, ".dll" )) *p = 0;
838
839     size = exports->NumberOfFunctions * sizeof(SNOOP_FUN);
840     NtAllocateVirtualMemory(GetCurrentProcess(), &addr, NULL, &size,
841                             MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
842     if (!addr) {
843         RtlFreeHeap(ntdll_get_process_heap(),0,*dll);
844         FIXME("out of memory\n");
845         return;
846     }
847     (*dll)->funs = addr;
848     memset((*dll)->funs,0,size);
849 }
850
851
852 /***********************************************************************
853  *           SNOOP_GetProcAddress
854  *
855  * Return the proc address to use for a given function.
856  */
857 FARPROC SNOOP_GetProcAddress( HMODULE hmod, IMAGE_EXPORT_DIRECTORY *exports,
858                               DWORD exp_size, FARPROC origfun, DWORD ordinal )
859 {
860         int i;
861         const char *ename;
862         WORD *ordinals;
863         DWORD *names;
864         SNOOP_DLL                       *dll = firstdll;
865         SNOOP_FUN                       *fun;
866         IMAGE_SECTION_HEADER *sec;
867
868         if (!TRACE_ON(snoop)) return origfun;
869         if (!*(LPBYTE)origfun) /* 0x00 is an imposs. opcode, poss. dataref. */
870                 return origfun;
871
872         sec = RtlImageRvaToSection( RtlImageNtHeader(hmod), hmod, (char *)origfun - (char *)hmod );
873
874         if (!sec || !(sec->Characteristics & IMAGE_SCN_CNT_CODE))
875             return origfun;  /* most likely a data reference */
876
877         while (dll) {
878                 if (hmod == dll->hmod)
879                         break;
880                 dll=dll->next;
881         }
882         if (!dll)       /* probably internal */
883                 return origfun;
884
885         /* try to find a name for it */
886         ename = NULL;
887         names = (DWORD *)((char *)hmod + exports->AddressOfNames);
888         ordinals = (WORD *)((char *)hmod + exports->AddressOfNameOrdinals);
889         if (names) for (i = 0; i < exports->NumberOfNames; i++)
890         {
891             if (ordinals[i] == ordinal)
892             {
893                 ename = (char *)hmod + names[i];
894                 break;
895             }
896         }
897         if (!SNOOP_ShowDebugmsgSnoop(dll->name,ordinal,ename))
898                 return origfun;
899         assert(ordinal < dll->nrofordinals);
900         fun = dll->funs+ordinal;
901         if (!fun->name)
902           {
903             fun->name = ename;
904             fun->lcall  = 0xe8;
905             /* NOTE: origreturn struct member MUST come directly after snoopentry */
906             fun->snoopentry     = (char*)SNOOP_Entry-((char*)(&fun->nrofargs));
907             fun->origfun        = origfun;
908             fun->nrofargs       = -1;
909           }
910         return (FARPROC)&(fun->lcall);
911 }
912
913 static void SNOOP_PrintArg(DWORD x)
914 {
915     int i,nostring;
916
917     DPRINTF("%08lx",x);
918     if (!HIWORD(x) || TRACE_ON(seh)) return; /* trivial reject to avoid faults */
919     __TRY
920     {
921         LPBYTE s=(LPBYTE)x;
922         i=0;nostring=0;
923         while (i<80) {
924             if (s[i]==0) break;
925             if (s[i]<0x20) {nostring=1;break;}
926             if (s[i]>=0x80) {nostring=1;break;}
927             i++;
928         }
929         if (!nostring && i > 5)
930             DPRINTF(" %s",debugstr_an((LPSTR)x,i));
931         else  /* try unicode */
932         {
933             LPWSTR s=(LPWSTR)x;
934             i=0;nostring=0;
935             while (i<80) {
936                 if (s[i]==0) break;
937                 if (s[i]<0x20) {nostring=1;break;}
938                 if (s[i]>0x100) {nostring=1;break;}
939                 i++;
940             }
941             if (!nostring && i > 5) DPRINTF(" %s",debugstr_wn((LPWSTR)x,i));
942         }
943     }
944     __EXCEPT(page_fault)
945     {
946     }
947     __ENDTRY
948 }
949
950 #define CALLER1REF (*(DWORD*)context->Esp)
951
952 void WINAPI SNOOP_DoEntry( CONTEXT86 *context )
953 {
954         DWORD           ordinal=0,entry = context->Eip - 5;
955         SNOOP_DLL       *dll = firstdll;
956         SNOOP_FUN       *fun = NULL;
957         SNOOP_RETURNENTRIES     **rets = &firstrets;
958         SNOOP_RETURNENTRY       *ret;
959         int             i=0, max;
960
961         while (dll) {
962                 if (    ((char*)entry>=(char*)dll->funs)        &&
963                         ((char*)entry<=(char*)(dll->funs+dll->nrofordinals))
964                 ) {
965                         fun = (SNOOP_FUN*)entry;
966                         ordinal = fun-dll->funs;
967                         break;
968                 }
969                 dll=dll->next;
970         }
971         if (!dll) {
972                 FIXME("entrypoint 0x%08lx not found\n",entry);
973                 return; /* oops */
974         }
975         /* guess cdecl ... */
976         if (fun->nrofargs<0) {
977                 /* Typical cdecl return frame is:
978                  *     add esp, xxxxxxxx
979                  * which has (for xxxxxxxx up to 255 the opcode "83 C4 xx".
980                  * (after that 81 C2 xx xx xx xx)
981                  */
982                 LPBYTE  reteip = (LPBYTE)CALLER1REF;
983
984                 if (reteip) {
985                         if ((reteip[0]==0x83)&&(reteip[1]==0xc4))
986                                 fun->nrofargs=reteip[2]/4;
987                 }
988         }
989
990
991         while (*rets) {
992                 for (i=0;i<sizeof((*rets)->entry)/sizeof((*rets)->entry[0]);i++)
993                         if (!(*rets)->entry[i].origreturn)
994                                 break;
995                 if (i!=sizeof((*rets)->entry)/sizeof((*rets)->entry[0]))
996                         break;
997                 rets = &((*rets)->next);
998         }
999         if (!*rets) {
1000                 SIZE_T size = 4096;
1001                 VOID* addr;
1002
1003                 NtAllocateVirtualMemory(GetCurrentProcess(), &addr, NULL, &size, 
1004                                         MEM_COMMIT | MEM_RESERVE,
1005                                         PAGE_EXECUTE_READWRITE);
1006                 if (!addr) return;
1007                 *rets = addr;
1008                 memset(*rets,0,4096);
1009                 i = 0;  /* entry 0 is free */
1010         }
1011         ret = &((*rets)->entry[i]);
1012         ret->lcall      = 0xe8;
1013         /* NOTE: origreturn struct member MUST come directly after snoopret */
1014         ret->snoopret   = ((char*)SNOOP_Return)-(char*)(&ret->origreturn);
1015         ret->origreturn = (FARPROC)CALLER1REF;
1016         CALLER1REF      = (DWORD)&ret->lcall;
1017         ret->dll        = dll;
1018         ret->args       = NULL;
1019         ret->ordinal    = ordinal;
1020         ret->origESP    = context->Esp;
1021
1022         context->Eip = (DWORD)fun->origfun;
1023
1024         if (fun->name) DPRINTF("%04lx:CALL %s.%s(",GetCurrentThreadId(),dll->name,fun->name);
1025         else DPRINTF("%04lx:CALL %s.%ld(",GetCurrentThreadId(),dll->name,dll->ordbase+ordinal);
1026         if (fun->nrofargs>0) {
1027                 max = fun->nrofargs; if (max>16) max=16;
1028                 for (i=0;i<max;i++)
1029                 {
1030                     SNOOP_PrintArg(*(DWORD*)(context->Esp + 4 + sizeof(DWORD)*i));
1031                     if (i<fun->nrofargs-1) DPRINTF(",");
1032                 }
1033                 if (max!=fun->nrofargs)
1034                         DPRINTF(" ...");
1035         } else if (fun->nrofargs<0) {
1036                 DPRINTF("<unknown, check return>");
1037                 ret->args = RtlAllocateHeap(ntdll_get_process_heap(),
1038                                             0,16*sizeof(DWORD));
1039                 memcpy(ret->args,(LPBYTE)(context->Esp + 4),sizeof(DWORD)*16);
1040         }
1041         DPRINTF(") ret=%08lx\n",(DWORD)ret->origreturn);
1042 }
1043
1044
1045 void WINAPI SNOOP_DoReturn( CONTEXT86 *context )
1046 {
1047         SNOOP_RETURNENTRY       *ret = (SNOOP_RETURNENTRY*)(context->Eip - 5);
1048         SNOOP_FUN *fun = &ret->dll->funs[ret->ordinal];
1049
1050         /* We haven't found out the nrofargs yet. If we called a cdecl
1051          * function it is too late anyway and we can just set '0' (which
1052          * will be the difference between orig and current ESP
1053          * If stdcall -> everything ok.
1054          */
1055         if (ret->dll->funs[ret->ordinal].nrofargs<0)
1056                 ret->dll->funs[ret->ordinal].nrofargs=(context->Esp - ret->origESP-4)/4;
1057         context->Eip = (DWORD)ret->origreturn;
1058         if (ret->args) {
1059                 int     i,max;
1060
1061                 if (fun->name)
1062                     DPRINTF("%04lx:RET  %s.%s(", GetCurrentThreadId(), ret->dll->name, fun->name);
1063                 else
1064                     DPRINTF("%04lx:RET  %s.%ld(", GetCurrentThreadId(),
1065                             ret->dll->name,ret->dll->ordbase+ret->ordinal);
1066
1067                 max = fun->nrofargs;
1068                 if (max>16) max=16;
1069
1070                 for (i=0;i<max;i++)
1071                 {
1072                     SNOOP_PrintArg(ret->args[i]);
1073                     if (i<max-1) DPRINTF(",");
1074                 }
1075                 DPRINTF(") retval=%08lx ret=%08lx\n",
1076                         context->Eax,(DWORD)ret->origreturn );
1077                 RtlFreeHeap(ntdll_get_process_heap(),0,ret->args);
1078                 ret->args = NULL;
1079         }
1080         else
1081         {
1082             if (fun->name)
1083                 DPRINTF("%04lx:RET  %s.%s() retval=%08lx ret=%08lx\n",
1084                         GetCurrentThreadId(),
1085                         ret->dll->name, fun->name, context->Eax, (DWORD)ret->origreturn);
1086             else
1087                 DPRINTF("%04lx:RET  %s.%ld() retval=%08lx ret=%08lx\n",
1088                         GetCurrentThreadId(),
1089                         ret->dll->name,ret->dll->ordbase+ret->ordinal,
1090                         context->Eax, (DWORD)ret->origreturn);
1091         }
1092         ret->origreturn = NULL; /* mark as empty */
1093 }
1094
1095 /* assembly wrappers that save the context */
1096 __ASM_GLOBAL_FUNC( SNOOP_Entry,
1097                    "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
1098                    ".long " __ASM_NAME("SNOOP_DoEntry") ",0" );
1099 __ASM_GLOBAL_FUNC( SNOOP_Return,
1100                    "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
1101                    ".long " __ASM_NAME("SNOOP_DoReturn") ",0" );
1102
1103 #else  /* __i386__ */
1104
1105 FARPROC RELAY_GetProcAddress( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
1106                               DWORD exp_size, FARPROC proc, const WCHAR *user )
1107 {
1108     return proc;
1109 }
1110
1111 FARPROC SNOOP_GetProcAddress( HMODULE hmod, IMAGE_EXPORT_DIRECTORY *exports,
1112                               DWORD exp_size, FARPROC origfun, DWORD ordinal )
1113 {
1114     return origfun;
1115 }
1116
1117 void RELAY_SetupDLL( HMODULE module )
1118 {
1119 }
1120
1121 void SNOOP_SetupDLL( HMODULE hmod )
1122 {
1123     FIXME("snooping works only on i386 for now.\n");
1124 }
1125
1126 #endif /* __i386__ */