Moved specification of relay and snoop include/exclude functions to
[wine] / if1632 / relay.c
1 /*
2  * Copyright 1993 Robert J. Amstadt
3  * Copyright 1995 Alexandre Julliard
4  *
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.
9  *
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.
14  *
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
18  */
19
20 #include <assert.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdio.h>
24
25 #include "wine/winbase16.h"
26 #include "winnt.h"
27 #include "module.h"
28 #include "stackframe.h"
29 #include "selectors.h"
30 #include "builtin16.h"
31 #include "syslevel.h"
32 #include "wine/library.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(relay);
36
37 /***********************************************************************
38  *           RELAY_Init
39  */
40 BOOL RELAY_Init(void)
41 {
42 #ifdef __i386__
43     WORD codesel;
44
45       /* Allocate the code selector for CallTo16 routines */
46
47     extern void Call16_Ret_Start(), Call16_Ret_End();
48     extern void CallTo16_Ret();
49     extern void CALL32_CBClient_Ret();
50     extern void CALL32_CBClientEx_Ret();
51     extern SEGPTR CallTo16_RetAddr;
52     extern DWORD CallTo16_DataSelector;
53     extern SEGPTR CALL32_CBClient_RetAddr;
54     extern SEGPTR CALL32_CBClientEx_RetAddr;
55
56     codesel = SELECTOR_AllocBlock( (void *)Call16_Ret_Start,
57                                    (char *)Call16_Ret_End - (char *)Call16_Ret_Start,
58                                    WINE_LDT_FLAGS_CODE | WINE_LDT_FLAGS_32BIT );
59     if (!codesel) return FALSE;
60
61       /* Patch the return addresses for CallTo16 routines */
62
63     CallTo16_DataSelector = wine_get_ds();
64     CallTo16_RetAddr =
65         MAKESEGPTR( codesel, (char*)CallTo16_Ret - (char*)Call16_Ret_Start );
66     CALL32_CBClient_RetAddr =
67         MAKESEGPTR( codesel, (char*)CALL32_CBClient_Ret - (char*)Call16_Ret_Start );
68     CALL32_CBClientEx_RetAddr =
69         MAKESEGPTR( codesel, (char*)CALL32_CBClientEx_Ret - (char*)Call16_Ret_Start );
70 #endif
71     return TRUE;
72 }
73
74 /*
75  * Stubs for the CallTo16/CallFrom16 routines on non-Intel architectures
76  * (these will never be called but need to be present to satisfy the linker ...)
77  */
78 #ifndef __i386__
79 /***********************************************************************
80  *              wine_call_to_16_word (KERNEL32.@)
81  */
82 WORD WINAPI wine_call_to_16_word( FARPROC16 target, INT nArgs )
83 {
84     assert( FALSE );
85 }
86
87 /***********************************************************************
88  *              wine_call_to_16_long (KERNEL32.@)
89  */
90 LONG WINAPI wine_call_to_16_long( FARPROC16 target, INT nArgs )
91 {
92     assert( FALSE );
93 }
94
95 /***********************************************************************
96  *              wine_call_to_16_regs_short (KERNEL32.@)
97  */
98 void WINAPI wine_call_to_16_regs_short( CONTEXT86 *context, INT nArgs )
99 {
100     assert( FALSE );
101 }
102
103 /***********************************************************************
104  *              wine_call_to_16_regs_long (KERNEL32.@)
105  */
106 void WINAPI wine_call_to_16_regs_long ( CONTEXT86 *context, INT nArgs )
107 {
108     assert( FALSE );
109 }
110
111 /***********************************************************************
112  *              __wine_call_from_16_word (KERNEL32.@)
113  */
114 WORD __wine_call_from_16_word()
115 {
116     assert( FALSE );
117 }
118
119 /***********************************************************************
120  *              __wine_call_from_16_long (KERNEL32.@)
121  */
122 LONG __wine_call_from_16_long()
123 {
124     assert( FALSE );
125 }
126
127 /***********************************************************************
128  *              __wine_call_from_16_regs (KERNEL32.@)
129  */
130 void __wine_call_from_16_regs()
131 {
132     assert( FALSE );
133 }
134
135 DWORD WINAPI CALL32_CBClient( FARPROC proc, LPWORD args, DWORD *esi )
136 { assert( FALSE ); }
137
138 DWORD WINAPI CALL32_CBClientEx( FARPROC proc, LPWORD args, DWORD *esi, INT *nArgs )
139 { assert( FALSE ); }
140 #endif
141
142
143 /***********************************************************************
144  *           RELAY_ShowDebugmsgRelay
145  *
146  * Simple function to decide if a particular debugging message is
147  * wanted.
148  */
149 static int RELAY_ShowDebugmsgRelay(const char *func)
150 {
151   /* from relay32/relay386.c */
152   extern const char **debug_relay_excludelist,**debug_relay_includelist;
153
154   if(debug_relay_excludelist || debug_relay_includelist) {
155     const char *term = strchr(func, ':');
156     const char **listitem;
157     int len, len2, itemlen, show;
158
159     if(debug_relay_excludelist) {
160       show = 1;
161       listitem = debug_relay_excludelist;
162     } else {
163       show = 0;
164       listitem = debug_relay_includelist;
165     }
166     assert(term);
167     assert(strlen(term) > 2);
168     len = term - func;
169     len2 = strchr(func, '.') - func;
170     assert(len2 && len2 > 0 && len2 < 64);
171     term += 2;
172     for(; *listitem; listitem++) {
173       itemlen = strlen(*listitem);
174       if((itemlen == len && !strncasecmp(*listitem, func, len)) ||
175          (itemlen == len2 && !strncasecmp(*listitem, func, len2)) ||
176          !strcasecmp(*listitem, term)) {
177         show = !show;
178        break;
179       }
180     }
181     return show;
182   }
183   return 1;
184 }
185
186
187 /***********************************************************************
188  *           get_entry_point
189  *
190  * Return the ordinal, name, and type info corresponding to a CS:IP address.
191  */
192 static const CALLFROM16 *get_entry_point( STACK16FRAME *frame, LPSTR name, WORD *pOrd )
193 {
194     WORD i, max_offset;
195     register BYTE *p;
196     NE_MODULE *pModule;
197     ET_BUNDLE *bundle;
198     ET_ENTRY *entry;
199
200     if (!(pModule = NE_GetPtr( FarGetOwner16( GlobalHandle16( frame->module_cs ) ))))
201         return NULL;
202
203     max_offset = 0;
204     *pOrd = 0;
205     bundle = (ET_BUNDLE *)((BYTE *)pModule + pModule->entry_table);
206     do
207     {
208         entry = (ET_ENTRY *)((BYTE *)bundle+6);
209         for (i = bundle->first + 1; i <= bundle->last; i++)
210         {
211             if ((entry->offs < frame->entry_ip)
212             && (entry->segnum == 1) /* code segment ? */
213             && (entry->offs >= max_offset))
214             {
215                 max_offset = entry->offs;
216                 *pOrd = i;
217             }
218             entry++;
219         }
220     } while ( (bundle->next)
221            && (bundle = (ET_BUNDLE *)((BYTE *)pModule+bundle->next)));
222
223     /* Search for the name in the resident names table */
224     /* (built-in modules have no non-resident table)   */
225
226     p = (BYTE *)pModule + pModule->name_table;
227     while (*p)
228     {
229         p += *p + 1 + sizeof(WORD);
230         if (*(WORD *)(p + *p + 1) == *pOrd) break;
231     }
232
233     sprintf( name, "%.*s.%d: %.*s",
234              *((BYTE *)pModule + pModule->name_table),
235              (char *)pModule + pModule->name_table + 1,
236              *pOrd, *p, (char *)(p + 1) );
237
238     /* Retrieve entry point call structure */
239     p = MapSL( MAKESEGPTR( frame->module_cs, frame->callfrom_ip ) );
240     /* p now points to lret, get the start of CALLFROM16 structure */
241     return (CALLFROM16 *)(p - (BYTE *)&((CALLFROM16 *)0)->lret);
242 }
243
244
245 /***********************************************************************
246  *           RELAY_DebugCallFrom16
247  */
248 void RELAY_DebugCallFrom16( CONTEXT86 *context )
249 {
250     STACK16FRAME *frame;
251     WORD ordinal;
252     char *args16, funstr[80];
253     const CALLFROM16 *call;
254     int i;
255
256     if (!TRACE_ON(relay)) return;
257
258     frame = CURRENT_STACK16;
259     call = get_entry_point( frame, funstr, &ordinal );
260     if (!call) return; /* happens for the two snoop register relays */
261     if (!RELAY_ShowDebugmsgRelay(funstr)) return;
262     DPRINTF( "%08lx:Call %s(",GetCurrentThreadId(),funstr);
263     VA_START16( args16 );
264
265     if (call->lret == 0xcb66)  /* cdecl */
266     {
267         for (i = 0; i < 20; i++)
268         {
269             int type = (call->arg_types[i / 10] >> (3 * (i % 10))) & 7;
270
271             if (type == ARG_NONE) break;
272             if (i) DPRINTF( "," );
273             switch(type)
274             {
275             case ARG_WORD:
276             case ARG_SWORD:
277                 DPRINTF( "%04x", *(WORD *)args16 );
278                 args16 += sizeof(WORD);
279                 break;
280             case ARG_LONG:
281                 DPRINTF( "%08x", *(int *)args16 );
282                 args16 += sizeof(int);
283                 break;
284             case ARG_PTR:
285                 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
286                 args16 += sizeof(SEGPTR);
287                 break;
288             case ARG_STR:
289                 DPRINTF( "%08x %s", *(int *)args16,
290                          debugstr_a( MapSL(*(SEGPTR *)args16 )));
291                 args16 += sizeof(int);
292                 break;
293             case ARG_SEGSTR:
294                 DPRINTF( "%04x:%04x %s", *(WORD *)(args16+2), *(WORD *)args16,
295                          debugstr_a( MapSL(*(SEGPTR *)args16 )) );
296                 args16 += sizeof(SEGPTR);
297                 break;
298             default:
299                 break;
300             }
301         }
302     }
303     else  /* not cdecl */
304     {
305         /* Start with the last arg */
306         args16 += call->nArgs;
307         for (i = 0; i < 20; i++)
308         {
309             int type = (call->arg_types[i / 10] >> (3 * (i % 10))) & 7;
310
311             if (type == ARG_NONE) break;
312             if (i) DPRINTF( "," );
313             switch(type)
314             {
315             case ARG_WORD:
316             case ARG_SWORD:
317                 args16 -= sizeof(WORD);
318                 DPRINTF( "%04x", *(WORD *)args16 );
319                 break;
320             case ARG_LONG:
321                 args16 -= sizeof(int);
322                 DPRINTF( "%08x", *(int *)args16 );
323                 break;
324             case ARG_PTR:
325                 args16 -= sizeof(SEGPTR);
326                 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
327                 break;
328             case ARG_STR:
329                 args16 -= sizeof(int);
330                 DPRINTF( "%08x %s", *(int *)args16,
331                          debugstr_a( MapSL(*(SEGPTR *)args16 )));
332                 break;
333             case ARG_SEGSTR:
334                 args16 -= sizeof(SEGPTR);
335                 DPRINTF( "%04x:%04x %s", *(WORD *)(args16+2), *(WORD *)args16,
336                          debugstr_a( MapSL(*(SEGPTR *)args16 )) );
337                 break;
338             default:
339                 break;
340             }
341         }
342     }
343
344     DPRINTF( ") ret=%04x:%04x ds=%04x\n", frame->cs, frame->ip, frame->ds );
345     VA_END16( args16 );
346
347     if (call->arg_types[0] & ARG_REGISTER)
348         DPRINTF("     AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
349                 AX_reg(context), BX_reg(context), CX_reg(context),
350                 DX_reg(context), SI_reg(context), DI_reg(context),
351                 (WORD)context->SegEs, context->EFlags );
352
353     SYSLEVEL_CheckNotLevel( 2 );
354 }
355
356
357 /***********************************************************************
358  *           RELAY_DebugCallFrom16Ret
359  */
360 void RELAY_DebugCallFrom16Ret( CONTEXT86 *context, int ret_val )
361 {
362     STACK16FRAME *frame;
363     WORD ordinal;
364     char funstr[80];
365     const CALLFROM16 *call;
366
367     if (!TRACE_ON(relay)) return;
368     frame = CURRENT_STACK16;
369     call = get_entry_point( frame, funstr, &ordinal );
370     if (!call) return;
371     if (!RELAY_ShowDebugmsgRelay(funstr)) return;
372     DPRINTF( "%08lx:Ret  %s() ",GetCurrentThreadId(),funstr);
373
374     if (call->arg_types[0] & ARG_REGISTER)
375     {
376         DPRINTF("retval=none ret=%04x:%04x ds=%04x\n",
377                 (WORD)context->SegCs, LOWORD(context->Eip), (WORD)context->SegDs);
378         DPRINTF("     AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
379                 AX_reg(context), BX_reg(context), CX_reg(context),
380                 DX_reg(context), SI_reg(context), DI_reg(context),
381                 (WORD)context->SegEs, context->EFlags );
382     }
383     else if (call->arg_types[0] & ARG_RET16)
384     {
385         DPRINTF( "retval=%04x ret=%04x:%04x ds=%04x\n",
386                  ret_val & 0xffff, frame->cs, frame->ip, frame->ds );
387     }
388     else
389     {
390         DPRINTF( "retval=%08x ret=%04x:%04x ds=%04x\n",
391                  ret_val, frame->cs, frame->ip, frame->ds );
392     }
393     SYSLEVEL_CheckNotLevel( 2 );
394 }
395
396
397 /***********************************************************************
398  *           RELAY_DebugCallTo16
399  *
400  * 'target' contains either the function to call (normal CallTo16)
401  * or a pointer to the CONTEXT86 struct (register CallTo16).
402  * 'nb_args' is the number of argument bytes on the 16-bit stack;
403  * 'reg_func' specifies whether we have a register CallTo16 or not.
404  */
405 void RELAY_DebugCallTo16( LPVOID target, int nb_args, BOOL reg_func )
406 {
407     WORD *stack16;
408     TEB *teb;
409
410     if (!TRACE_ON(relay)) return;
411     teb = NtCurrentTeb();
412     stack16 = (WORD *)THREAD_STACK16(teb);
413
414     nb_args /= sizeof(WORD);
415
416     if ( reg_func )
417     {
418         CONTEXT86 *context = (CONTEXT86 *)target;
419
420         DPRINTF("%08lx:CallTo16(func=%04lx:%04x,ds=%04lx",
421                 GetCurrentThreadId(),
422                 context->SegCs, LOWORD(context->Eip), context->SegDs );
423         while (nb_args--) DPRINTF( ",%04x", *--stack16 );
424         DPRINTF(") ss:sp=%04x:%04x", SELECTOROF(teb->cur_stack),
425                 OFFSETOF(teb->cur_stack) );
426         DPRINTF(" ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x bp=%04x es=%04x fs=%04x\n",
427                 AX_reg(context), BX_reg(context), CX_reg(context),
428                 DX_reg(context), SI_reg(context), DI_reg(context),
429                 BP_reg(context), (WORD)context->SegEs, (WORD)context->SegFs );
430     }
431     else
432     {
433         DPRINTF("%08lx:CallTo16(func=%04x:%04x,ds=%04x",
434                 GetCurrentThreadId(),
435                 HIWORD(target), LOWORD(target), SELECTOROF(teb->cur_stack) );
436         while (nb_args--) DPRINTF( ",%04x", *--stack16 );
437         DPRINTF(") ss:sp=%04x:%04x\n", SELECTOROF(teb->cur_stack),
438                 OFFSETOF(teb->cur_stack) );
439     }
440
441     SYSLEVEL_CheckNotLevel( 2 );
442 }
443
444
445 /***********************************************************************
446  *           RELAY_DebugCallTo16Ret
447  */
448 void RELAY_DebugCallTo16Ret( BOOL reg_func, int ret_val )
449 {
450     if (!TRACE_ON(relay)) return;
451
452     if (!reg_func)
453     {
454         DPRINTF("%08lx:RetFrom16() ss:sp=%04x:%04x retval=%08x\n",
455                 GetCurrentThreadId(),
456                 SELECTOROF(NtCurrentTeb()->cur_stack),
457                 OFFSETOF(NtCurrentTeb()->cur_stack), ret_val);
458     }
459     else
460     {
461         CONTEXT86 *context = (CONTEXT86 *)ret_val;
462
463         DPRINTF("%08lx:RetFrom16() ss:sp=%04x:%04x ",
464                 GetCurrentThreadId(),
465                 SELECTOROF(NtCurrentTeb()->cur_stack),
466                 OFFSETOF(NtCurrentTeb()->cur_stack));
467         DPRINTF(" ax=%04x bx=%04x cx=%04x dx=%04x bp=%04x sp=%04x\n",
468                 AX_reg(context), BX_reg(context), CX_reg(context),
469                 DX_reg(context), BP_reg(context), LOWORD(context->Esp));
470     }
471
472     SYSLEVEL_CheckNotLevel( 2 );
473 }