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
22 #include "wine/port.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 /***********************************************************************
51 * Build a function list from a ';'-separated string.
53 static const char **build_list( const WCHAR
*bufferW
)
57 const char *p
= buffer
;
60 RtlUnicodeToMultiByteN( buffer
, sizeof(buffer
), NULL
,
61 bufferW
, (strlenW(bufferW
)+1) * sizeof(WCHAR
) );
63 while ((p
= strchr( 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);
74 strcpy( str
, buffer
);
79 if (!(p
= strchr( p
, ';' ))) break;
88 /***********************************************************************
89 * RELAY_InitDebugLists
91 * Build the relay include/exclude function lists.
93 void RELAY_InitDebugLists(void)
95 OBJECT_ATTRIBUTES attr
;
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
;
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
);
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 */
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
;
194 if (!debug_relay_excludelist
&& !debug_relay_includelist
) return TRUE
;
195 if (debug_relay_excludelist
)
198 listitem
= debug_relay_excludelist
;
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
;
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
;
233 if (!debug_from_relay_excludelist
&& !debug_from_relay_includelist
) return TRUE
;
234 if (debug_from_relay_excludelist
)
237 listitem
= debug_from_relay_excludelist
;
242 listitem
= debug_from_relay_includelist
;
244 for(; *listitem
; listitem
++)
248 if (!strcasecmp( *listitem
, module
)) return !show
;
249 len
= strlen( *listitem
);
250 if (!strncasecmp( *listitem
, module
, len
) && !strcasecmp( module
+ len
, ".dll" ))
257 /***********************************************************************
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
)
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
];
277 /***********************************************************************
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
;
289 PLIST_ENTRY mark
, entry
;
290 PLDR_MODULE mod
= NULL
;
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
);
302 debug
= (DEBUG_ENTRY_POINT
*)((char *)exp
+ size
);
303 if (debug
<= relay
&& relay
< debug
+ exp
->NumberOfFunctions
)
305 ordinal
= relay
- debug
;
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
);
320 sprintf( p
, ".%ld", ordinal
+ exp
->Base
);
324 /***********************************************************************
327 static inline void RELAY_PrintArgs( int *args
, int nb_args
, unsigned int typemask
)
331 if ((typemask
& 3) && HIWORD(*args
))
334 DPRINTF( "%08x %s", *args
, debugstr_w((LPWSTR
)*args
) );
336 DPRINTF( "%08x %s", *args
, debugstr_a((LPCSTR
)*args
) );
338 else DPRINTF( "%08x", *args
);
339 if (nb_args
) DPRINTF( "," );
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
)
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],
366 case 7: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
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],
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],
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;
392 ERR( "Unsupported nb of args %d\n", nb_args
);
401 /***********************************************************************
402 * call_stdcall_function
404 static LONGLONG
call_stdcall_function( LONGLONG_FARPROC func
, int nb_args
, const int *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],
417 case 7: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
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],
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],
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;
443 ERR( "Unsupported nb of args %d\n", nb_args
);
452 /***********************************************************************
455 * Stack layout on entry to this function:
460 * (esp) return addr to relay code
462 static LONGLONG
RELAY_CallFrom32( int ret_addr
, ... )
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);
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
);
488 ret
= call_stdcall_function( (LONGLONG_FARPROC
)relay
->orig
, nb_args
, args
);
493 BOOL ret64
= (relay
->argtypes
& 0x80000000) && (nb_args
< 16);
495 DPRINTF( "%04lx:Ret %s() retval=%08x%08x ret=%08x\n",
496 GetCurrentThreadId(),
497 buffer
, (UINT
)(ret
>> 32), (UINT
)ret
, ret_addr
);
499 DPRINTF( "%04lx:Ret %s() retval=%08x ret=%08x\n",
500 GetCurrentThreadId(),
501 buffer
, (UINT
)ret
, ret_addr
);
507 /***********************************************************************
508 * RELAY_CallFrom32Regs
510 * Stack layout (esp is context->Esp, not the current %esp):
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
)
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 */ );
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
);
566 call_stdcall_function( *(LONGLONG_FARPROC
*)(entry_point
+ 5), nb_args
+1, args_copy
);
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();
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 */
629 /***********************************************************************
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
;
641 char *p
, dllname
[80];
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
++)
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
);
665 debug
->call
= 0xe8; /* call relative */
666 if (is_register_entry_point( debug
->orig
))
667 debug
->callfrom32
= (char *)RELAY_CallFrom32Regs
- (char *)&debug
->ret
;
669 debug
->callfrom32
= (char *)RELAY_CallFrom32
- (char *)&debug
->ret
;
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
;
684 FARPROC
RELAY_GetProcAddress( HMODULE module
, IMAGE_EXPORT_DIRECTORY
*exports
,
685 DWORD exp_size
, FARPROC proc
, const char *user
)
690 void RELAY_SetupDLL( const char *module
)
694 #endif /* __i386__ */