Global constructors using `.section .ctors' are bogus for NetBSD's
[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
18
19 /***********************************************************************
20  *           RELAY_Init
21  */
22 BOOL32 RELAY_Init(void)
23 {
24     WORD codesel;
25     extern BOOL32 THUNK_Init(void);
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 DWORD CALLTO16_RetAddr_word;
34     extern DWORD CALLTO16_RetAddr_long;
35     extern DWORD CALLTO16_RetAddr_eax;
36     extern DWORD CALL32_CBClient_RetAddr;
37
38     codesel = GLOBAL_CreateBlock( GMEM_FIXED, (void *)CALLTO16_Start,
39                                    (int)CALLTO16_End - (int)CALLTO16_Start,
40                                    0, TRUE, TRUE, FALSE, NULL );
41     if (!codesel) return FALSE;
42
43       /* Patch the return addresses for CallTo16 routines */
44
45     CALLTO16_RetAddr_word=MAKELONG( (int)CALLTO16_Ret_word-(int)CALLTO16_Start,
46                                     codesel );
47     CALLTO16_RetAddr_long=MAKELONG( (int)CALLTO16_Ret_long-(int)CALLTO16_Start,
48                                     codesel );
49     CALLTO16_RetAddr_eax =MAKELONG( (int)CALLTO16_Ret_eax -(int)CALLTO16_Start,
50                                     codesel );
51     CALL32_CBClient_RetAddr = 
52         MAKELONG( (int)CALL32_CBClient_Ret -(int)CALLTO16_Start, codesel );
53
54     /* Create built-in modules */
55     if (!BUILTIN_Init()) return FALSE;
56
57     /* Initialize thunking */
58     return THUNK_Init();
59 }
60
61
62     /* from relay32/relay386.c */
63     extern debug_relay_includelist;
64     extern debug_relay_excludelist;
65
66 /***********************************************************************
67  *           RELAY_DebugCallFrom16
68  */
69 void RELAY_DebugCallFrom16( int func_type, char *args,
70                             void *entry_point, CONTEXT *context )
71 {
72     STACK16FRAME *frame;
73     WORD ordinal;
74     char *args16;
75     const char *funstr;
76     int i;
77     /* from relay32/relay386.c */
78     extern int RELAY_ShowDebugmsgRelay(const char *);
79
80     if (!TRACE_ON(relay)) return;
81
82     frame = CURRENT_STACK16;
83     funstr = BUILTIN_GetEntryPoint16(frame->entry_cs,frame->entry_ip,&ordinal);
84     if (!funstr) return; /* happens for the two snoop register relays */
85     if (!RELAY_ShowDebugmsgRelay(funstr)) return;
86     DPRINTF( "Call %s(",funstr);
87     VA_START16( args16 );
88
89     if (func_type & 4)  /* cdecl */
90     {
91         while (*args)
92         {
93             switch(*args)
94             {
95             case 'w':
96             case 's':
97                 DPRINTF( "0x%04x", *(WORD *)args16 );
98                 args16 += 2;
99                 break;
100             case 'l':
101                 DPRINTF( "0x%08x", *(int *)args16 );
102                 args16 += 4;
103                 break;
104             case 't':
105                 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
106                 if (HIWORD(*(SEGPTR *)args16))
107                     debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
108                 args16 += 4;
109                 break;
110             case 'p':
111                 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
112                 args16 += 4;
113                 break;
114             case 'T':
115                 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
116                 if (HIWORD( *(SEGPTR *)args16 ))
117                     debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
118                 args16 += 4;
119                 break;
120             }
121             args++;
122             if (*args) DPRINTF( "," );
123         }
124     }
125     else  /* not cdecl */
126     {
127         /* Start with the last arg */
128         for (i = 0; args[i]; i++)
129         {
130             switch(args[i])
131             {
132             case 'w':
133             case 's':
134                 args16 += 2;
135                 break;
136             case 'l':
137             case 'p':
138             case 't':
139             case 'T':
140                 args16 += 4;
141                 break;
142             }
143         }
144
145         while (*args)
146         {
147             switch(*args)
148             {
149             case 'w':
150             case 's':
151                 args16 -= 2;
152                 DPRINTF( "0x%04x", *(WORD *)args16 );
153                 break;
154             case 'l':
155                 args16 -= 4;
156                 DPRINTF( "0x%08x", *(int *)args16 );
157                 break;
158             case 't':
159                 args16 -= 4;
160                 DPRINTF( "0x%08x", *(int *)args16 );
161                 if (HIWORD(*(SEGPTR *)args16))
162                     debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
163                 break;
164             case 'p':
165                 args16 -= 4;
166                 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
167                 break;
168             case 'T':
169                 args16 -= 4;
170                 DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
171                 if (HIWORD( *(SEGPTR *)args16 ))
172                     debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
173                 break;
174             }
175             args++;
176             if (*args) DPRINTF( "," );
177         }
178     }
179
180     DPRINTF( ") ret=%04x:%04x ds=%04x\n", frame->cs, frame->ip, frame->ds );
181     VA_END16( args16 );
182
183     if (func_type & 2)  /* register function */
184         DPRINTF( "     AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
185                  AX_reg(context), BX_reg(context), CX_reg(context),
186                  DX_reg(context), SI_reg(context), DI_reg(context),
187                  (WORD)ES_reg(context), EFL_reg(context) );
188 }
189
190
191 /***********************************************************************
192  *           RELAY_DebugCallFrom16Ret
193  */
194 void RELAY_DebugCallFrom16Ret( int func_type, int ret_val, CONTEXT *context)
195 {
196     STACK16FRAME *frame;
197     WORD ordinal;
198     const char *funstr;
199     /* from relay32/relay386.c */
200     extern int RELAY_ShowDebugmsgRelay(const char *);
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 Catch( 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 Throw( 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         FARPROC32 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, FARPROC32 );
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 WIN16_CallProc32W()
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 WIN16_CallProcEx32W()
522 {
523         return RELAY_CallProc32W(TRUE);
524 }