2 * Win32 relay and snoop functions
4 * Copyright 1997 Alexandre Julliard
5 * Copyright 1998 Marcus Meissner
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "wine/port.h"
35 #include "wine/exception.h"
36 #include "ntdll_misc.h"
37 #include "wine/unicode.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(relay
);
41 WINE_DECLARE_DEBUG_CHANNEL(snoop
);
42 WINE_DECLARE_DEBUG_CHANNEL(seh
);
44 const char **debug_relay_excludelist
= NULL
;
45 const char **debug_relay_includelist
= NULL
;
46 const char **debug_snoop_excludelist
= NULL
;
47 const char **debug_snoop_includelist
= NULL
;
49 static const char **debug_from_relay_excludelist
;
50 static const char **debug_from_relay_includelist
;
52 /***********************************************************************
55 * Build a function list from a ';'-separated string.
57 static const char **build_list( const WCHAR
*bufferW
)
61 const char *p
= buffer
;
64 RtlUnicodeToMultiByteN( buffer
, sizeof(buffer
), NULL
,
65 bufferW
, (strlenW(bufferW
)+1) * sizeof(WCHAR
) );
67 while ((p
= strchr( p
, ';' )))
72 /* allocate count+1 pointers, plus the space for a copy of the string */
73 if ((ret
= RtlAllocateHeap( ntdll_get_process_heap(), 0, (count
+1) * sizeof(char*) + strlen(buffer
) + 1 )))
75 char *str
= (char *)(ret
+ count
+ 1);
78 strcpy( str
, buffer
);
83 if (!(p
= strchr( p
, ';' ))) break;
92 /***********************************************************************
93 * RELAY_InitDebugLists
95 * Build the relay include/exclude function lists.
97 void RELAY_InitDebugLists(void)
99 OBJECT_ATTRIBUTES attr
;
105 static const WCHAR configW
[] = {'M','a','c','h','i','n','e','\\',
106 'S','o','f','t','w','a','r','e','\\',
107 'W','i','n','e','\\',
108 'W','i','n','e','\\',
109 'C','o','n','f','i','g','\\',
110 'D','e','b','u','g',0};
111 static const WCHAR RelayIncludeW
[] = {'R','e','l','a','y','I','n','c','l','u','d','e',0};
112 static const WCHAR RelayExcludeW
[] = {'R','e','l','a','y','E','x','c','l','u','d','e',0};
113 static const WCHAR SnoopIncludeW
[] = {'S','n','o','o','p','I','n','c','l','u','d','e',0};
114 static const WCHAR SnoopExcludeW
[] = {'S','n','o','o','p','E','x','c','l','u','d','e',0};
115 static const WCHAR RelayFromIncludeW
[] = {'R','e','l','a','y','F','r','o','m','I','n','c','l','u','d','e',0};
116 static const WCHAR RelayFromExcludeW
[] = {'R','e','l','a','y','F','r','o','m','E','x','c','l','u','d','e',0};
118 attr
.Length
= sizeof(attr
);
119 attr
.RootDirectory
= 0;
120 attr
.ObjectName
= &name
;
122 attr
.SecurityDescriptor
= NULL
;
123 attr
.SecurityQualityOfService
= NULL
;
124 RtlInitUnicodeString( &name
, configW
);
126 if (NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
)) return;
128 str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)buffer
)->Data
;
129 RtlInitUnicodeString( &name
, RelayIncludeW
);
130 if (!NtQueryValueKey( hkey
, &name
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
132 TRACE("RelayInclude = %s\n", debugstr_w(str
) );
133 debug_relay_includelist
= build_list( str
);
136 RtlInitUnicodeString( &name
, RelayExcludeW
);
137 if (!NtQueryValueKey( hkey
, &name
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
139 TRACE( "RelayExclude = %s\n", debugstr_w(str
) );
140 debug_relay_excludelist
= build_list( str
);
143 RtlInitUnicodeString( &name
, SnoopIncludeW
);
144 if (!NtQueryValueKey( hkey
, &name
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
146 TRACE_(snoop
)( "SnoopInclude = %s\n", debugstr_w(str
) );
147 debug_snoop_includelist
= build_list( str
);
150 RtlInitUnicodeString( &name
, SnoopExcludeW
);
151 if (!NtQueryValueKey( hkey
, &name
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
153 TRACE_(snoop
)( "SnoopExclude = %s\n", debugstr_w(str
) );
154 debug_snoop_excludelist
= build_list( str
);
157 RtlInitUnicodeString( &name
, RelayFromIncludeW
);
158 if (!NtQueryValueKey( hkey
, &name
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
160 TRACE("RelayFromInclude = %s\n", debugstr_w(str
) );
161 debug_from_relay_includelist
= build_list( str
);
164 RtlInitUnicodeString( &name
, RelayFromExcludeW
);
165 if (!NtQueryValueKey( hkey
, &name
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
167 TRACE( "RelayFromExclude = %s\n", debugstr_w(str
) );
168 debug_from_relay_excludelist
= build_list( str
);
177 #include "pshpack1.h"
181 BYTE call
; /* 0xe8 call callfrom32 (relative) */
182 DWORD callfrom32
; /* RELAY_CallFrom32 relative addr */
183 BYTE ret
; /* 0xc2 ret $n or 0xc3 ret */
184 WORD args
; /* nb of args to remove from the stack */
185 void *orig
; /* original entry point */
186 DWORD argtypes
; /* argument types */
192 BYTE lcall
; /* 0xe8 call snoopentry (relative) */
193 /* NOTE: If you move snoopentry OR nrofargs fix the relative offset
196 DWORD snoopentry
; /* SNOOP_Entry relative */
203 typedef struct tagSNOOP_DLL
{
208 struct tagSNOOP_DLL
*next
;
215 BYTE lcall
; /* 0xe8 call snoopret relative*/
216 /* NOTE: If you move snoopret OR origreturn fix the relative offset
219 DWORD snoopret
; /* SNOOP_Ret relative */
225 DWORD
*args
; /* saved args across a stdcall */
228 typedef struct tagSNOOP_RETURNENTRIES
{
229 SNOOP_RETURNENTRY entry
[4092/sizeof(SNOOP_RETURNENTRY
)];
230 struct tagSNOOP_RETURNENTRIES
*next
;
231 } SNOOP_RETURNENTRIES
;
235 extern void WINAPI
SNOOP_Entry();
236 extern void WINAPI
SNOOP_Return();
238 static SNOOP_DLL
*firstdll
;
239 static SNOOP_RETURNENTRIES
*firstrets
;
241 static WINE_EXCEPTION_FILTER(page_fault
)
243 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION
||
244 GetExceptionCode() == EXCEPTION_PRIV_INSTRUCTION
)
245 return EXCEPTION_EXECUTE_HANDLER
;
246 return EXCEPTION_CONTINUE_SEARCH
;
249 /***********************************************************************
250 * check_relay_include
252 * Check if a given function must be included in the relay output.
254 static BOOL
check_relay_include( const char *module
, const char *func
)
256 const char **listitem
;
259 if (!debug_relay_excludelist
&& !debug_relay_includelist
) return TRUE
;
260 if (debug_relay_excludelist
)
263 listitem
= debug_relay_excludelist
;
268 listitem
= debug_relay_includelist
;
270 for(; *listitem
; listitem
++)
272 char *p
= strrchr( *listitem
, '.' );
273 if (p
&& p
> *listitem
) /* check module and function */
275 int len
= p
- *listitem
;
276 if (strncasecmp( *listitem
, module
, len
-1 ) || module
[len
]) continue;
277 if (!strcmp( p
+ 1, func
) || !strcmp( p
+ 1, "*" )) return !show
;
279 else /* function only */
281 if (!strcmp( *listitem
, func
)) return !show
;
288 /***********************************************************************
289 * check_relay_from_module
291 * Check if calls from a given module must be included in the relay output.
293 static BOOL
check_relay_from_module( const char *module
)
295 const char **listitem
;
298 if (!debug_from_relay_excludelist
&& !debug_from_relay_includelist
) return TRUE
;
299 if (debug_from_relay_excludelist
)
302 listitem
= debug_from_relay_excludelist
;
307 listitem
= debug_from_relay_includelist
;
309 for(; *listitem
; listitem
++)
313 if (!strcasecmp( *listitem
, module
)) return !show
;
314 len
= strlen( *listitem
);
315 if (!strncasecmp( *listitem
, module
, len
) && !strcasecmp( module
+ len
, ".dll" ))
322 /***********************************************************************
325 * Find the name of an exported function.
327 static const char *find_exported_name( HMODULE module
,
328 IMAGE_EXPORT_DIRECTORY
*exp
, int ordinal
)
331 const char *ret
= NULL
;
333 WORD
*ordptr
= (WORD
*)((char *)module
+ exp
->AddressOfNameOrdinals
);
334 for (i
= 0; i
< exp
->NumberOfNames
; i
++, ordptr
++)
335 if (*ordptr
+ exp
->Base
== ordinal
) break;
336 if (i
< exp
->NumberOfNames
)
337 ret
= (char *)module
+ ((DWORD
*)((char *)module
+ exp
->AddressOfNames
))[i
];
342 /***********************************************************************
345 * Get the name of the DLL entry point corresponding to a relay address.
347 static void get_entry_point( char *buffer
, DEBUG_ENTRY_POINT
*relay
)
349 IMAGE_EXPORT_DIRECTORY
*exp
= NULL
;
350 DEBUG_ENTRY_POINT
*debug
;
354 PLIST_ENTRY mark
, entry
;
355 PLDR_MODULE mod
= NULL
;
358 /* First find the module */
360 mark
= &NtCurrentTeb()->Peb
->LdrData
->InLoadOrderModuleList
;
361 for (entry
= mark
->Flink
; entry
!= mark
; entry
= entry
->Flink
)
363 mod
= CONTAINING_RECORD(entry
, LDR_MODULE
, InLoadOrderModuleList
);
364 if (!(mod
->Flags
& LDR_WINE_INTERNAL
)) continue;
365 exp
= RtlImageDirectoryEntryToData( mod
->BaseAddress
, TRUE
, IMAGE_DIRECTORY_ENTRY_EXPORT
, &size
);
367 debug
= (DEBUG_ENTRY_POINT
*)((char *)exp
+ size
);
368 if (debug
<= relay
&& relay
< debug
+ exp
->NumberOfFunctions
)
370 ordinal
= relay
- debug
;
375 /* Now find the function */
377 strcpy( buffer
, (char *)mod
->BaseAddress
+ exp
->Name
);
378 p
= buffer
+ strlen(buffer
);
379 if (p
> buffer
+ 4 && !strcasecmp( p
- 4, ".dll" )) p
-= 4;
381 if ((name
= find_exported_name( mod
->BaseAddress
, exp
, ordinal
+ exp
->Base
)))
382 sprintf( p
, ".%s", name
);
384 sprintf( p
, ".%ld", ordinal
+ exp
->Base
);
388 /***********************************************************************
391 static inline void RELAY_PrintArgs( int *args
, int nb_args
, unsigned int typemask
)
395 if ((typemask
& 3) && HIWORD(*args
))
398 DPRINTF( "%08x %s", *args
, debugstr_w((LPWSTR
)*args
) );
400 DPRINTF( "%08x %s", *args
, debugstr_a((LPCSTR
)*args
) );
402 else DPRINTF( "%08x", *args
);
403 if (nb_args
) DPRINTF( "," );
410 typedef LONGLONG (*LONGLONG_CPROC
)();
411 typedef LONGLONG (WINAPI
*LONGLONG_FARPROC
)();
414 /***********************************************************************
415 * call_cdecl_function
417 static LONGLONG
call_cdecl_function( LONGLONG_CPROC func
, int nb_args
, const int *args
)
422 case 0: ret
= func(); break;
423 case 1: ret
= func(args
[0]); break;
424 case 2: ret
= func(args
[0],args
[1]); break;
425 case 3: ret
= func(args
[0],args
[1],args
[2]); break;
426 case 4: ret
= func(args
[0],args
[1],args
[2],args
[3]); break;
427 case 5: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4]); break;
428 case 6: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],
430 case 7: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
432 case 8: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
433 args
[6],args
[7]); break;
434 case 9: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
435 args
[6],args
[7],args
[8]); break;
436 case 10: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
437 args
[6],args
[7],args
[8],args
[9]); break;
438 case 11: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
439 args
[6],args
[7],args
[8],args
[9],args
[10]); break;
440 case 12: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
441 args
[6],args
[7],args
[8],args
[9],args
[10],
443 case 13: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
444 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
446 case 14: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
447 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
448 args
[12],args
[13]); break;
449 case 15: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
450 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
451 args
[12],args
[13],args
[14]); break;
452 case 16: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
453 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
454 args
[12],args
[13],args
[14],args
[15]); break;
456 ERR( "Unsupported nb of args %d\n", nb_args
);
465 /***********************************************************************
466 * call_stdcall_function
468 static LONGLONG
call_stdcall_function( LONGLONG_FARPROC func
, int nb_args
, const int *args
)
473 case 0: ret
= func(); break;
474 case 1: ret
= func(args
[0]); break;
475 case 2: ret
= func(args
[0],args
[1]); break;
476 case 3: ret
= func(args
[0],args
[1],args
[2]); break;
477 case 4: ret
= func(args
[0],args
[1],args
[2],args
[3]); break;
478 case 5: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4]); break;
479 case 6: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],
481 case 7: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
483 case 8: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
484 args
[6],args
[7]); break;
485 case 9: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
486 args
[6],args
[7],args
[8]); break;
487 case 10: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
488 args
[6],args
[7],args
[8],args
[9]); break;
489 case 11: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
490 args
[6],args
[7],args
[8],args
[9],args
[10]); break;
491 case 12: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
492 args
[6],args
[7],args
[8],args
[9],args
[10],
494 case 13: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
495 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
497 case 14: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
498 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
499 args
[12],args
[13]); break;
500 case 15: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
501 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
502 args
[12],args
[13],args
[14]); break;
503 case 16: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
504 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
505 args
[12],args
[13],args
[14],args
[15]); break;
507 ERR( "Unsupported nb of args %d\n", nb_args
);
516 /***********************************************************************
519 * Stack layout on entry to this function:
524 * (esp) return addr to relay code
526 static LONGLONG
RELAY_CallFrom32( int ret_addr
, ... )
531 int *args
= &ret_addr
+ 1;
532 /* Relay addr is the return address for this function */
533 BYTE
*relay_addr
= (BYTE
*)__builtin_return_address(0);
534 DEBUG_ENTRY_POINT
*relay
= (DEBUG_ENTRY_POINT
*)(relay_addr
- 5);
535 WORD nb_args
= relay
->args
/ sizeof(int);
539 get_entry_point( buffer
, relay
);
541 DPRINTF( "%04lx:Call %s(", GetCurrentThreadId(), buffer
);
542 RELAY_PrintArgs( args
, nb_args
, relay
->argtypes
);
543 DPRINTF( ") ret=%08x\n", ret_addr
);
546 if (relay
->ret
== 0xc3) /* cdecl */
548 ret
= call_cdecl_function( (LONGLONG_CPROC
)relay
->orig
, nb_args
, args
);
552 ret
= call_stdcall_function( (LONGLONG_FARPROC
)relay
->orig
, nb_args
, args
);
557 BOOL ret64
= (relay
->argtypes
& 0x80000000) && (nb_args
< 16);
559 DPRINTF( "%04lx:Ret %s() retval=%08x%08x ret=%08x\n",
560 GetCurrentThreadId(),
561 buffer
, (UINT
)(ret
>> 32), (UINT
)ret
, ret_addr
);
563 DPRINTF( "%04lx:Ret %s() retval=%08x ret=%08x\n",
564 GetCurrentThreadId(),
565 buffer
, (UINT
)ret
, ret_addr
);
571 /***********************************************************************
572 * RELAY_CallFrom32Regs
574 * Stack layout (esp is context->Esp, not the current %esp):
578 * (esp) return addr to caller
579 * (esp-4) return addr to DEBUG_ENTRY_POINT
580 * (esp-8) ptr to relay entry code for RELAY_CallFrom32Regs
581 * ... >128 bytes space free to be modified (ensured by the assembly glue)
583 void WINAPI
RELAY_DoCallFrom32Regs( CONTEXT86
*context
)
590 BYTE
*relay_addr
= *((BYTE
**)context
->Esp
- 1);
591 DEBUG_ENTRY_POINT
*relay
= (DEBUG_ENTRY_POINT
*)(relay_addr
- 5);
592 WORD nb_args
= relay
->args
/ sizeof(int);
594 /* remove extra stuff from the stack */
595 context
->Eip
= *(DWORD
*)context
->Esp
;
596 context
->Esp
+= sizeof(DWORD
);
597 args
= (int *)context
->Esp
;
598 if (relay
->ret
== 0xc2) /* stdcall */
599 context
->Esp
+= nb_args
* sizeof(int);
601 entry_point
= (BYTE
*)relay
->orig
;
602 assert( *entry_point
== 0xe8 /* lcall */ );
606 get_entry_point( buffer
, relay
);
608 DPRINTF( "%04lx:Call %s(", GetCurrentThreadId(), buffer
);
609 RELAY_PrintArgs( args
, nb_args
, relay
->argtypes
);
610 DPRINTF( ") ret=%08lx fs=%04lx\n", context
->Eip
, context
->SegFs
);
612 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
613 context
->Eax
, context
->Ebx
, context
->Ecx
,
614 context
->Edx
, context
->Esi
, context
->Edi
);
615 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
616 context
->Ebp
, context
->Esp
, context
->SegDs
,
617 context
->SegEs
, context
->SegGs
, context
->EFlags
);
620 /* Now call the real function */
622 memcpy( args_copy
, args
, nb_args
* sizeof(args
[0]) );
623 args_copy
[nb_args
] = (int)context
; /* append context argument */
624 if (relay
->ret
== 0xc3) /* cdecl */
626 call_cdecl_function( *(LONGLONG_CPROC
*)(entry_point
+ 5), nb_args
+1, args_copy
);
630 call_stdcall_function( *(LONGLONG_FARPROC
*)(entry_point
+ 5), nb_args
+1, args_copy
);
635 DPRINTF( "%04lx:Ret %s() retval=%08lx ret=%08lx fs=%04lx\n",
636 GetCurrentThreadId(),
637 buffer
, context
->Eax
, context
->Eip
, context
->SegFs
);
639 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
640 context
->Eax
, context
->Ebx
, context
->Ecx
,
641 context
->Edx
, context
->Esi
, context
->Edi
);
642 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
643 context
->Ebp
, context
->Esp
, context
->SegDs
,
644 context
->SegEs
, context
->SegGs
, context
->EFlags
);
648 void WINAPI
RELAY_CallFrom32Regs(void);
649 __ASM_GLOBAL_FUNC( RELAY_CallFrom32Regs
,
650 "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
651 ".long " __ASM_NAME("RELAY_DoCallFrom32Regs") ",0" );
654 /* check whether the function at addr starts with a call to __wine_call_from_32_regs */
655 static BOOL
is_register_entry_point( const BYTE
*addr
)
657 extern void __wine_call_from_32_regs();
661 if (*addr
!= 0xe8) return FALSE
; /* not a call */
662 /* check if call target is __wine_call_from_32_regs */
663 offset
= (int *)(addr
+ 1);
664 if (*offset
== (char *)__wine_call_from_32_regs
- (char *)(offset
+ 1)) return TRUE
;
665 /* now check if call target is an import table jump to __wine_call_from_32_regs */
666 addr
= (BYTE
*)(offset
+ 1) + *offset
;
667 if (addr
[0] != 0xff || addr
[1] != 0x25) return FALSE
; /* not an indirect jmp */
668 ptr
= *(void **)(addr
+ 2); /* get indirect jmp target address */
669 return (*(char **)ptr
== (char *)__wine_call_from_32_regs
);
673 /***********************************************************************
674 * RELAY_GetProcAddress
676 * Return the proc address to use for a given function.
678 FARPROC
RELAY_GetProcAddress( HMODULE module
, IMAGE_EXPORT_DIRECTORY
*exports
,
679 DWORD exp_size
, FARPROC proc
, const char *user
)
681 DEBUG_ENTRY_POINT
*debug
= (DEBUG_ENTRY_POINT
*)proc
;
682 DEBUG_ENTRY_POINT
*list
= (DEBUG_ENTRY_POINT
*)((char *)exports
+ exp_size
);
684 if (debug
< list
|| debug
>= list
+ exports
->NumberOfFunctions
) return proc
;
685 if (list
+ (debug
- list
) != debug
) return proc
; /* not a valid address */
686 if (check_relay_from_module( user
)) return proc
; /* we want to relay it */
687 if (!debug
->call
) return proc
; /* not a normal function */
688 if (debug
->call
!= 0xe8 && debug
->call
!= 0xe9) return proc
; /* not a debug thunk at all */
693 /***********************************************************************
696 * Setup relay debugging for a built-in dll.
698 void RELAY_SetupDLL( HMODULE module
)
700 IMAGE_EXPORT_DIRECTORY
*exports
;
701 DEBUG_ENTRY_POINT
*debug
;
705 char *p
, dllname
[80];
708 exports
= RtlImageDirectoryEntryToData( module
, TRUE
, IMAGE_DIRECTORY_ENTRY_EXPORT
, &size
);
709 if (!exports
) return;
710 debug
= (DEBUG_ENTRY_POINT
*)((char *)exports
+ size
);
711 funcs
= (DWORD
*)((char *)module
+ exports
->AddressOfFunctions
);
712 strcpy( dllname
, (char *)module
+ exports
->Name
);
713 p
= dllname
+ strlen(dllname
) - 4;
714 if (p
> dllname
&& !strcasecmp( p
, ".dll" )) *p
= 0;
716 for (i
= 0; i
< exports
->NumberOfFunctions
; i
++, funcs
++, debug
++)
720 if (!debug
->call
) continue; /* not a normal function */
721 if (debug
->call
!= 0xe8 && debug
->call
!= 0xe9) break; /* not a debug thunk at all */
723 if ((name
= find_exported_name( module
, exports
, i
+ exports
->Base
)))
724 on
= check_relay_include( dllname
, name
);
728 debug
->call
= 0xe8; /* call relative */
729 if (is_register_entry_point( debug
->orig
))
730 debug
->callfrom32
= (char *)RELAY_CallFrom32Regs
- (char *)&debug
->ret
;
732 debug
->callfrom32
= (char *)RELAY_CallFrom32
- (char *)&debug
->ret
;
736 debug
->call
= 0xe9; /* jmp relative */
737 debug
->callfrom32
= (char *)debug
->orig
- (char *)&debug
->ret
;
740 debug
->orig
= (FARPROC
)((char *)module
+ (DWORD
)*funcs
);
741 *funcs
= (char *)debug
- (char *)module
;
746 /***********************************************************************
747 * SNOOP_ShowDebugmsgSnoop
749 * Simple function to decide if a particular debugging message is
752 int SNOOP_ShowDebugmsgSnoop(const char *dll
, int ord
, const char *fname
) {
754 if(debug_snoop_excludelist
|| debug_snoop_includelist
) {
755 const char **listitem
;
757 int len
, len2
, itemlen
, show
;
759 if(debug_snoop_excludelist
) {
761 listitem
= debug_snoop_excludelist
;
764 listitem
= debug_snoop_includelist
;
768 sprintf(buf
, "%s.%d", dll
, ord
);
770 for(; *listitem
; listitem
++) {
771 itemlen
= strlen(*listitem
);
772 if((itemlen
== len
&& !strncasecmp(*listitem
, buf
, len
)) ||
773 (itemlen
== len2
&& !strncasecmp(*listitem
, buf
, len2
)) ||
774 !strcasecmp(*listitem
, fname
)) {
785 /***********************************************************************
788 * Setup snoop debugging for a native dll.
790 void SNOOP_SetupDLL(HMODULE hmod
)
792 SNOOP_DLL
**dll
= &firstdll
;
796 IMAGE_EXPORT_DIRECTORY
*exports
;
798 exports
= RtlImageDirectoryEntryToData( hmod
, TRUE
, IMAGE_DIRECTORY_ENTRY_EXPORT
, &size
);
799 if (!exports
) return;
800 name
= (char *)hmod
+ exports
->Name
;
802 TRACE("hmod=%p, name=%s\n", hmod
, name
);
805 if ((*dll
)->hmod
== hmod
)
807 /* another dll, loaded at the same address */
809 size
= (*dll
)->nrofordinals
* sizeof(SNOOP_FUN
);
810 NtFreeVirtualMemory(GetCurrentProcess(), &addr
, &size
, MEM_RELEASE
);
813 dll
= &((*dll
)->next
);
815 *dll
= RtlReAllocateHeap(ntdll_get_process_heap(),
816 HEAP_ZERO_MEMORY
, *dll
,
817 sizeof(SNOOP_DLL
) + strlen(name
));
819 (*dll
)->ordbase
= exports
->Base
;
820 (*dll
)->nrofordinals
= exports
->NumberOfFunctions
;
821 strcpy( (*dll
)->name
, name
);
822 p
= (*dll
)->name
+ strlen((*dll
)->name
) - 4;
823 if (p
> (*dll
)->name
&& !strcasecmp( p
, ".dll" )) *p
= 0;
825 size
= exports
->NumberOfFunctions
* sizeof(SNOOP_FUN
);
826 NtAllocateVirtualMemory(GetCurrentProcess(), &addr
, NULL
, &size
,
827 MEM_COMMIT
| MEM_RESERVE
, PAGE_EXECUTE_READWRITE
);
829 RtlFreeHeap(ntdll_get_process_heap(),0,*dll
);
830 FIXME("out of memory\n");
834 memset((*dll
)->funs
,0,size
);
838 /***********************************************************************
839 * SNOOP_GetProcAddress
841 * Return the proc address to use for a given function.
843 FARPROC
SNOOP_GetProcAddress( HMODULE hmod
, IMAGE_EXPORT_DIRECTORY
*exports
,
844 DWORD exp_size
, FARPROC origfun
, DWORD ordinal
)
850 SNOOP_DLL
*dll
= firstdll
;
852 IMAGE_SECTION_HEADER
*sec
;
854 if (!TRACE_ON(snoop
)) return origfun
;
855 if (!*(LPBYTE
)origfun
) /* 0x00 is an imposs. opcode, poss. dataref. */
858 sec
= RtlImageRvaToSection( RtlImageNtHeader(hmod
), hmod
, (char *)origfun
- (char *)hmod
);
860 if (!sec
|| !(sec
->Characteristics
& IMAGE_SCN_CNT_CODE
))
861 return origfun
; /* most likely a data reference */
864 if (hmod
== dll
->hmod
)
868 if (!dll
) /* probably internal */
871 /* try to find a name for it */
873 names
= (DWORD
*)((char *)hmod
+ exports
->AddressOfNames
);
874 ordinals
= (WORD
*)((char *)hmod
+ exports
->AddressOfNameOrdinals
);
875 if (names
) for (i
= 0; i
< exports
->NumberOfNames
; i
++)
877 if (ordinals
[i
] == ordinal
)
879 ename
= (char *)hmod
+ names
[i
];
883 if (!SNOOP_ShowDebugmsgSnoop(dll
->name
,ordinal
,ename
))
885 assert(ordinal
< dll
->nrofordinals
);
886 fun
= dll
->funs
+ordinal
;
891 /* NOTE: origreturn struct member MUST come directly after snoopentry */
892 fun
->snoopentry
= (char*)SNOOP_Entry
-((char*)(&fun
->nrofargs
));
893 fun
->origfun
= origfun
;
896 return (FARPROC
)&(fun
->lcall
);
899 static void SNOOP_PrintArg(DWORD x
)
904 if (!HIWORD(x
) || TRACE_ON(seh
)) return; /* trivial reject to avoid faults */
911 if (s
[i
]<0x20) {nostring
=1;break;}
912 if (s
[i
]>=0x80) {nostring
=1;break;}
915 if (!nostring
&& i
> 5)
916 DPRINTF(" %s",debugstr_an((LPSTR
)x
,i
));
917 else /* try unicode */
923 if (s
[i
]<0x20) {nostring
=1;break;}
924 if (s
[i
]>0x100) {nostring
=1;break;}
927 if (!nostring
&& i
> 5) DPRINTF(" %s",debugstr_wn((LPWSTR
)x
,i
));
936 #define CALLER1REF (*(DWORD*)context->Esp)
938 void WINAPI
SNOOP_DoEntry( CONTEXT86
*context
)
940 DWORD ordinal
=0,entry
= context
->Eip
- 5;
941 SNOOP_DLL
*dll
= firstdll
;
942 SNOOP_FUN
*fun
= NULL
;
943 SNOOP_RETURNENTRIES
**rets
= &firstrets
;
944 SNOOP_RETURNENTRY
*ret
;
948 if ( ((char*)entry
>=(char*)dll
->funs
) &&
949 ((char*)entry
<=(char*)(dll
->funs
+dll
->nrofordinals
))
951 fun
= (SNOOP_FUN
*)entry
;
952 ordinal
= fun
-dll
->funs
;
958 FIXME("entrypoint 0x%08lx not found\n",entry
);
961 /* guess cdecl ... */
962 if (fun
->nrofargs
<0) {
963 /* Typical cdecl return frame is:
965 * which has (for xxxxxxxx up to 255 the opcode "83 C4 xx".
966 * (after that 81 C2 xx xx xx xx)
968 LPBYTE reteip
= (LPBYTE
)CALLER1REF
;
971 if ((reteip
[0]==0x83)&&(reteip
[1]==0xc4))
972 fun
->nrofargs
=reteip
[2]/4;
978 for (i
=0;i
<sizeof((*rets
)->entry
)/sizeof((*rets
)->entry
[0]);i
++)
979 if (!(*rets
)->entry
[i
].origreturn
)
981 if (i
!=sizeof((*rets
)->entry
)/sizeof((*rets
)->entry
[0]))
983 rets
= &((*rets
)->next
);
989 NtAllocateVirtualMemory(GetCurrentProcess(), &addr
, NULL
, &size
,
990 MEM_COMMIT
| MEM_RESERVE
,
991 PAGE_EXECUTE_READWRITE
);
994 memset(*rets
,0,4096);
995 i
= 0; /* entry 0 is free */
997 ret
= &((*rets
)->entry
[i
]);
999 /* NOTE: origreturn struct member MUST come directly after snoopret */
1000 ret
->snoopret
= ((char*)SNOOP_Return
)-(char*)(&ret
->origreturn
);
1001 ret
->origreturn
= (FARPROC
)CALLER1REF
;
1002 CALLER1REF
= (DWORD
)&ret
->lcall
;
1005 ret
->ordinal
= ordinal
;
1006 ret
->origESP
= context
->Esp
;
1008 context
->Eip
= (DWORD
)fun
->origfun
;
1010 if (fun
->name
) DPRINTF("%04lx:CALL %s.%s(",GetCurrentThreadId(),dll
->name
,fun
->name
);
1011 else DPRINTF("%04lx:CALL %s.%ld(",GetCurrentThreadId(),dll
->name
,dll
->ordbase
+ordinal
);
1012 if (fun
->nrofargs
>0) {
1013 max
= fun
->nrofargs
; if (max
>16) max
=16;
1016 SNOOP_PrintArg(*(DWORD
*)(context
->Esp
+ 4 + sizeof(DWORD
)*i
));
1017 if (i
<fun
->nrofargs
-1) DPRINTF(",");
1019 if (max
!=fun
->nrofargs
)
1021 } else if (fun
->nrofargs
<0) {
1022 DPRINTF("<unknown, check return>");
1023 ret
->args
= RtlAllocateHeap(ntdll_get_process_heap(),
1024 0,16*sizeof(DWORD
));
1025 memcpy(ret
->args
,(LPBYTE
)(context
->Esp
+ 4),sizeof(DWORD
)*16);
1027 DPRINTF(") ret=%08lx\n",(DWORD
)ret
->origreturn
);
1031 void WINAPI
SNOOP_DoReturn( CONTEXT86
*context
)
1033 SNOOP_RETURNENTRY
*ret
= (SNOOP_RETURNENTRY
*)(context
->Eip
- 5);
1034 SNOOP_FUN
*fun
= &ret
->dll
->funs
[ret
->ordinal
];
1036 /* We haven't found out the nrofargs yet. If we called a cdecl
1037 * function it is too late anyway and we can just set '0' (which
1038 * will be the difference between orig and current ESP
1039 * If stdcall -> everything ok.
1041 if (ret
->dll
->funs
[ret
->ordinal
].nrofargs
<0)
1042 ret
->dll
->funs
[ret
->ordinal
].nrofargs
=(context
->Esp
- ret
->origESP
-4)/4;
1043 context
->Eip
= (DWORD
)ret
->origreturn
;
1048 DPRINTF("%04lx:RET %s.%s(", GetCurrentThreadId(), ret
->dll
->name
, fun
->name
);
1050 DPRINTF("%04lx:RET %s.%ld(", GetCurrentThreadId(),
1051 ret
->dll
->name
,ret
->dll
->ordbase
+ret
->ordinal
);
1053 max
= fun
->nrofargs
;
1058 SNOOP_PrintArg(ret
->args
[i
]);
1059 if (i
<max
-1) DPRINTF(",");
1061 DPRINTF(") retval=%08lx ret=%08lx\n",
1062 context
->Eax
,(DWORD
)ret
->origreturn
);
1063 RtlFreeHeap(ntdll_get_process_heap(),0,ret
->args
);
1069 DPRINTF("%04lx:RET %s.%s() retval=%08lx ret=%08lx\n",
1070 GetCurrentThreadId(),
1071 ret
->dll
->name
, fun
->name
, context
->Eax
, (DWORD
)ret
->origreturn
);
1073 DPRINTF("%04lx:RET %s.%ld() retval=%08lx ret=%08lx\n",
1074 GetCurrentThreadId(),
1075 ret
->dll
->name
,ret
->dll
->ordbase
+ret
->ordinal
,
1076 context
->Eax
, (DWORD
)ret
->origreturn
);
1078 ret
->origreturn
= NULL
; /* mark as empty */
1081 /* assembly wrappers that save the context */
1082 __ASM_GLOBAL_FUNC( SNOOP_Entry
,
1083 "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
1084 ".long " __ASM_NAME("SNOOP_DoEntry") ",0" );
1085 __ASM_GLOBAL_FUNC( SNOOP_Return
,
1086 "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
1087 ".long " __ASM_NAME("SNOOP_DoReturn") ",0" );
1089 #else /* __i386__ */
1091 FARPROC
RELAY_GetProcAddress( HMODULE module
, IMAGE_EXPORT_DIRECTORY
*exports
,
1092 DWORD exp_size
, FARPROC proc
, const char *user
)
1097 FARPROC
SNOOP_GetProcAddress( HMODULE hmod
, IMAGE_EXPORT_DIRECTORY
*exports
,
1098 DWORD exp_size
, FARPROC origfun
, DWORD ordinal
)
1103 void RELAY_SetupDLL( HMODULE module
)
1107 void SNOOP_SetupDLL( HMODULE hmod
)
1109 FIXME("snooping works only on i386 for now.\n");
1112 #endif /* __i386__ */