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.
This commit is contained in:
Alexandre Julliard 2005-07-05 12:52:07 +00:00
parent 2440dcfe88
commit 2b33634018
4 changed files with 293 additions and 135 deletions

View File

@ -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);

View File

@ -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
}

View File

@ -281,61 +281,165 @@ static const CALLFROM16 *get_entry_point( STACK16FRAME *frame, LPSTR module, LPS
}
typedef int (*CDECL_PROC)();
typedef int (WINAPI *PASCAL_PROC)();
/***********************************************************************
* RELAY_DebugCallFrom16
* call_cdecl_function
*/
void RELAY_DebugCallFrom16( CONTEXT86 *context )
static int call_cdecl_function( CDECL_PROC func, int nb_args, const int *args )
{
STACK16FRAME *frame;
WORD ordinal;
char *args16, module[10], func[64];
const CALLFROM16 *call;
int i;
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;
}
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;
DPRINTF( "%04lx:Call %s.%d: %s(",GetCurrentThreadId(), module, ordinal, func );
args16 = (char *)(frame + 1);
/***********************************************************************
* 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++)
for (i = 0; i < 20; i++, nb_args++)
{
int type = (call->arg_types[i / 10] >> (3 * (i % 10))) & 7;
if (type == ARG_NONE) break;
if (i) DPRINTF( "," );
switch(type)
{
case ARG_WORD:
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 );
case ARG_SEGSTR:
args32[nb_args] = *(int *)args16;
args16 += sizeof(int);
break;
case ARG_PTR:
DPRINTF( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 );
args16 += sizeof(SEGPTR);
break;
case ARG_STR:
DPRINTF( "%08x %s", *(int *)args16,
debugstr_a( 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] = (int)MapSL( *(SEGPTR *)args16 );
args16 += sizeof(SEGPTR);
break;
case ARG_VARARG:
DPRINTF( "..." );
args32[nb_args] = (int)args16;
break;
default:
break;
@ -346,7 +450,72 @@ 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;
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_call_from_16
*
* Replacement for the 16-bit relay functions when relay debugging is on.
*/
int relay_call_from_16( void *entry_point, unsigned char *args16, CONTEXT86 *context )
{
STACK16FRAME *frame;
WORD ordinal;
int i, ret_val, nb_args, args32[20];
char module[10], func[64];
const CALLFROM16 *call;
frame = CURRENT_STACK16;
call = get_entry_point( frame, module, func, &ordinal );
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 );
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;
@ -355,30 +524,93 @@ 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;
}
}
}
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;
if (i) DPRINTF( "," );
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 );
}
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 );
/***********************************************************************
* RELAY_DebugCallFrom16Ret
*/
void RELAY_DebugCallFrom16Ret( CONTEXT86 *context, int ret_val )
{
STACK16FRAME *frame;
WORD ordinal;
char module[10], func[64];
const CALLFROM16 *call;
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__ */

View File

@ -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",