mshtml: Use Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME in CreateUri calls.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "ntstatus.h"
31 #define WIN32_NO_STATUS
32 #include "windef.h"
33 #include "winternl.h"
34 #include "wine/exception.h"
35 #include "ntdll_misc.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(relay);
40
41 #if defined(__i386__) || defined(__x86_64__) || defined(__arm__)
42
43 WINE_DECLARE_DEBUG_CHANNEL(timestamp);
44
45 struct relay_descr  /* descriptor for a module */
46 {
47     void               *magic;               /* signature */
48     void               *relay_call;          /* functions to call from relay thunks */
49     void               *relay_call_regs;
50     void               *private;             /* reserved for the relay code private data */
51     const char         *entry_point_base;    /* base address of entry point thunks */
52     const unsigned int *entry_point_offsets; /* offsets of entry points thunks */
53     const unsigned int *arg_types;           /* table of argument types for all entry points */
54 };
55
56 #define RELAY_DESCR_MAGIC  ((void *)0xdeb90001)
57 #define IS_INTARG(x)       (((ULONG_PTR)(x) >> 16) == 0)
58
59 /* private data built at dll load time */
60
61 struct relay_entry_point
62 {
63     void       *orig_func;    /* original entry point function */
64     const char *name;         /* function name (if any) */
65 };
66
67 struct relay_private_data
68 {
69     HMODULE                  module;            /* module handle of this dll */
70     unsigned int             base;              /* ordinal base */
71     char                     dllname[40];       /* dll name (without .dll extension) */
72     struct relay_entry_point entry_points[1];   /* list of dll entry points */
73 };
74
75 static const WCHAR **debug_relay_excludelist;
76 static const WCHAR **debug_relay_includelist;
77 static const WCHAR **debug_snoop_excludelist;
78 static const WCHAR **debug_snoop_includelist;
79 static const WCHAR **debug_from_relay_excludelist;
80 static const WCHAR **debug_from_relay_includelist;
81 static const WCHAR **debug_from_snoop_excludelist;
82 static const WCHAR **debug_from_snoop_includelist;
83
84 static BOOL init_done;
85
86 /* compare an ASCII and a Unicode string without depending on the current codepage */
87 static inline int strcmpAW( const char *strA, const WCHAR *strW )
88 {
89     while (*strA && ((unsigned char)*strA == *strW)) { strA++; strW++; }
90     return (unsigned char)*strA - *strW;
91 }
92
93 /* compare an ASCII and a Unicode string without depending on the current codepage */
94 static inline int strncmpiAW( const char *strA, const WCHAR *strW, int n )
95 {
96     int ret = 0;
97     for ( ; n > 0; n--, strA++, strW++)
98         if ((ret = toupperW((unsigned char)*strA) - toupperW(*strW)) || !*strA) break;
99     return ret;
100 }
101
102 /***********************************************************************
103  *           build_list
104  *
105  * Build a function list from a ';'-separated string.
106  */
107 static const WCHAR **build_list( const WCHAR *buffer )
108 {
109     int count = 1;
110     const WCHAR *p = buffer;
111     const WCHAR **ret;
112
113     while ((p = strchrW( p, ';' )))
114     {
115         count++;
116         p++;
117     }
118     /* allocate count+1 pointers, plus the space for a copy of the string */
119     if ((ret = RtlAllocateHeap( GetProcessHeap(), 0,
120                                 (count+1) * sizeof(WCHAR*) + (strlenW(buffer)+1) * sizeof(WCHAR) )))
121     {
122         WCHAR *str = (WCHAR *)(ret + count + 1);
123         WCHAR *q = str;
124
125         strcpyW( str, buffer );
126         count = 0;
127         for (;;)
128         {
129             ret[count++] = q;
130             if (!(q = strchrW( q, ';' ))) break;
131             *q++ = 0;
132         }
133         ret[count++] = NULL;
134     }
135     return ret;
136 }
137
138 /***********************************************************************
139  *           load_list_value
140  *
141  * Load a function list from a registry value.
142  */
143 static const WCHAR **load_list( HKEY hkey, const WCHAR *value )
144 {
145     char initial_buffer[4096];
146     char *buffer = initial_buffer;
147     DWORD count;
148     NTSTATUS status;
149     UNICODE_STRING name;
150     const WCHAR **list = NULL;
151
152     RtlInitUnicodeString( &name, value );
153     status = NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(initial_buffer), &count );
154     if (status == STATUS_BUFFER_OVERFLOW)
155     {
156         buffer = RtlAllocateHeap( GetProcessHeap(), 0, count );
157         status = NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, count, &count );
158     }
159     if (status == STATUS_SUCCESS)
160     {
161         WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)buffer)->Data;
162         list = build_list( str );
163         if (list) TRACE( "%s = %s\n", debugstr_w(value), debugstr_w(str) );
164     }
165
166     if (buffer != initial_buffer) RtlFreeHeap( GetProcessHeap(), 0, buffer );
167     return list;
168 }
169
170 /***********************************************************************
171  *           init_debug_lists
172  *
173  * Build the relay include/exclude function lists.
174  */
175 static void init_debug_lists(void)
176 {
177     OBJECT_ATTRIBUTES attr;
178     UNICODE_STRING name;
179     HANDLE root, hkey;
180     static const WCHAR configW[] = {'S','o','f','t','w','a','r','e','\\',
181                                     'W','i','n','e','\\',
182                                     'D','e','b','u','g',0};
183     static const WCHAR RelayIncludeW[] = {'R','e','l','a','y','I','n','c','l','u','d','e',0};
184     static const WCHAR RelayExcludeW[] = {'R','e','l','a','y','E','x','c','l','u','d','e',0};
185     static const WCHAR SnoopIncludeW[] = {'S','n','o','o','p','I','n','c','l','u','d','e',0};
186     static const WCHAR SnoopExcludeW[] = {'S','n','o','o','p','E','x','c','l','u','d','e',0};
187     static const WCHAR RelayFromIncludeW[] = {'R','e','l','a','y','F','r','o','m','I','n','c','l','u','d','e',0};
188     static const WCHAR RelayFromExcludeW[] = {'R','e','l','a','y','F','r','o','m','E','x','c','l','u','d','e',0};
189     static const WCHAR SnoopFromIncludeW[] = {'S','n','o','o','p','F','r','o','m','I','n','c','l','u','d','e',0};
190     static const WCHAR SnoopFromExcludeW[] = {'S','n','o','o','p','F','r','o','m','E','x','c','l','u','d','e',0};
191
192     if (init_done) return;
193     init_done = TRUE;
194
195     RtlOpenCurrentUser( KEY_ALL_ACCESS, &root );
196     attr.Length = sizeof(attr);
197     attr.RootDirectory = root;
198     attr.ObjectName = &name;
199     attr.Attributes = 0;
200     attr.SecurityDescriptor = NULL;
201     attr.SecurityQualityOfService = NULL;
202     RtlInitUnicodeString( &name, configW );
203
204     /* @@ Wine registry key: HKCU\Software\Wine\Debug */
205     if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) hkey = 0;
206     NtClose( root );
207     if (!hkey) return;
208
209     debug_relay_includelist = load_list( hkey, RelayIncludeW );
210     debug_relay_excludelist = load_list( hkey, RelayExcludeW );
211     debug_snoop_includelist = load_list( hkey, SnoopIncludeW );
212     debug_snoop_excludelist = load_list( hkey, SnoopExcludeW );
213     debug_from_relay_includelist = load_list( hkey, RelayFromIncludeW );
214     debug_from_relay_excludelist = load_list( hkey, RelayFromExcludeW );
215     debug_from_snoop_includelist = load_list( hkey, SnoopFromIncludeW );
216     debug_from_snoop_excludelist = load_list( hkey, SnoopFromExcludeW );
217
218     NtClose( hkey );
219 }
220
221
222 /***********************************************************************
223  *           check_list
224  *
225  * Check if a given module and function is in the list.
226  */
227 static BOOL check_list( const char *module, int ordinal, const char *func, const WCHAR *const *list )
228 {
229     char ord_str[10];
230
231     sprintf( ord_str, "%d", ordinal );
232     for(; *list; list++)
233     {
234         const WCHAR *p = strrchrW( *list, '.' );
235         if (p && p > *list)  /* check module and function */
236         {
237             int len = p - *list;
238             if (strncmpiAW( module, *list, len-1 ) || module[len]) continue;
239             if (p[1] == '*' && !p[2]) return TRUE;
240             if (!strcmpAW( ord_str, p + 1 )) return TRUE;
241             if (func && !strcmpAW( func, p + 1 )) return TRUE;
242         }
243         else  /* function only */
244         {
245             if (func && !strcmpAW( func, *list )) return TRUE;
246         }
247     }
248     return FALSE;
249 }
250
251
252 /***********************************************************************
253  *           check_relay_include
254  *
255  * Check if a given function must be included in the relay output.
256  */
257 static BOOL check_relay_include( const char *module, int ordinal, const char *func )
258 {
259     if (debug_relay_excludelist && check_list( module, ordinal, func, debug_relay_excludelist ))
260         return FALSE;
261     if (debug_relay_includelist && !check_list( module, ordinal, func, debug_relay_includelist ))
262         return FALSE;
263     return TRUE;
264 }
265
266 /***********************************************************************
267  *           check_from_module
268  *
269  * Check if calls from a given module must be included in the relay/snoop output,
270  * given the exclusion and inclusion lists.
271  */
272 static BOOL check_from_module( const WCHAR **includelist, const WCHAR **excludelist, const WCHAR *module )
273 {
274     static const WCHAR dllW[] = {'.','d','l','l',0 };
275     const WCHAR **listitem;
276     BOOL show;
277
278     if (!module) return TRUE;
279     if (!includelist && !excludelist) return TRUE;
280     if (excludelist)
281     {
282         show = TRUE;
283         listitem = excludelist;
284     }
285     else
286     {
287         show = FALSE;
288         listitem = includelist;
289     }
290     for(; *listitem; listitem++)
291     {
292         int len;
293
294         if (!strcmpiW( *listitem, module )) return !show;
295         len = strlenW( *listitem );
296         if (!strncmpiW( *listitem, module, len ) && !strcmpiW( module + len, dllW ))
297             return !show;
298     }
299     return show;
300 }
301
302 /***********************************************************************
303  *           RELAY_PrintArgs
304  */
305 static inline void RELAY_PrintArgs( const INT_PTR *args, int nb_args, unsigned int typemask )
306 {
307     while (nb_args--)
308     {
309         if ((typemask & 3) && !IS_INTARG(*args))
310         {
311             if (typemask & 2)
312                 DPRINTF( "%08lx %s", *args, debugstr_w((LPCWSTR)*args) );
313             else
314                 DPRINTF( "%08lx %s", *args, debugstr_a((LPCSTR)*args) );
315         }
316         else DPRINTF( "%08lx", *args );
317         if (nb_args) DPRINTF( "," );
318         args++;
319         typemask >>= 2;
320     }
321 }
322
323 extern LONGLONG CDECL call_entry_point( void *func, int nb_args, const INT_PTR *args, int flags );
324 #ifdef __i386__
325 __ASM_GLOBAL_FUNC( call_entry_point,
326                    "pushl %ebp\n\t"
327                    __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
328                    __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
329                    "movl %esp,%ebp\n\t"
330                    __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
331                    "pushl %esi\n\t"
332                   __ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
333                    "pushl %edi\n\t"
334                   __ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
335                    "movl 12(%ebp),%edx\n\t"
336                    "shll $2,%edx\n\t"
337                    "jz 1f\n\t"
338                    "subl %edx,%esp\n\t"
339                    "andl $~15,%esp\n\t"
340                    "movl 12(%ebp),%ecx\n\t"
341                    "movl 16(%ebp),%esi\n\t"
342                    "movl %esp,%edi\n\t"
343                    "cld\n\t"
344                    "rep; movsl\n"
345                    "testl $2,20(%ebp)\n\t"  /* (flags & 2) -> thiscall */
346                    "jz 1f\n\t"
347                    "popl %ecx\n\t"
348                    "1:\tcall *8(%ebp)\n\t"
349                    "leal -8(%ebp),%esp\n\t"
350                    "popl %edi\n\t"
351                    __ASM_CFI(".cfi_same_value %edi\n\t")
352                    "popl %esi\n\t"
353                    __ASM_CFI(".cfi_same_value %esi\n\t")
354                    "popl %ebp\n\t"
355                    __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
356                    __ASM_CFI(".cfi_same_value %ebp\n\t")
357                    "ret" )
358 #elif defined(__arm__)
359 __ASM_GLOBAL_FUNC( call_entry_point,
360                    "push {r4, r5, LR}\n\t"
361                    "mov r4, r0\n\t"
362                    "mov r5, SP\n\t"
363                    "lsl r3, r1, #2\n\t"
364                    "cmp r3, #0\n\t"
365                    "beq 5f\n\t"
366                    "sub SP, SP, r3\n\t"
367                    "tst r1, #1\n\t"
368                    "subeq SP, SP, #4\n\t"
369                    "1:\tsub r3, r3, #4\n\t"
370                    "ldr r0, [r2, r3]\n\t"
371                    "str r0, [SP, r3]\n\t"
372                    "cmp r3, #0\n\t"
373                    "bgt 1b\n\t"
374                    "cmp r1, #1\n\t"
375                    "bgt 2f\n\t"
376                    "pop {r0}\n\t"
377                    "b 5f\n\t"
378                    "2:\tcmp r1, #2\n\t"
379                    "bgt 3f\n\t"
380                    "pop {r0-r1}\n\t"
381                    "b 5f\n\t"
382                    "3:\tcmp r1, #3\n\t"
383                    "bgt 4f\n\t"
384                    "pop {r0-r2}\n\t"
385                    "b 5f\n\t"
386                    "4:\tpop {r0-r3}\n\t"
387                    "5:\tblx r4\n\t"
388                    "mov SP, r5\n\t"
389                    "pop {r4, r5, PC}" )
390 #else
391 __ASM_GLOBAL_FUNC( call_entry_point,
392                    "pushq %rbp\n\t"
393                    __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
394                    __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
395                    "movq %rsp,%rbp\n\t"
396                    __ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
397                    "pushq %rsi\n\t"
398                    __ASM_CFI(".cfi_rel_offset %rsi,-8\n\t")
399                    "pushq %rdi\n\t"
400                    __ASM_CFI(".cfi_rel_offset %rdi,-16\n\t")
401                    "movq %rcx,%rax\n\t"
402                    "movq $4,%rcx\n\t"
403                    "cmp %rcx,%rdx\n\t"
404                    "cmovgq %rdx,%rcx\n\t"
405                    "leaq 0(,%rcx,8),%rdx\n\t"
406                    "subq %rdx,%rsp\n\t"
407                    "andq $~15,%rsp\n\t"
408                    "movq %rsp,%rdi\n\t"
409                    "movq %r8,%rsi\n\t"
410                    "rep; movsq\n\t"
411                    "movq 0(%rsp),%rcx\n\t"
412                    "movq 8(%rsp),%rdx\n\t"
413                    "movq 16(%rsp),%r8\n\t"
414                    "movq 24(%rsp),%r9\n\t"
415                    "movq %rcx,%xmm0\n\t"
416                    "movq %rdx,%xmm1\n\t"
417                    "movq %r8,%xmm2\n\t"
418                    "movq %r9,%xmm3\n\t"
419                    "callq *%rax\n\t"
420                    "leaq -16(%rbp),%rsp\n\t"
421                    "popq %rdi\n\t"
422                    __ASM_CFI(".cfi_same_value %rdi\n\t")
423                    "popq %rsi\n\t"
424                    __ASM_CFI(".cfi_same_value %rsi\n\t")
425                    __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
426                    "popq %rbp\n\t"
427                    __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
428                    __ASM_CFI(".cfi_same_value %rbp\n\t")
429                    "ret")
430 #endif
431
432
433 static void print_timestamp(void)
434 {
435     ULONG ticks = NtGetTickCount();
436     DPRINTF( "%3u.%03u:", ticks / 1000, ticks % 1000 );
437 }
438
439
440 /***********************************************************************
441  *           relay_call
442  *
443  * stack points to the return address, i.e. the first argument is stack[1].
444  */
445 static LONGLONG WINAPI relay_call( struct relay_descr *descr, unsigned int idx, const INT_PTR *stack )
446 {
447     LONGLONG ret;
448     WORD ordinal = LOWORD(idx);
449     BYTE nb_args = LOBYTE(HIWORD(idx));
450     BYTE flags   = HIBYTE(HIWORD(idx));
451     struct relay_private_data *data = descr->private;
452     struct relay_entry_point *entry_point = data->entry_points + ordinal;
453
454     if (!TRACE_ON(relay))
455         ret = call_entry_point( entry_point->orig_func, nb_args, stack + 1, flags );
456     else
457     {
458         if (TRACE_ON(timestamp))
459             print_timestamp();
460         if (entry_point->name)
461             DPRINTF( "%04x:Call %s.%s(", GetCurrentThreadId(), data->dllname, entry_point->name );
462         else
463             DPRINTF( "%04x:Call %s.%u(", GetCurrentThreadId(), data->dllname, data->base + ordinal );
464         RELAY_PrintArgs( stack + 1, nb_args, descr->arg_types[ordinal] );
465         DPRINTF( ") ret=%08lx\n", stack[0] );
466
467         ret = call_entry_point( entry_point->orig_func, nb_args, stack + 1, flags );
468
469         if (TRACE_ON(timestamp))
470             print_timestamp();
471         if (entry_point->name)
472             DPRINTF( "%04x:Ret  %s.%s()", GetCurrentThreadId(), data->dllname, entry_point->name );
473         else
474             DPRINTF( "%04x:Ret  %s.%u()", GetCurrentThreadId(), data->dllname, data->base + ordinal );
475
476         if (flags & 1)  /* 64-bit return value */
477             DPRINTF( " retval=%08x%08x ret=%08lx\n",
478                      (UINT)(ret >> 32), (UINT)ret, stack[0] );
479         else
480             DPRINTF( " retval=%08lx ret=%08lx\n", (UINT_PTR)ret, stack[0] );
481     }
482     return ret;
483 }
484
485
486 /***********************************************************************
487  *           relay_call_regs
488  */
489 #ifdef __i386__
490 void WINAPI __regs_relay_call_regs( struct relay_descr *descr, unsigned int idx,
491                                     unsigned int orig_eax, unsigned int ret_addr,
492                                     CONTEXT *context )
493 {
494     WORD ordinal = LOWORD(idx);
495     BYTE nb_args = LOBYTE(HIWORD(idx));
496     struct relay_private_data *data = descr->private;
497     struct relay_entry_point *entry_point = data->entry_points + ordinal;
498     BYTE *orig_func = entry_point->orig_func;
499     INT_PTR *args = (INT_PTR *)context->Esp;
500     INT_PTR args_copy[32];
501
502     /* restore the context to what it was before the relay thunk */
503     context->Eax = orig_eax;
504     context->Eip = ret_addr;
505     context->Esp += nb_args * sizeof(int);
506
507     if (TRACE_ON(relay))
508     {
509         if (entry_point->name)
510             DPRINTF( "%04x:Call %s.%s(", GetCurrentThreadId(), data->dllname, entry_point->name );
511         else
512             DPRINTF( "%04x:Call %s.%u(", GetCurrentThreadId(), data->dllname, data->base + ordinal );
513         RELAY_PrintArgs( args, nb_args, descr->arg_types[ordinal] );
514         DPRINTF( ") ret=%08x\n", ret_addr );
515
516         DPRINTF( "%04x:  eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x "
517                  "ebp=%08x esp=%08x ds=%04x es=%04x fs=%04x gs=%04x flags=%08x\n",
518                  GetCurrentThreadId(), context->Eax, context->Ebx, context->Ecx,
519                  context->Edx, context->Esi, context->Edi, context->Ebp, context->Esp,
520                  context->SegDs, context->SegEs, context->SegFs, context->SegGs, context->EFlags );
521
522         assert( orig_func[0] == 0x68 /* pushl func */ );
523         assert( orig_func[5] == 0x6a /* pushl args */ );
524         assert( orig_func[7] == 0xe8 /* call */ );
525     }
526
527     /* now call the real function */
528
529     memcpy( args_copy, args, nb_args * sizeof(args[0]) );
530     args_copy[nb_args++] = (INT_PTR)context;  /* append context argument */
531
532     call_entry_point( orig_func + 12 + *(int *)(orig_func + 1), nb_args, args_copy, 0 );
533
534
535     if (TRACE_ON(relay))
536     {
537         if (entry_point->name)
538             DPRINTF( "%04x:Ret  %s.%s() retval=%08x ret=%08x\n",
539                      GetCurrentThreadId(), data->dllname, entry_point->name,
540                      context->Eax, context->Eip );
541         else
542             DPRINTF( "%04x:Ret  %s.%u() retval=%08x ret=%08x\n",
543                      GetCurrentThreadId(), data->dllname, data->base + ordinal,
544                      context->Eax, context->Eip );
545         DPRINTF( "%04x:  eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x "
546                  "ebp=%08x esp=%08x ds=%04x es=%04x fs=%04x gs=%04x flags=%08x\n",
547                  GetCurrentThreadId(), context->Eax, context->Ebx, context->Ecx,
548                  context->Edx, context->Esi, context->Edi, context->Ebp, context->Esp,
549                  context->SegDs, context->SegEs, context->SegFs, context->SegGs, context->EFlags );
550     }
551 }
552 extern void WINAPI relay_call_regs(void);
553 DEFINE_REGS_ENTRYPOINT( relay_call_regs, 4 )
554
555 #else  /* __i386__ */
556
557 void WINAPI relay_call_regs( struct relay_descr *descr, INT_PTR idx, INT_PTR *stack )
558 {
559     assert(0);  /* should never be called */
560 }
561
562 #endif  /* __i386__ */
563
564
565 /***********************************************************************
566  *           RELAY_GetProcAddress
567  *
568  * Return the proc address to use for a given function.
569  */
570 FARPROC RELAY_GetProcAddress( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
571                               DWORD exp_size, FARPROC proc, DWORD ordinal, const WCHAR *user )
572 {
573     struct relay_private_data *data;
574     const struct relay_descr *descr = (const struct relay_descr *)((const char *)exports + exp_size);
575
576     if (descr->magic != RELAY_DESCR_MAGIC || !(data = descr->private)) return proc;  /* no relay data */
577     if (!data->entry_points[ordinal].orig_func) return proc;  /* not a relayed function */
578     if (check_from_module( debug_from_relay_includelist, debug_from_relay_excludelist, user ))
579         return proc;  /* we want to relay it */
580     return data->entry_points[ordinal].orig_func;
581 }
582
583
584 /***********************************************************************
585  *           RELAY_SetupDLL
586  *
587  * Setup relay debugging for a built-in dll.
588  */
589 void RELAY_SetupDLL( HMODULE module )
590 {
591     IMAGE_EXPORT_DIRECTORY *exports;
592     DWORD *funcs;
593     unsigned int i, len;
594     DWORD size, entry_point_rva;
595     struct relay_descr *descr;
596     struct relay_private_data *data;
597     const WORD *ordptr;
598
599     if (!init_done) init_debug_lists();
600
601     exports = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size );
602     if (!exports) return;
603
604     descr = (struct relay_descr *)((char *)exports + size);
605     if (descr->magic != RELAY_DESCR_MAGIC) return;
606
607     if (!(data = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) +
608                                   (exports->NumberOfFunctions-1) * sizeof(data->entry_points) )))
609         return;
610
611     descr->relay_call = relay_call;
612     descr->relay_call_regs = relay_call_regs;
613     descr->private = data;
614
615     data->module = module;
616     data->base   = exports->Base;
617     len = strlen( (char *)module + exports->Name );
618     if (len > 4 && !strcasecmp( (char *)module + exports->Name + len - 4, ".dll" )) len -= 4;
619     len = min( len, sizeof(data->dllname) - 1 );
620     memcpy( data->dllname, (char *)module + exports->Name, len );
621     data->dllname[len] = 0;
622
623     /* fetch name pointer for all entry points and store them in the private structure */
624
625     ordptr = (const WORD *)((char *)module + exports->AddressOfNameOrdinals);
626     for (i = 0; i < exports->NumberOfNames; i++, ordptr++)
627     {
628         DWORD name_rva = ((DWORD*)((char *)module + exports->AddressOfNames))[i];
629         data->entry_points[*ordptr].name = (const char *)module + name_rva;
630     }
631
632     /* patch the functions in the export table to point to the relay thunks */
633
634     funcs = (DWORD *)((char *)module + exports->AddressOfFunctions);
635     entry_point_rva = descr->entry_point_base - (const char *)module;
636     for (i = 0; i < exports->NumberOfFunctions; i++, funcs++)
637     {
638         if (!descr->entry_point_offsets[i]) continue;   /* not a normal function */
639         if (!check_relay_include( data->dllname, i + exports->Base, data->entry_points[i].name ))
640             continue;  /* don't include this entry point */
641
642         data->entry_points[i].orig_func = (char *)module + *funcs;
643         *funcs = entry_point_rva + descr->entry_point_offsets[i];
644     }
645 }
646
647 #else  /* __i386__ || __x86_64__ */
648
649 FARPROC RELAY_GetProcAddress( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
650                               DWORD exp_size, FARPROC proc, DWORD ordinal, const WCHAR *user )
651 {
652     return proc;
653 }
654
655 void RELAY_SetupDLL( HMODULE module )
656 {
657 }
658
659 #endif  /* __i386__ || __x86_64__ */
660
661
662 /***********************************************************************/
663 /* snoop support */
664 /***********************************************************************/
665
666 #ifdef __i386__
667
668 WINE_DECLARE_DEBUG_CHANNEL(seh);
669 WINE_DECLARE_DEBUG_CHANNEL(snoop);
670
671 #include "pshpack1.h"
672
673 typedef struct
674 {
675         /* code part */
676         BYTE            lcall;          /* 0xe8 call snoopentry (relative) */
677         /* NOTE: If you move snoopentry OR nrofargs fix the relative offset
678          * calculation!
679          */
680         DWORD           snoopentry;     /* SNOOP_Entry relative */
681         /* unreached */
682         int             nrofargs;
683         FARPROC origfun;
684         const char *name;
685 } SNOOP_FUN;
686
687 typedef struct tagSNOOP_DLL {
688         HMODULE hmod;
689         SNOOP_FUN       *funs;
690         DWORD           ordbase;
691         DWORD           nrofordinals;
692         struct tagSNOOP_DLL     *next;
693         char name[1];
694 } SNOOP_DLL;
695
696 typedef struct
697 {
698         /* code part */
699         BYTE            lcall;          /* 0xe8 call snoopret relative*/
700         /* NOTE: If you move snoopret OR origreturn fix the relative offset
701          * calculation!
702          */
703         DWORD           snoopret;       /* SNOOP_Ret relative */
704         /* unreached */
705         FARPROC origreturn;
706         SNOOP_DLL       *dll;
707         DWORD           ordinal;
708         DWORD           origESP;
709         DWORD           *args;          /* saved args across a stdcall */
710 } SNOOP_RETURNENTRY;
711
712 typedef struct tagSNOOP_RETURNENTRIES {
713         SNOOP_RETURNENTRY entry[4092/sizeof(SNOOP_RETURNENTRY)];
714         struct tagSNOOP_RETURNENTRIES   *next;
715 } SNOOP_RETURNENTRIES;
716
717 #include "poppack.h"
718
719 extern void WINAPI SNOOP_Entry(void);
720 extern void WINAPI SNOOP_Return(void);
721
722 static SNOOP_DLL *firstdll;
723 static SNOOP_RETURNENTRIES *firstrets;
724
725
726 /***********************************************************************
727  *          SNOOP_ShowDebugmsgSnoop
728  *
729  * Simple function to decide if a particular debugging message is
730  * wanted.
731  */
732 static BOOL SNOOP_ShowDebugmsgSnoop(const char *module, int ordinal, const char *func)
733 {
734     if (debug_snoop_excludelist && check_list( module, ordinal, func, debug_snoop_excludelist ))
735         return FALSE;
736     if (debug_snoop_includelist && !check_list( module, ordinal, func, debug_snoop_includelist ))
737         return FALSE;
738     return TRUE;
739 }
740
741
742 /***********************************************************************
743  *           SNOOP_SetupDLL
744  *
745  * Setup snoop debugging for a native dll.
746  */
747 void SNOOP_SetupDLL(HMODULE hmod)
748 {
749     SNOOP_DLL **dll = &firstdll;
750     char *p, *name;
751     void *addr;
752     SIZE_T size;
753     ULONG size32;
754     IMAGE_EXPORT_DIRECTORY *exports;
755
756     if (!init_done) init_debug_lists();
757
758     exports = RtlImageDirectoryEntryToData( hmod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size32 );
759     if (!exports || !exports->NumberOfFunctions) return;
760     name = (char *)hmod + exports->Name;
761     size = size32;
762
763     TRACE_(snoop)("hmod=%p, name=%s\n", hmod, name);
764
765     while (*dll) {
766         if ((*dll)->hmod == hmod)
767         {
768             /* another dll, loaded at the same address */
769             addr = (*dll)->funs;
770             size = (*dll)->nrofordinals * sizeof(SNOOP_FUN);
771             NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE);
772             break;
773         }
774         dll = &((*dll)->next);
775     }
776     if (*dll)
777         *dll = RtlReAllocateHeap(GetProcessHeap(),
778                              HEAP_ZERO_MEMORY, *dll,
779                              sizeof(SNOOP_DLL) + strlen(name));
780     else
781         *dll = RtlAllocateHeap(GetProcessHeap(),
782                              HEAP_ZERO_MEMORY,
783                              sizeof(SNOOP_DLL) + strlen(name));
784     (*dll)->hmod        = hmod;
785     (*dll)->ordbase = exports->Base;
786     (*dll)->nrofordinals = exports->NumberOfFunctions;
787     strcpy( (*dll)->name, name );
788     p = (*dll)->name + strlen((*dll)->name) - 4;
789     if (p > (*dll)->name && !strcasecmp( p, ".dll" )) *p = 0;
790
791     size = exports->NumberOfFunctions * sizeof(SNOOP_FUN);
792     addr = NULL;
793     NtAllocateVirtualMemory(NtCurrentProcess(), &addr, 0, &size,
794                             MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
795     if (!addr) {
796         RtlFreeHeap(GetProcessHeap(),0,*dll);
797         FIXME("out of memory\n");
798         return;
799     }
800     (*dll)->funs = addr;
801     memset((*dll)->funs,0,size);
802 }
803
804
805 /***********************************************************************
806  *           SNOOP_GetProcAddress
807  *
808  * Return the proc address to use for a given function.
809  */
810 FARPROC SNOOP_GetProcAddress( HMODULE hmod, const IMAGE_EXPORT_DIRECTORY *exports,
811                               DWORD exp_size, FARPROC origfun, DWORD ordinal,
812                               const WCHAR *user)
813 {
814     unsigned int i;
815     const char *ename;
816     const WORD *ordinals;
817     const DWORD *names;
818     SNOOP_DLL *dll = firstdll;
819     SNOOP_FUN *fun;
820     const IMAGE_SECTION_HEADER *sec;
821
822     if (!TRACE_ON(snoop)) return origfun;
823     if (!check_from_module( debug_from_snoop_includelist, debug_from_snoop_excludelist, user ))
824         return origfun; /* the calling module was explicitly excluded */
825
826     if (!*(LPBYTE)origfun) /* 0x00 is an impossible opcode, possible dataref. */
827         return origfun;
828
829     sec = RtlImageRvaToSection( RtlImageNtHeader(hmod), hmod, (char *)origfun - (char *)hmod );
830
831     if (!sec || !(sec->Characteristics & IMAGE_SCN_CNT_CODE))
832         return origfun;  /* most likely a data reference */
833
834     while (dll) {
835         if (hmod == dll->hmod)
836             break;
837         dll = dll->next;
838     }
839     if (!dll)   /* probably internal */
840         return origfun;
841
842     /* try to find a name for it */
843     ename = NULL;
844     names = (const DWORD *)((const char *)hmod + exports->AddressOfNames);
845     ordinals = (const WORD *)((const char *)hmod + exports->AddressOfNameOrdinals);
846     if (names) for (i = 0; i < exports->NumberOfNames; i++)
847     {
848         if (ordinals[i] == ordinal)
849         {
850             ename = (const char *)hmod + names[i];
851             break;
852         }
853     }
854     if (!SNOOP_ShowDebugmsgSnoop(dll->name,ordinal,ename))
855         return origfun;
856     assert(ordinal < dll->nrofordinals);
857     fun = dll->funs + ordinal;
858     if (!fun->name)
859     {
860         fun->name       = ename;
861         fun->lcall      = 0xe8;
862         /* NOTE: origreturn struct member MUST come directly after snoopentry */
863         fun->snoopentry = (char*)SNOOP_Entry-((char*)(&fun->nrofargs));
864         fun->origfun    = origfun;
865         fun->nrofargs   = -1;
866     }
867     return (FARPROC)&(fun->lcall);
868 }
869
870 static void SNOOP_PrintArg(DWORD x)
871 {
872     int i,nostring;
873
874     DPRINTF("%08x",x);
875     if (IS_INTARG(x) || TRACE_ON(seh)) return; /* trivial reject to avoid faults */
876     __TRY
877     {
878         LPBYTE s=(LPBYTE)x;
879         i=0;nostring=0;
880         while (i<80) {
881             if (s[i]==0) break;
882             if (s[i]<0x20) {nostring=1;break;}
883             if (s[i]>=0x80) {nostring=1;break;}
884             i++;
885         }
886         if (!nostring && i > 5)
887             DPRINTF(" %s",debugstr_an((LPSTR)x,i));
888         else  /* try unicode */
889         {
890             LPWSTR s=(LPWSTR)x;
891             i=0;nostring=0;
892             while (i<80) {
893                 if (s[i]==0) break;
894                 if (s[i]<0x20) {nostring=1;break;}
895                 if (s[i]>0x100) {nostring=1;break;}
896                 i++;
897             }
898             if (!nostring && i > 5) DPRINTF(" %s",debugstr_wn((LPWSTR)x,i));
899         }
900     }
901     __EXCEPT_PAGE_FAULT
902     {
903     }
904     __ENDTRY
905 }
906
907 #define CALLER1REF (*(DWORD*)context->Esp)
908
909 void WINAPI __regs_SNOOP_Entry( CONTEXT *context )
910 {
911         DWORD           ordinal=0,entry = context->Eip - 5;
912         SNOOP_DLL       *dll = firstdll;
913         SNOOP_FUN       *fun = NULL;
914         SNOOP_RETURNENTRIES     **rets = &firstrets;
915         SNOOP_RETURNENTRY       *ret;
916         int             i=0, max;
917
918         while (dll) {
919                 if (    ((char*)entry>=(char*)dll->funs)        &&
920                         ((char*)entry<=(char*)(dll->funs+dll->nrofordinals))
921                 ) {
922                         fun = (SNOOP_FUN*)entry;
923                         ordinal = fun-dll->funs;
924                         break;
925                 }
926                 dll=dll->next;
927         }
928         if (!dll) {
929                 FIXME("entrypoint 0x%08x not found\n",entry);
930                 return; /* oops */
931         }
932         /* guess cdecl ... */
933         if (fun->nrofargs<0) {
934                 /* Typical cdecl return frame is:
935                  *     add esp, xxxxxxxx
936                  * which has (for xxxxxxxx up to 255 the opcode "83 C4 xx".
937                  * (after that 81 C2 xx xx xx xx)
938                  */
939                 LPBYTE  reteip = (LPBYTE)CALLER1REF;
940
941                 if (reteip) {
942                         if ((reteip[0]==0x83)&&(reteip[1]==0xc4))
943                                 fun->nrofargs=reteip[2]/4;
944                 }
945         }
946
947
948         while (*rets) {
949                 for (i=0;i<sizeof((*rets)->entry)/sizeof((*rets)->entry[0]);i++)
950                         if (!(*rets)->entry[i].origreturn)
951                                 break;
952                 if (i!=sizeof((*rets)->entry)/sizeof((*rets)->entry[0]))
953                         break;
954                 rets = &((*rets)->next);
955         }
956         if (!*rets) {
957                 SIZE_T size = 4096;
958                 VOID* addr = NULL;
959
960                 NtAllocateVirtualMemory(NtCurrentProcess(), &addr, 0, &size, 
961                                         MEM_COMMIT | MEM_RESERVE,
962                                         PAGE_EXECUTE_READWRITE);
963                 if (!addr) return;
964                 *rets = addr;
965                 memset(*rets,0,4096);
966                 i = 0;  /* entry 0 is free */
967         }
968         ret = &((*rets)->entry[i]);
969         ret->lcall      = 0xe8;
970         /* NOTE: origreturn struct member MUST come directly after snoopret */
971         ret->snoopret   = ((char*)SNOOP_Return)-(char*)(&ret->origreturn);
972         ret->origreturn = (FARPROC)CALLER1REF;
973         CALLER1REF      = (DWORD)&ret->lcall;
974         ret->dll        = dll;
975         ret->args       = NULL;
976         ret->ordinal    = ordinal;
977         ret->origESP    = context->Esp;
978
979         context->Eip = (DWORD)fun->origfun;
980
981         if (TRACE_ON(timestamp))
982                 print_timestamp();
983         if (fun->name) DPRINTF("%04x:CALL %s.%s(",GetCurrentThreadId(),dll->name,fun->name);
984         else DPRINTF("%04x:CALL %s.%d(",GetCurrentThreadId(),dll->name,dll->ordbase+ordinal);
985         if (fun->nrofargs>0) {
986                 max = fun->nrofargs; if (max>16) max=16;
987                 for (i=0;i<max;i++)
988                 {
989                     SNOOP_PrintArg(*(DWORD*)(context->Esp + 4 + sizeof(DWORD)*i));
990                     if (i<fun->nrofargs-1) DPRINTF(",");
991                 }
992                 if (max!=fun->nrofargs)
993                         DPRINTF(" ...");
994         } else if (fun->nrofargs<0) {
995                 DPRINTF("<unknown, check return>");
996                 ret->args = RtlAllocateHeap(GetProcessHeap(),
997                                             0,16*sizeof(DWORD));
998                 memcpy(ret->args,(LPBYTE)(context->Esp + 4),sizeof(DWORD)*16);
999         }
1000         DPRINTF(") ret=%08x\n",(DWORD)ret->origreturn);
1001 }
1002
1003
1004 void WINAPI __regs_SNOOP_Return( CONTEXT *context )
1005 {
1006         SNOOP_RETURNENTRY       *ret = (SNOOP_RETURNENTRY*)(context->Eip - 5);
1007         SNOOP_FUN *fun = &ret->dll->funs[ret->ordinal];
1008
1009         /* We haven't found out the nrofargs yet. If we called a cdecl
1010          * function it is too late anyway and we can just set '0' (which
1011          * will be the difference between orig and current ESP
1012          * If stdcall -> everything ok.
1013          */
1014         if (ret->dll->funs[ret->ordinal].nrofargs<0)
1015                 ret->dll->funs[ret->ordinal].nrofargs=(context->Esp - ret->origESP-4)/4;
1016         context->Eip = (DWORD)ret->origreturn;
1017         if (TRACE_ON(timestamp))
1018                 print_timestamp();
1019         if (ret->args) {
1020                 int     i,max;
1021
1022                 if (fun->name)
1023                     DPRINTF("%04x:RET  %s.%s(", GetCurrentThreadId(), ret->dll->name, fun->name);
1024                 else
1025                     DPRINTF("%04x:RET  %s.%d(", GetCurrentThreadId(),
1026                             ret->dll->name,ret->dll->ordbase+ret->ordinal);
1027
1028                 max = fun->nrofargs;
1029                 if (max>16) max=16;
1030
1031                 for (i=0;i<max;i++)
1032                 {
1033                     SNOOP_PrintArg(ret->args[i]);
1034                     if (i<max-1) DPRINTF(",");
1035                 }
1036                 DPRINTF(") retval=%08x ret=%08x\n",
1037                         context->Eax,(DWORD)ret->origreturn );
1038                 RtlFreeHeap(GetProcessHeap(),0,ret->args);
1039                 ret->args = NULL;
1040         }
1041         else
1042         {
1043             if (fun->name)
1044                 DPRINTF("%04x:RET  %s.%s() retval=%08x ret=%08x\n",
1045                         GetCurrentThreadId(),
1046                         ret->dll->name, fun->name, context->Eax, (DWORD)ret->origreturn);
1047             else
1048                 DPRINTF("%04x:RET  %s.%d() retval=%08x ret=%08x\n",
1049                         GetCurrentThreadId(),
1050                         ret->dll->name,ret->dll->ordbase+ret->ordinal,
1051                         context->Eax, (DWORD)ret->origreturn);
1052         }
1053         ret->origreturn = NULL; /* mark as empty */
1054 }
1055
1056 /* assembly wrappers that save the context */
1057 DEFINE_REGS_ENTRYPOINT( SNOOP_Entry, 0 )
1058 DEFINE_REGS_ENTRYPOINT( SNOOP_Return, 0 )
1059
1060 #else  /* __i386__ */
1061
1062 FARPROC SNOOP_GetProcAddress( HMODULE hmod, const IMAGE_EXPORT_DIRECTORY *exports, DWORD exp_size,
1063                               FARPROC origfun, DWORD ordinal, const WCHAR *user )
1064 {
1065     return origfun;
1066 }
1067
1068 void SNOOP_SetupDLL( HMODULE hmod )
1069 {
1070     FIXME("snooping works only on i386 for now.\n");
1071 }
1072
1073 #endif /* __i386__ */