Fix the case of product and company names.
[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 <stdarg.h>
27 #include <stdio.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winreg.h"
32 #include "winternl.h"
33 #include "wine/unicode.h"
34 #include "wine/debug.h"
35 #include "ntdll_misc.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(relay);
38 WINE_DECLARE_DEBUG_CHANNEL(snoop);
39
40 const char **debug_relay_excludelist = NULL;
41 const char **debug_relay_includelist = NULL;
42 const char **debug_snoop_excludelist = NULL;
43 const char **debug_snoop_includelist = NULL;
44
45 static const char **debug_from_relay_excludelist;
46 static const char **debug_from_relay_includelist;
47
48 /***********************************************************************
49  *           build_list
50  *
51  * Build a function list from a ';'-separated string.
52  */
53 static const char **build_list( const WCHAR *bufferW )
54 {
55     int count = 1;
56     char buffer[1024];
57     const char *p = buffer;
58     const char **ret;
59
60     RtlUnicodeToMultiByteN( buffer, sizeof(buffer), NULL,
61                             bufferW, (strlenW(bufferW)+1) * sizeof(WCHAR) );
62
63     while ((p = strchr( p, ';' )))
64     {
65          count++;
66         p++;
67     }
68     /* allocate count+1 pointers, plus the space for a copy of the string */
69     if ((ret = RtlAllocateHeap( ntdll_get_process_heap(), 0, (count+1) * sizeof(char*) + strlen(buffer) + 1 )))
70     {
71         char *str = (char *)(ret + count + 1);
72         char *p = str;
73
74         strcpy( str, buffer );
75         count = 0;
76         for (;;)
77         {
78             ret[count++] = p;
79             if (!(p = strchr( p, ';' ))) break;
80             *p++ = 0;
81         }
82         ret[count++] = NULL;
83     }
84     return ret;
85 }
86
87
88 /***********************************************************************
89  *           RELAY_InitDebugLists
90  *
91  * Build the relay include/exclude function lists.
92  */
93 void RELAY_InitDebugLists(void)
94 {
95     OBJECT_ATTRIBUTES attr;
96     UNICODE_STRING name;
97     char buffer[1024];
98     HKEY hkey;
99     DWORD count;
100     WCHAR *str;
101     static const WCHAR configW[] = {'M','a','c','h','i','n','e','\\',
102                                     'S','o','f','t','w','a','r','e','\\',
103                                     'W','i','n','e','\\',
104                                     'W','i','n','e','\\',
105                                     'C','o','n','f','i','g','\\',
106                                     'D','e','b','u','g',0};
107     static const WCHAR RelayIncludeW[] = {'R','e','l','a','y','I','n','c','l','u','d','e',0};
108     static const WCHAR RelayExcludeW[] = {'R','e','l','a','y','E','x','c','l','u','d','e',0};
109     static const WCHAR SnoopIncludeW[] = {'S','n','o','o','p','I','n','c','l','u','d','e',0};
110     static const WCHAR SnoopExcludeW[] = {'S','n','o','o','p','E','x','c','l','u','d','e',0};
111     static const WCHAR RelayFromIncludeW[] = {'R','e','l','a','y','F','r','o','m','I','n','c','l','u','d','e',0};
112     static const WCHAR RelayFromExcludeW[] = {'R','e','l','a','y','F','r','o','m','E','x','c','l','u','d','e',0};
113
114     attr.Length = sizeof(attr);
115     attr.RootDirectory = 0;
116     attr.ObjectName = &name;
117     attr.Attributes = 0;
118     attr.SecurityDescriptor = NULL;
119     attr.SecurityQualityOfService = NULL;
120     RtlInitUnicodeString( &name, configW );
121
122     if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return;
123
124     str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)buffer)->Data;
125     RtlInitUnicodeString( &name, RelayIncludeW );
126     if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
127     {
128         TRACE("RelayInclude = %s\n", debugstr_w(str) );
129         debug_relay_includelist = build_list( str );
130     }
131
132     RtlInitUnicodeString( &name, RelayExcludeW );
133     if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
134     {
135         TRACE( "RelayExclude = %s\n", debugstr_w(str) );
136         debug_relay_excludelist = build_list( str );
137     }
138
139     RtlInitUnicodeString( &name, SnoopIncludeW );
140     if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
141     {
142         TRACE_(snoop)( "SnoopInclude = %s\n", debugstr_w(str) );
143         debug_snoop_includelist = build_list( str );
144     }
145
146     RtlInitUnicodeString( &name, SnoopExcludeW );
147     if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
148     {
149         TRACE_(snoop)( "SnoopExclude = %s\n", debugstr_w(str) );
150         debug_snoop_excludelist = build_list( str );
151     }
152
153     RtlInitUnicodeString( &name, RelayFromIncludeW );
154     if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
155     {
156         TRACE("RelayFromInclude = %s\n", debugstr_w(str) );
157         debug_from_relay_includelist = build_list( str );
158     }
159
160     RtlInitUnicodeString( &name, RelayFromExcludeW );
161     if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
162     {
163         TRACE( "RelayFromExclude = %s\n", debugstr_w(str) );
164         debug_from_relay_excludelist = build_list( str );
165     }
166
167     NtClose( hkey );
168 }
169
170
171 #ifdef __i386__
172
173 typedef struct
174 {
175     BYTE          call;                    /* 0xe8 call callfrom32 (relative) */
176     DWORD         callfrom32 WINE_PACKED;  /* RELAY_CallFrom32 relative addr */
177     BYTE          ret;                     /* 0xc2 ret $n  or  0xc3 ret */
178     WORD          args;                    /* nb of args to remove from the stack */
179     void         *orig;                    /* original entry point */
180     DWORD         argtypes;                /* argument types */
181 } DEBUG_ENTRY_POINT;
182
183
184 /***********************************************************************
185  *           check_relay_include
186  *
187  * Check if a given function must be included in the relay output.
188  */
189 static BOOL check_relay_include( const char *module, const char *func )
190 {
191     const char **listitem;
192     BOOL show;
193
194     if (!debug_relay_excludelist && !debug_relay_includelist) return TRUE;
195     if (debug_relay_excludelist)
196     {
197         show = TRUE;
198         listitem = debug_relay_excludelist;
199     }
200     else
201     {
202         show = FALSE;
203         listitem = debug_relay_includelist;
204     }
205     for(; *listitem; listitem++)
206     {
207         char *p = strrchr( *listitem, '.' );
208         if (p && p > *listitem)  /* check module and function */
209         {
210             int len = p - *listitem;
211             if (strncasecmp( *listitem, module, len-1 ) || module[len]) continue;
212             if (!strcmp( p + 1, func ) || !strcmp( p + 1, "*" )) return !show;
213         }
214         else  /* function only */
215         {
216             if (!strcmp( *listitem, func )) return !show;
217         }
218     }
219     return show;
220 }
221
222
223 /***********************************************************************
224  *           check_relay_from_module
225  *
226  * Check if calls from a given module must be included in the relay output.
227  */
228 static BOOL check_relay_from_module( const char *module )
229 {
230     const char **listitem;
231     BOOL show;
232
233     if (!debug_from_relay_excludelist && !debug_from_relay_includelist) return TRUE;
234     if (debug_from_relay_excludelist)
235     {
236         show = TRUE;
237         listitem = debug_from_relay_excludelist;
238     }
239     else
240     {
241         show = FALSE;
242         listitem = debug_from_relay_includelist;
243     }
244     for(; *listitem; listitem++)
245     {
246         int len;
247
248         if (!strcasecmp( *listitem, module )) return !show;
249         len = strlen( *listitem );
250         if (!strncasecmp( *listitem, module, len ) && !strcasecmp( module + len, ".dll" ))
251             return !show;
252     }
253     return show;
254 }
255
256
257 /***********************************************************************
258  *           find_exported_name
259  *
260  * Find the name of an exported function.
261  */
262 static const char *find_exported_name( const char *module,
263                                        IMAGE_EXPORT_DIRECTORY *exp, int ordinal )
264 {
265     int i;
266     const char *ret = NULL;
267
268     WORD *ordptr = (WORD *)(module + exp->AddressOfNameOrdinals);
269     for (i = 0; i < exp->NumberOfNames; i++, ordptr++)
270         if (*ordptr + exp->Base == ordinal) break;
271     if (i < exp->NumberOfNames)
272         ret = module + ((DWORD*)(module + exp->AddressOfNames))[i];
273     return ret;
274 }
275
276
277 /***********************************************************************
278  *           get_entry_point
279  *
280  * Get the name of the DLL entry point corresponding to a relay address.
281  */
282 static void get_entry_point( char *buffer, DEBUG_ENTRY_POINT *relay )
283 {
284     IMAGE_EXPORT_DIRECTORY *exp = NULL;
285     DEBUG_ENTRY_POINT *debug;
286     char *p, *base = NULL;
287     const char *name;
288     int ordinal = 0;
289     PLIST_ENTRY mark, entry;
290     PLDR_MODULE mod = NULL;
291     DWORD size;
292
293     /* First find the module */
294
295     mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
296     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
297     {
298         mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
299         if (!(mod->Flags & LDR_WINE_INTERNAL)) continue;
300         exp = RtlImageDirectoryEntryToData( mod->BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size );
301         if (!exp) continue;
302         debug = (DEBUG_ENTRY_POINT *)((char *)exp + size);
303         if (debug <= relay && relay < debug + exp->NumberOfFunctions)
304         {
305             ordinal = relay - debug;
306             break;
307         }
308     }
309
310     /* Now find the function */
311
312     base = (char *)mod->BaseAddress;
313     strcpy( buffer, base + exp->Name );
314     p = buffer + strlen(buffer);
315     if (p > buffer + 4 && !strcasecmp( p - 4, ".dll" )) p -= 4;
316
317     if ((name = find_exported_name( base, exp, ordinal + exp->Base )))
318         sprintf( p, ".%s", name );
319     else
320         sprintf( p, ".%ld", ordinal + exp->Base );
321 }
322
323
324 /***********************************************************************
325  *           RELAY_PrintArgs
326  */
327 static inline void RELAY_PrintArgs( int *args, int nb_args, unsigned int typemask )
328 {
329     while (nb_args--)
330     {
331         if ((typemask & 3) && HIWORD(*args))
332         {
333             if (typemask & 2)
334                 DPRINTF( "%08x %s", *args, debugstr_w((LPWSTR)*args) );
335             else
336                 DPRINTF( "%08x %s", *args, debugstr_a((LPCSTR)*args) );
337         }
338         else DPRINTF( "%08x", *args );
339         if (nb_args) DPRINTF( "," );
340         args++;
341         typemask >>= 2;
342     }
343 }
344
345
346 typedef LONGLONG (*LONGLONG_CPROC)();
347 typedef LONGLONG (WINAPI *LONGLONG_FARPROC)();
348
349
350 /***********************************************************************
351  *           call_cdecl_function
352  */
353 static LONGLONG call_cdecl_function( LONGLONG_CPROC func, int nb_args, const int *args )
354 {
355     LONGLONG ret;
356     switch(nb_args)
357     {
358     case 0: ret = func(); break;
359     case 1: ret = func(args[0]); break;
360     case 2: ret = func(args[0],args[1]); break;
361     case 3: ret = func(args[0],args[1],args[2]); break;
362     case 4: ret = func(args[0],args[1],args[2],args[3]); break;
363     case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
364     case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
365                        args[5]); break;
366     case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
367                        args[6]); break;
368     case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
369                        args[6],args[7]); break;
370     case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
371                        args[6],args[7],args[8]); break;
372     case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
373                         args[6],args[7],args[8],args[9]); break;
374     case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
375                         args[6],args[7],args[8],args[9],args[10]); break;
376     case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
377                         args[6],args[7],args[8],args[9],args[10],
378                         args[11]); break;
379     case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
380                         args[6],args[7],args[8],args[9],args[10],args[11],
381                         args[12]); break;
382     case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
383                         args[6],args[7],args[8],args[9],args[10],args[11],
384                         args[12],args[13]); break;
385     case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
386                         args[6],args[7],args[8],args[9],args[10],args[11],
387                         args[12],args[13],args[14]); break;
388     case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
389                         args[6],args[7],args[8],args[9],args[10],args[11],
390                         args[12],args[13],args[14],args[15]); break;
391     default:
392         ERR( "Unsupported nb of args %d\n", nb_args );
393         assert(FALSE);
394         ret = 0;
395         break;
396     }
397     return ret;
398 }
399
400
401 /***********************************************************************
402  *           call_stdcall_function
403  */
404 static LONGLONG call_stdcall_function( LONGLONG_FARPROC func, int nb_args, const int *args )
405 {
406     LONGLONG ret;
407     switch(nb_args)
408     {
409     case 0: ret = func(); break;
410     case 1: ret = func(args[0]); break;
411     case 2: ret = func(args[0],args[1]); break;
412     case 3: ret = func(args[0],args[1],args[2]); break;
413     case 4: ret = func(args[0],args[1],args[2],args[3]); break;
414     case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
415     case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
416                        args[5]); break;
417     case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
418                        args[6]); break;
419     case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
420                        args[6],args[7]); break;
421     case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
422                        args[6],args[7],args[8]); break;
423     case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
424                         args[6],args[7],args[8],args[9]); break;
425     case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
426                         args[6],args[7],args[8],args[9],args[10]); break;
427     case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
428                         args[6],args[7],args[8],args[9],args[10],
429                         args[11]); break;
430     case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
431                         args[6],args[7],args[8],args[9],args[10],args[11],
432                         args[12]); break;
433     case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
434                         args[6],args[7],args[8],args[9],args[10],args[11],
435                         args[12],args[13]); break;
436     case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
437                         args[6],args[7],args[8],args[9],args[10],args[11],
438                         args[12],args[13],args[14]); break;
439     case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
440                         args[6],args[7],args[8],args[9],args[10],args[11],
441                         args[12],args[13],args[14],args[15]); break;
442     default:
443         ERR( "Unsupported nb of args %d\n", nb_args );
444         assert(FALSE);
445         ret = 0;
446         break;
447     }
448     return ret;
449 }
450
451
452 /***********************************************************************
453  *           RELAY_CallFrom32
454  *
455  * Stack layout on entry to this function:
456  *  ...      ...
457  * (esp+12)  arg2
458  * (esp+8)   arg1
459  * (esp+4)   ret_addr
460  * (esp)     return addr to relay code
461  */
462 static LONGLONG RELAY_CallFrom32( int ret_addr, ... )
463 {
464     LONGLONG ret;
465     char buffer[80];
466
467     int *args = &ret_addr + 1;
468     /* Relay addr is the return address for this function */
469     BYTE *relay_addr = (BYTE *)__builtin_return_address(0);
470     DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
471     WORD nb_args = relay->args / sizeof(int);
472
473     if (TRACE_ON(relay))
474     {
475         get_entry_point( buffer, relay );
476
477         DPRINTF( "%04lx:Call %s(", GetCurrentThreadId(), buffer );
478         RELAY_PrintArgs( args, nb_args, relay->argtypes );
479         DPRINTF( ") ret=%08x\n", ret_addr );
480     }
481
482     if (relay->ret == 0xc3) /* cdecl */
483     {
484         ret = call_cdecl_function( (LONGLONG_CPROC)relay->orig, nb_args, args );
485     }
486     else  /* stdcall */
487     {
488         ret = call_stdcall_function( (LONGLONG_FARPROC)relay->orig, nb_args, args );
489     }
490
491     if (TRACE_ON(relay))
492     {
493         BOOL ret64 = (relay->argtypes & 0x80000000) && (nb_args < 16);
494         if (ret64)
495             DPRINTF( "%04lx:Ret  %s() retval=%08x%08x ret=%08x\n",
496                      GetCurrentThreadId(),
497                      buffer, (UINT)(ret >> 32), (UINT)ret, ret_addr );
498         else
499             DPRINTF( "%04lx:Ret  %s() retval=%08x ret=%08x\n",
500                      GetCurrentThreadId(),
501                      buffer, (UINT)ret, ret_addr );
502     }
503     return ret;
504 }
505
506
507 /***********************************************************************
508  *           RELAY_CallFrom32Regs
509  *
510  * Stack layout (esp is context->Esp, not the current %esp):
511  *
512  * ...
513  * (esp+4) first arg
514  * (esp)   return addr to caller
515  * (esp-4) return addr to DEBUG_ENTRY_POINT
516  * (esp-8) ptr to relay entry code for RELAY_CallFrom32Regs
517  *  ...    >128 bytes space free to be modified (ensured by the assembly glue)
518  */
519 void WINAPI RELAY_DoCallFrom32Regs( CONTEXT86 *context )
520 {
521     char buffer[80];
522     int* args;
523     int args_copy[17];
524     BYTE *entry_point;
525
526     BYTE *relay_addr = *((BYTE **)context->Esp - 1);
527     DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
528     WORD nb_args = relay->args / sizeof(int);
529
530     /* remove extra stuff from the stack */
531     context->Eip = *(DWORD *)context->Esp;
532     context->Esp += sizeof(DWORD);
533     args = (int *)context->Esp;
534     if (relay->ret == 0xc2) /* stdcall */
535         context->Esp += nb_args * sizeof(int);
536
537     entry_point = (BYTE *)relay->orig;
538     assert( *entry_point == 0xe8 /* lcall */ );
539
540     if (TRACE_ON(relay))
541     {
542         get_entry_point( buffer, relay );
543
544         DPRINTF( "%04lx:Call %s(", GetCurrentThreadId(), buffer );
545         RELAY_PrintArgs( args, nb_args, relay->argtypes );
546         DPRINTF( ") ret=%08lx fs=%04lx\n", context->Eip, context->SegFs );
547
548         DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
549                 context->Eax, context->Ebx, context->Ecx,
550                 context->Edx, context->Esi, context->Edi );
551         DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
552                 context->Ebp, context->Esp, context->SegDs,
553                 context->SegEs, context->SegGs, context->EFlags );
554     }
555
556     /* Now call the real function */
557
558     memcpy( args_copy, args, nb_args * sizeof(args[0]) );
559     args_copy[nb_args] = (int)context;  /* append context argument */
560     if (relay->ret == 0xc3) /* cdecl */
561     {
562         call_cdecl_function( *(LONGLONG_CPROC *)(entry_point + 5), nb_args+1, args_copy );
563     }
564     else  /* stdcall */
565     {
566         call_stdcall_function( *(LONGLONG_FARPROC *)(entry_point + 5), nb_args+1, args_copy );
567     }
568
569     if (TRACE_ON(relay))
570     {
571         DPRINTF( "%04lx:Ret  %s() retval=%08lx ret=%08lx fs=%04lx\n",
572                  GetCurrentThreadId(),
573                  buffer, context->Eax, context->Eip, context->SegFs );
574
575         DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
576                 context->Eax, context->Ebx, context->Ecx,
577                 context->Edx, context->Esi, context->Edi );
578         DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
579                 context->Ebp, context->Esp, context->SegDs,
580                 context->SegEs, context->SegGs, context->EFlags );
581     }
582 }
583
584 void WINAPI RELAY_CallFrom32Regs(void);
585 __ASM_GLOBAL_FUNC( RELAY_CallFrom32Regs,
586                    "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
587                    ".long " __ASM_NAME("RELAY_DoCallFrom32Regs") ",0" );
588
589
590 /* check whether the function at addr starts with a call to __wine_call_from_32_regs */
591 static BOOL is_register_entry_point( const BYTE *addr )
592 {
593     extern void __wine_call_from_32_regs();
594     int *offset;
595     void *ptr;
596
597     if (*addr != 0xe8) return FALSE;  /* not a call */
598     /* check if call target is __wine_call_from_32_regs */
599     offset = (int *)(addr + 1);
600     if (*offset == (char *)__wine_call_from_32_regs - (char *)(offset + 1)) return TRUE;
601     /* now check if call target is an import table jump to __wine_call_from_32_regs */
602     addr = (BYTE *)(offset + 1) + *offset;
603     if (addr[0] != 0xff || addr[1] != 0x25) return FALSE;  /* not an indirect jmp */
604     ptr = *(void **)(addr + 2);  /* get indirect jmp target address */
605     return (*(char **)ptr == (char *)__wine_call_from_32_regs);
606 }
607
608
609 /***********************************************************************
610  *           RELAY_GetProcAddress
611  *
612  * Return the proc address to use for a given function.
613  */
614 FARPROC RELAY_GetProcAddress( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
615                               DWORD exp_size, FARPROC proc, const char *user )
616 {
617     DEBUG_ENTRY_POINT *debug = (DEBUG_ENTRY_POINT *)proc;
618     DEBUG_ENTRY_POINT *list = (DEBUG_ENTRY_POINT *)((char *)exports + exp_size);
619
620     if (debug < list || debug >= list + exports->NumberOfFunctions) return proc;
621     if (list + (debug - list) != debug) return proc;  /* not a valid address */
622     if (check_relay_from_module( user )) return proc;  /* we want to relay it */
623     if (!debug->call) return proc;  /* not a normal function */
624     if (debug->call != 0xe8 && debug->call != 0xe9) return proc; /* not a debug thunk at all */
625     return debug->orig;
626 }
627
628
629 /***********************************************************************
630  *           RELAY_SetupDLL
631  *
632  * Setup relay debugging for a built-in dll.
633  */
634 void RELAY_SetupDLL( const char *module )
635 {
636     IMAGE_EXPORT_DIRECTORY *exports;
637     DEBUG_ENTRY_POINT *debug;
638     DWORD *funcs;
639     int i;
640     const char *name;
641     char *p, dllname[80];
642     DWORD size;
643
644     exports = RtlImageDirectoryEntryToData( (HMODULE)module, TRUE,
645                                             IMAGE_DIRECTORY_ENTRY_EXPORT, &size );
646     if (!exports) return;
647     debug = (DEBUG_ENTRY_POINT *)((char *)exports + size);
648     funcs = (DWORD *)(module + exports->AddressOfFunctions);
649     strcpy( dllname, module + exports->Name );
650     p = dllname + strlen(dllname) - 4;
651     if (p > dllname && !strcasecmp( p, ".dll" )) *p = 0;
652
653     for (i = 0; i < exports->NumberOfFunctions; i++, funcs++, debug++)
654     {
655         int on = 1;
656
657         if (!debug->call) continue;  /* not a normal function */
658         if (debug->call != 0xe8 && debug->call != 0xe9) break; /* not a debug thunk at all */
659
660         if ((name = find_exported_name( module, exports, i + exports->Base )))
661             on = check_relay_include( dllname, name );
662
663         if (on)
664         {
665             debug->call = 0xe8;  /* call relative */
666             if (is_register_entry_point( debug->orig ))
667                 debug->callfrom32 = (char *)RELAY_CallFrom32Regs - (char *)&debug->ret;
668             else
669                 debug->callfrom32 = (char *)RELAY_CallFrom32 - (char *)&debug->ret;
670         }
671         else
672         {
673             debug->call = 0xe9;  /* jmp relative */
674             debug->callfrom32 = (char *)debug->orig - (char *)&debug->ret;
675         }
676
677         debug->orig = (FARPROC)(module + (DWORD)*funcs);
678         *funcs = (char *)debug - module;
679     }
680 }
681
682 #else  /* __i386__ */
683
684 FARPROC RELAY_GetProcAddress( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
685                               DWORD exp_size, FARPROC proc, const char *user )
686 {
687     return proc;
688 }
689
690 void RELAY_SetupDLL( const char *module )
691 {
692 }
693
694 #endif /* __i386__ */