Release 971012
[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 "module.h"
13 #include "stackframe.h"
14 #include "task.h"
15 #include "xmalloc.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(), CALLTO16_Ret_regs();
38     extern DWORD CALLTO16_RetAddr_word;
39     extern DWORD CALLTO16_RetAddr_long;
40     extern DWORD CALLTO16_RetAddr_regs;
41
42     codesel = GLOBAL_CreateBlock( GMEM_FIXED, (void *)CALLTO16_Start,
43                                    (int)CALLTO16_End - (int)CALLTO16_Start,
44                                    0, TRUE, TRUE, FALSE, NULL );
45     if (!codesel) return FALSE;
46
47       /* Patch the return addresses for CallTo16 routines */
48
49     CALLTO16_RetAddr_word=MAKELONG( (int)CALLTO16_Ret_word-(int)CALLTO16_Start,
50                                     codesel );
51     CALLTO16_RetAddr_long=MAKELONG( (int)CALLTO16_Ret_long-(int)CALLTO16_Start,
52                                     codesel );
53     CALLTO16_RetAddr_regs=MAKELONG( (int)CALLTO16_Ret_regs-(int)CALLTO16_Start,
54                                     codesel );
55
56     /* Initialize thunking */
57
58     return THUNK_Init();
59 }
60
61
62 /***********************************************************************
63  *           RELAY_DebugCallFrom16
64  */
65 void RELAY_DebugCallFrom16( int func_type, char *args,
66                             void *entry_point, CONTEXT *context )
67 {
68     STACK16FRAME *frame;
69     WORD ordinal;
70     char *args16;
71     int i;
72
73     if (!debugging_relay) return;
74
75     frame = CURRENT_STACK16;
76     printf( "Call %s(", BUILTIN_GetEntryPoint16( frame->entry_cs,
77                                                  frame->entry_ip,
78                                                  &ordinal ));
79     VA_START16( args16 );
80     for (i = 0; i < strlen(args); i++)
81     {
82         switch(args[i])
83         {
84         case 'w':
85         case 's':
86             args16 += 2;
87             break;
88         case 'l':
89         case 'p':
90         case 't':
91         case 'T':
92             args16 += 4;
93             break;
94         }
95     }
96
97     while (*args)
98     {
99         switch(*args)
100         {
101         case 'w':
102         case 's':
103             args16 -= 2;
104             printf( "0x%04x", *(WORD *)args16 );
105             break;
106         case 'l':
107             args16 -= 4;
108             printf( "0x%08x", *(int *)args16 );
109             break;
110         case 't':
111             args16 -= 4;
112             printf( "0x%08x", *(int *)args16 );
113             if (HIWORD(*(int *)args16))
114                 printf( " \"%s\"", (char *)PTR_SEG_TO_LIN(*(int *)args16) );
115             break;
116         case 'p':
117             args16 -= 4;
118             printf( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
119             break;
120         case 'T':
121             args16 -= 4;
122             printf( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
123             if (HIWORD(*(int *)args16))
124                 printf( " \"%s\"", (char *)PTR_SEG_TO_LIN(*(int *)args16) );
125             break;
126         }
127         args++;
128         if (*args) printf( "," );
129     }
130     printf( ") ret=%04x:%04x ds=%04x\n", frame->cs, frame->ip, frame->ds );
131     VA_END16( args16 );
132
133     if (func_type == 2)  /* register function */
134         printf( "     AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
135                 AX_reg(context), BX_reg(context), CX_reg(context),
136                 DX_reg(context), SI_reg(context), DI_reg(context),
137                 (WORD)ES_reg(context), EFL_reg(context) );
138 }
139
140
141 /***********************************************************************
142  *           RELAY_DebugCallFrom16Ret
143  */
144 void RELAY_DebugCallFrom16Ret( int func_type, int ret_val, CONTEXT *context)
145 {
146     STACK16FRAME *frame;
147     WORD ordinal;
148
149     if (!debugging_relay) return;
150     frame = CURRENT_STACK16;
151     printf( "Ret  %s() ", BUILTIN_GetEntryPoint16( frame->entry_cs,
152                                                    frame->entry_ip,
153                                                    &ordinal ));
154     switch(func_type)
155     {
156     case 0: /* long */
157         printf( "retval=0x%08x ret=%04x:%04x ds=%04x\n",
158                 ret_val, frame->cs, frame->ip, frame->ds );
159         break;
160     case 1: /* word */
161         printf( "retval=0x%04x ret=%04x:%04x ds=%04x\n",
162                 ret_val & 0xffff, frame->cs, frame->ip, frame->ds );
163         break;
164     case 2: /* regs */
165         printf( "retval=none ret=%04x:%04x ds=%04x\n",
166                 (WORD)CS_reg(context), IP_reg(context), (WORD)DS_reg(context));
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         break;
172     }
173 }
174
175
176 /***********************************************************************
177  *           RELAY_Unimplemented16
178  *
179  * This function is called for unimplemented 16-bit entry points (declared
180  * as 'stub' in the spec file).
181  */
182 void RELAY_Unimplemented16(void)
183 {
184     WORD ordinal;
185     STACK16FRAME *frame = CURRENT_STACK16;
186     fprintf(stderr,"No handler for Win16 routine %s (called from %04x:%04x)\n",
187             BUILTIN_GetEntryPoint16(frame->entry_cs,frame->entry_ip,&ordinal),
188             frame->cs, frame->ip );
189     TASK_KillCurrentTask(1);
190 }
191
192
193 /***********************************************************************
194  *           RELAY_DebugCallTo16
195  *
196  * 'stack' points to the called function address on the 32-bit stack.
197  * Stack layout:
198  *  ...        ...
199  * (stack+8)   arg2
200  * (stack+4)   arg1
201  * (stack)     func to call
202  */
203 void RELAY_DebugCallTo16( int* stack, int nb_args )
204 {
205     if (!debugging_relay) return;
206
207     if (nb_args == -1)  /* Register function */
208     {
209         CONTEXT *context = (CONTEXT *)stack[0];
210         WORD *stack16 = (WORD *)CURRENT_STACK16 - 2 /* for saved %%esp */;
211         printf( "CallTo16(func=%04lx:%04x,ds=%04lx",
212                 CS_reg(context), IP_reg(context), DS_reg(context) );
213         nb_args = -stack[1] / sizeof(WORD);
214         while (nb_args--) printf( ",0x%04x", *(--stack16) );
215         printf( ")\n" );
216         printf( "     AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x BP=%04x ES=%04x\n",
217                 AX_reg(context), BX_reg(context), CX_reg(context),
218                 DX_reg(context), SI_reg(context), DI_reg(context),
219                 BP_reg(context), (WORD)ES_reg(context) );
220     }
221     else
222     {
223         printf( "CallTo16(func=%04x:%04x,ds=%04x",
224                 HIWORD(stack[0]), LOWORD(stack[0]),
225                 SELECTOROF(IF1632_Saved16_ss_sp) );
226         stack++;
227         while (nb_args--) printf( ",0x%04x", *stack++ );
228         printf( ")\n" );
229     }
230 }
231
232
233 /***********************************************************************
234  *           RELAY_CallFrom32
235  *
236  * Stack layout on entry to this function:
237  *  ...      ...
238  * (esp+12)  arg2
239  * (esp+8)   arg1
240  * (esp+4)   ret_addr
241  * (esp)     return addr to relay code
242  */
243 int RELAY_CallFrom32( int ret_addr, ... )
244 {
245     int i, ret;
246     char buffer[80];
247     FARPROC32 func;
248
249     int *args = &ret_addr;
250     /* Relay addr is the return address for this function */
251     BYTE *relay_addr = (BYTE *)args[-1];
252     WORD nb_args = *(WORD *)(relay_addr + 1) / sizeof(int);
253
254     assert(debugging_relay);
255     func = BUILTIN_GetEntryPoint32( buffer, relay_addr - 5 );
256     printf( "Call %s(", buffer );
257     args++;
258     for (i = 0; i < nb_args; i++)
259     {
260         if (i) printf( "," );
261         printf( "%08x", args[i] );
262     }
263     printf( ") ret=%08x\n", ret_addr );
264     if (*relay_addr == 0xc3) /* cdecl */
265     {
266         LRESULT (*cfunc)() = (LRESULT(*)())func;
267         switch(nb_args)
268         {
269         case 0: ret = cfunc(); break;
270         case 1: ret = cfunc(args[0]); break;
271         case 2: ret = cfunc(args[0],args[1]); break;
272         case 3: ret = cfunc(args[0],args[1],args[2]); break;
273         case 4: ret = cfunc(args[0],args[1],args[2],args[3]); break;
274         case 5: ret = cfunc(args[0],args[1],args[2],args[3],args[4]); break;
275         case 6: ret = cfunc(args[0],args[1],args[2],args[3],args[4],
276                             args[5]); break;
277         case 7: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
278                             args[6]); break;
279         case 8: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
280                             args[6],args[7]); break;
281         case 9: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
282                             args[6],args[7],args[8]); break;
283         case 10: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
284                              args[6],args[7],args[8],args[9]); break;
285         case 11: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
286                              args[6],args[7],args[8],args[9],args[10]); break;
287         case 12: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
288                              args[6],args[7],args[8],args[9],args[10],
289                              args[11]); break;
290         case 13: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
291                              args[6],args[7],args[8],args[9],args[10],args[11],
292                              args[12]); break;
293         case 14: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
294                              args[6],args[7],args[8],args[9],args[10],args[11],
295                              args[12],args[13]); break;
296         case 15: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
297                              args[6],args[7],args[8],args[9],args[10],args[11],
298                              args[12],args[13],args[14]); break;
299         default:
300             fprintf( stderr, "RELAY_CallFrom32: Unsupported nb args %d\n",
301                      nb_args );
302             assert(FALSE);
303         }
304     }
305     else  /* stdcall */
306     {
307         switch(nb_args)
308         {
309         case 0: ret = func(); break;
310         case 1: ret = func(args[0]); break;
311         case 2: ret = func(args[0],args[1]); break;
312         case 3: ret = func(args[0],args[1],args[2]); break;
313         case 4: ret = func(args[0],args[1],args[2],args[3]); break;
314         case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break;
315         case 6: ret = func(args[0],args[1],args[2],args[3],args[4],
316                            args[5]); break;
317         case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
318                            args[6]); break;
319         case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
320                            args[6],args[7]); break;
321         case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
322                            args[6],args[7],args[8]); break;
323         case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
324                             args[6],args[7],args[8],args[9]); break;
325         case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
326                             args[6],args[7],args[8],args[9],args[10]); break;
327         case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
328                             args[6],args[7],args[8],args[9],args[10],
329                             args[11]); break;
330         case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
331                             args[6],args[7],args[8],args[9],args[10],args[11],
332                             args[12]); break;
333         case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
334                             args[6],args[7],args[8],args[9],args[10],args[11],
335                             args[12],args[13]); break;
336         case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
337                             args[6],args[7],args[8],args[9],args[10],args[11],
338                             args[12],args[13],args[14]); break;
339         default:
340             fprintf( stderr, "RELAY_CallFrom32: Unsupported nb args %d\n",
341                      nb_args );
342             assert(FALSE);
343         }
344     }
345     printf( "Ret  %s() retval=%08x ret=%08x\n", buffer, ret, ret_addr );
346     return ret;
347 }
348
349
350 /***********************************************************************
351  *           RELAY_CallFrom32Regs
352  *
353  * 'stack' points to the relay addr on the stack.
354  * Stack layout:
355  *  ...      ...
356  * (esp+216) ret_addr
357  * (esp+212) return to relay debugging code (only when debugging_relay)
358  * (esp+208) entry point to call
359  * (esp+4)   CONTEXT
360  * (esp)     return addr to relay code
361  */
362 void RELAY_CallFrom32Regs( CONTEXT context,
363                            void (CALLBACK *entry_point)(CONTEXT *),
364                            BYTE *relay_addr, int ret_addr )
365 {
366     if (!debugging_relay)
367     {
368         /* Simply call the entry point */
369         entry_point( &context );
370     }
371     else
372     {
373         char buffer[80];
374
375         /* Fixup the context structure because of the extra parameter */
376         /* pushed by the relay debugging code */
377
378         EIP_reg(&context) = ret_addr;
379         ESP_reg(&context) += sizeof(int);
380
381         BUILTIN_GetEntryPoint32( buffer, relay_addr - 5 );
382         printf("Call %s(regs) ret=%08x\n", buffer, ret_addr );
383         printf(" EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx ESI=%08lx EDI=%08lx\n",
384                 EAX_reg(&context), EBX_reg(&context), ECX_reg(&context),
385                 EDX_reg(&context), ESI_reg(&context), EDI_reg(&context) );
386         printf(" EBP=%08lx ESP=%08lx EIP=%08lx DS=%04lx ES=%04lx FS=%04lx GS=%04lx EFL=%08lx\n",
387                 EBP_reg(&context), ESP_reg(&context), EIP_reg(&context),
388                 DS_reg(&context), ES_reg(&context), FS_reg(&context),
389                 GS_reg(&context), EFL_reg(&context) );
390
391         /* Now call the real function */
392         entry_point( &context );
393
394         printf("Ret  %s() retval=regs ret=%08x\n", buffer, ret_addr );
395         printf(" EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx ESI=%08lx EDI=%08lx\n",
396                 EAX_reg(&context), EBX_reg(&context), ECX_reg(&context),
397                 EDX_reg(&context), ESI_reg(&context), EDI_reg(&context) );
398         printf(" EBP=%08lx ESP=%08lx EIP=%08lx DS=%04lx ES=%04lx FS=%04lx GS=%04lx EFL=%08lx\n",
399                 EBP_reg(&context), ESP_reg(&context), EIP_reg(&context),
400                 DS_reg(&context), ES_reg(&context), FS_reg(&context),
401                 GS_reg(&context), EFL_reg(&context) );
402     }
403 }
404
405
406 /***********************************************************************
407  *           RELAY_Unimplemented32
408  *
409  * This function is called for unimplemented 32-bit entry points (declared
410  * as 'stub' in the spec file).
411  */
412 void RELAY_Unimplemented32( const char *dll_name, int ordinal,
413                             const char *func_name, int ret_addr )
414 {
415     __RESTORE_ES;  /* Just in case */
416     fprintf( stderr, "No handler for Win32 routine %s.%d: %s (called from %08x)\n",
417              dll_name, ordinal, func_name, ret_addr );
418     TASK_KillCurrentTask(1);
419 }
420
421
422 /**********************************************************************
423  *           Catch    (KERNEL.55)
424  *
425  * Real prototype is:
426  *   INT16 WINAPI Catch( LPCATCHBUF lpbuf );
427  */
428 void WINAPI Catch( CONTEXT *context )
429 {
430     VA_LIST16 valist;
431     SEGPTR buf;
432     LPCATCHBUF lpbuf;
433     STACK16FRAME *pFrame = CURRENT_STACK16;
434
435     VA_START16( valist );
436     buf   = VA_ARG16( valist, SEGPTR );
437     lpbuf = (LPCATCHBUF)PTR_SEG_TO_LIN( buf );
438     VA_END16( valist );
439
440     /* Note: we don't save the current ss, as the catch buffer is */
441     /* only 9 words long. Hopefully no one will have the silly    */
442     /* idea to change the current stack before calling Throw()... */
443
444     /* Windows uses:
445      * lpbuf[0] = ip
446      * lpbuf[1] = cs
447      * lpbuf[2] = sp
448      * lpbuf[3] = bp
449      * lpbuf[4] = si
450      * lpbuf[5] = di
451      * lpbuf[6] = ds
452      * lpbuf[7] = unused
453      * lpbuf[8] = ss
454      */
455
456     lpbuf[0] = IP_reg(context);
457     lpbuf[1] = CS_reg(context);
458     lpbuf[2] = LOWORD(pFrame->saved_ss_sp);
459     lpbuf[3] = BP_reg(context);
460     lpbuf[4] = SI_reg(context);
461     lpbuf[5] = DI_reg(context);
462     lpbuf[6] = DS_reg(context);
463     lpbuf[7] = OFFSETOF(IF1632_Saved16_ss_sp);
464     lpbuf[8] = HIWORD(pFrame->saved_ss_sp);
465     AX_reg(context) = 0;  /* Return 0 */
466 }
467
468
469 /**********************************************************************
470  *           Throw    (KERNEL.56)
471  *
472  * Real prototype is:
473  *   INT16 WINAPI Throw( LPCATCHBUF lpbuf, INT16 retval );
474  */
475 void WINAPI Throw( CONTEXT *context )
476 {
477     VA_LIST16 valist;
478     SEGPTR buf;
479     LPCATCHBUF lpbuf;
480     STACK16FRAME *pFrame;
481
482     VA_START16( valist );
483     AX_reg(context) = VA_ARG16( valist, WORD );  /* retval */
484     buf    = VA_ARG16( valist, SEGPTR );
485     lpbuf  = (LPCATCHBUF)PTR_SEG_TO_LIN( buf );
486     VA_END16( valist );
487
488     IF1632_Saved16_ss_sp = MAKELONG( lpbuf[7] - sizeof(WORD),
489                                      HIWORD(IF1632_Saved16_ss_sp) );
490     pFrame = CURRENT_STACK16;
491     pFrame->saved_ss_sp = MAKELONG( lpbuf[2], lpbuf[8] );
492     IP_reg(context) = lpbuf[0];
493     CS_reg(context) = lpbuf[1];
494     BP_reg(context) = lpbuf[3];
495     SI_reg(context) = lpbuf[4];
496     DI_reg(context) = lpbuf[5];
497     DS_reg(context) = lpbuf[6];
498
499     if (debugging_relay)  /* Make sure we have a valid entry point address */
500     {
501         static FARPROC16 entryPoint = NULL;
502
503         if (!entryPoint)  /* Get entry point for Throw() */
504             entryPoint = MODULE_GetEntryPoint( GetModuleHandle16("KERNEL"),
505                                                56 );
506         pFrame->entry_cs = SELECTOROF(entryPoint);
507         pFrame->entry_ip = OFFSETOF(entryPoint);
508     }
509 }
510
511 /**********************************************************************
512  *           CallProc32W    (KERNEL.517)
513  */
514 DWORD WINAPI WIN16_CallProc32W()
515 {
516         DWORD nrofargs, argconvmask;
517         FARPROC32 proc32;
518         DWORD *args, ret;
519         VA_LIST16 valist;
520         int i;
521
522         VA_START16( valist );
523         nrofargs    = VA_ARG16( valist, DWORD );
524         argconvmask = VA_ARG16( valist, DWORD );
525         proc32      = VA_ARG16( valist, FARPROC32 );
526         fprintf(stderr,"CallProc32W(%ld,%ld,%p,args[",nrofargs,argconvmask,proc32);
527         args = (DWORD*)xmalloc(sizeof(DWORD)*nrofargs);
528         for (i=nrofargs;i--;) {
529                 if (argconvmask & (1<<i))
530                 {
531                     SEGPTR ptr = VA_ARG16( valist, SEGPTR );
532                     args[nrofargs-i-1] = (DWORD)PTR_SEG_TO_LIN(ptr);
533                     fprintf(stderr,"%08lx(%p),",ptr,PTR_SEG_TO_LIN(ptr));
534                 }
535                 else
536                 {
537                     args[nrofargs-i-1] = VA_ARG16( valist, DWORD );
538                     fprintf(stderr,"%ld,",args[nrofargs-i-1]);
539                 }
540         }
541         fprintf(stderr,"]) - ");
542         VA_END16( valist );
543
544         switch (nrofargs) {
545         case 0: ret = proc32();
546                 break;
547         case 1: ret = proc32(args[0]);
548                 break;
549         case 2: ret = proc32(args[0],args[1]);
550                 break;
551         case 3: ret = proc32(args[0],args[1],args[2]);
552                 break;
553         case 4: ret = proc32(args[0],args[1],args[2],args[3]);
554                 break;
555         case 5: ret = proc32(args[0],args[1],args[2],args[3],args[4]);
556                 break;
557         case 6: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5]);
558                 break;
559         case 7: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
560                 break;
561         default:
562                 /* FIXME: should go up to 32  arguments */
563                 fprintf(stderr,"CallProc32W: unsupported number of arguments %ld, please report.\n",nrofargs);
564                 ret = 0;
565                 break;
566         }
567         /* POP nrofargs DWORD arguments and 3 DWORD parameters */
568         STACK16_POP( (3 + nrofargs) * sizeof(DWORD) );
569
570         fprintf(stderr,"returns %08lx\n",ret);
571         free(args);
572         return ret;
573 }