From 2b336340185ac11535158570ba2645a0bc161166 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 5 Jul 2005 12:52:07 +0000 Subject: [PATCH] Intercept functions for 16-bit relay debugging by patching the CALLFROM16 table instead of having the wine_call_from_16 functions call out the relay functions explicitly. --- dlls/kernel/kernel16_private.h | 3 + dlls/kernel/ne_module.c | 23 ++-- dlls/kernel/relay16.c | 296 ++++++++++++++++++++++++++++++++++++----- tools/winebuild/relay.c | 68 ---------- 4 files changed, 274 insertions(+), 116 deletions(-) diff --git a/dlls/kernel/kernel16_private.h b/dlls/kernel/kernel16_private.h index ee561732b7b..cb9c165bf2f 100644 --- a/dlls/kernel/kernel16_private.h +++ b/dlls/kernel/kernel16_private.h @@ -210,6 +210,9 @@ extern void SELECTOR_FreeBlock( WORD sel ); #define IS_SELECTOR_32BIT(sel) \ (wine_ldt_is_system(sel) || (wine_ldt_copy.flags[LOWORD(sel) >> 3] & WINE_LDT_FLAGS_32BIT)) +/* relay16.c */ +extern int relay_call_from_16( void *entry_point, unsigned char *args16, CONTEXT86 *context ); + /* snoop16.c */ extern void SNOOP16_RegisterDLL(HMODULE16,LPCSTR); extern FARPROC16 SNOOP16_GetProcAddress16(HMODULE16,DWORD,FARPROC16); diff --git a/dlls/kernel/ne_module.c b/dlls/kernel/ne_module.c index d2eefbbc9cb..f4a8d292561 100644 --- a/dlls/kernel/ne_module.c +++ b/dlls/kernel/ne_module.c @@ -45,6 +45,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(module); WINE_DECLARE_DEBUG_CHANNEL(loaddll); +WINE_DECLARE_DEBUG_CHANNEL(relay); #include "pshpack1.h" typedef struct _GPHANDLERDEF @@ -103,21 +104,19 @@ inline static void patch_code_segment( NE_MODULE *pModule ) { #ifdef __i386__ int i; + CALLFROM16 *call; SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule ); for (i = 0; i < pModule->ne_cseg; i++, pSeg++) - { - if (!(pSeg->flags & NE_SEGFLAGS_DATA)) /* found the code segment */ - { - CALLFROM16 *call = GlobalLock16( pSeg->hSeg ); - if (call->flatcs == wine_get_cs()) return; /* nothing to patch */ - while (call->pushl == 0x68) - { - call->flatcs = wine_get_cs(); - call++; - } - } - } + if (!(pSeg->flags & NE_SEGFLAGS_DATA)) break; /* found the code segment */ + + call = GlobalLock16( pSeg->hSeg ); + + if (call->flatcs != wine_get_cs()) /* need to patch cs values */ + for (i = 0; call[i].pushl == 0x68; i++) call[i].flatcs = wine_get_cs(); + + if (TRACE_ON(relay)) /* patch relay functions to all point to relay_call_from_16 */ + for (i = 0; call[i].pushl == 0x68; i++) call[i].relay = relay_call_from_16; #endif } diff --git a/dlls/kernel/relay16.c b/dlls/kernel/relay16.c index fc0faddb72e..cdf8a81e7ad 100644 --- a/dlls/kernel/relay16.c +++ b/dlls/kernel/relay16.c @@ -281,29 +281,241 @@ static const CALLFROM16 *get_entry_point( STACK16FRAME *frame, LPSTR module, LPS } +typedef int (*CDECL_PROC)(); +typedef int (WINAPI *PASCAL_PROC)(); + +/*********************************************************************** + * call_cdecl_function + */ +static int call_cdecl_function( CDECL_PROC func, int nb_args, const int *args ) +{ + int ret; + switch(nb_args) + { + case 0: ret = func(); break; + case 1: ret = func(args[0]); break; + case 2: ret = func(args[0],args[1]); break; + case 3: ret = func(args[0],args[1],args[2]); break; + case 4: ret = func(args[0],args[1],args[2],args[3]); break; + case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break; + case 6: ret = func(args[0],args[1],args[2],args[3],args[4], + args[5]); break; + case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6]); break; + case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7]); break; + case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8]); break; + case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9]); break; + case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9],args[10]); break; + case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9],args[10], + args[11]); break; + case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9],args[10],args[11], + args[12]); break; + case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9],args[10],args[11], + args[12],args[13]); break; + case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9],args[10],args[11], + args[12],args[13],args[14]); break; + case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9],args[10],args[11], + args[12],args[13],args[14],args[15]); break; + case 17: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9],args[10],args[11], + args[12],args[13],args[14],args[15],args[16]); break; + case 18: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9],args[10],args[11], + args[12],args[13],args[14],args[15],args[16], + args[17]); break; + default: + ERR( "Unsupported nb of args %d\n", nb_args ); + assert(FALSE); + ret = 0; + break; + } + return ret; +} + + +/*********************************************************************** + * call_pascal_function + */ +static inline int call_pascal_function( PASCAL_PROC func, int nb_args, const int *args ) +{ + int ret; + switch(nb_args) + { + case 0: ret = func(); break; + case 1: ret = func(args[0]); break; + case 2: ret = func(args[0],args[1]); break; + case 3: ret = func(args[0],args[1],args[2]); break; + case 4: ret = func(args[0],args[1],args[2],args[3]); break; + case 5: ret = func(args[0],args[1],args[2],args[3],args[4]); break; + case 6: ret = func(args[0],args[1],args[2],args[3],args[4], + args[5]); break; + case 7: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6]); break; + case 8: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7]); break; + case 9: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8]); break; + case 10: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9]); break; + case 11: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9],args[10]); break; + case 12: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9],args[10], + args[11]); break; + case 13: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9],args[10],args[11], + args[12]); break; + case 14: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9],args[10],args[11], + args[12],args[13]); break; + case 15: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9],args[10],args[11], + args[12],args[13],args[14]); break; + case 16: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9],args[10],args[11], + args[12],args[13],args[14],args[15]); break; + case 17: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9],args[10],args[11], + args[12],args[13],args[14],args[15],args[16]); break; + case 18: ret = func(args[0],args[1],args[2],args[3],args[4],args[5], + args[6],args[7],args[8],args[9],args[10],args[11], + args[12],args[13],args[14],args[15],args[16], + args[17]); break; + default: + ERR( "Unsupported nb of args %d\n", nb_args ); + assert(FALSE); + ret = 0; + break; + } + return ret; +} + + +/*********************************************************************** + * relay_call_from_16_no_debug + * + * Same as relay_call_from_16 but doesn't print any debug information. + */ +static int relay_call_from_16_no_debug( void *entry_point, unsigned char *args16, CONTEXT86 *context, + const CALLFROM16 *call ) +{ + int i, nb_args, args32[20]; + + nb_args = 0; + if (call->lret == 0xcb66) /* cdecl */ + { + for (i = 0; i < 20; i++, nb_args++) + { + int type = (call->arg_types[i / 10] >> (3 * (i % 10))) & 7; + + if (type == ARG_NONE) break; + switch(type) + { + case ARG_WORD: + args32[nb_args] = *(WORD *)args16; + args16 += sizeof(WORD); + break; + case ARG_SWORD: + args32[nb_args] = *(short *)args16; + args16 += sizeof(WORD); + break; + case ARG_LONG: + case ARG_SEGSTR: + args32[nb_args] = *(int *)args16; + args16 += sizeof(int); + break; + case ARG_PTR: + case ARG_STR: + args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 ); + args16 += sizeof(SEGPTR); + break; + case ARG_VARARG: + args32[nb_args] = (int)args16; + break; + default: + break; + } + } + } + else /* not cdecl */ + { + /* Start with the last arg */ + args16 += call->nArgs; + for (i = 0; i < 20; i++, nb_args++) + { + int type = (call->arg_types[i / 10] >> (3 * (i % 10))) & 7; + + if (type == ARG_NONE) break; + switch(type) + { + case ARG_WORD: + args16 -= sizeof(WORD); + args32[nb_args] = *(WORD *)args16; + break; + case ARG_SWORD: + args16 -= sizeof(WORD); + args32[nb_args] = *(short *)args16; + break; + case ARG_LONG: + case ARG_SEGSTR: + args16 -= sizeof(int); + args32[nb_args] = *(int *)args16; + break; + case ARG_PTR: + case ARG_STR: + args16 -= sizeof(SEGPTR); + args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 ); + break; + default: + break; + } + } + } + + if (call->arg_types[0] & ARG_REGISTER) args32[nb_args++] = (int)context; + + SYSLEVEL_CheckNotLevel( 2 ); + + if (call->lret == 0xcb66) /* cdecl */ + return call_cdecl_function( entry_point, nb_args, args32 ); + else + return call_pascal_function( entry_point, nb_args, args32 ); +} + + /*********************************************************************** - * RELAY_DebugCallFrom16 + * relay_call_from_16 + * + * Replacement for the 16-bit relay functions when relay debugging is on. */ -void RELAY_DebugCallFrom16( CONTEXT86 *context ) +int relay_call_from_16( void *entry_point, unsigned char *args16, CONTEXT86 *context ) { STACK16FRAME *frame; WORD ordinal; - char *args16, module[10], func[64]; + int i, ret_val, nb_args, args32[20]; + char module[10], func[64]; const CALLFROM16 *call; - int i; - - if (!TRACE_ON(relay)) return; frame = CURRENT_STACK16; call = get_entry_point( frame, module, func, &ordinal ); - if (!call) return; /* happens for the two snoop register relays */ - if (!RELAY_ShowDebugmsgRelay( module, ordinal, func )) return; + if (!TRACE_ON(relay) || !RELAY_ShowDebugmsgRelay( module, ordinal, func )) + return relay_call_from_16_no_debug( entry_point, args16, context, call ); + DPRINTF( "%04lx:Call %s.%d: %s(",GetCurrentThreadId(), module, ordinal, func ); - args16 = (char *)(frame + 1); + nb_args = 0; if (call->lret == 0xcb66) /* cdecl */ { - for (i = 0; i < 20; i++) + for (i = 0; i < 20; i++, nb_args++) { int type = (call->arg_types[i / 10] >> (3 * (i % 10))) & 7; @@ -312,30 +524,40 @@ void RELAY_DebugCallFrom16( CONTEXT86 *context ) switch(type) { case ARG_WORD: + DPRINTF( "%04x", *(WORD *)args16 ); + args32[nb_args] = *(WORD *)args16; + args16 += sizeof(WORD); + break; case ARG_SWORD: DPRINTF( "%04x", *(WORD *)args16 ); + args32[nb_args] = *(short *)args16; args16 += sizeof(WORD); break; case ARG_LONG: DPRINTF( "%08x", *(int *)args16 ); + args32[nb_args] = *(int *)args16; args16 += sizeof(int); break; case ARG_PTR: DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 ); + args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 ); args16 += sizeof(SEGPTR); break; case ARG_STR: DPRINTF( "%08x %s", *(int *)args16, debugstr_a( MapSL(*(SEGPTR *)args16 ))); + args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 ); args16 += sizeof(int); break; case ARG_SEGSTR: DPRINTF( "%04x:%04x %s", *(WORD *)(args16+2), *(WORD *)args16, debugstr_a( MapSL(*(SEGPTR *)args16 )) ); + args32[nb_args] = *(SEGPTR *)args16; args16 += sizeof(SEGPTR); break; case ARG_VARARG: DPRINTF( "..." ); + args32[nb_args] = (int)args16; break; default: break; @@ -346,7 +568,7 @@ void RELAY_DebugCallFrom16( CONTEXT86 *context ) { /* Start with the last arg */ args16 += call->nArgs; - for (i = 0; i < 20; i++) + for (i = 0; i < 20; i++, nb_args++) { int type = (call->arg_types[i / 10] >> (3 * (i % 10))) & 7; @@ -355,30 +577,40 @@ void RELAY_DebugCallFrom16( CONTEXT86 *context ) switch(type) { case ARG_WORD: + args16 -= sizeof(WORD); + args32[nb_args] = *(WORD *)args16; + DPRINTF( "%04x", *(WORD *)args16 ); + break; case ARG_SWORD: args16 -= sizeof(WORD); + args32[nb_args] = *(short *)args16; DPRINTF( "%04x", *(WORD *)args16 ); break; case ARG_LONG: args16 -= sizeof(int); + args32[nb_args] = *(int *)args16; DPRINTF( "%08x", *(int *)args16 ); break; case ARG_PTR: args16 -= sizeof(SEGPTR); + args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 ); DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 ); break; case ARG_STR: args16 -= sizeof(int); + args32[nb_args] = (int)MapSL( *(SEGPTR *)args16 ); DPRINTF( "%08x %s", *(int *)args16, debugstr_a( MapSL(*(SEGPTR *)args16 ))); break; case ARG_SEGSTR: args16 -= sizeof(SEGPTR); + args32[nb_args] = *(SEGPTR *)args16; DPRINTF( "%04x:%04x %s", *(WORD *)(args16+2), *(WORD *)args16, debugstr_a( MapSL(*(SEGPTR *)args16 )) ); break; case ARG_VARARG: DPRINTF( "..." ); + args32[nb_args] = (int)args16; break; default: break; @@ -389,32 +621,24 @@ void RELAY_DebugCallFrom16( CONTEXT86 *context ) DPRINTF( ") ret=%04x:%04x ds=%04x\n", frame->cs, frame->ip, frame->ds ); if (call->arg_types[0] & ARG_REGISTER) + { + args32[nb_args++] = (int)context; DPRINTF(" AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n", (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx, (WORD)context->Edx, (WORD)context->Esi, (WORD)context->Edi, (WORD)context->SegEs, context->EFlags ); + } SYSLEVEL_CheckNotLevel( 2 ); -} - -/*********************************************************************** - * RELAY_DebugCallFrom16Ret - */ -void RELAY_DebugCallFrom16Ret( CONTEXT86 *context, int ret_val ) -{ - STACK16FRAME *frame; - WORD ordinal; - char module[10], func[64]; - const CALLFROM16 *call; + if (call->lret == 0xcb66) /* cdecl */ + ret_val = call_cdecl_function( entry_point, nb_args, args32 ); + else + ret_val = call_pascal_function( entry_point, nb_args, args32 ); - if (!TRACE_ON(relay)) return; - frame = CURRENT_STACK16; - call = get_entry_point( frame, module, func, &ordinal ); - if (!call) return; - if (!RELAY_ShowDebugmsgRelay( module, ordinal, func )) return; - DPRINTF( "%04lx:Ret %s.%d: %s() ", GetCurrentThreadId(), module, ordinal, func ); + SYSLEVEL_CheckNotLevel( 2 ); + DPRINTF( "%04lx:Ret %s.%d: %s() ",GetCurrentThreadId(), module, ordinal, func ); if (call->arg_types[0] & ARG_REGISTER) { DPRINTF("retval=none ret=%04x:%04x ds=%04x\n", @@ -424,17 +648,17 @@ void RELAY_DebugCallFrom16Ret( CONTEXT86 *context, int ret_val ) (WORD)context->Edx, (WORD)context->Esi, (WORD)context->Edi, (WORD)context->SegEs, context->EFlags ); } - else if (call->arg_types[0] & ARG_RET16) - { - DPRINTF( "retval=%04x ret=%04x:%04x ds=%04x\n", - ret_val & 0xffff, frame->cs, frame->ip, frame->ds ); - } else { - DPRINTF( "retval=%08x ret=%04x:%04x ds=%04x\n", - ret_val, frame->cs, frame->ip, frame->ds ); + frame = CURRENT_STACK16; /* might have be changed by the entry point */ + if (call->arg_types[0] & ARG_RET16) + DPRINTF( "retval=%04x ret=%04x:%04x ds=%04x\n", + ret_val & 0xffff, frame->cs, frame->ip, frame->ds ); + else + DPRINTF( "retval=%08x ret=%04x:%04x ds=%04x\n", + ret_val, frame->cs, frame->ip, frame->ds ); } - SYSLEVEL_CheckNotLevel( 2 ); + return ret_val; } #else /* __i386__ */ diff --git a/tools/winebuild/relay.c b/tools/winebuild/relay.c index 2c9eb0b067d..78923a8c950 100644 --- a/tools/winebuild/relay.c +++ b/tools/winebuild/relay.c @@ -293,80 +293,12 @@ static void BuildCallFrom16Core( FILE *outfile, int reg_func, int thunk, int sho fprintf( outfile, "\tpushl %%esp\n" ); } - - /* Print debug info before call */ - if ( debugging ) - { - if ( UsePIC ) - { - fprintf( outfile, "\tpushl %%ebx\n" ); - - /* Get Global Offset Table into %ebx (for PLT call) */ - fprintf( outfile, "\tcall .L__wine_call_from_16_%s.getgot2\n", name ); - fprintf( outfile, ".L__wine_call_from_16_%s.getgot2:\n", name ); - fprintf( outfile, "\tpopl %%ebx\n" ); - fprintf( outfile, "\taddl $_GLOBAL_OFFSET_TABLE_+[.-.L__wine_call_from_16_%s.getgot2], %%ebx\n", name ); - } - - fprintf( outfile, "\tpushl %%edx\n" ); - if ( reg_func ) - fprintf( outfile, "\tleal -%d(%%ebp), %%eax\n\tpushl %%eax\n", - sizeof(CONTEXT) + STRUCTOFFSET(STACK32FRAME, ebp) ); - else - fprintf( outfile, "\tpushl $0\n" ); - - if ( UsePIC ) - fprintf( outfile, "\tcall %s\n ", asm_name("RELAY_DebugCallFrom16@PLT")); - else - fprintf( outfile, "\tcall %s\n ", asm_name("RELAY_DebugCallFrom16")); - - fprintf( outfile, "\tpopl %%edx\n" ); - fprintf( outfile, "\tpopl %%edx\n" ); - - if ( UsePIC ) - fprintf( outfile, "\tpopl %%ebx\n" ); - } - /* Call relay routine (which will call the API entry point) */ fprintf( outfile, "\tleal %d(%%edx), %%eax\n", sizeof(STACK16FRAME) ); fprintf( outfile, "\tpushl %%eax\n" ); fprintf( outfile, "\tpushl %d(%%edx)\n", STACK16OFFSET(entry_point) ); fprintf( outfile, "\tcall *%d(%%edx)\n", STACK16OFFSET(relay) ); - /* Print debug info after call */ - if ( debugging ) - { - if ( UsePIC ) - { - fprintf( outfile, "\tpushl %%ebx\n" ); - - /* Get Global Offset Table into %ebx (for PLT call) */ - fprintf( outfile, "\tcall .L__wine_call_from_16_%s.getgot3\n", name ); - fprintf( outfile, ".L__wine_call_from_16_%s.getgot3:\n", name ); - fprintf( outfile, "\tpopl %%ebx\n" ); - fprintf( outfile, "\taddl $_GLOBAL_OFFSET_TABLE_+[.-.L__wine_call_from_16_%s.getgot3], %%ebx\n", name ); - } - - fprintf( outfile, "\tpushl %%eax\n" ); - if ( reg_func ) - fprintf( outfile, "\tleal -%d(%%ebp), %%eax\n\tpushl %%eax\n", - sizeof(CONTEXT) + STRUCTOFFSET(STACK32FRAME, ebp) ); - else - fprintf( outfile, "\tpushl $0\n" ); - - if ( UsePIC ) - fprintf( outfile, "\tcall %s\n ", asm_name("RELAY_DebugCallFrom16Ret@PLT")); - else - fprintf( outfile, "\tcall %s\n ", asm_name("RELAY_DebugCallFrom16Ret")); - - fprintf( outfile, "\tpopl %%eax\n" ); - fprintf( outfile, "\tpopl %%eax\n" ); - - if ( UsePIC ) - fprintf( outfile, "\tpopl %%ebx\n" ); - } - - if ( reg_func ) { fprintf( outfile, "\tleal -%d(%%ebp), %%ebx\n", -- 2.11.4.GIT