Release 980201
[wine] / if1632 / relay.c
1 /*
2  * Copyright 1993 Robert J. Amstadt
3  * Copyright 1995 Alexandre Julliard
4  */
5
6 #include <assert.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include "windows.h"
10 #include "winnt.h"
11 #include "global.h"
12 #include "heap.h"
13 #include "module.h"
14 #include "stackframe.h"
15 #include "task.h"
16 #include "stddebug.h"
17 /* #define DEBUG_RELAY */
18 #include "debug.h"
19
20 #if 0
21 /* Make make_debug think these were really used */
22 dprintf_relay
23 #endif
24
25
26 /***********************************************************************
27  *           RELAY_Init
28  */
29 BOOL32 RELAY_Init(void)
30 {
31     WORD codesel;
32     extern BOOL32 THUNK_Init(void);
33
34       /* Allocate the code selector for CallTo16 routines */
35
36     extern void CALLTO16_Start(), CALLTO16_End();
37     extern void CALLTO16_Ret_word(), CALLTO16_Ret_long();
38     extern DWORD CALLTO16_RetAddr_word;
39     extern DWORD CALLTO16_RetAddr_long;
40
41     codesel = GLOBAL_CreateBlock( GMEM_FIXED, (void *)CALLTO16_Start,
42                                    (int)CALLTO16_End - (int)CALLTO16_Start,
43                                    0, TRUE, TRUE, FALSE, NULL );
44     if (!codesel) return FALSE;
45
46       /* Patch the return addresses for CallTo16 routines */
47
48     CALLTO16_RetAddr_word=MAKELONG( (int)CALLTO16_Ret_word-(int)CALLTO16_Start,
49                                     codesel );
50     CALLTO16_RetAddr_long=MAKELONG( (int)CALLTO16_Ret_long-(int)CALLTO16_Start,
51                                     codesel );
52
53     /* Create built-in modules */
54     if (!BUILTIN_Init()) return FALSE;
55
56     /* Initialize thunking */
57     return THUNK_Init();
58 }
59
60
61 /***********************************************************************
62  *           RELAY_DebugCallFrom16
63  */
64 void RELAY_DebugCallFrom16( int func_type, char *args,
65                             void *entry_point, CONTEXT *context )
66 {
67     STACK16FRAME *frame;
68     WORD ordinal;
69     char *args16;
70     int i;
71
72     if (!debugging_relay) return;
73
74     frame = CURRENT_STACK16;
75     printf( "Call %s(", BUILTIN_GetEntryPoint16( frame->entry_cs,
76                                                  frame->entry_ip,
77                                                  &ordinal ));
78     VA_START16( args16 );
79     for (i = 0; i < strlen(args); i++)
80     {
81         switch(args[i])
82         {
83         case 'w':
84         case 's':
85             args16 += 2;
86             break;
87         case 'l':
88         case 'p':
89         case 't':
90         case 'T':
91             args16 += 4;
92             break;
93         }
94     }
95
96     while (*args)
97     {
98         switch(*args)
99         {
100         case 'w':
101         case 's':
102             args16 -= 2;
103             printf( "0x%04x", *(WORD *)args16 );
104             break;
105         case 'l':
106             args16 -= 4;
107             printf( "0x%08x", *(int *)args16 );
108             break;
109         case 't':
110             args16 -= 4;
111             printf( "0x%08x", *(int *)args16 );
112             if (HIWORD(*(int *)args16)) {
113                 LPBYTE s = (LPBYTE)PTR_SEG_TO_LIN(*(int*)args16);
114
115                 /* filter out non printable chars, which would destroy output */
116                 fputs(" \"",stdout);
117                 while (*s) {
118                         if (*s < ' ') {
119                                 printf( "\\0x%02x",*s++);
120                                 continue;
121                         }
122                         if (*s=='\\') {
123                                 fputs( "\\\\",stdout);
124                                 s++;
125                                 continue;
126                         }
127                         fputc(*s++,stdout);
128                 }
129                 fputs("\"",stdout);
130             }
131             break;
132         case 'p':
133             args16 -= 4;
134             printf( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
135             break;
136         case 'T':
137             args16 -= 4;
138             printf( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
139             if (HIWORD(*(int *)args16)) {
140                 LPBYTE s = (LPBYTE)PTR_SEG_TO_LIN(*(int*)args16);
141
142                 /* filter out non printable chars, which would destroy output */
143                 fputs(" \"",stdout);
144                 while (*s) {
145                         if (*s < ' ') {
146                                 printf( "\\0x%02x",*s++);
147                                 continue;
148                         }
149                         if (*s=='\\') {
150                                 fputs( "\\\\",stdout);
151                                 s++;
152                                 continue;
153                         }
154                         fputc(*s++,stdout);
155                 }
156                 fputs("\"",stdout);
157             }
158             break;
159         }
160         args++;
161         if (*args) printf( "," );
162     }
163     printf( ") ret=%04x:%04x ds=%04x\n", frame->cs, frame->ip, frame->ds );
164     VA_END16( args16 );
165
166     if (func_type == 2)  /* register function */
167         printf( "     AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
168                 AX_reg(context), BX_reg(context), CX_reg(context),
169                 DX_reg(context), SI_reg(context), DI_reg(context),
170                 (WORD)ES_reg(context), EFL_reg(context) );
171 }
172
173
174 /***********************************************************************
175  *           RELAY_DebugCallFrom16Ret
176  */
177 void RELAY_DebugCallFrom16Ret( int func_type, int ret_val, CONTEXT *context)
178 {
179     STACK16FRAME *frame;
180     WORD ordinal;
181
182     if (!debugging_relay) return;
183     frame = CURRENT_STACK16;
184     printf( "Ret  %s() ", BUILTIN_GetEntryPoint16( frame->entry_cs,
185                                                    frame->entry_ip,
186                                                    &ordinal ));
187     switch(func_type)
188     {
189     case 0: /* long */
190         printf( "retval=0x%08x ret=%04x:%04x ds=%04x\n",
191                 ret_val, frame->cs, frame->ip, frame->ds );
192         break;
193     case 1: /* word */
194         printf( "retval=0x%04x ret=%04x:%04x ds=%04x\n",
195                 ret_val & 0xffff, frame->cs, frame->ip, frame->ds );
196         break;
197     case 2: /* regs */
198         printf( "retval=none ret=%04x:%04x ds=%04x\n",
199                 (WORD)CS_reg(context), IP_reg(context), (WORD)DS_reg(context));
200         printf( "     AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
201                 AX_reg(context), BX_reg(context), CX_reg(context),
202                 DX_reg(context), SI_reg(context), DI_reg(context),
203                 (WORD)ES_reg(context), EFL_reg(context) );
204         break;
205     }
206 }
207
208
209 /***********************************************************************
210  *           RELAY_Unimplemented16
211  *
212  * This function is called for unimplemented 16-bit entry points (declared
213  * as 'stub' in the spec file).
214  */
215 void RELAY_Unimplemented16(void)
216 {
217     WORD ordinal;
218     STACK16FRAME *frame = CURRENT_STACK16;
219     fprintf(stderr,"No handler for Win16 routine %s (called from %04x:%04x)\n",
220             BUILTIN_GetEntryPoint16(frame->entry_cs,frame->entry_ip,&ordinal),
221             frame->cs, frame->ip );
222     TASK_KillCurrentTask(1);
223 }
224
225
226 /***********************************************************************
227  *           RELAY_DebugCallTo16
228  *
229  * 'stack' points to the called function address on the 32-bit stack.
230  * Stack layout:
231  *  ...        ...
232  * (stack+8)   arg2
233  * (stack+4)   arg1
234  * (stack)     func to call
235  */
236 void RELAY_DebugCallTo16( int* stack, int nb_args )
237 {
238     THDB *thdb;
239
240     if (!debugging_relay) return;
241     thdb = THREAD_Current();
242
243     if (nb_args == -1)  /* Register function */
244     {
245         CONTEXT *context = (CONTEXT *)stack[0];
246         WORD *stack16 = (WORD *)THREAD_STACK16(thdb);
247         printf( "CallTo16(func=%04lx:%04x,ds=%04lx",
248                 CS_reg(context), IP_reg(context), DS_reg(context) );
249         nb_args = stack[1] / sizeof(WORD);
250         while (nb_args--) printf( ",0x%04x", *(--stack16) );
251         printf( ")\n" );
252         printf( "     AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x BP=%04x ES=%04x\n",
253                 AX_reg(context), BX_reg(context), CX_reg(context),
254                 DX_reg(context), SI_reg(context), DI_reg(context),
255                 BP_reg(context), (WORD)ES_reg(context) );
256     }
257     else
258     {
259         printf( "CallTo16(func=%04x:%04x,ds=%04x",
260                 HIWORD(stack[0]), LOWORD(stack[0]),
261                 SELECTOROF(thdb->cur_stack) );
262         stack++;
263         while (nb_args--) printf( ",0x%04x", *stack++ );
264         printf( ")\n" );
265     }
266 }
267
268
269 /**********************************************************************
270  *           Catch    (KERNEL.55)
271  *
272  * Real prototype is:
273  *   INT16 WINAPI Catch( LPCATCHBUF lpbuf );
274  */
275 void WINAPI Catch( CONTEXT *context )
276 {
277     VA_LIST16 valist;
278     SEGPTR buf;
279     LPCATCHBUF lpbuf;
280
281     VA_START16( valist );
282     buf   = VA_ARG16( valist, SEGPTR );
283     lpbuf = (LPCATCHBUF)PTR_SEG_TO_LIN( buf );
284     VA_END16( valist );
285
286     /* Note: we don't save the current ss, as the catch buffer is */
287     /* only 9 words long. Hopefully no one will have the silly    */
288     /* idea to change the current stack before calling Throw()... */
289
290     /* Windows uses:
291      * lpbuf[0] = ip
292      * lpbuf[1] = cs
293      * lpbuf[2] = sp
294      * lpbuf[3] = bp
295      * lpbuf[4] = si
296      * lpbuf[5] = di
297      * lpbuf[6] = ds
298      * lpbuf[7] = unused
299      * lpbuf[8] = ss
300      */
301
302     lpbuf[0] = IP_reg(context);
303     lpbuf[1] = CS_reg(context);
304     lpbuf[2] = SP_reg(context);
305     lpbuf[3] = BP_reg(context);
306     lpbuf[4] = SI_reg(context);
307     lpbuf[5] = DI_reg(context);
308     lpbuf[6] = DS_reg(context);
309     lpbuf[7] = 0;
310     lpbuf[8] = SS_reg(context);
311     AX_reg(context) = 0;  /* Return 0 */
312 }
313
314
315 /**********************************************************************
316  *           Throw    (KERNEL.56)
317  *
318  * Real prototype is:
319  *   INT16 WINAPI Throw( LPCATCHBUF lpbuf, INT16 retval );
320  */
321 void WINAPI Throw( CONTEXT *context )
322 {
323     VA_LIST16 valist;
324     SEGPTR buf;
325     LPCATCHBUF lpbuf;
326     STACK16FRAME *pFrame;
327     STACK32FRAME *frame32;
328     THDB *thdb = THREAD_Current();
329
330     VA_START16( valist );
331     AX_reg(context) = VA_ARG16( valist, WORD );  /* retval */
332     buf    = VA_ARG16( valist, SEGPTR );
333     lpbuf  = (LPCATCHBUF)PTR_SEG_TO_LIN( buf );
334     VA_END16( valist );
335
336     /* Find the frame32 corresponding to the frame16 we are jumping to */
337     frame32 = THREAD_STACK16( thdb )->frame32;
338     while (frame32 && frame32->frame16)
339     {
340         if (OFFSETOF(frame32->frame16) > lpbuf[2]) break;
341         frame32 = ((STACK16FRAME *)PTR_SEG_TO_LIN(frame32->frame16))->frame32;
342     }
343
344     thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR( lpbuf[8], lpbuf[2]-sizeof(WORD) );
345     pFrame = THREAD_STACK16( thdb );
346     pFrame->frame32 = frame32;
347     IP_reg(context) = lpbuf[0];
348     CS_reg(context) = lpbuf[1];
349     BP_reg(context) = lpbuf[3];
350     SI_reg(context) = lpbuf[4];
351     DI_reg(context) = lpbuf[5];
352     DS_reg(context) = lpbuf[6];
353
354     if (debugging_relay)  /* Make sure we have a valid entry point address */
355     {
356         static FARPROC16 entryPoint = NULL;
357
358         if (!entryPoint)  /* Get entry point for Throw() */
359             entryPoint = MODULE_GetEntryPoint( GetModuleHandle16("KERNEL"),
360                                                56 );
361         pFrame->entry_cs = SELECTOROF(entryPoint);
362         pFrame->entry_ip = OFFSETOF(entryPoint);
363     }
364 }
365
366
367 /**********************************************************************
368  *           RELAY_CallProc32W
369  *
370  * Helper for CallProc[Ex]32W
371  */
372 static DWORD RELAY_CallProc32W(int Ex)
373 {
374         DWORD nrofargs, argconvmask;
375         FARPROC32 proc32;
376         DWORD *args, ret;
377         VA_LIST16 valist;
378         int i;
379
380         VA_START16( valist );
381         nrofargs    = VA_ARG16( valist, DWORD );
382         argconvmask = VA_ARG16( valist, DWORD );
383         proc32      = VA_ARG16( valist, FARPROC32 );
384         dprintf_relay(stddeb,"CallProc32W(%ld,%ld,%p, Ex%d args[",nrofargs,argconvmask,proc32,Ex);
385         args = (DWORD*)HEAP_xalloc( GetProcessHeap(), 0,
386                                     sizeof(DWORD)*nrofargs );
387         for (i=0;i<nrofargs;i++) {
388                 if (argconvmask & (1<<i))
389                 {
390                     SEGPTR ptr = VA_ARG16( valist, SEGPTR );
391                     args[nrofargs-i-1] = (DWORD)PTR_SEG_TO_LIN(ptr);
392                     dprintf_relay(stddeb,"%08lx(%p),",ptr,PTR_SEG_TO_LIN(ptr));
393                 }
394                 else
395                 {
396                     args[nrofargs-i-1] = VA_ARG16( valist, DWORD );
397                     dprintf_relay(stddeb,"%ld,",args[nrofargs-i-1]);
398                 }
399         }
400         dprintf_relay(stddeb,"]) - ");
401         VA_END16( valist );
402
403         switch (nrofargs) {
404         case 0: ret = proc32();
405                 break;
406         case 1: ret = proc32(args[0]);
407                 break;
408         case 2: ret = proc32(args[0],args[1]);
409                 break;
410         case 3: ret = proc32(args[0],args[1],args[2]);
411                 break;
412         case 4: ret = proc32(args[0],args[1],args[2],args[3]);
413                 break;
414         case 5: ret = proc32(args[0],args[1],args[2],args[3],args[4]);
415                 break;
416         case 6: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5]);
417                 break;
418         case 7: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
419                 break;
420         case 8: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
421                 break;
422         case 9: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
423                 break;
424         case 10:        ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
425                 break;
426         case 11:        ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
427                 break;
428         default:
429                 /* FIXME: should go up to 32  arguments */
430                 fprintf(stderr,"CallProc32W: unsupported number of arguments %ld, please report.\n",nrofargs);
431                 ret = 0;
432                 break;
433         }
434         /* POP nrofargs DWORD arguments and 3 DWORD parameters */
435         if (!Ex) STACK16_POP( THREAD_Current(),
436                               (3 + nrofargs) * sizeof(DWORD) );
437
438         dprintf_relay(stddeb,"returns %08lx\n",ret);
439         HeapFree( GetProcessHeap(), 0, args );
440         return ret;
441 }
442
443
444 /**********************************************************************
445  *           CallProc32W    (KERNEL.517)
446  */
447 DWORD WINAPI WIN16_CallProc32W()
448 {
449         return RELAY_CallProc32W(0);
450 }
451
452
453 /**********************************************************************
454 *           CallProcEx32W()   (KERNEL.518)        
455 *
456 *      C - style linkage to CallProc32W - caller pops stack.
457 */ 
458 DWORD WINAPI WIN16_CallProcEx32W()
459 {
460         return RELAY_CallProc32W(TRUE);
461 }