Release 980503
[wine/hacks.git] / if1632 / relay.c
blob1999d7678346c811b676b00d42ddb7d30b49fe87
1 /*
2 * Copyright 1993 Robert J. Amstadt
3 * Copyright 1995 Alexandre Julliard
4 */
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 "debugstr.h"
17 #include "debug.h"
20 /***********************************************************************
21 * RELAY_Init
23 BOOL32 RELAY_Init(void)
25 WORD codesel;
26 extern BOOL32 THUNK_Init(void);
28 /* Allocate the code selector for CallTo16 routines */
30 extern void CALLTO16_Start(), CALLTO16_End();
31 extern void CALLTO16_Ret_word(), CALLTO16_Ret_long();
32 extern void CALLTO16_Ret_eax();
33 extern DWORD CALLTO16_RetAddr_word;
34 extern DWORD CALLTO16_RetAddr_long;
35 extern DWORD CALLTO16_RetAddr_eax;
37 codesel = GLOBAL_CreateBlock( GMEM_FIXED, (void *)CALLTO16_Start,
38 (int)CALLTO16_End - (int)CALLTO16_Start,
39 0, TRUE, TRUE, FALSE, NULL );
40 if (!codesel) return FALSE;
42 /* Patch the return addresses for CallTo16 routines */
44 CALLTO16_RetAddr_word=MAKELONG( (int)CALLTO16_Ret_word-(int)CALLTO16_Start,
45 codesel );
46 CALLTO16_RetAddr_long=MAKELONG( (int)CALLTO16_Ret_long-(int)CALLTO16_Start,
47 codesel );
48 CALLTO16_RetAddr_eax =MAKELONG( (int)CALLTO16_Ret_eax -(int)CALLTO16_Start,
49 codesel );
51 /* Create built-in modules */
52 if (!BUILTIN_Init()) return FALSE;
54 /* Initialize thunking */
55 return THUNK_Init();
60 /***********************************************************************
61 * RELAY_DebugCallFrom16
63 void RELAY_DebugCallFrom16( int func_type, char *args,
64 void *entry_point, CONTEXT *context )
66 STACK16FRAME *frame;
67 WORD ordinal;
68 char *args16;
69 int i;
71 if (!TRACE_ON(relay)) return;
73 frame = CURRENT_STACK16;
74 printf( "Call %s(", BUILTIN_GetEntryPoint16( frame->entry_cs,
75 frame->entry_ip,
76 &ordinal ));
77 VA_START16( args16 );
79 if (func_type & 4) /* cdecl */
81 while (*args)
83 switch(*args)
85 case 'w':
86 case 's':
87 printf( "0x%04x", *(WORD *)args16 );
88 args16 += 2;
89 break;
90 case 'l':
91 printf( "0x%08x", *(int *)args16 );
92 args16 += 4;
93 break;
94 case 't':
95 printf( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
96 if (HIWORD(*(SEGPTR *)args16))
97 debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
98 args16 += 4;
99 break;
100 case 'p':
101 printf( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
102 args16 += 4;
103 break;
104 case 'T':
105 printf( "%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;
111 args++;
112 if (*args) printf( "," );
115 else /* not cdecl */
117 /* Start with the last arg */
118 for (i = 0; args[i]; i++)
120 switch(args[i])
122 case 'w':
123 case 's':
124 args16 += 2;
125 break;
126 case 'l':
127 case 'p':
128 case 't':
129 case 'T':
130 args16 += 4;
131 break;
135 while (*args)
137 switch(*args)
139 case 'w':
140 case 's':
141 args16 -= 2;
142 printf( "0x%04x", *(WORD *)args16 );
143 break;
144 case 'l':
145 args16 -= 4;
146 printf( "0x%08x", *(int *)args16 );
147 break;
148 case 't':
149 args16 -= 4;
150 printf( "0x%08x", *(int *)args16 );
151 if (HIWORD(*(SEGPTR *)args16))
152 debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
153 break;
154 case 'p':
155 args16 -= 4;
156 printf( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
157 break;
158 case 'T':
159 args16 -= 4;
160 printf( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
161 if (HIWORD( *(SEGPTR *)args16 ))
162 debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 ));
163 break;
165 args++;
166 if (*args) printf( "," );
170 printf( ") ret=%04x:%04x ds=%04x\n", frame->cs, frame->ip, frame->ds );
171 VA_END16( args16 );
173 if (func_type & 2) /* register function */
174 printf( " AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
175 AX_reg(context), BX_reg(context), CX_reg(context),
176 DX_reg(context), SI_reg(context), DI_reg(context),
177 (WORD)ES_reg(context), EFL_reg(context) );
181 /***********************************************************************
182 * RELAY_DebugCallFrom16Ret
184 void RELAY_DebugCallFrom16Ret( int func_type, int ret_val, CONTEXT *context)
186 STACK16FRAME *frame;
187 WORD ordinal;
189 if (!TRACE_ON(relay)) return;
190 frame = CURRENT_STACK16;
191 printf( "Ret %s() ", BUILTIN_GetEntryPoint16( frame->entry_cs,
192 frame->entry_ip,
193 &ordinal ));
194 switch(func_type)
196 case 0: /* long */
197 printf( "retval=0x%08x ret=%04x:%04x ds=%04x\n",
198 ret_val, frame->cs, frame->ip, frame->ds );
199 break;
200 case 1: /* word */
201 printf( "retval=0x%04x ret=%04x:%04x ds=%04x\n",
202 ret_val & 0xffff, frame->cs, frame->ip, frame->ds );
203 break;
204 case 2: /* regs */
205 printf( "retval=none ret=%04x:%04x ds=%04x\n",
206 (WORD)CS_reg(context), IP_reg(context), (WORD)DS_reg(context));
207 printf( " AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n",
208 AX_reg(context), BX_reg(context), CX_reg(context),
209 DX_reg(context), SI_reg(context), DI_reg(context),
210 (WORD)ES_reg(context), EFL_reg(context) );
211 break;
216 /***********************************************************************
217 * RELAY_Unimplemented16
219 * This function is called for unimplemented 16-bit entry points (declared
220 * as 'stub' in the spec file).
222 void RELAY_Unimplemented16(void)
224 WORD ordinal;
225 STACK16FRAME *frame = CURRENT_STACK16;
226 MSG("No handler for Win16 routine %s (called from %04x:%04x)\n",
227 BUILTIN_GetEntryPoint16(frame->entry_cs,frame->entry_ip,&ordinal),
228 frame->cs, frame->ip );
229 TASK_KillCurrentTask(1);
233 /***********************************************************************
234 * RELAY_DebugCallTo16
236 * 'stack' points to the called function address on the 32-bit stack.
237 * Stack layout:
238 * ... ...
239 * (stack+8) arg2
240 * (stack+4) arg1
241 * (stack) func to call
243 void RELAY_DebugCallTo16( int* stack, int nb_args )
245 THDB *thdb;
247 if (!TRACE_ON(relay)) return;
248 thdb = THREAD_Current();
250 if (nb_args == -1) /* Register function */
252 CONTEXT *context = (CONTEXT *)stack[0];
253 WORD *stack16 = (WORD *)THREAD_STACK16(thdb);
254 printf( "CallTo16(func=%04lx:%04x,ds=%04lx",
255 CS_reg(context), IP_reg(context), DS_reg(context) );
256 nb_args = stack[1] / sizeof(WORD);
257 while (nb_args--) printf( ",0x%04x", *(--stack16) );
258 printf( ") ss:sp=%04x:%04x\n", SELECTOROF(thdb->cur_stack),
259 OFFSETOF(thdb->cur_stack) );
260 printf( " AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x BP=%04x ES=%04x\n",
261 AX_reg(context), BX_reg(context), CX_reg(context),
262 DX_reg(context), SI_reg(context), DI_reg(context),
263 BP_reg(context), (WORD)ES_reg(context) );
265 else
267 printf( "CallTo16(func=%04x:%04x,ds=%04x",
268 HIWORD(stack[0]), LOWORD(stack[0]),
269 SELECTOROF(thdb->cur_stack) );
270 stack++;
271 while (nb_args--) printf( ",0x%04x", *stack++ );
272 printf( ") ss:sp=%04x:%04x\n", SELECTOROF(thdb->cur_stack),
273 OFFSETOF(thdb->cur_stack) );
278 /**********************************************************************
279 * Catch (KERNEL.55)
281 * Real prototype is:
282 * INT16 WINAPI Catch( LPCATCHBUF lpbuf );
284 void WINAPI Catch( CONTEXT *context )
286 VA_LIST16 valist;
287 SEGPTR buf;
288 LPCATCHBUF lpbuf;
290 VA_START16( valist );
291 buf = VA_ARG16( valist, SEGPTR );
292 lpbuf = (LPCATCHBUF)PTR_SEG_TO_LIN( buf );
293 VA_END16( valist );
295 /* Note: we don't save the current ss, as the catch buffer is */
296 /* only 9 words long. Hopefully no one will have the silly */
297 /* idea to change the current stack before calling Throw()... */
299 /* Windows uses:
300 * lpbuf[0] = ip
301 * lpbuf[1] = cs
302 * lpbuf[2] = sp
303 * lpbuf[3] = bp
304 * lpbuf[4] = si
305 * lpbuf[5] = di
306 * lpbuf[6] = ds
307 * lpbuf[7] = unused
308 * lpbuf[8] = ss
311 lpbuf[0] = IP_reg(context);
312 lpbuf[1] = CS_reg(context);
313 /* Windows pushes 4 more words before saving sp */
314 lpbuf[2] = SP_reg(context) - 4 * sizeof(WORD);
315 lpbuf[3] = BP_reg(context);
316 lpbuf[4] = SI_reg(context);
317 lpbuf[5] = DI_reg(context);
318 lpbuf[6] = DS_reg(context);
319 lpbuf[7] = 0;
320 lpbuf[8] = SS_reg(context);
321 AX_reg(context) = 0; /* Return 0 */
325 /**********************************************************************
326 * Throw (KERNEL.56)
328 * Real prototype is:
329 * INT16 WINAPI Throw( LPCATCHBUF lpbuf, INT16 retval );
331 void WINAPI Throw( CONTEXT *context )
333 VA_LIST16 valist;
334 SEGPTR buf;
335 LPCATCHBUF lpbuf;
336 STACK16FRAME *pFrame;
337 STACK32FRAME *frame32;
338 THDB *thdb = THREAD_Current();
340 VA_START16( valist );
341 AX_reg(context) = VA_ARG16( valist, WORD ); /* retval */
342 buf = VA_ARG16( valist, SEGPTR );
343 lpbuf = (LPCATCHBUF)PTR_SEG_TO_LIN( buf );
344 VA_END16( valist );
346 /* Find the frame32 corresponding to the frame16 we are jumping to */
347 pFrame = THREAD_STACK16( thdb );
348 frame32 = THREAD_STACK16( thdb )->frame32;
349 while (frame32 && frame32->frame16)
351 if (OFFSETOF(frame32->frame16) < OFFSETOF(thdb->cur_stack))
352 break; /* Something strange is going on */
353 if (OFFSETOF(frame32->frame16) > lpbuf[2])
355 /* We found the right frame */
356 pFrame->frame32 = frame32;
357 break;
359 frame32 = ((STACK16FRAME *)PTR_SEG_TO_LIN(frame32->frame16))->frame32;
362 IP_reg(context) = lpbuf[0];
363 CS_reg(context) = lpbuf[1];
364 SP_reg(context) = lpbuf[2] + 4 * sizeof(WORD) - sizeof(WORD) /*extra arg*/;
365 BP_reg(context) = lpbuf[3];
366 SI_reg(context) = lpbuf[4];
367 DI_reg(context) = lpbuf[5];
368 DS_reg(context) = lpbuf[6];
370 if (lpbuf[8] != SS_reg(context))
371 ERR(relay, "Switching stack segment with Throw() not supported; expect crash now\n" );
373 if (TRACE_ON(relay)) /* Make sure we have a valid entry point address */
375 static FARPROC16 entryPoint = NULL;
377 if (!entryPoint) /* Get entry point for Throw() */
378 entryPoint = NE_GetEntryPoint( GetModuleHandle16("KERNEL"), 56 );
379 pFrame->entry_cs = SELECTOROF(entryPoint);
380 pFrame->entry_ip = OFFSETOF(entryPoint);
385 /**********************************************************************
386 * RELAY_CallProc32W
388 * Helper for CallProc[Ex]32W
390 static DWORD RELAY_CallProc32W(int Ex)
392 DWORD nrofargs, argconvmask;
393 FARPROC32 proc32;
394 DWORD *args, ret;
395 VA_LIST16 valist;
396 int i;
397 dbg_decl_str(relay, 1024);
399 VA_START16( valist );
400 nrofargs = VA_ARG16( valist, DWORD );
401 argconvmask = VA_ARG16( valist, DWORD );
402 proc32 = VA_ARG16( valist, FARPROC32 );
403 dsprintf(relay, "CallProc32W(%ld,%ld,%p, Ex%d args[",nrofargs,argconvmask,proc32,Ex);
404 args = (DWORD*)HEAP_xalloc( GetProcessHeap(), 0,
405 sizeof(DWORD)*nrofargs );
406 for (i=0;i<nrofargs;i++) {
407 if (argconvmask & (1<<i))
409 SEGPTR ptr = VA_ARG16( valist, SEGPTR );
410 args[nrofargs-i-1] = (DWORD)PTR_SEG_TO_LIN(ptr);
411 dsprintf(relay,"%08lx(%p),",ptr,PTR_SEG_TO_LIN(ptr));
413 else
415 args[nrofargs-i-1] = VA_ARG16( valist, DWORD );
416 dsprintf(relay,"%ld,",args[nrofargs-i-1]);
419 dsprintf(relay,"])");
420 VA_END16( valist );
422 switch (nrofargs) {
423 case 0: ret = proc32();
424 break;
425 case 1: ret = proc32(args[0]);
426 break;
427 case 2: ret = proc32(args[0],args[1]);
428 break;
429 case 3: ret = proc32(args[0],args[1],args[2]);
430 break;
431 case 4: ret = proc32(args[0],args[1],args[2],args[3]);
432 break;
433 case 5: ret = proc32(args[0],args[1],args[2],args[3],args[4]);
434 break;
435 case 6: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5]);
436 break;
437 case 7: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
438 break;
439 case 8: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
440 break;
441 case 9: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
442 break;
443 case 10: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
444 break;
445 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]);
446 break;
447 default:
448 /* FIXME: should go up to 32 arguments */
449 ERR(relay,"Unsupported number of arguments %ld, please report.\n",nrofargs);
450 ret = 0;
451 break;
453 /* POP nrofargs DWORD arguments and 3 DWORD parameters */
454 if (!Ex) STACK16_POP( THREAD_Current(),
455 (3 + nrofargs) * sizeof(DWORD) );
457 TRACE(relay,"%s - returns %08lx\n",dbg_str(relay),ret);
458 HeapFree( GetProcessHeap(), 0, args );
459 return ret;
463 /**********************************************************************
464 * CallProc32W (KERNEL.517)
466 DWORD WINAPI WIN16_CallProc32W()
468 return RELAY_CallProc32W(0);
472 /**********************************************************************
473 * CallProcEx32W() (KERNEL.518)
475 * C - style linkage to CallProc32W - caller pops stack.
477 DWORD WINAPI WIN16_CallProcEx32W()
479 return RELAY_CallProc32W(TRUE);