Fixed some bugs in MCI message mapping (32A => 16).
[wine] / if1632 / relay.c
1 /*
2  * Copyright 1993 Robert J. Amstadt
3  * Copyright 1995 Alexandre Julliard
4  */
5
6 #include <assert.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include "wine/winbase16.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 "debugstr.h"
17 #include "debug.h"
18 #include "main.h"
19
20
21 /***********************************************************************
22  *           RELAY_Init
23  */
24 BOOL RELAY_Init(void)
25 {
26     WORD codesel;
27
28       /* Allocate the code selector for CallTo16 routines */
29
30     extern void CALLTO16_Start(), CALLTO16_End();
31     extern void CALLTO16_Ret_word(), CALLTO16_Ret_long();
32     extern void CALLTO16_Ret_eax();
33     extern void CALL32_CBClient_Ret();
34     extern void CALL32_CBClientEx_Ret();
35     extern DWORD CALLTO16_RetAddr_word;
36     extern DWORD CALLTO16_RetAddr_long;
37     extern DWORD CALLTO16_RetAddr_eax;
38     extern DWORD CALL32_CBClient_RetAddr;
39     extern DWORD CALL32_CBClientEx_RetAddr;
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     CALLTO16_RetAddr_eax =MAKELONG( (int)CALLTO16_Ret_eax -(int)CALLTO16_Start,
53                                     codesel );
54     CALL32_CBClient_RetAddr = 
55         MAKELONG( (int)CALL32_CBClient_Ret -(int)CALLTO16_Start, codesel );
56     CALL32_CBClientEx_RetAddr = 
57         MAKELONG( (int)CALL32_CBClientEx_Ret -(int)CALLTO16_Start, codesel );
58
59     /* Create built-in modules */
60     if (!BUILTIN_Init()) return FALSE;
61
62     /* Initialize thunking */
63     return THUNK_Init();
64 }
65
66
67 /* from relay32/relay386.c */
68 extern char **debug_relay_excludelist,**debug_relay_includelist;
69
70 /***********************************************************************
71  *           RELAY_DebugCallFrom16
72  */
73 void RELAY_DebugCallFrom16( int func_type, char *args,
74                             void *entry_point, CONTEXT *context )
75 {
76     STACK16FRAME *frame;
77     WORD ordinal;
78     char *args16;
79     const char *funstr;
80     int i;
81
82     if (!TRACE_ON(relay)) return;
83
84     frame = CURRENT_STACK16;
85     funstr = BUILTIN_GetEntryPoint16(frame->entry_cs,frame->entry_ip,&ordinal);
86     if (!funstr) return; /* happens for the two snoop register relays */
87     if (!RELAY_ShowDebugmsgRelay(funstr)) return;
88     DPRINTF( "Call %s(",funstr);
89     VA_START16( args16 );
90
91     if (func_type & 4)  /* cdecl */
92     {
93         while (*args)
94         {
95             switch(*args)
96             {
97             case 'w':
98             case 's':
99                 DPRINTF( "0x%04x", *(WORD *)args16 );
100                 args16 += 2;
101                 break;
102             case 'l':
103                 DPRINTF( "0x%08x", *(int *)args16 );
104                 args16 += 4;
105                 break;
106             case 't':
107                 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
108                 if (HIWORD(*(SEGPTR *)args16))
109                     debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
110                 args16 += 4;
111                 break;
112             case 'p':
113                 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
114                 args16 += 4;
115                 break;
116             case 'T':
117                 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
118                 if (HIWORD( *(SEGPTR *)args16 ))
119                     debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
120                 args16 += 4;
121                 break;
122             }
123             args++;
124             if (*args) DPRINTF( "," );
125         }
126     }
127     else  /* not cdecl */
128     {
129         /* Start with the last arg */
130         for (i = 0; args[i]; i++)
131         {
132             switch(args[i])
133             {
134             case 'w':
135             case 's':
136                 args16 += 2;
137                 break;
138             case 'l':
139             case 'p':
140             case 't':
141             case 'T':
142                 args16 += 4;
143                 break;
144             }
145         }
146
147         while (*args)
148         {
149             switch(*args)
150             {
151             case 'w':
152             case 's':
153                 args16 -= 2;
154                 DPRINTF( "0x%04x", *(WORD *)args16 );
155                 break;
156             case 'l':
157                 args16 -= 4;
158                 DPRINTF( "0x%08x", *(int *)args16 );
159                 break;
160             case 't':
161                 args16 -= 4;
162                 DPRINTF( "0x%08x", *(int *)args16 );
163                 if (HIWORD(*(SEGPTR *)args16))
164                     debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
165                 break;
166             case 'p':
167                 args16 -= 4;
168                 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
169                 break;
170             case 'T':
171                 args16 -= 4;
172                 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
173                 if (HIWORD( *(SEGPTR *)args16 ))
174                     debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
175                 break;
176             }
177             args++;
178             if (*args) DPRINTF( "," );
179         }
180     }
181
182     DPRINTF( ") ret=%04x:%04x ds=%04x\n", frame->cs, frame->ip, frame->ds );
183     VA_END16( args16 );
184
185     if (func_type & 2)  /* register function */
186         DPRINTF( "     AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
187                  AX_reg(context), BX_reg(context), CX_reg(context),
188                  DX_reg(context), SI_reg(context), DI_reg(context),
189                  (WORD)ES_reg(context), EFL_reg(context) );
190 }
191
192
193 /***********************************************************************
194  *           RELAY_DebugCallFrom16Ret
195  */
196 void RELAY_DebugCallFrom16Ret( int func_type, int ret_val, CONTEXT *context)
197 {
198     STACK16FRAME *frame;
199     WORD ordinal;
200     const char *funstr;
201
202     if (!TRACE_ON(relay)) return;
203     frame = CURRENT_STACK16;
204     funstr = BUILTIN_GetEntryPoint16(frame->entry_cs,frame->entry_ip,&ordinal);
205     if (!funstr) return;
206     if (!RELAY_ShowDebugmsgRelay(funstr)) return;
207     DPRINTF( "Ret  %s() ",funstr);
208     switch(func_type)
209     {
210     case 0: /* long */
211         DPRINTF( "retval=0x%08x ret=%04x:%04x ds=%04x\n",
212                  ret_val, frame->cs, frame->ip, frame->ds );
213         break;
214     case 1: /* word */
215         DPRINTF( "retval=0x%04x ret=%04x:%04x ds=%04x\n",
216                  ret_val & 0xffff, frame->cs, frame->ip, frame->ds );
217         break;
218     case 2: /* regs */
219         DPRINTF("retval=none ret=%04x:%04x ds=%04x\n",
220                 (WORD)CS_reg(context), IP_reg(context), (WORD)DS_reg(context));
221         DPRINTF("     AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
222                 AX_reg(context), BX_reg(context), CX_reg(context),
223                 DX_reg(context), SI_reg(context), DI_reg(context),
224                 (WORD)ES_reg(context), EFL_reg(context) );
225         break;
226     }
227 }
228
229
230 /***********************************************************************
231  *           RELAY_Unimplemented16
232  *
233  * This function is called for unimplemented 16-bit entry points (declared
234  * as 'stub' in the spec file).
235  */
236 void RELAY_Unimplemented16(void)
237 {
238     WORD ordinal;
239     STACK16FRAME *frame = CURRENT_STACK16;
240     MSG("No handler for Win16 routine %s (called from %04x:%04x)\n",
241             BUILTIN_GetEntryPoint16(frame->entry_cs,frame->entry_ip,&ordinal),
242             frame->cs, frame->ip );
243     ExitProcess(1);
244 }
245
246
247 /***********************************************************************
248  *           RELAY_DebugCallTo16
249  *
250  * 'stack' points to the called function address on the 32-bit stack.
251  * Stack layout:
252  *  ...        ...
253  * (stack+8)   arg2
254  * (stack+4)   arg1
255  * (stack)     func to call
256  */
257 void RELAY_DebugCallTo16( int* stack, int nb_args )
258 {
259     THDB *thdb;
260
261     if (!TRACE_ON(relay)) return;
262     thdb = THREAD_Current();
263
264     if (nb_args == -1)  /* Register function */
265     {
266         CONTEXT *context = (CONTEXT *)stack[0];
267         WORD *stack16 = (WORD *)THREAD_STACK16(thdb);
268         DPRINTF("CallTo16(func=%04lx:%04x,ds=%04lx",
269                 CS_reg(context), IP_reg(context), DS_reg(context) );
270         nb_args = stack[1] / sizeof(WORD);
271         while (nb_args--) {
272             --stack16;
273             DPRINTF( ",0x%04x", *stack16 );
274         }
275         DPRINTF(") ss:sp=%04x:%04x\n", SELECTOROF(thdb->cur_stack),
276                 OFFSETOF(thdb->cur_stack) );
277         DPRINTF("     AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x BP=%04x ES=%04x FS=%04x\n",
278                 AX_reg(context), BX_reg(context), CX_reg(context),
279                 DX_reg(context), SI_reg(context), DI_reg(context),
280                 BP_reg(context), (WORD)ES_reg(context), (WORD)FS_reg(context) );
281     }
282     else
283     {
284         DPRINTF("CallTo16(func=%04x:%04x,ds=%04x",
285                 HIWORD(stack[0]), LOWORD(stack[0]),
286                 SELECTOROF(thdb->cur_stack) );
287         stack++;
288         while (nb_args--) {
289             DPRINTF(",0x%04x", *stack );
290             stack++;
291         }
292         DPRINTF(") ss:sp=%04x:%04x\n", SELECTOROF(thdb->cur_stack),
293                 OFFSETOF(thdb->cur_stack) );
294     }
295 }
296
297
298 /***********************************************************************
299  *           RELAY_DebugCallTo16Ret
300  */
301 void RELAY_DebugCallTo16Ret( int ret_val )
302 {
303     THDB *thdb;
304
305     if (!TRACE_ON(relay)) return;
306     thdb = THREAD_Current();
307
308     DPRINTF("CallTo16() ss:sp=%04x:%04x retval=0x%08x\n", 
309             SELECTOROF(thdb->cur_stack), OFFSETOF(thdb->cur_stack), ret_val);
310 }
311
312
313 /**********************************************************************
314  *           Catch    (KERNEL.55)
315  *
316  * Real prototype is:
317  *   INT16 WINAPI Catch( LPCATCHBUF lpbuf );
318  */
319 void WINAPI Catch16( CONTEXT *context )
320 {
321     VA_LIST16 valist;
322     SEGPTR buf;
323     LPCATCHBUF lpbuf;
324
325     VA_START16( valist );
326     buf   = VA_ARG16( valist, SEGPTR );
327     lpbuf = (LPCATCHBUF)PTR_SEG_TO_LIN( buf );
328     VA_END16( valist );
329
330     /* Note: we don't save the current ss, as the catch buffer is */
331     /* only 9 words long. Hopefully no one will have the silly    */
332     /* idea to change the current stack before calling Throw()... */
333
334     /* Windows uses:
335      * lpbuf[0] = ip
336      * lpbuf[1] = cs
337      * lpbuf[2] = sp
338      * lpbuf[3] = bp
339      * lpbuf[4] = si
340      * lpbuf[5] = di
341      * lpbuf[6] = ds
342      * lpbuf[7] = unused
343      * lpbuf[8] = ss
344      */
345
346     lpbuf[0] = IP_reg(context);
347     lpbuf[1] = CS_reg(context);
348     /* Windows pushes 4 more words before saving sp */
349     lpbuf[2] = SP_reg(context) - 4 * sizeof(WORD);
350     lpbuf[3] = BP_reg(context);
351     lpbuf[4] = SI_reg(context);
352     lpbuf[5] = DI_reg(context);
353     lpbuf[6] = DS_reg(context);
354     lpbuf[7] = 0;
355     lpbuf[8] = SS_reg(context);
356     AX_reg(context) = 0;  /* Return 0 */
357 }
358
359
360 /**********************************************************************
361  *           Throw    (KERNEL.56)
362  *
363  * Real prototype is:
364  *   INT16 WINAPI Throw( LPCATCHBUF lpbuf, INT16 retval );
365  */
366 void WINAPI Throw16( CONTEXT *context )
367 {
368     VA_LIST16 valist;
369     SEGPTR buf;
370     LPCATCHBUF lpbuf;
371     STACK16FRAME *pFrame;
372     STACK32FRAME *frame32;
373     THDB *thdb = THREAD_Current();
374
375     VA_START16( valist );
376     AX_reg(context) = VA_ARG16( valist, WORD );  /* retval */
377     buf    = VA_ARG16( valist, SEGPTR );
378     lpbuf  = (LPCATCHBUF)PTR_SEG_TO_LIN( buf );
379     VA_END16( valist );
380
381     /* Find the frame32 corresponding to the frame16 we are jumping to */
382     pFrame = THREAD_STACK16( thdb );
383     frame32 = THREAD_STACK16( thdb )->frame32;
384     while (frame32 && frame32->frame16)
385     {
386         if (OFFSETOF(frame32->frame16) < OFFSETOF(thdb->cur_stack))
387             break;  /* Something strange is going on */
388         if (OFFSETOF(frame32->frame16) > lpbuf[2])
389         {
390             /* We found the right frame */
391             pFrame->frame32 = frame32;
392             break;
393         }
394         frame32 = ((STACK16FRAME *)PTR_SEG_TO_LIN(frame32->frame16))->frame32;
395     }
396
397     IP_reg(context) = lpbuf[0];
398     CS_reg(context) = lpbuf[1];
399     SP_reg(context) = lpbuf[2] + 4 * sizeof(WORD) - sizeof(WORD) /*extra arg*/;
400     BP_reg(context) = lpbuf[3];
401     SI_reg(context) = lpbuf[4];
402     DI_reg(context) = lpbuf[5];
403     DS_reg(context) = lpbuf[6];
404
405     if (lpbuf[8] != SS_reg(context))
406         ERR(relay, "Switching stack segment with Throw() not supported; expect crash now\n" );
407
408     if (TRACE_ON(relay))  /* Make sure we have a valid entry point address */
409     {
410         static FARPROC16 entryPoint = NULL;
411
412         if (!entryPoint)  /* Get entry point for Throw() */
413             entryPoint = NE_GetEntryPoint( GetModuleHandle16("KERNEL"), 56 );
414         pFrame->entry_cs = SELECTOROF(entryPoint);
415         pFrame->entry_ip = OFFSETOF(entryPoint);
416     }
417 }
418
419
420 /**********************************************************************
421  *           RELAY_CallProc32W
422  *
423  * Helper for CallProc[Ex]32W
424  */
425 static DWORD RELAY_CallProc32W(int Ex)
426 {
427         DWORD nrofargs, argconvmask;
428         FARPROC proc32;
429         DWORD *args, ret;
430         VA_LIST16 valist;
431         int i;
432         int aix;
433         dbg_decl_str(relay, 1024);
434
435         VA_START16( valist );
436         nrofargs    = VA_ARG16( valist, DWORD );
437         argconvmask = VA_ARG16( valist, DWORD );
438         proc32      = VA_ARG16( valist, FARPROC );
439         dsprintf(relay, "CallProc32W(%ld,%ld,%p, Ex%d args[",nrofargs,argconvmask,proc32,Ex);
440         args = (DWORD*)HEAP_xalloc( GetProcessHeap(), 0,
441                                     sizeof(DWORD)*nrofargs );
442         /* CallProcEx doesn't need its args reversed */
443         for (i=0;i<nrofargs;i++) {
444                 if (Ex) {
445                    aix = i;
446                 } else {
447                    aix = nrofargs - i - 1;
448                 }
449                 if (argconvmask & (1<<i))
450                 {
451                     SEGPTR ptr = VA_ARG16( valist, SEGPTR );
452                     args[aix] = (DWORD)PTR_SEG_TO_LIN(ptr);
453                     dsprintf(relay,"%08lx(%p),",ptr,PTR_SEG_TO_LIN(ptr));
454                 }
455                 else
456                 {
457                     args[aix] = VA_ARG16( valist, DWORD );
458                     dsprintf(relay,"%ld,",args[aix]);
459                 }
460         }
461         dsprintf(relay,"])");
462         VA_END16( valist );
463
464         if (!proc32) ret = 0;
465         else switch (nrofargs)
466         {
467         case 0: ret = proc32();
468                 break;
469         case 1: ret = proc32(args[0]);
470                 break;
471         case 2: ret = proc32(args[0],args[1]);
472                 break;
473         case 3: ret = proc32(args[0],args[1],args[2]);
474                 break;
475         case 4: ret = proc32(args[0],args[1],args[2],args[3]);
476                 break;
477         case 5: ret = proc32(args[0],args[1],args[2],args[3],args[4]);
478                 break;
479         case 6: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5]);
480                 break;
481         case 7: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
482                 break;
483         case 8: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
484                 break;
485         case 9: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
486                 break;
487         case 10:        ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
488                 break;
489         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]);
490                 break;
491         default:
492                 /* FIXME: should go up to 32  arguments */
493                 ERR(relay,"Unsupported number of arguments %ld, please report.\n",nrofargs);
494                 ret = 0;
495                 break;
496         }
497         /* POP nrofargs DWORD arguments and 3 DWORD parameters */
498         if (!Ex) STACK16_POP( THREAD_Current(),
499                               (3 + nrofargs) * sizeof(DWORD) );
500
501         TRACE(relay,"%s - returns %08lx\n",dbg_str(relay),ret);
502         HeapFree( GetProcessHeap(), 0, args );
503         return ret;
504 }
505
506
507 /**********************************************************************
508  *           CallProc32W    (KERNEL.517)
509  */
510 DWORD WINAPI CallProc32W_16()
511 {
512         return RELAY_CallProc32W(0);
513 }
514
515
516 /**********************************************************************
517 *           CallProcEx32W()   (KERNEL.518)
518 *
519 *      C - style linkage to CallProc32W - caller pops stack.
520 */
521 DWORD WINAPI CallProcEx32W_16()
522 {
523         return RELAY_CallProc32W(TRUE);
524 }