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