2 * Copyright 1993 Robert J. Amstadt
3 * Copyright 1995 Alexandre Julliard
4 * Copyright 2002 Jukka Heinonen
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "wine/winbase16.h"
31 #include "kernel16_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(relay
);
37 static const char **debug_relay_excludelist
;
38 static const char **debug_relay_includelist
;
39 static const char **debug_snoop_excludelist
;
40 static const char **debug_snoop_includelist
;
43 /***********************************************************************
46 * Build a function list from a ';'-separated string.
48 static const char **build_list( const WCHAR
*buffer
)
51 const WCHAR
*p
= buffer
;
54 while ((p
= wcschr( p
, ';' )))
59 /* allocate count+1 pointers, plus the space for a copy of the string */
60 if ((ret
= RtlAllocateHeap( GetProcessHeap(), 0,
61 (count
+ 1) * sizeof(char *) + (lstrlenW(buffer
) + 1) )))
63 char *str
= (char *)(ret
+ count
+ 1);
66 while ((*str
++ = *buffer
++));
71 if (!(p
= strchr( p
, ';' ))) break;
80 /***********************************************************************
81 * RELAY16_InitDebugLists
83 * Build the relay include/exclude function lists.
85 void RELAY16_InitDebugLists(void)
87 OBJECT_ATTRIBUTES attr
;
92 UNICODE_STRING config
= RTL_CONSTANT_STRING( L
"Software\\Wine\\Debug" );
93 UNICODE_STRING relay_include
= RTL_CONSTANT_STRING( L
"RelayInclude" );
94 UNICODE_STRING relay_exclude
= RTL_CONSTANT_STRING( L
"RelayExclude" );
95 UNICODE_STRING snoop_include
= RTL_CONSTANT_STRING( L
"SnoopInclude" );
96 UNICODE_STRING snoop_exclude
= RTL_CONSTANT_STRING( L
"SnoopExclude" );
98 RtlOpenCurrentUser( KEY_READ
, &root
);
99 attr
.Length
= sizeof(attr
);
100 attr
.RootDirectory
= root
;
101 attr
.ObjectName
= &config
;
103 attr
.SecurityDescriptor
= NULL
;
104 attr
.SecurityQualityOfService
= NULL
;
106 /* @@ Wine registry key: HKCU\Software\Wine\Debug */
107 if (NtOpenKey( &hkey
, KEY_READ
, &attr
)) hkey
= 0;
111 str
= (WCHAR
*)((KEY_VALUE_PARTIAL_INFORMATION
*)buffer
)->Data
;
112 if (!NtQueryValueKey( hkey
, &relay_include
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
114 debug_relay_includelist
= build_list( str
);
117 if (!NtQueryValueKey( hkey
, &relay_exclude
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
119 debug_relay_excludelist
= build_list( str
);
122 if (!NtQueryValueKey( hkey
, &snoop_include
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
124 debug_snoop_includelist
= build_list( str
);
127 if (!NtQueryValueKey( hkey
, &snoop_exclude
, KeyValuePartialInformation
, buffer
, sizeof(buffer
), &count
))
129 debug_snoop_excludelist
= build_list( str
);
135 /***********************************************************************
138 * Check if a given module and function is in the list.
140 static BOOL
check_list( const char *module
, int ordinal
, const char *func
, const char **list
)
144 sprintf( ord_str
, "%d", ordinal
);
147 const char *p
= strrchr( *list
, '.' );
148 if (p
&& p
> *list
) /* check module and function */
151 if (_strnicmp( module
, *list
, len
-1 ) || module
[len
]) continue;
152 if (p
[1] == '*' && !p
[2]) return TRUE
;
153 if (!strcmp( ord_str
, p
+ 1 )) return TRUE
;
154 if (func
&& !stricmp( func
, p
+ 1 )) return TRUE
;
156 else /* function only */
158 if (func
&& !stricmp( func
, *list
)) return TRUE
;
165 /***********************************************************************
166 * RELAY_ShowDebugmsgRelay
168 * Simple function to decide if a particular debugging message is
171 static BOOL
RELAY_ShowDebugmsgRelay(const char *module
, int ordinal
, const char *func
)
173 if (debug_relay_excludelist
&& check_list( module
, ordinal
, func
, debug_relay_excludelist
))
175 if (debug_relay_includelist
&& !check_list( module
, ordinal
, func
, debug_relay_includelist
))
181 /***********************************************************************
182 * SNOOP16_ShowDebugmsgSnoop
184 * Simple function to decide if a particular debugging message is
187 BOOL
SNOOP16_ShowDebugmsgSnoop(const char *module
, int ordinal
, const char *func
)
189 if (debug_snoop_excludelist
&& check_list( module
, ordinal
, func
, debug_snoop_excludelist
))
191 if (debug_snoop_includelist
&& !check_list( module
, ordinal
, func
, debug_snoop_includelist
))
197 /***********************************************************************
200 * Return the ordinal, name, and type info corresponding to a CS:IP address.
202 static const CALLFROM16
*get_entry_point( STACK16FRAME
*frame
, LPSTR module
, LPSTR func
, WORD
*pOrd
)
211 if (!(pModule
= NE_GetPtr( FarGetOwner16( GlobalHandle16( frame
->module_cs
) ))))
215 bundle
= (ET_BUNDLE
*)((BYTE
*)pModule
+ pModule
->ne_enttab
);
218 entry
= (ET_ENTRY
*)((BYTE
*)bundle
+6);
219 for (i
= bundle
->first
+ 1; i
<= bundle
->last
; i
++)
221 if ((entry
->offs
< frame
->entry_ip
)
222 && (entry
->segnum
== 1) /* code segment ? */
223 && (entry
->offs
>= max_offset
))
225 max_offset
= entry
->offs
;
230 } while ( (bundle
->next
)
231 && (bundle
= (ET_BUNDLE
*)((BYTE
*)pModule
+bundle
->next
)));
233 /* Search for the name in the resident names table */
234 /* (built-in modules have no non-resident table) */
236 p
= (BYTE
*)pModule
+ pModule
->ne_restab
;
237 memcpy( module
, p
+ 1, *p
);
242 p
+= *p
+ 1 + sizeof(WORD
);
243 if (*(WORD
*)(p
+ *p
+ 1) == *pOrd
) break;
245 memcpy( func
, p
+ 1, *p
);
248 /* Retrieve entry point call structure */
249 p
= MapSL( MAKESEGPTR( frame
->module_cs
, frame
->callfrom_ip
) );
250 /* p now points to lret, get the start of CALLFROM16 structure */
251 return (CALLFROM16
*)(p
- FIELD_OFFSET( CALLFROM16
, ret
));
255 extern int call_entry_point( void *func
, int nb_args
, const int *args
);
256 __ASM_GLOBAL_FUNC( call_entry_point
,
258 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
259 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
261 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
263 __ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
265 __ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
266 "movl 12(%ebp),%edx\n\t"
271 "movl 12(%ebp),%ecx\n\t"
272 "movl 16(%ebp),%esi\n\t"
276 "1:\tcall *8(%ebp)\n\t"
277 "leal -8(%ebp),%esp\n\t"
279 __ASM_CFI(".cfi_same_value %edi\n\t")
281 __ASM_CFI(".cfi_same_value %esi\n\t")
283 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
284 __ASM_CFI(".cfi_same_value %ebp\n\t")
288 /***********************************************************************
289 * relay_call_from_16_no_debug
291 * Same as relay_call_from_16 but doesn't print any debug information.
293 static int relay_call_from_16_no_debug( void *entry_point
, unsigned char *args16
, CONTEXT
*context
,
294 const CALLFROM16
*call
)
296 unsigned int i
, j
, nb_args
= 0;
299 /* look for the ret instruction */
300 for (j
= 0; j
< ARRAY_SIZE(call
->ret
); j
++)
301 if (call
->ret
[j
] == 0xca66 || call
->ret
[j
] == 0xcb66) break;
303 if (call
->ret
[j
] == 0xcb66) /* cdecl */
305 for (i
= 0; i
< 20; i
++, nb_args
++)
307 int type
= (call
->arg_types
[i
/ 10] >> (3 * (i
% 10))) & 7;
309 if (type
== ARG_NONE
) break;
313 args32
[nb_args
] = *(WORD
*)args16
;
314 args16
+= sizeof(WORD
);
317 args32
[nb_args
] = *(short *)args16
;
318 args16
+= sizeof(WORD
);
322 args32
[nb_args
] = *(int *)args16
;
323 args16
+= sizeof(int);
327 args32
[nb_args
] = (int)MapSL( *(SEGPTR
*)args16
);
328 args16
+= sizeof(SEGPTR
);
331 args32
[nb_args
] = (int)args16
;
340 /* Start with the last arg */
341 args16
+= call
->ret
[j
+ 1];
342 for (i
= 0; i
< 20; i
++, nb_args
++)
344 int type
= (call
->arg_types
[i
/ 10] >> (3 * (i
% 10))) & 7;
346 if (type
== ARG_NONE
) break;
350 args16
-= sizeof(WORD
);
351 args32
[nb_args
] = *(WORD
*)args16
;
354 args16
-= sizeof(WORD
);
355 args32
[nb_args
] = *(short *)args16
;
359 args16
-= sizeof(int);
360 args32
[nb_args
] = *(int *)args16
;
364 args16
-= sizeof(SEGPTR
);
365 args32
[nb_args
] = (int)MapSL( *(SEGPTR
*)args16
);
373 if (!j
) /* register function */
374 args32
[nb_args
++] = (int)context
;
376 SYSLEVEL_CheckNotLevel( 2 );
378 return call_entry_point( entry_point
, nb_args
, args32
);
382 /***********************************************************************
385 * Replacement for the 16-bit relay functions when relay debugging is on.
387 int relay_call_from_16( void *entry_point
, unsigned char *args16
, CONTEXT
*context
)
391 unsigned int i
, j
, nb_args
= 0;
392 int ret_val
, args32
[20];
393 char module
[10], func
[64];
394 const CALLFROM16
*call
;
396 frame
= CURRENT_STACK16
;
397 call
= get_entry_point( frame
, module
, func
, &ordinal
);
398 if (!TRACE_ON(relay
) || !RELAY_ShowDebugmsgRelay( module
, ordinal
, func
))
399 return relay_call_from_16_no_debug( entry_point
, args16
, context
, call
);
401 TRACE( "\1Call %s.%d: %s(", module
, ordinal
, func
);
403 /* look for the ret instruction */
404 for (j
= 0; j
< ARRAY_SIZE(call
->ret
); j
++)
405 if (call
->ret
[j
] == 0xca66 || call
->ret
[j
] == 0xcb66) break;
407 if (call
->ret
[j
] == 0xcb66) /* cdecl */
409 for (i
= 0; i
< 20; i
++, nb_args
++)
411 int type
= (call
->arg_types
[i
/ 10] >> (3 * (i
% 10))) & 7;
413 if (type
== ARG_NONE
) break;
418 TRACE( "%04x", *(WORD
*)args16
);
419 args32
[nb_args
] = *(WORD
*)args16
;
420 args16
+= sizeof(WORD
);
423 TRACE( "%04x", *(WORD
*)args16
);
424 args32
[nb_args
] = *(short *)args16
;
425 args16
+= sizeof(WORD
);
428 TRACE( "%08x", *(int *)args16
);
429 args32
[nb_args
] = *(int *)args16
;
430 args16
+= sizeof(int);
433 TRACE( "%04x:%04x", *(WORD
*)(args16
+2), *(WORD
*)args16
);
434 args32
[nb_args
] = (int)MapSL( *(SEGPTR
*)args16
);
435 args16
+= sizeof(SEGPTR
);
438 TRACE( "%08x %s", *(int *)args16
, debugstr_a( MapSL(*(SEGPTR
*)args16
)));
439 args32
[nb_args
] = (int)MapSL( *(SEGPTR
*)args16
);
440 args16
+= sizeof(int);
443 TRACE( "%04x:%04x %s", *(WORD
*)(args16
+2), *(WORD
*)args16
,
444 debugstr_a( MapSL(*(SEGPTR
*)args16
)) );
445 args32
[nb_args
] = *(SEGPTR
*)args16
;
446 args16
+= sizeof(SEGPTR
);
450 args32
[nb_args
] = (int)args16
;
459 /* Start with the last arg */
460 args16
+= call
->ret
[j
+ 1];
461 for (i
= 0; i
< 20; i
++, nb_args
++)
463 int type
= (call
->arg_types
[i
/ 10] >> (3 * (i
% 10))) & 7;
465 if (type
== ARG_NONE
) break;
470 args16
-= sizeof(WORD
);
471 args32
[nb_args
] = *(WORD
*)args16
;
472 TRACE( "%04x", *(WORD
*)args16
);
475 args16
-= sizeof(WORD
);
476 args32
[nb_args
] = *(short *)args16
;
477 TRACE( "%04x", *(WORD
*)args16
);
480 args16
-= sizeof(int);
481 args32
[nb_args
] = *(int *)args16
;
482 TRACE( "%08x", *(int *)args16
);
485 args16
-= sizeof(SEGPTR
);
486 args32
[nb_args
] = (int)MapSL( *(SEGPTR
*)args16
);
487 TRACE( "%04x:%04x", *(WORD
*)(args16
+2), *(WORD
*)args16
);
490 args16
-= sizeof(int);
491 args32
[nb_args
] = (int)MapSL( *(SEGPTR
*)args16
);
492 TRACE( "%08x %s", *(int *)args16
, debugstr_a( MapSL(*(SEGPTR
*)args16
)));
495 args16
-= sizeof(SEGPTR
);
496 args32
[nb_args
] = *(SEGPTR
*)args16
;
497 TRACE( "%04x:%04x %s", *(WORD
*)(args16
+2), *(WORD
*)args16
,
498 debugstr_a( MapSL(*(SEGPTR
*)args16
)) );
502 args32
[nb_args
] = (int)args16
;
510 if (!j
) /* register function */
512 args32
[nb_args
++] = (int)context
;
513 TRACE( ") ret=%04x:%04x ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x bp=%04x ss:sp=%04x:%04x ds=%04x es=%04x efl=%08lx\n",
514 frame
->cs
, frame
->ip
, (WORD
)context
->Eax
, (WORD
)context
->Ebx
, (WORD
)context
->Ecx
,
515 (WORD
)context
->Edx
, (WORD
)context
->Esi
, (WORD
)context
->Edi
, (WORD
)context
->Ebp
,
516 (WORD
)context
->SegSs
, (WORD
)context
->Esp
, (WORD
)context
->SegDs
, (WORD
)context
->SegEs
, context
->EFlags
);
518 else TRACE( ") ret=%04x:%04x ds=%04x\n", frame
->cs
, frame
->ip
, frame
->ds
);
520 SYSLEVEL_CheckNotLevel( 2 );
522 ret_val
= call_entry_point( entry_point
, nb_args
, args32
);
524 SYSLEVEL_CheckNotLevel( 2 );
526 TRACE( "\1Ret %s.%d: %s() ", module
, ordinal
, func
);
527 if (!j
) /* register function */
529 TRACE( "retval=none ret=%04x:%04x ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x ds=%04x es=%04x efl=%08lx\n",
530 (WORD
)context
->SegCs
, LOWORD(context
->Eip
), (WORD
)context
->Eax
, (WORD
)context
->Ebx
,
531 (WORD
)context
->Ecx
, (WORD
)context
->Edx
, (WORD
)context
->Esi
, (WORD
)context
->Edi
,
532 (WORD
)context
->SegDs
, (WORD
)context
->SegEs
, context
->EFlags
);
536 frame
= CURRENT_STACK16
; /* might have be changed by the entry point */
537 if (j
== 1) /* 16-bit return sequence */
538 TRACE( "retval=%04x ret=%04x:%04x ds=%04x\n",
539 ret_val
& 0xffff, frame
->cs
, frame
->ip
, frame
->ds
);
541 TRACE( "retval=%08x ret=%04x:%04x ds=%04x\n",
542 ret_val
, frame
->cs
, frame
->ip
, frame
->ds
);