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