/* * Copyright 1993 Robert J. Amstadt * Copyright 1995 Alexandre Julliard */ #include #include #include #include "wine/winbase16.h" #include "winnt.h" #include "global.h" #include "heap.h" #include "module.h" #include "stackframe.h" #include "task.h" #include "syslevel.h" #include "debugstr.h" #include "debugtools.h" #include "main.h" DEFAULT_DEBUG_CHANNEL(relay) /*********************************************************************** * RELAY_Init */ BOOL RELAY_Init(void) { WORD codesel; /* Allocate the code selector for CallTo16 routines */ extern void CALLTO16_Start(), CALLTO16_End(); extern void CALLTO16_Ret_word(), CALLTO16_Ret_long(); extern void CALLTO16_Ret_eax(); extern void CALL32_CBClient_Ret(); extern void CALL32_CBClientEx_Ret(); extern DWORD CALLTO16_RetAddr_word; extern DWORD CALLTO16_RetAddr_long; extern DWORD CALLTO16_RetAddr_eax; extern DWORD CALL32_CBClient_RetAddr; extern DWORD CALL32_CBClientEx_RetAddr; codesel = GLOBAL_CreateBlock( GMEM_FIXED, (void *)CALLTO16_Start, (int)CALLTO16_End - (int)CALLTO16_Start, 0, TRUE, TRUE, FALSE, NULL ); if (!codesel) return FALSE; /* Patch the return addresses for CallTo16 routines */ CALLTO16_RetAddr_word=MAKELONG( (int)CALLTO16_Ret_word-(int)CALLTO16_Start, codesel ); CALLTO16_RetAddr_long=MAKELONG( (int)CALLTO16_Ret_long-(int)CALLTO16_Start, codesel ); CALLTO16_RetAddr_eax =MAKELONG( (int)CALLTO16_Ret_eax -(int)CALLTO16_Start, codesel ); CALL32_CBClient_RetAddr = MAKELONG( (int)CALL32_CBClient_Ret -(int)CALLTO16_Start, codesel ); CALL32_CBClientEx_RetAddr = MAKELONG( (int)CALL32_CBClientEx_Ret -(int)CALLTO16_Start, codesel ); /* Create built-in modules */ if (!BUILTIN_Init()) return FALSE; /* Initialize thunking */ return THUNK_Init(); } /* from relay32/relay386.c */ extern char **debug_relay_excludelist,**debug_relay_includelist; /*********************************************************************** * RELAY_DebugCallFrom16 */ void RELAY_DebugCallFrom16( int func_type, char *args, void *entry_point, CONTEXT86 *context ) { STACK16FRAME *frame; WORD ordinal; char *args16; const char *funstr; int i; if (!TRACE_ON(relay)) return; frame = CURRENT_STACK16; funstr = BUILTIN_GetEntryPoint16(frame->entry_cs,frame->entry_ip,&ordinal); if (!funstr) return; /* happens for the two snoop register relays */ if (!RELAY_ShowDebugmsgRelay(funstr)) return; DPRINTF( "Call %s(",funstr); VA_START16( args16 ); if (func_type & 4) /* cdecl */ { while (*args) { switch(*args) { case 'w': case 's': DPRINTF( "0x%04x", *(WORD *)args16 ); args16 += 2; break; case 'l': DPRINTF( "0x%08x", *(int *)args16 ); args16 += 4; break; case 't': DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 ); if (HIWORD(*(SEGPTR *)args16)) debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 )); args16 += 4; break; case 'p': DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 ); args16 += 4; break; case 'T': DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 ); if (HIWORD( *(SEGPTR *)args16 )) debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 )); args16 += 4; break; } args++; if (*args) DPRINTF( "," ); } } else /* not cdecl */ { /* Start with the last arg */ for (i = 0; args[i]; i++) { switch(args[i]) { case 'w': case 's': args16 += 2; break; case 'l': case 'p': case 't': case 'T': args16 += 4; break; } } while (*args) { switch(*args) { case 'w': case 's': args16 -= 2; DPRINTF( "0x%04x", *(WORD *)args16 ); break; case 'l': args16 -= 4; DPRINTF( "0x%08x", *(int *)args16 ); break; case 't': args16 -= 4; DPRINTF( "0x%08x", *(int *)args16 ); if (HIWORD(*(SEGPTR *)args16)) debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 )); break; case 'p': args16 -= 4; DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 ); break; case 'T': args16 -= 4; DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 ); if (HIWORD( *(SEGPTR *)args16 )) debug_dumpstr( (LPSTR)PTR_SEG_TO_LIN(*(SEGPTR *)args16 )); break; } args++; if (*args) DPRINTF( "," ); } } DPRINTF( ") ret=%04x:%04x ds=%04x\n", frame->cs, frame->ip, frame->ds ); VA_END16( args16 ); if (func_type & 2) /* register function */ DPRINTF( " AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n", AX_reg(context), BX_reg(context), CX_reg(context), DX_reg(context), SI_reg(context), DI_reg(context), (WORD)ES_reg(context), EFL_reg(context) ); SYSLEVEL_CheckNotLevel( 2 ); } /*********************************************************************** * RELAY_DebugCallFrom16Ret */ void RELAY_DebugCallFrom16Ret( int func_type, int ret_val, CONTEXT86 *context) { STACK16FRAME *frame; WORD ordinal; const char *funstr; if (!TRACE_ON(relay)) return; frame = CURRENT_STACK16; funstr = BUILTIN_GetEntryPoint16(frame->entry_cs,frame->entry_ip,&ordinal); if (!funstr) return; if (!RELAY_ShowDebugmsgRelay(funstr)) return; DPRINTF( "Ret %s() ",funstr); switch(func_type) { case 0: /* long */ DPRINTF( "retval=0x%08x ret=%04x:%04x ds=%04x\n", ret_val, frame->cs, frame->ip, frame->ds ); break; case 1: /* word */ DPRINTF( "retval=0x%04x ret=%04x:%04x ds=%04x\n", ret_val & 0xffff, frame->cs, frame->ip, frame->ds ); break; case 2: /* regs */ DPRINTF("retval=none ret=%04x:%04x ds=%04x\n", (WORD)CS_reg(context), IP_reg(context), (WORD)DS_reg(context)); DPRINTF(" AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n", AX_reg(context), BX_reg(context), CX_reg(context), DX_reg(context), SI_reg(context), DI_reg(context), (WORD)ES_reg(context), EFL_reg(context) ); break; } SYSLEVEL_CheckNotLevel( 2 ); } /*********************************************************************** * RELAY_Unimplemented16 * * This function is called for unimplemented 16-bit entry points (declared * as 'stub' in the spec file). */ void RELAY_Unimplemented16(void) { WORD ordinal; STACK16FRAME *frame = CURRENT_STACK16; MESSAGE("No handler for Win16 routine %s (called from %04x:%04x)\n", BUILTIN_GetEntryPoint16(frame->entry_cs,frame->entry_ip,&ordinal), frame->cs, frame->ip ); ExitProcess(1); } /*********************************************************************** * RELAY_DebugCallTo16 * * 'stack' points to the called function address on the 32-bit stack. * Stack layout: * ... ... * (stack+8) arg2 * (stack+4) arg1 * (stack) func to call */ void RELAY_DebugCallTo16( int* stack, int nb_args ) { TEB *teb; if (!TRACE_ON(relay)) return; teb = NtCurrentTeb(); if (nb_args == -1) /* Register function */ { CONTEXT86 *context = (CONTEXT86 *)stack[0]; WORD *stack16 = (WORD *)THREAD_STACK16(teb); DPRINTF("CallTo16(func=%04lx:%04x,ds=%04lx", CS_reg(context), IP_reg(context), DS_reg(context) ); nb_args = stack[1] / sizeof(WORD); while (nb_args--) { --stack16; DPRINTF( ",0x%04x", *stack16 ); } DPRINTF(") ss:sp=%04x:%04x\n", SELECTOROF(teb->cur_stack), OFFSETOF(teb->cur_stack) ); DPRINTF(" AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x BP=%04x ES=%04x FS=%04x\n", AX_reg(context), BX_reg(context), CX_reg(context), DX_reg(context), SI_reg(context), DI_reg(context), BP_reg(context), (WORD)ES_reg(context), (WORD)FS_reg(context) ); } else { DPRINTF("CallTo16(func=%04x:%04x,ds=%04x", HIWORD(stack[0]), LOWORD(stack[0]), SELECTOROF(teb->cur_stack) ); stack++; while (nb_args--) { DPRINTF(",0x%04x", *stack ); stack++; } DPRINTF(") ss:sp=%04x:%04x\n", SELECTOROF(teb->cur_stack), OFFSETOF(teb->cur_stack) ); } SYSLEVEL_CheckNotLevel( 2 ); } /*********************************************************************** * RELAY_DebugCallTo16Ret */ void RELAY_DebugCallTo16Ret( int ret_val ) { if (!TRACE_ON(relay)) return; DPRINTF("CallTo16() ss:sp=%04x:%04x retval=0x%08x\n", SELECTOROF(NtCurrentTeb()->cur_stack), OFFSETOF(NtCurrentTeb()->cur_stack), ret_val); SYSLEVEL_CheckNotLevel( 2 ); } /********************************************************************** * Catch (KERNEL.55) * * Real prototype is: * INT16 WINAPI Catch( LPCATCHBUF lpbuf ); */ void WINAPI Catch16( CONTEXT86 *context ) { VA_LIST16 valist; SEGPTR buf; LPCATCHBUF lpbuf; VA_START16( valist ); buf = VA_ARG16( valist, SEGPTR ); lpbuf = (LPCATCHBUF)PTR_SEG_TO_LIN( buf ); VA_END16( valist ); /* Note: we don't save the current ss, as the catch buffer is */ /* only 9 words long. Hopefully no one will have the silly */ /* idea to change the current stack before calling Throw()... */ /* Windows uses: * lpbuf[0] = ip * lpbuf[1] = cs * lpbuf[2] = sp * lpbuf[3] = bp * lpbuf[4] = si * lpbuf[5] = di * lpbuf[6] = ds * lpbuf[7] = unused * lpbuf[8] = ss */ lpbuf[0] = IP_reg(context); lpbuf[1] = CS_reg(context); /* Windows pushes 4 more words before saving sp */ lpbuf[2] = SP_reg(context) - 4 * sizeof(WORD); lpbuf[3] = BP_reg(context); lpbuf[4] = SI_reg(context); lpbuf[5] = DI_reg(context); lpbuf[6] = DS_reg(context); lpbuf[7] = 0; lpbuf[8] = SS_reg(context); AX_reg(context) = 0; /* Return 0 */ } /********************************************************************** * Throw (KERNEL.56) * * Real prototype is: * INT16 WINAPI Throw( LPCATCHBUF lpbuf, INT16 retval ); */ void WINAPI Throw16( CONTEXT86 *context ) { VA_LIST16 valist; SEGPTR buf; LPCATCHBUF lpbuf; STACK16FRAME *pFrame; STACK32FRAME *frame32; TEB *teb = NtCurrentTeb(); VA_START16( valist ); AX_reg(context) = VA_ARG16( valist, WORD ); /* retval */ buf = VA_ARG16( valist, SEGPTR ); lpbuf = (LPCATCHBUF)PTR_SEG_TO_LIN( buf ); VA_END16( valist ); /* Find the frame32 corresponding to the frame16 we are jumping to */ pFrame = THREAD_STACK16(teb); frame32 = pFrame->frame32; while (frame32 && frame32->frame16) { if (OFFSETOF(frame32->frame16) < OFFSETOF(teb->cur_stack)) break; /* Something strange is going on */ if (OFFSETOF(frame32->frame16) > lpbuf[2]) { /* We found the right frame */ pFrame->frame32 = frame32; break; } frame32 = ((STACK16FRAME *)PTR_SEG_TO_LIN(frame32->frame16))->frame32; } IP_reg(context) = lpbuf[0]; CS_reg(context) = lpbuf[1]; SP_reg(context) = lpbuf[2] + 4 * sizeof(WORD) - sizeof(WORD) /*extra arg*/; BP_reg(context) = lpbuf[3]; SI_reg(context) = lpbuf[4]; DI_reg(context) = lpbuf[5]; DS_reg(context) = lpbuf[6]; if (lpbuf[8] != SS_reg(context)) ERR("Switching stack segment with Throw() not supported; expect crash now\n" ); if (TRACE_ON(relay)) /* Make sure we have a valid entry point address */ { static FARPROC16 entryPoint = NULL; if (!entryPoint) /* Get entry point for Throw() */ entryPoint = NE_GetEntryPoint( GetModuleHandle16("KERNEL"), 56 ); pFrame->entry_cs = SELECTOROF(entryPoint); pFrame->entry_ip = OFFSETOF(entryPoint); } } /********************************************************************** * RELAY_CallProc32W * * Helper for CallProc[Ex]32W */ static DWORD RELAY_CallProc32W(int Ex) { DWORD nrofargs, argconvmask; FARPROC proc32; DWORD *args, ret; VA_LIST16 valist; int i; int aix; dbg_decl_str(relay, 1024); SYSLEVEL_ReleaseWin16Lock(); VA_START16( valist ); nrofargs = VA_ARG16( valist, DWORD ); argconvmask = VA_ARG16( valist, DWORD ); proc32 = VA_ARG16( valist, FARPROC ); dsprintf(relay, "CallProc32W(%ld,%ld,%p, Ex%d args[",nrofargs,argconvmask,proc32,Ex); args = (DWORD*)HEAP_xalloc( GetProcessHeap(), 0, sizeof(DWORD)*nrofargs ); /* CallProcEx doesn't need its args reversed */ for (i=0;i