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