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 static const WCHAR
**debug_relay_excludelist
;
45 static const WCHAR
**debug_relay_includelist
;
46 static const WCHAR
**debug_snoop_excludelist
;
47 static const WCHAR
**debug_snoop_includelist
;
48 static const WCHAR
**debug_from_relay_excludelist
;
49 static const WCHAR
**debug_from_relay_includelist
;
50 static const WCHAR
**debug_from_snoop_excludelist
;
51 static const WCHAR
**debug_from_snoop_includelist
;
53 /* compare an ASCII and a Unicode string without depending on the current codepage */
54 inline static int strcmpAW( const char *strA
, const WCHAR
*strW
)
56 while (*strA
&& ((unsigned char)*strA
== *strW
)) { strA
++; strW
++; }
57 return (unsigned char)*strA
- *strW
;
60 /* compare an ASCII and a Unicode string without depending on the current codepage */
61 inline static int strncmpiAW( const char *strA
, const WCHAR
*strW
, int n
)
64 for ( ; n
> 0; n
--, strA
++, strW
++)
65 if ((ret
= toupperW((unsigned char)*strA
) - toupperW(*strW
)) || !*strA
) break;
69 /***********************************************************************
72 * Build a function list from a ';'-separated string.
74 static const WCHAR
**build_list( const WCHAR
*buffer
)
77 const WCHAR
*p
= buffer
;
80 while ((p
= strchrW( p
, ';' )))
85 /* allocate count+1 pointers, plus the space for a copy of the string */
86 if ((ret
= RtlAllocateHeap( GetProcessHeap(), 0,
87 (count
+1) * sizeof(WCHAR
*) + (strlenW(buffer
)+1) * sizeof(WCHAR
) )))
89 WCHAR
*str
= (WCHAR
*)(ret
+ count
+ 1);
92 strcpyW( str
, buffer
);
97 if (!(p
= strchrW( p
, ';' ))) break;
106 /***********************************************************************
107 * RELAY_InitDebugLists
109 * Build the relay include/exclude function lists.
111 void RELAY_InitDebugLists(void)
113 OBJECT_ATTRIBUTES attr
;
119 static const WCHAR configW
[] = {'M','a','c','h','i','n','e','\\',
120 'S','o','f','t','w','a','r','e','\\',
121 'W','i','n','e','\\',
122 'W','i','n','e','\\',
123 'C','o','n','f','i','g','\\',
124 'D','e','b','u','g',0};
125 static const WCHAR RelayIncludeW
[] = {'R','e','l','a','y','I','n','c','l','u','d','e',0};
126 static const WCHAR RelayExcludeW
[] = {'R','e','l','a','y','E','x','c','l','u','d','e',0};
127 static const WCHAR SnoopIncludeW
[] = {'S','n','o','o','p','I','n','c','l','u','d','e',0};
128 static const WCHAR SnoopExcludeW
[] = {'S','n','o','o','p','E','x','c','l','u','d','e',0};
129 static const WCHAR RelayFromIncludeW
[] = {'R','e','l','a','y','F','r','o','m','I','n','c','l','u','d','e',0};
130 static const WCHAR RelayFromExcludeW
[] = {'R','e','l','a','y','F','r','o','m','E','x','c','l','u','d','e',0};
131 static const WCHAR SnoopFromIncludeW
[] = {'S','n','o','o','p','F','r','o','m','I','n','c','l','u','d','e',0};
132 static const WCHAR SnoopFromExcludeW
[] = {'S','n','o','o','p','F','r','o','m','E','x','c','l','u','d','e',0};
134 attr
.Length
= sizeof(attr
);
135 attr
.RootDirectory
= 0;
136 attr
.ObjectName
= &name
;
138 attr
.SecurityDescriptor
= NULL
;
139 attr
.SecurityQualityOfService
= NULL
;
140 RtlInitUnicodeString( &name
, configW
);
142 if (NtOpenKey( &hkey
, KEY_ALL_ACCESS
, &attr
)) return;
144 str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)buffer
)->Data
;
145 RtlInitUnicodeString( &name
, RelayIncludeW
);
146 if (!NtQueryValueKey( hkey
, &name
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
148 TRACE("RelayInclude = %s\n", debugstr_w(str
) );
149 debug_relay_includelist
= build_list( str
);
152 RtlInitUnicodeString( &name
, RelayExcludeW
);
153 if (!NtQueryValueKey( hkey
, &name
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
155 TRACE( "RelayExclude = %s\n", debugstr_w(str
) );
156 debug_relay_excludelist
= build_list( str
);
159 RtlInitUnicodeString( &name
, SnoopIncludeW
);
160 if (!NtQueryValueKey( hkey
, &name
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
162 TRACE_(snoop
)( "SnoopInclude = %s\n", debugstr_w(str
) );
163 debug_snoop_includelist
= build_list( str
);
166 RtlInitUnicodeString( &name
, SnoopExcludeW
);
167 if (!NtQueryValueKey( hkey
, &name
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
169 TRACE_(snoop
)( "SnoopExclude = %s\n", debugstr_w(str
) );
170 debug_snoop_excludelist
= build_list( str
);
173 RtlInitUnicodeString( &name
, RelayFromIncludeW
);
174 if (!NtQueryValueKey( hkey
, &name
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
176 TRACE("RelayFromInclude = %s\n", debugstr_w(str
) );
177 debug_from_relay_includelist
= build_list( str
);
180 RtlInitUnicodeString( &name
, RelayFromExcludeW
);
181 if (!NtQueryValueKey( hkey
, &name
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
183 TRACE( "RelayFromExclude = %s\n", debugstr_w(str
) );
184 debug_from_relay_excludelist
= build_list( str
);
187 RtlInitUnicodeString( &name
, SnoopFromIncludeW
);
188 if (!NtQueryValueKey( hkey
, &name
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
190 TRACE_(snoop
)("SnoopFromInclude = %s\n", debugstr_w(str
) );
191 debug_from_snoop_includelist
= build_list( str
);
194 RtlInitUnicodeString( &name
, SnoopFromExcludeW
);
195 if (!NtQueryValueKey( hkey
, &name
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
197 TRACE_(snoop
)( "SnoopFromExclude = %s\n", debugstr_w(str
) );
198 debug_from_snoop_excludelist
= build_list( str
);
207 #include "pshpack1.h"
211 BYTE call
; /* 0xe8 call callfrom32 (relative) */
212 DWORD callfrom32
; /* RELAY_CallFrom32 relative addr */
213 BYTE ret
; /* 0xc2 ret $n or 0xc3 ret */
214 WORD args
; /* nb of args to remove from the stack */
215 void *orig
; /* original entry point */
216 DWORD argtypes
; /* argument types */
222 BYTE lcall
; /* 0xe8 call snoopentry (relative) */
223 /* NOTE: If you move snoopentry OR nrofargs fix the relative offset
226 DWORD snoopentry
; /* SNOOP_Entry relative */
233 typedef struct tagSNOOP_DLL
{
238 struct tagSNOOP_DLL
*next
;
245 BYTE lcall
; /* 0xe8 call snoopret relative*/
246 /* NOTE: If you move snoopret OR origreturn fix the relative offset
249 DWORD snoopret
; /* SNOOP_Ret relative */
255 DWORD
*args
; /* saved args across a stdcall */
258 typedef struct tagSNOOP_RETURNENTRIES
{
259 SNOOP_RETURNENTRY entry
[4092/sizeof(SNOOP_RETURNENTRY
)];
260 struct tagSNOOP_RETURNENTRIES
*next
;
261 } SNOOP_RETURNENTRIES
;
265 extern void WINAPI
SNOOP_Entry();
266 extern void WINAPI
SNOOP_Return();
268 static SNOOP_DLL
*firstdll
;
269 static SNOOP_RETURNENTRIES
*firstrets
;
271 static WINE_EXCEPTION_FILTER(page_fault
)
273 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION
||
274 GetExceptionCode() == EXCEPTION_PRIV_INSTRUCTION
)
275 return EXCEPTION_EXECUTE_HANDLER
;
276 return EXCEPTION_CONTINUE_SEARCH
;
279 /***********************************************************************
282 * Check if a given module and function is in the list.
284 static BOOL
check_list( const char *module
, int ordinal
, const char *func
, const WCHAR
**list
)
288 sprintf( ord_str
, "%d", ordinal
);
291 const WCHAR
*p
= strrchrW( *list
, '.' );
292 if (p
&& p
> *list
) /* check module and function */
295 if (strncmpiAW( module
, *list
, len
-1 ) || module
[len
]) continue;
296 if (p
[1] == '*' && !p
[2]) return TRUE
;
297 if (!strcmpAW( ord_str
, p
+ 1 )) return TRUE
;
298 if (func
&& !strcmpAW( func
, p
+ 1 )) return TRUE
;
300 else /* function only */
302 if (func
&& !strcmpAW( func
, *list
)) return TRUE
;
309 /***********************************************************************
310 * check_relay_include
312 * Check if a given function must be included in the relay output.
314 static BOOL
check_relay_include( const char *module
, int ordinal
, const char *func
)
316 if (debug_relay_excludelist
&& check_list( module
, ordinal
, func
, debug_relay_excludelist
))
318 if (debug_relay_includelist
&& !check_list( module
, ordinal
, func
, debug_relay_includelist
))
323 /***********************************************************************
326 * Check if calls from a given module must be included in the relay/snoop output,
327 * given the exclusion and inclusion lists.
329 static BOOL
check_from_module( const WCHAR
**includelist
, const WCHAR
**excludelist
, const WCHAR
*module
)
331 static const WCHAR dllW
[] = {'.','d','l','l',0 };
332 const WCHAR
**listitem
;
335 if (!includelist
&& !excludelist
) return TRUE
;
339 listitem
= excludelist
;
344 listitem
= includelist
;
346 for(; *listitem
; listitem
++)
350 if (!strcmpiW( *listitem
, module
)) return !show
;
351 len
= strlenW( *listitem
);
352 if (!strncmpiW( *listitem
, module
, len
) && !strcmpiW( module
+ len
, dllW
))
358 /***********************************************************************
361 * Find the name of an exported function.
363 static const char *find_exported_name( HMODULE module
,
364 IMAGE_EXPORT_DIRECTORY
*exp
, int ordinal
)
367 const char *ret
= NULL
;
369 WORD
*ordptr
= (WORD
*)((char *)module
+ exp
->AddressOfNameOrdinals
);
370 for (i
= 0; i
< exp
->NumberOfNames
; i
++, ordptr
++)
371 if (*ordptr
+ exp
->Base
== ordinal
) break;
372 if (i
< exp
->NumberOfNames
)
373 ret
= (char *)module
+ ((DWORD
*)((char *)module
+ exp
->AddressOfNames
))[i
];
378 /***********************************************************************
381 * Get the name of the DLL entry point corresponding to a relay address.
383 static void get_entry_point( char *buffer
, DEBUG_ENTRY_POINT
*relay
)
385 IMAGE_EXPORT_DIRECTORY
*exp
= NULL
;
386 DEBUG_ENTRY_POINT
*debug
;
390 PLIST_ENTRY mark
, entry
;
391 PLDR_MODULE mod
= NULL
;
394 /* First find the module */
396 mark
= &NtCurrentTeb()->Peb
->LdrData
->InLoadOrderModuleList
;
397 for (entry
= mark
->Flink
; entry
!= mark
; entry
= entry
->Flink
)
399 mod
= CONTAINING_RECORD(entry
, LDR_MODULE
, InLoadOrderModuleList
);
400 if (!(mod
->Flags
& LDR_WINE_INTERNAL
)) continue;
401 exp
= RtlImageDirectoryEntryToData( mod
->BaseAddress
, TRUE
, IMAGE_DIRECTORY_ENTRY_EXPORT
, &size
);
403 debug
= (DEBUG_ENTRY_POINT
*)((char *)exp
+ size
);
404 if (debug
<= relay
&& relay
< debug
+ exp
->NumberOfFunctions
)
406 ordinal
= relay
- debug
;
411 /* Now find the function */
413 strcpy( buffer
, (char *)mod
->BaseAddress
+ exp
->Name
);
414 p
= buffer
+ strlen(buffer
);
415 if (p
> buffer
+ 4 && !strcasecmp( p
- 4, ".dll" )) p
-= 4;
417 if ((name
= find_exported_name( mod
->BaseAddress
, exp
, ordinal
+ exp
->Base
)))
418 sprintf( p
, ".%s", name
);
420 sprintf( p
, ".%ld", ordinal
+ exp
->Base
);
424 /***********************************************************************
427 static inline void RELAY_PrintArgs( int *args
, int nb_args
, unsigned int typemask
)
431 if ((typemask
& 3) && HIWORD(*args
))
434 DPRINTF( "%08x %s", *args
, debugstr_w((LPWSTR
)*args
) );
436 DPRINTF( "%08x %s", *args
, debugstr_a((LPCSTR
)*args
) );
438 else DPRINTF( "%08x", *args
);
439 if (nb_args
) DPRINTF( "," );
446 typedef LONGLONG (*LONGLONG_CPROC
)();
447 typedef LONGLONG (WINAPI
*LONGLONG_FARPROC
)();
450 /***********************************************************************
451 * call_cdecl_function
453 static LONGLONG
call_cdecl_function( LONGLONG_CPROC func
, int nb_args
, const int *args
)
458 case 0: ret
= func(); break;
459 case 1: ret
= func(args
[0]); break;
460 case 2: ret
= func(args
[0],args
[1]); break;
461 case 3: ret
= func(args
[0],args
[1],args
[2]); break;
462 case 4: ret
= func(args
[0],args
[1],args
[2],args
[3]); break;
463 case 5: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4]); break;
464 case 6: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],
466 case 7: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
468 case 8: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
469 args
[6],args
[7]); break;
470 case 9: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
471 args
[6],args
[7],args
[8]); break;
472 case 10: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
473 args
[6],args
[7],args
[8],args
[9]); break;
474 case 11: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
475 args
[6],args
[7],args
[8],args
[9],args
[10]); break;
476 case 12: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
477 args
[6],args
[7],args
[8],args
[9],args
[10],
479 case 13: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
480 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
482 case 14: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
483 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
484 args
[12],args
[13]); break;
485 case 15: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
486 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
487 args
[12],args
[13],args
[14]); break;
488 case 16: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
489 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
490 args
[12],args
[13],args
[14],args
[15]); break;
492 ERR( "Unsupported nb of args %d\n", nb_args
);
501 /***********************************************************************
502 * call_stdcall_function
504 static LONGLONG
call_stdcall_function( LONGLONG_FARPROC func
, int nb_args
, const int *args
)
509 case 0: ret
= func(); break;
510 case 1: ret
= func(args
[0]); break;
511 case 2: ret
= func(args
[0],args
[1]); break;
512 case 3: ret
= func(args
[0],args
[1],args
[2]); break;
513 case 4: ret
= func(args
[0],args
[1],args
[2],args
[3]); break;
514 case 5: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4]); break;
515 case 6: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],
517 case 7: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
519 case 8: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
520 args
[6],args
[7]); break;
521 case 9: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
522 args
[6],args
[7],args
[8]); break;
523 case 10: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
524 args
[6],args
[7],args
[8],args
[9]); break;
525 case 11: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
526 args
[6],args
[7],args
[8],args
[9],args
[10]); break;
527 case 12: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
528 args
[6],args
[7],args
[8],args
[9],args
[10],
530 case 13: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
531 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
533 case 14: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
534 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
535 args
[12],args
[13]); break;
536 case 15: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
537 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
538 args
[12],args
[13],args
[14]); break;
539 case 16: ret
= func(args
[0],args
[1],args
[2],args
[3],args
[4],args
[5],
540 args
[6],args
[7],args
[8],args
[9],args
[10],args
[11],
541 args
[12],args
[13],args
[14],args
[15]); break;
543 ERR( "Unsupported nb of args %d\n", nb_args
);
552 /***********************************************************************
555 * Stack layout on entry to this function:
560 * (esp) return addr to relay code
562 static LONGLONG
RELAY_CallFrom32( int ret_addr
, ... )
567 int *args
= &ret_addr
+ 1;
568 /* Relay addr is the return address for this function */
569 BYTE
*relay_addr
= (BYTE
*)__builtin_return_address(0);
570 DEBUG_ENTRY_POINT
*relay
= (DEBUG_ENTRY_POINT
*)(relay_addr
- 5);
571 WORD nb_args
= relay
->args
/ sizeof(int);
575 get_entry_point( buffer
, relay
);
577 DPRINTF( "%04lx:Call %s(", GetCurrentThreadId(), buffer
);
578 RELAY_PrintArgs( args
, nb_args
, relay
->argtypes
);
579 DPRINTF( ") ret=%08x\n", ret_addr
);
582 if (relay
->ret
== 0xc3) /* cdecl */
584 ret
= call_cdecl_function( (LONGLONG_CPROC
)relay
->orig
, nb_args
, args
);
588 ret
= call_stdcall_function( (LONGLONG_FARPROC
)relay
->orig
, nb_args
, args
);
593 BOOL ret64
= (relay
->argtypes
& 0x80000000) && (nb_args
< 16);
595 DPRINTF( "%04lx:Ret %s() retval=%08x%08x ret=%08x\n",
596 GetCurrentThreadId(),
597 buffer
, (UINT
)(ret
>> 32), (UINT
)ret
, ret_addr
);
599 DPRINTF( "%04lx:Ret %s() retval=%08x ret=%08x\n",
600 GetCurrentThreadId(),
601 buffer
, (UINT
)ret
, ret_addr
);
607 /***********************************************************************
608 * RELAY_CallFrom32Regs
610 * Stack layout (esp is context->Esp, not the current %esp):
614 * (esp) return addr to caller
615 * (esp-4) return addr to DEBUG_ENTRY_POINT
616 * (esp-8) ptr to relay entry code for RELAY_CallFrom32Regs
617 * ... >128 bytes space free to be modified (ensured by the assembly glue)
619 void WINAPI
RELAY_DoCallFrom32Regs( CONTEXT86
*context
)
626 BYTE
*relay_addr
= *((BYTE
**)context
->Esp
- 1);
627 DEBUG_ENTRY_POINT
*relay
= (DEBUG_ENTRY_POINT
*)(relay_addr
- 5);
628 WORD nb_args
= relay
->args
/ sizeof(int);
630 /* remove extra stuff from the stack */
631 context
->Eip
= *(DWORD
*)context
->Esp
;
632 context
->Esp
+= sizeof(DWORD
);
633 args
= (int *)context
->Esp
;
634 if (relay
->ret
== 0xc2) /* stdcall */
635 context
->Esp
+= nb_args
* sizeof(int);
637 entry_point
= (BYTE
*)relay
->orig
;
638 assert( *entry_point
== 0xe8 /* lcall */ );
642 get_entry_point( buffer
, relay
);
644 DPRINTF( "%04lx:Call %s(", GetCurrentThreadId(), buffer
);
645 RELAY_PrintArgs( args
, nb_args
, relay
->argtypes
);
646 DPRINTF( ") ret=%08lx fs=%04lx\n", context
->Eip
, context
->SegFs
);
648 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
649 context
->Eax
, context
->Ebx
, context
->Ecx
,
650 context
->Edx
, context
->Esi
, context
->Edi
);
651 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
652 context
->Ebp
, context
->Esp
, context
->SegDs
,
653 context
->SegEs
, context
->SegGs
, context
->EFlags
);
656 /* Now call the real function */
658 memcpy( args_copy
, args
, nb_args
* sizeof(args
[0]) );
659 args_copy
[nb_args
] = (int)context
; /* append context argument */
660 if (relay
->ret
== 0xc3) /* cdecl */
662 call_cdecl_function( *(LONGLONG_CPROC
*)(entry_point
+ 5), nb_args
+1, args_copy
);
666 call_stdcall_function( *(LONGLONG_FARPROC
*)(entry_point
+ 5), nb_args
+1, args_copy
);
671 DPRINTF( "%04lx:Ret %s() retval=%08lx ret=%08lx fs=%04lx\n",
672 GetCurrentThreadId(),
673 buffer
, context
->Eax
, context
->Eip
, context
->SegFs
);
675 DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
676 context
->Eax
, context
->Ebx
, context
->Ecx
,
677 context
->Edx
, context
->Esi
, context
->Edi
);
678 DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
679 context
->Ebp
, context
->Esp
, context
->SegDs
,
680 context
->SegEs
, context
->SegGs
, context
->EFlags
);
684 void WINAPI
RELAY_CallFrom32Regs(void);
685 __ASM_GLOBAL_FUNC( RELAY_CallFrom32Regs
,
686 "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
687 ".long " __ASM_NAME("RELAY_DoCallFrom32Regs") ",0" );
690 /* check whether the function at addr starts with a call to __wine_call_from_32_regs */
691 static BOOL
is_register_entry_point( const BYTE
*addr
)
693 extern void __wine_call_from_32_regs();
697 if (*addr
!= 0xe8) return FALSE
; /* not a call */
698 /* check if call target is __wine_call_from_32_regs */
699 offset
= (const int *)(addr
+ 1);
700 if (*offset
== (const char *)__wine_call_from_32_regs
- (const char *)(offset
+ 1)) return TRUE
;
701 /* now check if call target is an import table jump to __wine_call_from_32_regs */
702 addr
= (const BYTE
*)(offset
+ 1) + *offset
;
703 if (addr
[0] != 0xff || addr
[1] != 0x25) return FALSE
; /* not an indirect jmp */
704 ptr
= *(const void * const*)(addr
+ 2); /* get indirect jmp target address */
705 return (*(const char * const*)ptr
== (char *)__wine_call_from_32_regs
);
709 /***********************************************************************
710 * RELAY_GetProcAddress
712 * Return the proc address to use for a given function.
714 FARPROC
RELAY_GetProcAddress( HMODULE module
, const IMAGE_EXPORT_DIRECTORY
*exports
,
715 DWORD exp_size
, FARPROC proc
, const WCHAR
*user
)
717 const DEBUG_ENTRY_POINT
*debug
= (DEBUG_ENTRY_POINT
*)proc
;
718 const DEBUG_ENTRY_POINT
*list
= (const DEBUG_ENTRY_POINT
*)((const char *)exports
+ exp_size
);
720 if (debug
< list
|| debug
>= list
+ exports
->NumberOfFunctions
) return proc
;
721 if (list
+ (debug
- list
) != debug
) return proc
; /* not a valid address */
722 if (check_from_module( debug_from_relay_includelist
, debug_from_relay_excludelist
, user
))
723 return proc
; /* we want to relay it */
724 if (!debug
->call
) return proc
; /* not a normal function */
725 if (debug
->call
!= 0xe8 && debug
->call
!= 0xe9) return proc
; /* not a debug thunk at all */
730 /***********************************************************************
733 * Setup relay debugging for a built-in dll.
735 void RELAY_SetupDLL( HMODULE module
)
737 IMAGE_EXPORT_DIRECTORY
*exports
;
738 DEBUG_ENTRY_POINT
*debug
;
742 char *p
, dllname
[80];
745 exports
= RtlImageDirectoryEntryToData( module
, TRUE
, IMAGE_DIRECTORY_ENTRY_EXPORT
, &size
);
746 if (!exports
) return;
747 debug
= (DEBUG_ENTRY_POINT
*)((char *)exports
+ size
);
748 funcs
= (DWORD
*)((char *)module
+ exports
->AddressOfFunctions
);
749 strcpy( dllname
, (char *)module
+ exports
->Name
);
750 p
= dllname
+ strlen(dllname
) - 4;
751 if (p
> dllname
&& !strcasecmp( p
, ".dll" )) *p
= 0;
753 for (i
= 0; i
< exports
->NumberOfFunctions
; i
++, funcs
++, debug
++)
757 if (!debug
->call
) continue; /* not a normal function */
758 if (debug
->call
!= 0xe8 && debug
->call
!= 0xe9) break; /* not a debug thunk at all */
760 name
= find_exported_name( module
, exports
, i
+ exports
->Base
);
761 on
= check_relay_include( dllname
, i
+ exports
->Base
, name
);
765 debug
->call
= 0xe8; /* call relative */
766 if (is_register_entry_point( debug
->orig
))
767 debug
->callfrom32
= (char *)RELAY_CallFrom32Regs
- (char *)&debug
->ret
;
769 debug
->callfrom32
= (char *)RELAY_CallFrom32
- (char *)&debug
->ret
;
773 debug
->call
= 0xe9; /* jmp relative */
774 debug
->callfrom32
= (char *)debug
->orig
- (char *)&debug
->ret
;
776 *funcs
= (char *)debug
- (char *)module
;
781 /***********************************************************************
782 * SNOOP_ShowDebugmsgSnoop
784 * Simple function to decide if a particular debugging message is
787 static BOOL
SNOOP_ShowDebugmsgSnoop(const char *module
, int ordinal
, const char *func
)
789 if (debug_snoop_excludelist
&& check_list( module
, ordinal
, func
, debug_snoop_excludelist
))
791 if (debug_snoop_includelist
&& !check_list( module
, ordinal
, func
, debug_snoop_includelist
))
797 /***********************************************************************
800 * Setup snoop debugging for a native dll.
802 void SNOOP_SetupDLL(HMODULE hmod
)
804 SNOOP_DLL
**dll
= &firstdll
;
808 IMAGE_EXPORT_DIRECTORY
*exports
;
810 exports
= RtlImageDirectoryEntryToData( hmod
, TRUE
, IMAGE_DIRECTORY_ENTRY_EXPORT
, &size
);
811 if (!exports
) return;
812 name
= (char *)hmod
+ exports
->Name
;
814 TRACE_(snoop
)("hmod=%p, name=%s\n", hmod
, name
);
817 if ((*dll
)->hmod
== hmod
)
819 /* another dll, loaded at the same address */
821 size
= (*dll
)->nrofordinals
* sizeof(SNOOP_FUN
);
822 NtFreeVirtualMemory(GetCurrentProcess(), &addr
, &size
, MEM_RELEASE
);
825 dll
= &((*dll
)->next
);
828 *dll
= RtlReAllocateHeap(GetProcessHeap(),
829 HEAP_ZERO_MEMORY
, *dll
,
830 sizeof(SNOOP_DLL
) + strlen(name
));
832 *dll
= RtlAllocateHeap(GetProcessHeap(),
834 sizeof(SNOOP_DLL
) + strlen(name
));
836 (*dll
)->ordbase
= exports
->Base
;
837 (*dll
)->nrofordinals
= exports
->NumberOfFunctions
;
838 strcpy( (*dll
)->name
, name
);
839 p
= (*dll
)->name
+ strlen((*dll
)->name
) - 4;
840 if (p
> (*dll
)->name
&& !strcasecmp( p
, ".dll" )) *p
= 0;
842 size
= exports
->NumberOfFunctions
* sizeof(SNOOP_FUN
);
843 NtAllocateVirtualMemory(GetCurrentProcess(), &addr
, NULL
, &size
,
844 MEM_COMMIT
| MEM_RESERVE
, PAGE_EXECUTE_READWRITE
);
846 RtlFreeHeap(GetProcessHeap(),0,*dll
);
847 FIXME("out of memory\n");
851 memset((*dll
)->funs
,0,size
);
855 /***********************************************************************
856 * SNOOP_GetProcAddress
858 * Return the proc address to use for a given function.
860 FARPROC
SNOOP_GetProcAddress( HMODULE hmod
, const IMAGE_EXPORT_DIRECTORY
*exports
,
861 DWORD exp_size
, FARPROC origfun
, DWORD ordinal
,
866 const WORD
*ordinals
;
868 SNOOP_DLL
*dll
= firstdll
;
870 const IMAGE_SECTION_HEADER
*sec
;
872 if (!TRACE_ON(snoop
)) return origfun
;
873 if (!check_from_module( debug_from_snoop_includelist
, debug_from_snoop_excludelist
, user
))
874 return origfun
; /* the calling module was explicitly excluded */
876 if (!*(LPBYTE
)origfun
) /* 0x00 is an imposs. opcode, poss. dataref. */
879 sec
= RtlImageRvaToSection( RtlImageNtHeader(hmod
), hmod
, (char *)origfun
- (char *)hmod
);
881 if (!sec
|| !(sec
->Characteristics
& IMAGE_SCN_CNT_CODE
))
882 return origfun
; /* most likely a data reference */
885 if (hmod
== dll
->hmod
)
889 if (!dll
) /* probably internal */
892 /* try to find a name for it */
894 names
= (const DWORD
*)((const char *)hmod
+ exports
->AddressOfNames
);
895 ordinals
= (const WORD
*)((const char *)hmod
+ exports
->AddressOfNameOrdinals
);
896 if (names
) for (i
= 0; i
< exports
->NumberOfNames
; i
++)
898 if (ordinals
[i
] == ordinal
)
900 ename
= (const char *)hmod
+ names
[i
];
904 if (!SNOOP_ShowDebugmsgSnoop(dll
->name
,ordinal
,ename
))
906 assert(ordinal
< dll
->nrofordinals
);
907 fun
= dll
->funs
+ ordinal
;
912 /* NOTE: origreturn struct member MUST come directly after snoopentry */
913 fun
->snoopentry
= (char*)SNOOP_Entry
-((char*)(&fun
->nrofargs
));
914 fun
->origfun
= origfun
;
917 return (FARPROC
)&(fun
->lcall
);
920 static void SNOOP_PrintArg(DWORD x
)
925 if (!HIWORD(x
) || TRACE_ON(seh
)) return; /* trivial reject to avoid faults */
932 if (s
[i
]<0x20) {nostring
=1;break;}
933 if (s
[i
]>=0x80) {nostring
=1;break;}
936 if (!nostring
&& i
> 5)
937 DPRINTF(" %s",debugstr_an((LPSTR
)x
,i
));
938 else /* try unicode */
944 if (s
[i
]<0x20) {nostring
=1;break;}
945 if (s
[i
]>0x100) {nostring
=1;break;}
948 if (!nostring
&& i
> 5) DPRINTF(" %s",debugstr_wn((LPWSTR
)x
,i
));
957 #define CALLER1REF (*(DWORD*)context->Esp)
959 void WINAPI
SNOOP_DoEntry( CONTEXT86
*context
)
961 DWORD ordinal
=0,entry
= context
->Eip
- 5;
962 SNOOP_DLL
*dll
= firstdll
;
963 SNOOP_FUN
*fun
= NULL
;
964 SNOOP_RETURNENTRIES
**rets
= &firstrets
;
965 SNOOP_RETURNENTRY
*ret
;
969 if ( ((char*)entry
>=(char*)dll
->funs
) &&
970 ((char*)entry
<=(char*)(dll
->funs
+dll
->nrofordinals
))
972 fun
= (SNOOP_FUN
*)entry
;
973 ordinal
= fun
-dll
->funs
;
979 FIXME("entrypoint 0x%08lx not found\n",entry
);
982 /* guess cdecl ... */
983 if (fun
->nrofargs
<0) {
984 /* Typical cdecl return frame is:
986 * which has (for xxxxxxxx up to 255 the opcode "83 C4 xx".
987 * (after that 81 C2 xx xx xx xx)
989 LPBYTE reteip
= (LPBYTE
)CALLER1REF
;
992 if ((reteip
[0]==0x83)&&(reteip
[1]==0xc4))
993 fun
->nrofargs
=reteip
[2]/4;
999 for (i
=0;i
<sizeof((*rets
)->entry
)/sizeof((*rets
)->entry
[0]);i
++)
1000 if (!(*rets
)->entry
[i
].origreturn
)
1002 if (i
!=sizeof((*rets
)->entry
)/sizeof((*rets
)->entry
[0]))
1004 rets
= &((*rets
)->next
);
1010 NtAllocateVirtualMemory(GetCurrentProcess(), &addr
, NULL
, &size
,
1011 MEM_COMMIT
| MEM_RESERVE
,
1012 PAGE_EXECUTE_READWRITE
);
1015 memset(*rets
,0,4096);
1016 i
= 0; /* entry 0 is free */
1018 ret
= &((*rets
)->entry
[i
]);
1020 /* NOTE: origreturn struct member MUST come directly after snoopret */
1021 ret
->snoopret
= ((char*)SNOOP_Return
)-(char*)(&ret
->origreturn
);
1022 ret
->origreturn
= (FARPROC
)CALLER1REF
;
1023 CALLER1REF
= (DWORD
)&ret
->lcall
;
1026 ret
->ordinal
= ordinal
;
1027 ret
->origESP
= context
->Esp
;
1029 context
->Eip
= (DWORD
)fun
->origfun
;
1031 if (fun
->name
) DPRINTF("%04lx:CALL %s.%s(",GetCurrentThreadId(),dll
->name
,fun
->name
);
1032 else DPRINTF("%04lx:CALL %s.%ld(",GetCurrentThreadId(),dll
->name
,dll
->ordbase
+ordinal
);
1033 if (fun
->nrofargs
>0) {
1034 max
= fun
->nrofargs
; if (max
>16) max
=16;
1037 SNOOP_PrintArg(*(DWORD
*)(context
->Esp
+ 4 + sizeof(DWORD
)*i
));
1038 if (i
<fun
->nrofargs
-1) DPRINTF(",");
1040 if (max
!=fun
->nrofargs
)
1042 } else if (fun
->nrofargs
<0) {
1043 DPRINTF("<unknown, check return>");
1044 ret
->args
= RtlAllocateHeap(GetProcessHeap(),
1045 0,16*sizeof(DWORD
));
1046 memcpy(ret
->args
,(LPBYTE
)(context
->Esp
+ 4),sizeof(DWORD
)*16);
1048 DPRINTF(") ret=%08lx\n",(DWORD
)ret
->origreturn
);
1052 void WINAPI
SNOOP_DoReturn( CONTEXT86
*context
)
1054 SNOOP_RETURNENTRY
*ret
= (SNOOP_RETURNENTRY
*)(context
->Eip
- 5);
1055 SNOOP_FUN
*fun
= &ret
->dll
->funs
[ret
->ordinal
];
1057 /* We haven't found out the nrofargs yet. If we called a cdecl
1058 * function it is too late anyway and we can just set '0' (which
1059 * will be the difference between orig and current ESP
1060 * If stdcall -> everything ok.
1062 if (ret
->dll
->funs
[ret
->ordinal
].nrofargs
<0)
1063 ret
->dll
->funs
[ret
->ordinal
].nrofargs
=(context
->Esp
- ret
->origESP
-4)/4;
1064 context
->Eip
= (DWORD
)ret
->origreturn
;
1069 DPRINTF("%04lx:RET %s.%s(", GetCurrentThreadId(), ret
->dll
->name
, fun
->name
);
1071 DPRINTF("%04lx:RET %s.%ld(", GetCurrentThreadId(),
1072 ret
->dll
->name
,ret
->dll
->ordbase
+ret
->ordinal
);
1074 max
= fun
->nrofargs
;
1079 SNOOP_PrintArg(ret
->args
[i
]);
1080 if (i
<max
-1) DPRINTF(",");
1082 DPRINTF(") retval=%08lx ret=%08lx\n",
1083 context
->Eax
,(DWORD
)ret
->origreturn
);
1084 RtlFreeHeap(GetProcessHeap(),0,ret
->args
);
1090 DPRINTF("%04lx:RET %s.%s() retval=%08lx ret=%08lx\n",
1091 GetCurrentThreadId(),
1092 ret
->dll
->name
, fun
->name
, context
->Eax
, (DWORD
)ret
->origreturn
);
1094 DPRINTF("%04lx:RET %s.%ld() retval=%08lx ret=%08lx\n",
1095 GetCurrentThreadId(),
1096 ret
->dll
->name
,ret
->dll
->ordbase
+ret
->ordinal
,
1097 context
->Eax
, (DWORD
)ret
->origreturn
);
1099 ret
->origreturn
= NULL
; /* mark as empty */
1102 /* assembly wrappers that save the context */
1103 __ASM_GLOBAL_FUNC( SNOOP_Entry
,
1104 "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
1105 ".long " __ASM_NAME("SNOOP_DoEntry") ",0" );
1106 __ASM_GLOBAL_FUNC( SNOOP_Return
,
1107 "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t"
1108 ".long " __ASM_NAME("SNOOP_DoReturn") ",0" );
1110 #else /* __i386__ */
1112 FARPROC
RELAY_GetProcAddress( HMODULE module
, IMAGE_EXPORT_DIRECTORY
*exports
,
1113 DWORD exp_size
, FARPROC proc
, const WCHAR
*user
)
1118 FARPROC
SNOOP_GetProcAddress( HMODULE hmod
, IMAGE_EXPORT_DIRECTORY
*exports
, DWORD exp_size
,
1119 FARPROC origfun
, DWORD ordinal
, const WCHAR
*user
)
1124 void RELAY_SetupDLL( HMODULE module
)
1128 void SNOOP_SetupDLL( HMODULE hmod
)
1130 FIXME("snooping works only on i386 for now.\n");
1133 #endif /* __i386__ */