winecoreaudio: Remove GetAudioSessionWrapper.
[wine.git] / dlls / krnl386.exe16 / relay.c
blob8b53f6bfd05afc77426418d9db4941691abc8652
1 /*
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
21 #include <assert.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdarg.h>
25 #include <stdio.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wine/winbase16.h"
30 #include "winternl.h"
31 #include "kernel16_private.h"
32 #include "dosexe.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 /***********************************************************************
44 * build_list
46 * Build a function list from a ';'-separated string.
48 static const char **build_list( const WCHAR *buffer )
50 int count = 1;
51 const WCHAR *p = buffer;
52 const char **ret;
54 while ((p = wcschr( p, ';' )))
56 count++;
57 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);
64 char *p = str;
66 while ((*str++ = *buffer++));
67 count = 0;
68 for (;;)
70 ret[count++] = p;
71 if (!(p = strchr( p, ';' ))) break;
72 *p++ = 0;
74 ret[count++] = NULL;
76 return ret;
80 /***********************************************************************
81 * RELAY16_InitDebugLists
83 * Build the relay include/exclude function lists.
85 void RELAY16_InitDebugLists(void)
87 OBJECT_ATTRIBUTES attr;
88 char buffer[1024];
89 HANDLE root, hkey;
90 DWORD count;
91 WCHAR *str;
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;
102 attr.Attributes = 0;
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;
108 NtClose( root );
109 if (!hkey) return;
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 );
131 NtClose( hkey );
135 /***********************************************************************
136 * check_list
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 )
142 char ord_str[10];
144 sprintf( ord_str, "%d", ordinal );
145 for(; *list; list++)
147 const char *p = strrchr( *list, '.' );
148 if (p && p > *list) /* check module and function */
150 int len = p - *list;
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;
161 return FALSE;
165 /***********************************************************************
166 * RELAY_ShowDebugmsgRelay
168 * Simple function to decide if a particular debugging message is
169 * wanted.
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 ))
174 return FALSE;
175 if (debug_relay_includelist && !check_list( module, ordinal, func, debug_relay_includelist ))
176 return FALSE;
177 return TRUE;
181 /***********************************************************************
182 * SNOOP16_ShowDebugmsgSnoop
184 * Simple function to decide if a particular debugging message is
185 * wanted.
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 ))
190 return FALSE;
191 if (debug_snoop_includelist && !check_list( module, ordinal, func, debug_snoop_includelist ))
192 return FALSE;
193 return TRUE;
197 /***********************************************************************
198 * get_entry_point
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 )
204 WORD i, max_offset;
205 register BYTE *p;
206 NE_MODULE *pModule;
207 ET_BUNDLE *bundle;
208 ET_ENTRY *entry;
210 *pOrd = 0;
211 if (!(pModule = NE_GetPtr( FarGetOwner16( GlobalHandle16( frame->module_cs ) ))))
212 return NULL;
214 max_offset = 0;
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;
226 *pOrd = i;
228 entry++;
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 );
238 module[*p] = 0;
240 while (*p)
242 p += *p + 1 + sizeof(WORD);
243 if (*(WORD *)(p + *p + 1) == *pOrd) break;
245 memcpy( func, p + 1, *p );
246 func[*p] = 0;
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,
257 "pushl %ebp\n\t"
258 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
259 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
260 "movl %esp,%ebp\n\t"
261 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
262 "pushl %esi\n\t"
263 __ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
264 "pushl %edi\n\t"
265 __ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
266 "movl 12(%ebp),%edx\n\t"
267 "shll $2,%edx\n\t"
268 "jz 1f\n\t"
269 "subl %edx,%esp\n\t"
270 "andl $~15,%esp\n\t"
271 "movl 12(%ebp),%ecx\n\t"
272 "movl 16(%ebp),%esi\n\t"
273 "movl %esp,%edi\n\t"
274 "cld\n\t"
275 "rep; movsl\n"
276 "1:\tcall *8(%ebp)\n\t"
277 "leal -8(%ebp),%esp\n\t"
278 "popl %edi\n\t"
279 __ASM_CFI(".cfi_same_value %edi\n\t")
280 "popl %esi\n\t"
281 __ASM_CFI(".cfi_same_value %esi\n\t")
282 "popl %ebp\n\t"
283 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
284 __ASM_CFI(".cfi_same_value %ebp\n\t")
285 "ret" )
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;
297 int args32[20];
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;
310 switch(type)
312 case ARG_WORD:
313 args32[nb_args] = *(WORD *)args16;
314 args16 += sizeof(WORD);
315 break;
316 case ARG_SWORD:
317 args32[nb_args] = *(short *)args16;
318 args16 += sizeof(WORD);
319 break;
320 case ARG_LONG:
321 case ARG_SEGSTR:
322 args32[nb_args] = *(int *)args16;
323 args16 += sizeof(int);
324 break;
325 case ARG_PTR:
326 case ARG_STR:
327 args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 );
328 args16 += sizeof(SEGPTR);
329 break;
330 case ARG_VARARG:
331 args32[nb_args] = (int)args16;
332 break;
333 default:
334 break;
338 else /* not cdecl */
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;
347 switch(type)
349 case ARG_WORD:
350 args16 -= sizeof(WORD);
351 args32[nb_args] = *(WORD *)args16;
352 break;
353 case ARG_SWORD:
354 args16 -= sizeof(WORD);
355 args32[nb_args] = *(short *)args16;
356 break;
357 case ARG_LONG:
358 case ARG_SEGSTR:
359 args16 -= sizeof(int);
360 args32[nb_args] = *(int *)args16;
361 break;
362 case ARG_PTR:
363 case ARG_STR:
364 args16 -= sizeof(SEGPTR);
365 args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 );
366 break;
367 default:
368 break;
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 /***********************************************************************
383 * relay_call_from_16
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 )
389 STACK16FRAME *frame;
390 WORD ordinal;
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;
414 if (i) TRACE( "," );
415 switch(type)
417 case ARG_WORD:
418 TRACE( "%04x", *(WORD *)args16 );
419 args32[nb_args] = *(WORD *)args16;
420 args16 += sizeof(WORD);
421 break;
422 case ARG_SWORD:
423 TRACE( "%04x", *(WORD *)args16 );
424 args32[nb_args] = *(short *)args16;
425 args16 += sizeof(WORD);
426 break;
427 case ARG_LONG:
428 TRACE( "%08x", *(int *)args16 );
429 args32[nb_args] = *(int *)args16;
430 args16 += sizeof(int);
431 break;
432 case ARG_PTR:
433 TRACE( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
434 args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 );
435 args16 += sizeof(SEGPTR);
436 break;
437 case ARG_STR:
438 TRACE( "%08x %s", *(int *)args16, debugstr_a( MapSL(*(SEGPTR *)args16 )));
439 args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 );
440 args16 += sizeof(int);
441 break;
442 case ARG_SEGSTR:
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);
447 break;
448 case ARG_VARARG:
449 TRACE( "..." );
450 args32[nb_args] = (int)args16;
451 break;
452 default:
453 break;
457 else /* not cdecl */
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;
466 if (i) TRACE( "," );
467 switch(type)
469 case ARG_WORD:
470 args16 -= sizeof(WORD);
471 args32[nb_args] = *(WORD *)args16;
472 TRACE( "%04x", *(WORD *)args16 );
473 break;
474 case ARG_SWORD:
475 args16 -= sizeof(WORD);
476 args32[nb_args] = *(short *)args16;
477 TRACE( "%04x", *(WORD *)args16 );
478 break;
479 case ARG_LONG:
480 args16 -= sizeof(int);
481 args32[nb_args] = *(int *)args16;
482 TRACE( "%08x", *(int *)args16 );
483 break;
484 case ARG_PTR:
485 args16 -= sizeof(SEGPTR);
486 args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 );
487 TRACE( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
488 break;
489 case ARG_STR:
490 args16 -= sizeof(int);
491 args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 );
492 TRACE( "%08x %s", *(int *)args16, debugstr_a( MapSL(*(SEGPTR *)args16 )));
493 break;
494 case ARG_SEGSTR:
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 )) );
499 break;
500 case ARG_VARARG:
501 TRACE( "..." );
502 args32[nb_args] = (int)args16;
503 break;
504 default:
505 break;
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 );
534 else
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 );
540 else
541 TRACE( "retval=%08x ret=%04x:%04x ds=%04x\n",
542 ret_val, frame->cs, frame->ip, frame->ds );
544 return ret_val;