Added comment about why changing ADDRESS_SPACE_LIMIT is wrong.
[wine/hacks.git] / relay32 / relay386.c
blob9b54308958b946b696992a04bd55603e34a103d3
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 <stdio.h>
28 #include "winternl.h"
29 #include "stackframe.h"
30 #include "module.h"
31 #include "wine/unicode.h"
32 #include "wine/debug.h"
33 #include "ntdll_misc.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(relay);
36 WINE_DECLARE_DEBUG_CHANNEL(snoop);
38 const char **debug_relay_excludelist = NULL;
39 const char **debug_relay_includelist = NULL;
40 const char **debug_snoop_excludelist = NULL;
41 const char **debug_snoop_includelist = NULL;
43 static const char **debug_from_relay_excludelist;
44 static const char **debug_from_relay_includelist;
46 /***********************************************************************
47 * build_list
49 * Build a function list from a ';'-separated string.
51 static const char **build_list( const WCHAR *bufferW )
53 int count = 1;
54 char buffer[1024];
55 const char *p = buffer;
56 const char **ret;
58 RtlUnicodeToMultiByteN( buffer, sizeof(buffer), NULL,
59 bufferW, (strlenW(bufferW)+1) * sizeof(WCHAR) );
61 while ((p = strchr( p, ';' )))
63 count++;
64 p++;
66 /* allocate count+1 pointers, plus the space for a copy of the string */
67 if ((ret = RtlAllocateHeap( ntdll_get_process_heap(), 0, (count+1) * sizeof(char*) + strlen(buffer) + 1 )))
69 char *str = (char *)(ret + count + 1);
70 char *p = str;
72 strcpy( str, buffer );
73 count = 0;
74 for (;;)
76 ret[count++] = p;
77 if (!(p = strchr( p, ';' ))) break;
78 *p++ = 0;
80 ret[count++] = NULL;
82 return ret;
86 /***********************************************************************
87 * RELAY_InitDebugLists
89 * Build the relay include/exclude function lists.
91 void RELAY_InitDebugLists(void)
93 OBJECT_ATTRIBUTES attr;
94 UNICODE_STRING name;
95 char buffer[1024];
96 HKEY hkey;
97 DWORD count;
98 WCHAR *str;
99 static const WCHAR configW[] = {'M','a','c','h','i','n','e','\\',
100 'S','o','f','t','w','a','r','e','\\',
101 'W','i','n','e','\\',
102 'W','i','n','e','\\',
103 'C','o','n','f','i','g','\\',
104 'D','e','b','u','g',0};
105 static const WCHAR RelayIncludeW[] = {'R','e','l','a','y','I','n','c','l','u','d','e',0};
106 static const WCHAR RelayExcludeW[] = {'R','e','l','a','y','E','x','c','l','u','d','e',0};
107 static const WCHAR SnoopIncludeW[] = {'S','n','o','o','p','I','n','c','l','u','d','e',0};
108 static const WCHAR SnoopExcludeW[] = {'S','n','o','o','p','E','x','c','l','u','d','e',0};
109 static const WCHAR RelayFromIncludeW[] = {'R','e','l','a','y','F','r','o','m','I','n','c','l','u','d','e',0};
110 static const WCHAR RelayFromExcludeW[] = {'R','e','l','a','y','F','r','o','m','E','x','c','l','u','d','e',0};
112 attr.Length = sizeof(attr);
113 attr.RootDirectory = 0;
114 attr.ObjectName = &name;
115 attr.Attributes = 0;
116 attr.SecurityDescriptor = NULL;
117 attr.SecurityQualityOfService = NULL;
118 RtlInitUnicodeString( &name, configW );
120 if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return;
122 str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)buffer)->Data;
123 RtlInitUnicodeString( &name, RelayIncludeW );
124 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
126 TRACE("RelayInclude = %s\n", debugstr_w(str) );
127 debug_relay_includelist = build_list( str );
130 RtlInitUnicodeString( &name, RelayExcludeW );
131 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
133 TRACE( "RelayExclude = %s\n", debugstr_w(str) );
134 debug_relay_excludelist = build_list( str );
137 RtlInitUnicodeString( &name, SnoopIncludeW );
138 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
140 TRACE_(snoop)( "SnoopInclude = %s\n", debugstr_w(str) );
141 debug_snoop_includelist = build_list( str );
144 RtlInitUnicodeString( &name, SnoopExcludeW );
145 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
147 TRACE_(snoop)( "SnoopExclude = %s\n", debugstr_w(str) );
148 debug_snoop_excludelist = build_list( str );
151 RtlInitUnicodeString( &name, RelayFromIncludeW );
152 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
154 TRACE("RelayFromInclude = %s\n", debugstr_w(str) );
155 debug_from_relay_includelist = build_list( str );
158 RtlInitUnicodeString( &name, RelayFromExcludeW );
159 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
161 TRACE( "RelayFromExclude = %s\n", debugstr_w(str) );
162 debug_from_relay_excludelist = build_list( str );
165 NtClose( hkey );
169 #ifdef __i386__
171 typedef struct
173 BYTE call; /* 0xe8 call callfrom32 (relative) */
174 DWORD callfrom32 WINE_PACKED; /* RELAY_CallFrom32 relative addr */
175 BYTE ret; /* 0xc2 ret $n or 0xc3 ret */
176 WORD args; /* nb of args to remove from the stack */
177 void *orig; /* original entry point */
178 DWORD argtypes; /* argument types */
179 } DEBUG_ENTRY_POINT;
182 /***********************************************************************
183 * check_relay_include
185 * Check if a given function must be included in the relay output.
187 static BOOL check_relay_include( const char *module, const char *func )
189 const char **listitem;
190 BOOL show;
192 if (!debug_relay_excludelist && !debug_relay_includelist) return TRUE;
193 if (debug_relay_excludelist)
195 show = TRUE;
196 listitem = debug_relay_excludelist;
198 else
200 show = FALSE;
201 listitem = debug_relay_includelist;
203 for(; *listitem; listitem++)
205 char *p = strrchr( *listitem, '.' );
206 if (p && p > *listitem) /* check module and function */
208 int len = p - *listitem;
209 if (strncasecmp( *listitem, module, len-1 ) || module[len]) continue;
210 if (!strcmp( p + 1, func ) || !strcmp( p + 1, "*" )) return !show;
212 else /* function only */
214 if (!strcmp( *listitem, func )) return !show;
217 return show;
221 /***********************************************************************
222 * check_relay_from_module
224 * Check if calls from a given module must be included in the relay output.
226 static BOOL check_relay_from_module( const char *module )
228 const char **listitem;
229 BOOL show;
231 if (!debug_from_relay_excludelist && !debug_from_relay_includelist) return TRUE;
232 if (debug_from_relay_excludelist)
234 show = TRUE;
235 listitem = debug_from_relay_excludelist;
237 else
239 show = FALSE;
240 listitem = debug_from_relay_includelist;
242 for(; *listitem; listitem++)
244 int len;
246 if (!strcasecmp( *listitem, module )) return !show;
247 len = strlen( *listitem );
248 if (!strncasecmp( *listitem, module, len ) && !strcasecmp( module + len, ".dll" ))
249 return !show;
251 return show;
255 /***********************************************************************
256 * find_exported_name
258 * Find the name of an exported function.
260 static const char *find_exported_name( const char *module,
261 IMAGE_EXPORT_DIRECTORY *exp, int ordinal )
263 int i;
264 const char *ret = NULL;
266 WORD *ordptr = (WORD *)(module + exp->AddressOfNameOrdinals);
267 for (i = 0; i < exp->NumberOfNames; i++, ordptr++)
268 if (*ordptr + exp->Base == ordinal) break;
269 if (i < exp->NumberOfNames)
270 ret = module + ((DWORD*)(module + exp->AddressOfNames))[i];
271 return ret;
275 /***********************************************************************
276 * get_entry_point
278 * Get the name of the DLL entry point corresponding to a relay address.
280 static void get_entry_point( char *buffer, DEBUG_ENTRY_POINT *relay )
282 IMAGE_EXPORT_DIRECTORY *exp = NULL;
283 DEBUG_ENTRY_POINT *debug;
284 char *p, *base = NULL;
285 const char *name;
286 int ordinal = 0;
287 WINE_MODREF *wm;
288 DWORD size;
290 /* First find the module */
292 for (wm = MODULE_modref_list; wm; wm = wm->next)
294 if (!(wm->ldr.Flags & LDR_WINE_INTERNAL)) continue;
295 exp = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size );
296 if (!exp) continue;
297 debug = (DEBUG_ENTRY_POINT *)((char *)exp + size);
298 if (debug <= relay && relay < debug + exp->NumberOfFunctions)
300 ordinal = relay - debug;
301 break;
305 /* Now find the function */
307 base = (char *)wm->ldr.BaseAddress;
308 strcpy( buffer, base + exp->Name );
309 p = buffer + strlen(buffer);
310 if (p > buffer + 4 && !strcasecmp( p - 4, ".dll" )) p -= 4;
312 if ((name = find_exported_name( base, exp, ordinal + exp->Base )))
313 sprintf( p, ".%s", name );
314 else
315 sprintf( p, ".%ld", ordinal + exp->Base );
319 /***********************************************************************
320 * RELAY_PrintArgs
322 static inline void RELAY_PrintArgs( int *args, int nb_args, unsigned int typemask )
324 while (nb_args--)
326 if ((typemask & 3) && HIWORD(*args))
328 if (typemask & 2)
329 DPRINTF( "%08x %s", *args, debugstr_w((LPWSTR)*args) );
330 else
331 DPRINTF( "%08x %s", *args, debugstr_a((LPCSTR)*args) );
333 else DPRINTF( "%08x", *args );
334 if (nb_args) DPRINTF( "," );
335 args++;
336 typemask >>= 2;
341 typedef LONGLONG (*LONGLONG_CPROC)();
342 typedef LONGLONG (WINAPI *LONGLONG_FARPROC)();
345 /***********************************************************************
346 * call_cdecl_function
348 static LONGLONG call_cdecl_function( LONGLONG_CPROC func, int nb_args, const int *args )
350 LONGLONG ret;
351 switch(nb_args)
353 case 0: ret = func(); break;
354 case 1: ret = func(args[0]); break;
355 case 2: ret = func(args[0],args[1]); break;
356 case 3: ret = func(args[0],args[1],args[2]); break;
357 case 4: ret = func(args[0],args[1],args[2],args[3]); break;
358 case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
359 case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
360 args[5]); break;
361 case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
362 args[6]); break;
363 case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
364 args[6],args[7]); break;
365 case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
366 args[6],args[7],args[8]); break;
367 case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
368 args[6],args[7],args[8],args[9]); break;
369 case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
370 args[6],args[7],args[8],args[9],args[10]); break;
371 case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
372 args[6],args[7],args[8],args[9],args[10],
373 args[11]); break;
374 case 13: 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],args[11],
376 args[12]); break;
377 case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
378 args[6],args[7],args[8],args[9],args[10],args[11],
379 args[12],args[13]); break;
380 case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
381 args[6],args[7],args[8],args[9],args[10],args[11],
382 args[12],args[13],args[14]); break;
383 case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
384 args[6],args[7],args[8],args[9],args[10],args[11],
385 args[12],args[13],args[14],args[15]); break;
386 default:
387 ERR( "Unsupported nb of args %d\n", nb_args );
388 assert(FALSE);
389 ret = 0;
390 break;
392 return ret;
396 /***********************************************************************
397 * call_stdcall_function
399 static LONGLONG call_stdcall_function( LONGLONG_FARPROC func, int nb_args, const int *args )
401 LONGLONG ret;
402 switch(nb_args)
404 case 0: ret = func(); break;
405 case 1: ret = func(args[0]); break;
406 case 2: ret = func(args[0],args[1]); break;
407 case 3: ret = func(args[0],args[1],args[2]); break;
408 case 4: ret = func(args[0],args[1],args[2],args[3]); break;
409 case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
410 case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
411 args[5]); break;
412 case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
413 args[6]); break;
414 case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
415 args[6],args[7]); break;
416 case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
417 args[6],args[7],args[8]); break;
418 case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
419 args[6],args[7],args[8],args[9]); break;
420 case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
421 args[6],args[7],args[8],args[9],args[10]); break;
422 case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
423 args[6],args[7],args[8],args[9],args[10],
424 args[11]); break;
425 case 13: 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],args[11],
427 args[12]); break;
428 case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
429 args[6],args[7],args[8],args[9],args[10],args[11],
430 args[12],args[13]); break;
431 case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
432 args[6],args[7],args[8],args[9],args[10],args[11],
433 args[12],args[13],args[14]); break;
434 case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
435 args[6],args[7],args[8],args[9],args[10],args[11],
436 args[12],args[13],args[14],args[15]); break;
437 default:
438 ERR( "Unsupported nb of args %d\n", nb_args );
439 assert(FALSE);
440 ret = 0;
441 break;
443 return ret;
447 /***********************************************************************
448 * RELAY_CallFrom32
450 * Stack layout on entry to this function:
451 * ... ...
452 * (esp+12) arg2
453 * (esp+8) arg1
454 * (esp+4) ret_addr
455 * (esp) return addr to relay code
457 static LONGLONG RELAY_CallFrom32( int ret_addr, ... )
459 LONGLONG ret;
460 char buffer[80];
462 int *args = &ret_addr + 1;
463 /* Relay addr is the return address for this function */
464 BYTE *relay_addr = (BYTE *)__builtin_return_address(0);
465 DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
466 WORD nb_args = relay->args / sizeof(int);
468 if (TRACE_ON(relay))
470 get_entry_point( buffer, relay );
472 DPRINTF( "%04lx:Call %s(", GetCurrentThreadId(), buffer );
473 RELAY_PrintArgs( args, nb_args, relay->argtypes );
474 DPRINTF( ") ret=%08x\n", ret_addr );
477 if (relay->ret == 0xc3) /* cdecl */
479 ret = call_cdecl_function( (LONGLONG_CPROC)relay->orig, nb_args, args );
481 else /* stdcall */
483 ret = call_stdcall_function( (LONGLONG_FARPROC)relay->orig, nb_args, args );
486 if (TRACE_ON(relay))
488 BOOL ret64 = (relay->argtypes & 0x80000000) && (nb_args < 16);
489 if (ret64)
490 DPRINTF( "%04lx:Ret %s() retval=%08x%08x ret=%08x\n",
491 GetCurrentThreadId(),
492 buffer, (UINT)(ret >> 32), (UINT)ret, ret_addr );
493 else
494 DPRINTF( "%04lx:Ret %s() retval=%08x ret=%08x\n",
495 GetCurrentThreadId(),
496 buffer, (UINT)ret, ret_addr );
498 return ret;
502 /***********************************************************************
503 * RELAY_CallFrom32Regs
505 * Stack layout (esp is context->Esp, not the current %esp):
507 * ...
508 * (esp+4) first arg
509 * (esp) return addr to caller
510 * (esp-4) return addr to DEBUG_ENTRY_POINT
511 * (esp-8) ptr to relay entry code for RELAY_CallFrom32Regs
512 * ... >128 bytes space free to be modified (ensured by the assembly glue)
514 void WINAPI RELAY_DoCallFrom32Regs( CONTEXT86 *context )
516 char buffer[80];
517 int* args;
518 int args_copy[17];
519 BYTE *entry_point;
521 BYTE *relay_addr = *((BYTE **)context->Esp - 1);
522 DEBUG_ENTRY_POINT *relay = (DEBUG_ENTRY_POINT *)(relay_addr - 5);
523 WORD nb_args = relay->args / sizeof(int);
525 /* remove extra stuff from the stack */
526 context->Eip = stack32_pop(context);
527 args = (int *)context->Esp;
528 if (relay->ret == 0xc2) /* stdcall */
529 context->Esp += nb_args * sizeof(int);
531 entry_point = (BYTE *)relay->orig;
532 assert( *entry_point == 0xe8 /* lcall */ );
534 if (TRACE_ON(relay))
536 get_entry_point( buffer, relay );
538 DPRINTF( "%04lx:Call %s(", GetCurrentThreadId(), buffer );
539 RELAY_PrintArgs( args, nb_args, relay->argtypes );
540 DPRINTF( ") ret=%08lx fs=%04lx\n", context->Eip, context->SegFs );
542 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
543 context->Eax, context->Ebx, context->Ecx,
544 context->Edx, context->Esi, context->Edi );
545 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
546 context->Ebp, context->Esp, context->SegDs,
547 context->SegEs, context->SegGs, context->EFlags );
550 /* Now call the real function */
552 memcpy( args_copy, args, nb_args * sizeof(args[0]) );
553 args_copy[nb_args] = (int)context; /* append context argument */
554 if (relay->ret == 0xc3) /* cdecl */
556 call_cdecl_function( *(LONGLONG_CPROC *)(entry_point + 5), nb_args+1, args_copy );
558 else /* stdcall */
560 call_stdcall_function( *(LONGLONG_FARPROC *)(entry_point + 5), nb_args+1, args_copy );
563 if (TRACE_ON(relay))
565 DPRINTF( "%04lx:Ret %s() retval=%08lx ret=%08lx fs=%04lx\n",
566 GetCurrentThreadId(),
567 buffer, context->Eax, context->Eip, context->SegFs );
569 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
570 context->Eax, context->Ebx, context->Ecx,
571 context->Edx, context->Esi, context->Edi );
572 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
573 context->Ebp, context->Esp, context->SegDs,
574 context->SegEs, context->SegGs, context->EFlags );
578 void WINAPI RELAY_CallFrom32Regs(void);
579 __ASM_GLOBAL_FUNC( RELAY_CallFrom32Regs,
580 "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
581 ".long " __ASM_NAME("RELAY_DoCallFrom32Regs") ",0" );
584 /* check whether the function at addr starts with a call to __wine_call_from_32_regs */
585 static BOOL is_register_entry_point( const BYTE *addr )
587 extern void __wine_call_from_32_regs();
588 int *offset;
589 void *ptr;
591 if (*addr != 0xe8) return FALSE; /* not a call */
592 /* check if call target is __wine_call_from_32_regs */
593 offset = (int *)(addr + 1);
594 if (*offset == (char *)__wine_call_from_32_regs - (char *)(offset + 1)) return TRUE;
595 /* now check if call target is an import table jump to __wine_call_from_32_regs */
596 addr = (BYTE *)(offset + 1) + *offset;
597 if (addr[0] != 0xff || addr[1] != 0x25) return FALSE; /* not an indirect jmp */
598 ptr = *(void **)(addr + 2); /* get indirect jmp target address */
599 return (*(char **)ptr == (char *)__wine_call_from_32_regs);
603 /***********************************************************************
604 * RELAY_GetProcAddress
606 * Return the proc address to use for a given function.
608 FARPROC RELAY_GetProcAddress( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
609 DWORD exp_size, FARPROC proc, const char *user )
611 DEBUG_ENTRY_POINT *debug = (DEBUG_ENTRY_POINT *)proc;
612 DEBUG_ENTRY_POINT *list = (DEBUG_ENTRY_POINT *)((char *)exports + exp_size);
614 if (debug < list || debug >= list + exports->NumberOfFunctions) return proc;
615 if (list + (debug - list) != debug) return proc; /* not a valid address */
616 if (check_relay_from_module( user )) return proc; /* we want to relay it */
617 if (!debug->call) return proc; /* not a normal function */
618 if (debug->call != 0xe8 && debug->call != 0xe9) return proc; /* not a debug thunk at all */
619 return debug->orig;
623 /***********************************************************************
624 * RELAY_SetupDLL
626 * Setup relay debugging for a built-in dll.
628 void RELAY_SetupDLL( const char *module )
630 IMAGE_EXPORT_DIRECTORY *exports;
631 DEBUG_ENTRY_POINT *debug;
632 DWORD *funcs;
633 int i;
634 const char *name;
635 char *p, dllname[80];
636 DWORD size;
638 exports = RtlImageDirectoryEntryToData( (HMODULE)module, TRUE,
639 IMAGE_DIRECTORY_ENTRY_EXPORT, &size );
640 if (!exports) return;
641 debug = (DEBUG_ENTRY_POINT *)((char *)exports + size);
642 funcs = (DWORD *)(module + exports->AddressOfFunctions);
643 strcpy( dllname, module + exports->Name );
644 p = dllname + strlen(dllname) - 4;
645 if (p > dllname && !strcasecmp( p, ".dll" )) *p = 0;
647 for (i = 0; i < exports->NumberOfFunctions; i++, funcs++, debug++)
649 int on = 1;
651 if (!debug->call) continue; /* not a normal function */
652 if (debug->call != 0xe8 && debug->call != 0xe9) break; /* not a debug thunk at all */
654 if ((name = find_exported_name( module, exports, i + exports->Base )))
655 on = check_relay_include( dllname, name );
657 if (on)
659 debug->call = 0xe8; /* call relative */
660 if (is_register_entry_point( debug->orig ))
661 debug->callfrom32 = (char *)RELAY_CallFrom32Regs - (char *)&debug->ret;
662 else
663 debug->callfrom32 = (char *)RELAY_CallFrom32 - (char *)&debug->ret;
665 else
667 debug->call = 0xe9; /* jmp relative */
668 debug->callfrom32 = (char *)debug->orig - (char *)&debug->ret;
671 debug->orig = (FARPROC)(module + (DWORD)*funcs);
672 *funcs = (char *)debug - module;
676 #else /* __i386__ */
678 FARPROC RELAY_GetProcAddress( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
679 DWORD exp_size, FARPROC proc, const char *user )
681 return proc;
684 void RELAY_SetupDLL( const char *module )
688 #endif /* __i386__ */