Fix French translation.
[wine/multimedia.git] / relay32 / relay386.c
blobf2a396d651f59249bc40748456add66b3e63dbc3
1 /*
2 * 386-specific Win32 relay functions
4 * Copyright 1997 Alexandre Julliard
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <stdio.h>
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"
37 WINE_DEFAULT_DEBUG_CHANNEL(relay);
38 WINE_DECLARE_DEBUG_CHANNEL(snoop);
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;
45 static const char **debug_from_relay_excludelist;
46 static const char **debug_from_relay_includelist;
48 /***********************************************************************
49 * build_list
51 * Build a function list from a ';'-separated string.
53 static const char **build_list( const WCHAR *bufferW )
55 int count = 1;
56 char buffer[1024];
57 const char *p = buffer;
58 const char **ret;
60 RtlUnicodeToMultiByteN( buffer, sizeof(buffer), NULL,
61 bufferW, (strlenW(bufferW)+1) * sizeof(WCHAR) );
63 while ((p = strchr( p, ';' )))
65 count++;
66 p++;
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 )))
71 char *str = (char *)(ret + count + 1);
72 char *p = str;
74 strcpy( str, buffer );
75 count = 0;
76 for (;;)
78 ret[count++] = p;
79 if (!(p = strchr( p, ';' ))) break;
80 *p++ = 0;
82 ret[count++] = NULL;
84 return ret;
88 /***********************************************************************
89 * RELAY_InitDebugLists
91 * Build the relay include/exclude function lists.
93 void RELAY_InitDebugLists(void)
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};
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 );
122 if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return;
124 str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)buffer)->Data;
125 RtlInitUnicodeString( &name, RelayIncludeW );
126 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
128 TRACE("RelayInclude = %s\n", debugstr_w(str) );
129 debug_relay_includelist = build_list( str );
132 RtlInitUnicodeString( &name, RelayExcludeW );
133 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
135 TRACE( "RelayExclude = %s\n", debugstr_w(str) );
136 debug_relay_excludelist = build_list( str );
139 RtlInitUnicodeString( &name, SnoopIncludeW );
140 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
142 TRACE_(snoop)( "SnoopInclude = %s\n", debugstr_w(str) );
143 debug_snoop_includelist = build_list( str );
146 RtlInitUnicodeString( &name, SnoopExcludeW );
147 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
149 TRACE_(snoop)( "SnoopExclude = %s\n", debugstr_w(str) );
150 debug_snoop_excludelist = build_list( str );
153 RtlInitUnicodeString( &name, RelayFromIncludeW );
154 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
156 TRACE("RelayFromInclude = %s\n", debugstr_w(str) );
157 debug_from_relay_includelist = build_list( str );
160 RtlInitUnicodeString( &name, RelayFromExcludeW );
161 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
163 TRACE( "RelayFromExclude = %s\n", debugstr_w(str) );
164 debug_from_relay_excludelist = build_list( str );
167 NtClose( hkey );
171 #ifdef __i386__
173 typedef struct
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;
184 /***********************************************************************
185 * check_relay_include
187 * Check if a given function must be included in the relay output.
189 static BOOL check_relay_include( const char *module, const char *func )
191 const char **listitem;
192 BOOL show;
194 if (!debug_relay_excludelist && !debug_relay_includelist) return TRUE;
195 if (debug_relay_excludelist)
197 show = TRUE;
198 listitem = debug_relay_excludelist;
200 else
202 show = FALSE;
203 listitem = debug_relay_includelist;
205 for(; *listitem; listitem++)
207 char *p = strrchr( *listitem, '.' );
208 if (p && p > *listitem) /* check module and function */
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;
214 else /* function only */
216 if (!strcmp( *listitem, func )) return !show;
219 return show;
223 /***********************************************************************
224 * check_relay_from_module
226 * Check if calls from a given module must be included in the relay output.
228 static BOOL check_relay_from_module( const char *module )
230 const char **listitem;
231 BOOL show;
233 if (!debug_from_relay_excludelist && !debug_from_relay_includelist) return TRUE;
234 if (debug_from_relay_excludelist)
236 show = TRUE;
237 listitem = debug_from_relay_excludelist;
239 else
241 show = FALSE;
242 listitem = debug_from_relay_includelist;
244 for(; *listitem; listitem++)
246 int len;
248 if (!strcasecmp( *listitem, module )) return !show;
249 len = strlen( *listitem );
250 if (!strncasecmp( *listitem, module, len ) && !strcasecmp( module + len, ".dll" ))
251 return !show;
253 return show;
257 /***********************************************************************
258 * find_exported_name
260 * Find the name of an exported function.
262 static const char *find_exported_name( const char *module,
263 IMAGE_EXPORT_DIRECTORY *exp, int ordinal )
265 int i;
266 const char *ret = NULL;
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;
277 /***********************************************************************
278 * get_entry_point
280 * Get the name of the DLL entry point corresponding to a relay address.
282 static void get_entry_point( char *buffer, DEBUG_ENTRY_POINT *relay )
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;
293 /* First find the module */
295 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
296 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
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)
305 ordinal = relay - debug;
306 break;
310 /* Now find the function */
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;
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 );
324 /***********************************************************************
325 * RELAY_PrintArgs
327 static inline void RELAY_PrintArgs( int *args, int nb_args, unsigned int typemask )
329 while (nb_args--)
331 if ((typemask & 3) && HIWORD(*args))
333 if (typemask & 2)
334 DPRINTF( "%08x %s", *args, debugstr_w((LPWSTR)*args) );
335 else
336 DPRINTF( "%08x %s", *args, debugstr_a((LPCSTR)*args) );
338 else DPRINTF( "%08x", *args );
339 if (nb_args) DPRINTF( "," );
340 args++;
341 typemask >>= 2;
346 typedef LONGLONG (*LONGLONG_CPROC)();
347 typedef LONGLONG (WINAPI *LONGLONG_FARPROC)();
350 /***********************************************************************
351 * call_cdecl_function
353 static LONGLONG call_cdecl_function( LONGLONG_CPROC func, int nb_args, const int *args )
355 LONGLONG ret;
356 switch(nb_args)
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;
397 return ret;
401 /***********************************************************************
402 * call_stdcall_function
404 static LONGLONG call_stdcall_function( LONGLONG_FARPROC func, int nb_args, const int *args )
406 LONGLONG ret;
407 switch(nb_args)
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;
448 return ret;
452 /***********************************************************************
453 * RELAY_CallFrom32
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
462 static LONGLONG RELAY_CallFrom32( int ret_addr, ... )
464 LONGLONG ret;
465 char buffer[80];
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);
473 if (TRACE_ON(relay))
475 get_entry_point( buffer, relay );
477 DPRINTF( "%04lx:Call %s(", GetCurrentThreadId(), buffer );
478 RELAY_PrintArgs( args, nb_args, relay->argtypes );
479 DPRINTF( ") ret=%08x\n", ret_addr );
482 if (relay->ret == 0xc3) /* cdecl */
484 ret = call_cdecl_function( (LONGLONG_CPROC)relay->orig, nb_args, args );
486 else /* stdcall */
488 ret = call_stdcall_function( (LONGLONG_FARPROC)relay->orig, nb_args, args );
491 if (TRACE_ON(relay))
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 );
503 return ret;
507 /***********************************************************************
508 * RELAY_CallFrom32Regs
510 * Stack layout (esp is context->Esp, not the current %esp):
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)
519 void WINAPI RELAY_DoCallFrom32Regs( CONTEXT86 *context )
521 char buffer[80];
522 int* args;
523 int args_copy[17];
524 BYTE *entry_point;
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);
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);
537 entry_point = (BYTE *)relay->orig;
538 assert( *entry_point == 0xe8 /* lcall */ );
540 if (TRACE_ON(relay))
542 get_entry_point( buffer, relay );
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 );
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 );
556 /* Now call the real function */
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 */
562 call_cdecl_function( *(LONGLONG_CPROC *)(entry_point + 5), nb_args+1, args_copy );
564 else /* stdcall */
566 call_stdcall_function( *(LONGLONG_FARPROC *)(entry_point + 5), nb_args+1, args_copy );
569 if (TRACE_ON(relay))
571 DPRINTF( "%04lx:Ret %s() retval=%08lx ret=%08lx fs=%04lx\n",
572 GetCurrentThreadId(),
573 buffer, context->Eax, context->Eip, context->SegFs );
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 );
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" );
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 )
593 extern void __wine_call_from_32_regs();
594 int *offset;
595 void *ptr;
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);
609 /***********************************************************************
610 * RELAY_GetProcAddress
612 * Return the proc address to use for a given function.
614 FARPROC RELAY_GetProcAddress( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
615 DWORD exp_size, FARPROC proc, const char *user )
617 DEBUG_ENTRY_POINT *debug = (DEBUG_ENTRY_POINT *)proc;
618 DEBUG_ENTRY_POINT *list = (DEBUG_ENTRY_POINT *)((char *)exports + exp_size);
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;
629 /***********************************************************************
630 * RELAY_SetupDLL
632 * Setup relay debugging for a built-in dll.
634 void RELAY_SetupDLL( const char *module )
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;
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;
653 for (i = 0; i < exports->NumberOfFunctions; i++, funcs++, debug++)
655 int on = 1;
657 if (!debug->call) continue; /* not a normal function */
658 if (debug->call != 0xe8 && debug->call != 0xe9) break; /* not a debug thunk at all */
660 if ((name = find_exported_name( module, exports, i + exports->Base )))
661 on = check_relay_include( dllname, name );
663 if (on)
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;
671 else
673 debug->call = 0xe9; /* jmp relative */
674 debug->callfrom32 = (char *)debug->orig - (char *)&debug->ret;
677 debug->orig = (FARPROC)(module + (DWORD)*funcs);
678 *funcs = (char *)debug - module;
682 #else /* __i386__ */
684 FARPROC RELAY_GetProcAddress( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
685 DWORD exp_size, FARPROC proc, const char *user )
687 return proc;
690 void RELAY_SetupDLL( const char *module )
694 #endif /* __i386__ */