winex11.drv: Release window data before calling sync_window_cursor().
[wine.git] / dlls / krnl386.exe16 / relay.c
blob1532df526760de6ac63967967bdd57955002907a
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 UNICODE_STRING name;
89 char buffer[1024];
90 HANDLE root, hkey;
91 DWORD count;
92 WCHAR *str;
93 static const WCHAR configW[] = {'S','o','f','t','w','a','r','e','\\',
94 'W','i','n','e','\\',
95 'D','e','b','u','g',0};
96 static const WCHAR RelayIncludeW[] = {'R','e','l','a','y','I','n','c','l','u','d','e',0};
97 static const WCHAR RelayExcludeW[] = {'R','e','l','a','y','E','x','c','l','u','d','e',0};
98 static const WCHAR SnoopIncludeW[] = {'S','n','o','o','p','I','n','c','l','u','d','e',0};
99 static const WCHAR SnoopExcludeW[] = {'S','n','o','o','p','E','x','c','l','u','d','e',0};
101 RtlOpenCurrentUser( KEY_READ, &root );
102 attr.Length = sizeof(attr);
103 attr.RootDirectory = root;
104 attr.ObjectName = &name;
105 attr.Attributes = 0;
106 attr.SecurityDescriptor = NULL;
107 attr.SecurityQualityOfService = NULL;
108 RtlInitUnicodeString( &name, configW );
110 /* @@ Wine registry key: HKCU\Software\Wine\Debug */
111 if (NtOpenKey( &hkey, KEY_READ, &attr )) hkey = 0;
112 NtClose( root );
113 if (!hkey) return;
115 str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)buffer)->Data;
116 RtlInitUnicodeString( &name, RelayIncludeW );
117 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
119 debug_relay_includelist = build_list( str );
122 RtlInitUnicodeString( &name, RelayExcludeW );
123 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
125 debug_relay_excludelist = build_list( str );
128 RtlInitUnicodeString( &name, SnoopIncludeW );
129 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
131 debug_snoop_includelist = build_list( str );
134 RtlInitUnicodeString( &name, SnoopExcludeW );
135 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
137 debug_snoop_excludelist = build_list( str );
139 NtClose( hkey );
143 /***********************************************************************
144 * check_list
146 * Check if a given module and function is in the list.
148 static BOOL check_list( const char *module, int ordinal, const char *func, const char **list )
150 char ord_str[10];
152 sprintf( ord_str, "%d", ordinal );
153 for(; *list; list++)
155 const char *p = strrchr( *list, '.' );
156 if (p && p > *list) /* check module and function */
158 int len = p - *list;
159 if (_strnicmp( module, *list, len-1 ) || module[len]) continue;
160 if (p[1] == '*' && !p[2]) return TRUE;
161 if (!strcmp( ord_str, p + 1 )) return TRUE;
162 if (func && !stricmp( func, p + 1 )) return TRUE;
164 else /* function only */
166 if (func && !stricmp( func, *list )) return TRUE;
169 return FALSE;
173 /***********************************************************************
174 * RELAY_ShowDebugmsgRelay
176 * Simple function to decide if a particular debugging message is
177 * wanted.
179 static BOOL RELAY_ShowDebugmsgRelay(const char *module, int ordinal, const char *func)
181 if (debug_relay_excludelist && check_list( module, ordinal, func, debug_relay_excludelist ))
182 return FALSE;
183 if (debug_relay_includelist && !check_list( module, ordinal, func, debug_relay_includelist ))
184 return FALSE;
185 return TRUE;
189 /***********************************************************************
190 * SNOOP16_ShowDebugmsgSnoop
192 * Simple function to decide if a particular debugging message is
193 * wanted.
195 BOOL SNOOP16_ShowDebugmsgSnoop(const char *module, int ordinal, const char *func)
197 if (debug_snoop_excludelist && check_list( module, ordinal, func, debug_snoop_excludelist ))
198 return FALSE;
199 if (debug_snoop_includelist && !check_list( module, ordinal, func, debug_snoop_includelist ))
200 return FALSE;
201 return TRUE;
205 /***********************************************************************
206 * get_entry_point
208 * Return the ordinal, name, and type info corresponding to a CS:IP address.
210 static const CALLFROM16 *get_entry_point( STACK16FRAME *frame, LPSTR module, LPSTR func, WORD *pOrd )
212 WORD i, max_offset;
213 register BYTE *p;
214 NE_MODULE *pModule;
215 ET_BUNDLE *bundle;
216 ET_ENTRY *entry;
218 *pOrd = 0;
219 if (!(pModule = NE_GetPtr( FarGetOwner16( GlobalHandle16( frame->module_cs ) ))))
220 return NULL;
222 max_offset = 0;
223 bundle = (ET_BUNDLE *)((BYTE *)pModule + pModule->ne_enttab);
226 entry = (ET_ENTRY *)((BYTE *)bundle+6);
227 for (i = bundle->first + 1; i <= bundle->last; i++)
229 if ((entry->offs < frame->entry_ip)
230 && (entry->segnum == 1) /* code segment ? */
231 && (entry->offs >= max_offset))
233 max_offset = entry->offs;
234 *pOrd = i;
236 entry++;
238 } while ( (bundle->next)
239 && (bundle = (ET_BUNDLE *)((BYTE *)pModule+bundle->next)));
241 /* Search for the name in the resident names table */
242 /* (built-in modules have no non-resident table) */
244 p = (BYTE *)pModule + pModule->ne_restab;
245 memcpy( module, p + 1, *p );
246 module[*p] = 0;
248 while (*p)
250 p += *p + 1 + sizeof(WORD);
251 if (*(WORD *)(p + *p + 1) == *pOrd) break;
253 memcpy( func, p + 1, *p );
254 func[*p] = 0;
256 /* Retrieve entry point call structure */
257 p = MapSL( MAKESEGPTR( frame->module_cs, frame->callfrom_ip ) );
258 /* p now points to lret, get the start of CALLFROM16 structure */
259 return (CALLFROM16 *)(p - FIELD_OFFSET( CALLFROM16, ret ));
263 extern int call_entry_point( void *func, int nb_args, const int *args );
264 __ASM_GLOBAL_FUNC( call_entry_point,
265 "pushl %ebp\n\t"
266 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
267 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
268 "movl %esp,%ebp\n\t"
269 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
270 "pushl %esi\n\t"
271 __ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
272 "pushl %edi\n\t"
273 __ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
274 "movl 12(%ebp),%edx\n\t"
275 "shll $2,%edx\n\t"
276 "jz 1f\n\t"
277 "subl %edx,%esp\n\t"
278 "andl $~15,%esp\n\t"
279 "movl 12(%ebp),%ecx\n\t"
280 "movl 16(%ebp),%esi\n\t"
281 "movl %esp,%edi\n\t"
282 "cld\n\t"
283 "rep; movsl\n"
284 "1:\tcall *8(%ebp)\n\t"
285 "leal -8(%ebp),%esp\n\t"
286 "popl %edi\n\t"
287 __ASM_CFI(".cfi_same_value %edi\n\t")
288 "popl %esi\n\t"
289 __ASM_CFI(".cfi_same_value %esi\n\t")
290 "popl %ebp\n\t"
291 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
292 __ASM_CFI(".cfi_same_value %ebp\n\t")
293 "ret" )
296 /***********************************************************************
297 * relay_call_from_16_no_debug
299 * Same as relay_call_from_16 but doesn't print any debug information.
301 static int relay_call_from_16_no_debug( void *entry_point, unsigned char *args16, CONTEXT *context,
302 const CALLFROM16 *call )
304 unsigned int i, j, nb_args = 0;
305 int args32[20];
307 /* look for the ret instruction */
308 for (j = 0; j < ARRAY_SIZE(call->ret); j++)
309 if (call->ret[j] == 0xca66 || call->ret[j] == 0xcb66) break;
311 if (call->ret[j] == 0xcb66) /* cdecl */
313 for (i = 0; i < 20; i++, nb_args++)
315 int type = (call->arg_types[i / 10] >> (3 * (i % 10))) & 7;
317 if (type == ARG_NONE) break;
318 switch(type)
320 case ARG_WORD:
321 args32[nb_args] = *(WORD *)args16;
322 args16 += sizeof(WORD);
323 break;
324 case ARG_SWORD:
325 args32[nb_args] = *(short *)args16;
326 args16 += sizeof(WORD);
327 break;
328 case ARG_LONG:
329 case ARG_SEGSTR:
330 args32[nb_args] = *(int *)args16;
331 args16 += sizeof(int);
332 break;
333 case ARG_PTR:
334 case ARG_STR:
335 args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 );
336 args16 += sizeof(SEGPTR);
337 break;
338 case ARG_VARARG:
339 args32[nb_args] = (int)args16;
340 break;
341 default:
342 break;
346 else /* not cdecl */
348 /* Start with the last arg */
349 args16 += call->ret[j + 1];
350 for (i = 0; i < 20; i++, nb_args++)
352 int type = (call->arg_types[i / 10] >> (3 * (i % 10))) & 7;
354 if (type == ARG_NONE) break;
355 switch(type)
357 case ARG_WORD:
358 args16 -= sizeof(WORD);
359 args32[nb_args] = *(WORD *)args16;
360 break;
361 case ARG_SWORD:
362 args16 -= sizeof(WORD);
363 args32[nb_args] = *(short *)args16;
364 break;
365 case ARG_LONG:
366 case ARG_SEGSTR:
367 args16 -= sizeof(int);
368 args32[nb_args] = *(int *)args16;
369 break;
370 case ARG_PTR:
371 case ARG_STR:
372 args16 -= sizeof(SEGPTR);
373 args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 );
374 break;
375 default:
376 break;
381 if (!j) /* register function */
382 args32[nb_args++] = (int)context;
384 SYSLEVEL_CheckNotLevel( 2 );
386 return call_entry_point( entry_point, nb_args, args32 );
390 /***********************************************************************
391 * relay_call_from_16
393 * Replacement for the 16-bit relay functions when relay debugging is on.
395 int relay_call_from_16( void *entry_point, unsigned char *args16, CONTEXT *context )
397 STACK16FRAME *frame;
398 WORD ordinal;
399 unsigned int i, j, nb_args = 0;
400 int ret_val, args32[20];
401 char module[10], func[64];
402 const CALLFROM16 *call;
404 frame = CURRENT_STACK16;
405 call = get_entry_point( frame, module, func, &ordinal );
406 if (!TRACE_ON(relay) || !RELAY_ShowDebugmsgRelay( module, ordinal, func ))
407 return relay_call_from_16_no_debug( entry_point, args16, context, call );
409 TRACE( "\1Call %s.%d: %s(", module, ordinal, func );
411 /* look for the ret instruction */
412 for (j = 0; j < ARRAY_SIZE(call->ret); j++)
413 if (call->ret[j] == 0xca66 || call->ret[j] == 0xcb66) break;
415 if (call->ret[j] == 0xcb66) /* cdecl */
417 for (i = 0; i < 20; i++, nb_args++)
419 int type = (call->arg_types[i / 10] >> (3 * (i % 10))) & 7;
421 if (type == ARG_NONE) break;
422 if (i) TRACE( "," );
423 switch(type)
425 case ARG_WORD:
426 TRACE( "%04x", *(WORD *)args16 );
427 args32[nb_args] = *(WORD *)args16;
428 args16 += sizeof(WORD);
429 break;
430 case ARG_SWORD:
431 TRACE( "%04x", *(WORD *)args16 );
432 args32[nb_args] = *(short *)args16;
433 args16 += sizeof(WORD);
434 break;
435 case ARG_LONG:
436 TRACE( "%08x", *(int *)args16 );
437 args32[nb_args] = *(int *)args16;
438 args16 += sizeof(int);
439 break;
440 case ARG_PTR:
441 TRACE( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
442 args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 );
443 args16 += sizeof(SEGPTR);
444 break;
445 case ARG_STR:
446 TRACE( "%08x %s", *(int *)args16, debugstr_a( MapSL(*(SEGPTR *)args16 )));
447 args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 );
448 args16 += sizeof(int);
449 break;
450 case ARG_SEGSTR:
451 TRACE( "%04x:%04x %s", *(WORD *)(args16+2), *(WORD *)args16,
452 debugstr_a( MapSL(*(SEGPTR *)args16 )) );
453 args32[nb_args] = *(SEGPTR *)args16;
454 args16 += sizeof(SEGPTR);
455 break;
456 case ARG_VARARG:
457 TRACE( "..." );
458 args32[nb_args] = (int)args16;
459 break;
460 default:
461 break;
465 else /* not cdecl */
467 /* Start with the last arg */
468 args16 += call->ret[j + 1];
469 for (i = 0; i < 20; i++, nb_args++)
471 int type = (call->arg_types[i / 10] >> (3 * (i % 10))) & 7;
473 if (type == ARG_NONE) break;
474 if (i) TRACE( "," );
475 switch(type)
477 case ARG_WORD:
478 args16 -= sizeof(WORD);
479 args32[nb_args] = *(WORD *)args16;
480 TRACE( "%04x", *(WORD *)args16 );
481 break;
482 case ARG_SWORD:
483 args16 -= sizeof(WORD);
484 args32[nb_args] = *(short *)args16;
485 TRACE( "%04x", *(WORD *)args16 );
486 break;
487 case ARG_LONG:
488 args16 -= sizeof(int);
489 args32[nb_args] = *(int *)args16;
490 TRACE( "%08x", *(int *)args16 );
491 break;
492 case ARG_PTR:
493 args16 -= sizeof(SEGPTR);
494 args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 );
495 TRACE( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
496 break;
497 case ARG_STR:
498 args16 -= sizeof(int);
499 args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 );
500 TRACE( "%08x %s", *(int *)args16, debugstr_a( MapSL(*(SEGPTR *)args16 )));
501 break;
502 case ARG_SEGSTR:
503 args16 -= sizeof(SEGPTR);
504 args32[nb_args] = *(SEGPTR *)args16;
505 TRACE( "%04x:%04x %s", *(WORD *)(args16+2), *(WORD *)args16,
506 debugstr_a( MapSL(*(SEGPTR *)args16 )) );
507 break;
508 case ARG_VARARG:
509 TRACE( "..." );
510 args32[nb_args] = (int)args16;
511 break;
512 default:
513 break;
518 if (!j) /* register function */
520 args32[nb_args++] = (int)context;
521 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",
522 frame->cs, frame->ip, (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx,
523 (WORD)context->Edx, (WORD)context->Esi, (WORD)context->Edi, (WORD)context->Ebp,
524 (WORD)context->SegSs, (WORD)context->Esp, (WORD)context->SegDs, (WORD)context->SegEs, context->EFlags );
526 else TRACE( ") ret=%04x:%04x ds=%04x\n", frame->cs, frame->ip, frame->ds );
528 SYSLEVEL_CheckNotLevel( 2 );
530 ret_val = call_entry_point( entry_point, nb_args, args32 );
532 SYSLEVEL_CheckNotLevel( 2 );
534 TRACE( "\1Ret %s.%d: %s() ", module, ordinal, func );
535 if (!j) /* register function */
537 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",
538 (WORD)context->SegCs, LOWORD(context->Eip), (WORD)context->Eax, (WORD)context->Ebx,
539 (WORD)context->Ecx, (WORD)context->Edx, (WORD)context->Esi, (WORD)context->Edi,
540 (WORD)context->SegDs, (WORD)context->SegEs, context->EFlags );
542 else
544 frame = CURRENT_STACK16; /* might have be changed by the entry point */
545 if (j == 1) /* 16-bit return sequence */
546 TRACE( "retval=%04x ret=%04x:%04x ds=%04x\n",
547 ret_val & 0xffff, frame->cs, frame->ip, frame->ds );
548 else
549 TRACE( "retval=%08x ret=%04x:%04x ds=%04x\n",
550 ret_val, frame->cs, frame->ip, frame->ds );
552 return ret_val;