2 * Copyright 1993 Robert J. Amstadt
3 * Copyright 1995 Alexandre Julliard
13 #include "stackframe.h"
17 /* #define DEBUG_RELAY */
21 /* Make make_debug think these were really used */
26 /***********************************************************************
29 BOOL32 RELAY_Init(void)
32 extern BOOL32 THUNK_Init(void);
34 /* Allocate the code selector for CallTo16 routines */
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;
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;
47 /* Patch the return addresses for CallTo16 routines */
49 CALLTO16_RetAddr_word=MAKELONG( (int)CALLTO16_Ret_word-(int)CALLTO16_Start,
51 CALLTO16_RetAddr_long=MAKELONG( (int)CALLTO16_Ret_long-(int)CALLTO16_Start,
53 CALLTO16_RetAddr_regs=MAKELONG( (int)CALLTO16_Ret_regs-(int)CALLTO16_Start,
56 /* Initialize thunking */
62 /***********************************************************************
63 * RELAY_DebugCallFrom16
65 void RELAY_DebugCallFrom16( int func_type, char *args,
66 void *entry_point, CONTEXT *context )
73 if (!debugging_relay) return;
75 frame = CURRENT_STACK16;
76 printf( "Call %s(", BUILTIN_GetEntryPoint16( frame->entry_cs,
80 for (i = 0; i < strlen(args); i++)
104 printf( "0x%04x", *(WORD *)args16 );
108 printf( "0x%08x", *(int *)args16 );
112 printf( "0x%08x", *(int *)args16 );
113 if (HIWORD(*(int *)args16))
114 printf( " \"%s\"", (char *)PTR_SEG_TO_LIN(*(int *)args16) );
118 printf( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
122 printf( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
123 if (HIWORD(*(int *)args16))
124 printf( " \"%s\"", (char *)PTR_SEG_TO_LIN(*(int *)args16) );
128 if (*args) printf( "," );
130 printf( ") ret=%04x:%04x ds=%04x\n", frame->cs, frame->ip, frame->ds );
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) );
141 /***********************************************************************
142 * RELAY_DebugCallFrom16Ret
144 void RELAY_DebugCallFrom16Ret( int func_type, int ret_val, CONTEXT *context)
149 if (!debugging_relay) return;
150 frame = CURRENT_STACK16;
151 printf( "Ret %s() ", BUILTIN_GetEntryPoint16( frame->entry_cs,
157 printf( "retval=0x%08x ret=%04x:%04x ds=%04x\n",
158 ret_val, frame->cs, frame->ip, frame->ds );
161 printf( "retval=0x%04x ret=%04x:%04x ds=%04x\n",
162 ret_val & 0xffff, frame->cs, frame->ip, frame->ds );
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) );
176 /***********************************************************************
177 * RELAY_Unimplemented16
179 * This function is called for unimplemented 16-bit entry points (declared
180 * as 'stub' in the spec file).
182 void RELAY_Unimplemented16(void)
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);
193 /***********************************************************************
194 * RELAY_DebugCallTo16
196 * 'stack' points to the called function address on the 32-bit stack.
201 * (stack) func to call
203 void RELAY_DebugCallTo16( int* stack, int nb_args )
205 if (!debugging_relay) return;
207 if (nb_args == -1) /* Register function */
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) );
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) );
223 printf( "CallTo16(func=%04x:%04x,ds=%04x",
224 HIWORD(stack[0]), LOWORD(stack[0]),
225 SELECTOROF(IF1632_Saved16_ss_sp) );
227 while (nb_args--) printf( ",0x%04x", *stack++ );
233 /***********************************************************************
236 * Stack layout on entry to this function:
241 * (esp) return addr to relay code
243 int RELAY_CallFrom32( int ret_addr, ... )
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);
254 assert(debugging_relay);
255 func = BUILTIN_GetEntryPoint32( buffer, relay_addr - 5 );
256 printf( "Call %s(", buffer );
258 for (i = 0; i < nb_args; i++)
260 if (i) printf( "," );
261 printf( "%08x", args[i] );
263 printf( ") ret=%08x\n", ret_addr );
264 if (*relay_addr == 0xc3) /* cdecl */
266 LRESULT (*cfunc)() = (LRESULT(*)())func;
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],
277 case 7: ret = cfunc(args[0],args[1],args[2],args[3],args[4],args[5],
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],
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],
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;
300 fprintf( stderr, "RELAY_CallFrom32: Unsupported nb args %d\n",
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],
317 case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5],
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],
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],
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;
340 fprintf( stderr, "RELAY_CallFrom32: Unsupported nb args %d\n",
345 printf( "Ret %s() retval=%08x ret=%08x\n", buffer, ret, ret_addr );
350 /***********************************************************************
351 * RELAY_CallFrom32Regs
353 * 'stack' points to the relay addr on the stack.
357 * (esp+212) return to relay debugging code (only when debugging_relay)
358 * (esp+208) entry point to call
360 * (esp) return addr to relay code
362 void RELAY_CallFrom32Regs( CONTEXT context,
363 void (CALLBACK *entry_point)(CONTEXT *),
364 BYTE *relay_addr, int ret_addr )
366 if (!debugging_relay)
368 /* Simply call the entry point */
369 entry_point( &context );
375 /* Fixup the context structure because of the extra parameter */
376 /* pushed by the relay debugging code */
378 EIP_reg(&context) = ret_addr;
379 ESP_reg(&context) += sizeof(int);
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) );
391 /* Now call the real function */
392 entry_point( &context );
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) );
406 /***********************************************************************
407 * RELAY_Unimplemented32
409 * This function is called for unimplemented 32-bit entry points (declared
410 * as 'stub' in the spec file).
412 void RELAY_Unimplemented32( const char *dll_name, int ordinal,
413 const char *func_name, int ret_addr )
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);
422 /**********************************************************************
426 * INT16 WINAPI Catch( LPCATCHBUF lpbuf );
428 void WINAPI Catch( CONTEXT *context )
433 STACK16FRAME *pFrame = CURRENT_STACK16;
435 VA_START16( valist );
436 buf = VA_ARG16( valist, SEGPTR );
437 lpbuf = (LPCATCHBUF)PTR_SEG_TO_LIN( buf );
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()... */
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 */
469 /**********************************************************************
473 * INT16 WINAPI Throw( LPCATCHBUF lpbuf, INT16 retval );
475 void WINAPI Throw( CONTEXT *context )
480 STACK16FRAME *pFrame;
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 );
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];
499 if (debugging_relay) /* Make sure we have a valid entry point address */
501 static FARPROC16 entryPoint = NULL;
503 if (!entryPoint) /* Get entry point for Throw() */
504 entryPoint = MODULE_GetEntryPoint( GetModuleHandle16("KERNEL"),
506 pFrame->entry_cs = SELECTOROF(entryPoint);
507 pFrame->entry_ip = OFFSETOF(entryPoint);
511 /**********************************************************************
512 * CallProc32W (KERNEL.517)
514 DWORD WINAPI WIN16_CallProc32W()
516 DWORD nrofargs, argconvmask;
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))
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));
537 args[nrofargs-i-1] = VA_ARG16( valist, DWORD );
538 fprintf(stderr,"%ld,",args[nrofargs-i-1]);
541 fprintf(stderr,"]) - ");
545 case 0: ret = proc32();
547 case 1: ret = proc32(args[0]);
549 case 2: ret = proc32(args[0],args[1]);
551 case 3: ret = proc32(args[0],args[1],args[2]);
553 case 4: ret = proc32(args[0],args[1],args[2],args[3]);
555 case 5: ret = proc32(args[0],args[1],args[2],args[3],args[4]);
557 case 6: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5]);
559 case 7: ret = proc32(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
562 /* FIXME: should go up to 32 arguments */
563 fprintf(stderr,"CallProc32W: unsupported number of arguments %ld, please report.\n",nrofargs);
567 /* POP nrofargs DWORD arguments and 3 DWORD parameters */
568 STACK16_POP( (3 + nrofargs) * sizeof(DWORD) );
570 fprintf(stderr,"returns %08lx\n",ret);