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