Moved the 16-bit storage interfaces out of the exported headers.
[wine/multimedia.git] / dlls / kernel / relay16.c
blobdc7bc6a66dce57a7b662c3d054fe44e8ea663e42
1 /*
2 * Copyright 1993 Robert J. Amstadt
3 * Copyright 1995 Alexandre Julliard
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "config.h"
21 #include "wine/port.h"
23 #include <assert.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <stdio.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wine/winbase16.h"
32 #include "module.h"
33 #include "stackframe.h"
34 #include "selectors.h"
35 #include "builtin16.h"
36 #include "kernel_private.h"
37 #include "wine/unicode.h"
38 #include "wine/library.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(relay);
43 #ifdef __i386__
45 static const WCHAR **debug_relay_excludelist;
46 static const WCHAR **debug_relay_includelist;
47 static const WCHAR **debug_snoop_excludelist;
48 static const WCHAR **debug_snoop_includelist;
50 /* compare an ASCII and a Unicode string without depending on the current codepage */
51 inline static int strncmpiAW( const char *strA, const WCHAR *strW, int n )
53 int ret = 0;
54 for ( ; n > 0; n--, strA++, strW++)
55 if ((ret = toupperW((unsigned char)*strA) - toupperW(*strW)) || !*strA) break;
56 return ret;
59 /***********************************************************************
60 * build_list
62 * Build a function list from a ';'-separated string.
64 static const WCHAR **build_list( const WCHAR *buffer )
66 int count = 1;
67 const WCHAR *p = buffer;
68 const WCHAR **ret;
70 while ((p = strchrW( p, ';' )))
72 count++;
73 p++;
75 /* allocate count+1 pointers, plus the space for a copy of the string */
76 if ((ret = RtlAllocateHeap( GetProcessHeap(), 0,
77 (count+1) * sizeof(WCHAR*) + (strlenW(buffer)+1) * sizeof(WCHAR) )))
79 WCHAR *str = (WCHAR *)(ret + count + 1);
80 WCHAR *p = str;
82 strcpyW( str, buffer );
83 count = 0;
84 for (;;)
86 ret[count++] = p;
87 if (!(p = strchrW( p, ';' ))) break;
88 *p++ = 0;
90 ret[count++] = NULL;
92 return ret;
96 /***********************************************************************
97 * RELAY16_InitDebugLists
99 * Build the relay include/exclude function lists.
101 void RELAY16_InitDebugLists(void)
103 OBJECT_ATTRIBUTES attr;
104 UNICODE_STRING name;
105 char buffer[1024];
106 HKEY hkey;
107 DWORD count;
108 WCHAR *str;
109 static const WCHAR configW[] = {'M','a','c','h','i','n','e','\\',
110 'S','o','f','t','w','a','r','e','\\',
111 'W','i','n','e','\\',
112 'W','i','n','e','\\',
113 'C','o','n','f','i','g','\\',
114 'D','e','b','u','g',0};
115 static const WCHAR RelayIncludeW[] = {'R','e','l','a','y','I','n','c','l','u','d','e',0};
116 static const WCHAR RelayExcludeW[] = {'R','e','l','a','y','E','x','c','l','u','d','e',0};
117 static const WCHAR SnoopIncludeW[] = {'S','n','o','o','p','I','n','c','l','u','d','e',0};
118 static const WCHAR SnoopExcludeW[] = {'S','n','o','o','p','E','x','c','l','u','d','e',0};
120 attr.Length = sizeof(attr);
121 attr.RootDirectory = 0;
122 attr.ObjectName = &name;
123 attr.Attributes = 0;
124 attr.SecurityDescriptor = NULL;
125 attr.SecurityQualityOfService = NULL;
126 RtlInitUnicodeString( &name, configW );
128 if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return;
130 str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)buffer)->Data;
131 RtlInitUnicodeString( &name, RelayIncludeW );
132 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
134 debug_relay_includelist = build_list( str );
137 RtlInitUnicodeString( &name, RelayExcludeW );
138 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
140 debug_relay_excludelist = build_list( str );
143 RtlInitUnicodeString( &name, SnoopIncludeW );
144 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
146 debug_snoop_includelist = build_list( str );
149 RtlInitUnicodeString( &name, SnoopExcludeW );
150 if (!NtQueryValueKey( hkey, &name, KeyValuePartialInformation, buffer, sizeof(buffer), &count ))
152 debug_snoop_excludelist = build_list( str );
154 NtClose( hkey );
158 /***********************************************************************
159 * RELAY_ShowDebugmsgRelay
161 * Simple function to decide if a particular debugging message is
162 * wanted.
164 static int RELAY_ShowDebugmsgRelay(const char *func)
166 if(debug_relay_excludelist || debug_relay_includelist) {
167 const char *term = strchr(func, ':');
168 const WCHAR **listitem;
169 int len, len2, itemlen, show;
171 if(debug_relay_excludelist) {
172 show = 1;
173 listitem = debug_relay_excludelist;
174 } else {
175 show = 0;
176 listitem = debug_relay_includelist;
178 assert(term);
179 assert(strlen(term) > 2);
180 len = term - func;
181 len2 = strchr(func, '.') - func;
182 assert(len2 && len2 > 0 && len2 < 64);
183 term += 2;
184 for(; *listitem; listitem++)
186 itemlen = strlenW(*listitem);
187 if (itemlen == len && !strncmpiAW(func, *listitem, len)) return !show;
188 if (itemlen == len2 && !strncmpiAW(func, *listitem, len2)) return !show;
189 if (!strncmpiAW(term, *listitem, itemlen) && !term[itemlen]) return !show;
191 return show;
193 return 1;
197 /***********************************************************************
198 * SNOOP16_ShowDebugmsgSnoop
200 * Simple function to decide if a particular debugging message is
201 * wanted.
203 int SNOOP16_ShowDebugmsgSnoop(const char *dll, int ord, const char *fname)
205 if(debug_snoop_excludelist || debug_snoop_includelist) {
206 const WCHAR **listitem;
207 char buf[80];
208 int len, len2, itemlen, show;
210 if(debug_snoop_excludelist) {
211 show = 1;
212 listitem = debug_snoop_excludelist;
213 } else {
214 show = 0;
215 listitem = debug_snoop_includelist;
217 len = strlen(dll);
218 assert(len < 64);
219 sprintf(buf, "%s.%d", dll, ord);
220 len2 = strlen(buf);
221 for(; *listitem; listitem++)
223 itemlen = strlenW(*listitem);
224 if (itemlen == len && !strncmpiAW( buf, *listitem, len)) return !show;
225 if (itemlen == len2 && !strncmpiAW(buf, *listitem, len2)) return !show;
226 if (fname && !strncmpiAW(fname, *listitem, itemlen) && !fname[itemlen]) return !show;
228 return show;
230 return 1;
234 /***********************************************************************
235 * get_entry_point
237 * Return the ordinal, name, and type info corresponding to a CS:IP address.
239 static const CALLFROM16 *get_entry_point( STACK16FRAME *frame, LPSTR name, WORD *pOrd )
241 WORD i, max_offset;
242 register BYTE *p;
243 NE_MODULE *pModule;
244 ET_BUNDLE *bundle;
245 ET_ENTRY *entry;
247 if (!(pModule = NE_GetPtr( FarGetOwner16( GlobalHandle16( frame->module_cs ) ))))
248 return NULL;
250 max_offset = 0;
251 *pOrd = 0;
252 bundle = (ET_BUNDLE *)((BYTE *)pModule + pModule->entry_table);
255 entry = (ET_ENTRY *)((BYTE *)bundle+6);
256 for (i = bundle->first + 1; i <= bundle->last; i++)
258 if ((entry->offs < frame->entry_ip)
259 && (entry->segnum == 1) /* code segment ? */
260 && (entry->offs >= max_offset))
262 max_offset = entry->offs;
263 *pOrd = i;
265 entry++;
267 } while ( (bundle->next)
268 && (bundle = (ET_BUNDLE *)((BYTE *)pModule+bundle->next)));
270 /* Search for the name in the resident names table */
271 /* (built-in modules have no non-resident table) */
273 p = (BYTE *)pModule + pModule->name_table;
274 while (*p)
276 p += *p + 1 + sizeof(WORD);
277 if (*(WORD *)(p + *p + 1) == *pOrd) break;
280 sprintf( name, "%.*s.%d: %.*s",
281 *((BYTE *)pModule + pModule->name_table),
282 (char *)pModule + pModule->name_table + 1,
283 *pOrd, *p, (char *)(p + 1) );
285 /* Retrieve entry point call structure */
286 p = MapSL( MAKESEGPTR( frame->module_cs, frame->callfrom_ip ) );
287 /* p now points to lret, get the start of CALLFROM16 structure */
288 return (CALLFROM16 *)(p - (BYTE *)&((CALLFROM16 *)0)->lret);
292 /***********************************************************************
293 * RELAY_DebugCallFrom16
295 void RELAY_DebugCallFrom16( CONTEXT86 *context )
297 STACK16FRAME *frame;
298 WORD ordinal;
299 char *args16, funstr[80];
300 const CALLFROM16 *call;
301 int i;
303 if (!TRACE_ON(relay)) return;
305 frame = CURRENT_STACK16;
306 call = get_entry_point( frame, funstr, &ordinal );
307 if (!call) return; /* happens for the two snoop register relays */
308 if (!RELAY_ShowDebugmsgRelay(funstr)) return;
309 DPRINTF( "%04lx:Call %s(",GetCurrentThreadId(),funstr);
310 args16 = (char *)(frame + 1);
312 if (call->lret == 0xcb66) /* cdecl */
314 for (i = 0; i < 20; i++)
316 int type = (call->arg_types[i / 10] >> (3 * (i % 10))) & 7;
318 if (type == ARG_NONE) break;
319 if (i) DPRINTF( "," );
320 switch(type)
322 case ARG_WORD:
323 case ARG_SWORD:
324 DPRINTF( "%04x", *(WORD *)args16 );
325 args16 += sizeof(WORD);
326 break;
327 case ARG_LONG:
328 DPRINTF( "%08x", *(int *)args16 );
329 args16 += sizeof(int);
330 break;
331 case ARG_PTR:
332 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
333 args16 += sizeof(SEGPTR);
334 break;
335 case ARG_STR:
336 DPRINTF( "%08x %s", *(int *)args16,
337 debugstr_a( MapSL(*(SEGPTR *)args16 )));
338 args16 += sizeof(int);
339 break;
340 case ARG_SEGSTR:
341 DPRINTF( "%04x:%04x %s", *(WORD *)(args16+2), *(WORD *)args16,
342 debugstr_a( MapSL(*(SEGPTR *)args16 )) );
343 args16 += sizeof(SEGPTR);
344 break;
345 default:
346 break;
350 else /* not cdecl */
352 /* Start with the last arg */
353 args16 += call->nArgs;
354 for (i = 0; i < 20; i++)
356 int type = (call->arg_types[i / 10] >> (3 * (i % 10))) & 7;
358 if (type == ARG_NONE) break;
359 if (i) DPRINTF( "," );
360 switch(type)
362 case ARG_WORD:
363 case ARG_SWORD:
364 args16 -= sizeof(WORD);
365 DPRINTF( "%04x", *(WORD *)args16 );
366 break;
367 case ARG_LONG:
368 args16 -= sizeof(int);
369 DPRINTF( "%08x", *(int *)args16 );
370 break;
371 case ARG_PTR:
372 args16 -= sizeof(SEGPTR);
373 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
374 break;
375 case ARG_STR:
376 args16 -= sizeof(int);
377 DPRINTF( "%08x %s", *(int *)args16,
378 debugstr_a( MapSL(*(SEGPTR *)args16 )));
379 break;
380 case ARG_SEGSTR:
381 args16 -= sizeof(SEGPTR);
382 DPRINTF( "%04x:%04x %s", *(WORD *)(args16+2), *(WORD *)args16,
383 debugstr_a( MapSL(*(SEGPTR *)args16 )) );
384 break;
385 default:
386 break;
391 DPRINTF( ") ret=%04x:%04x ds=%04x\n", frame->cs, frame->ip, frame->ds );
393 if (call->arg_types[0] & ARG_REGISTER)
394 DPRINTF(" AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
395 (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx,
396 (WORD)context->Edx, (WORD)context->Esi, (WORD)context->Edi,
397 (WORD)context->SegEs, context->EFlags );
399 SYSLEVEL_CheckNotLevel( 2 );
403 /***********************************************************************
404 * RELAY_DebugCallFrom16Ret
406 void RELAY_DebugCallFrom16Ret( CONTEXT86 *context, int ret_val )
408 STACK16FRAME *frame;
409 WORD ordinal;
410 char funstr[80];
411 const CALLFROM16 *call;
413 if (!TRACE_ON(relay)) return;
414 frame = CURRENT_STACK16;
415 call = get_entry_point( frame, funstr, &ordinal );
416 if (!call) return;
417 if (!RELAY_ShowDebugmsgRelay(funstr)) return;
418 DPRINTF( "%04lx:Ret %s() ",GetCurrentThreadId(),funstr);
420 if (call->arg_types[0] & ARG_REGISTER)
422 DPRINTF("retval=none ret=%04x:%04x ds=%04x\n",
423 (WORD)context->SegCs, LOWORD(context->Eip), (WORD)context->SegDs);
424 DPRINTF(" AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
425 (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx,
426 (WORD)context->Edx, (WORD)context->Esi, (WORD)context->Edi,
427 (WORD)context->SegEs, context->EFlags );
429 else if (call->arg_types[0] & ARG_RET16)
431 DPRINTF( "retval=%04x ret=%04x:%04x ds=%04x\n",
432 ret_val & 0xffff, frame->cs, frame->ip, frame->ds );
434 else
436 DPRINTF( "retval=%08x ret=%04x:%04x ds=%04x\n",
437 ret_val, frame->cs, frame->ip, frame->ds );
439 SYSLEVEL_CheckNotLevel( 2 );
442 #else /* __i386__ */
445 * Stubs for the CallTo16/CallFrom16 routines on non-Intel architectures
446 * (these will never be called but need to be present to satisfy the linker ...)
449 /***********************************************************************
450 * __wine_call_from_16_word (KERNEL32.@)
452 WORD __wine_call_from_16_word()
454 assert( FALSE );
457 /***********************************************************************
458 * __wine_call_from_16_long (KERNEL32.@)
460 LONG __wine_call_from_16_long()
462 assert( FALSE );
465 /***********************************************************************
466 * __wine_call_from_16_regs (KERNEL32.@)
468 void __wine_call_from_16_regs()
470 assert( FALSE );
473 DWORD WINAPI CALL32_CBClient( FARPROC proc, LPWORD args, DWORD *esi )
474 { assert( FALSE ); }
476 DWORD WINAPI CALL32_CBClientEx( FARPROC proc, LPWORD args, DWORD *esi, INT *nArgs )
477 { assert( FALSE ); }
479 #endif /* __i386__ */