x86trace.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 397 行
C
397 行
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: Execution tracing support for x86.
*
****************************************************************************/
#include <stddef.h>
#include <string.h>
#include "x86.h"
#include "madregs.h"
unsigned DIGENTRY MITraceSize( void )
{
return( sizeof( mad_trace_data ) );
}
void DIGENTRY MITraceInit( mad_trace_data *td, const mad_registers *mr )
{
td->prev_ins_type = -1;
td->prev_ins_flags = 0;
}
mad_status DIGENTRY MITraceHaveRecursed( address watch_stack, const mad_registers *mr )
{
if( mr->x86.cpu.ss == watch_stack.mach.segment
&& mr->x86.cpu.esp < watch_stack.mach.offset ) {
/*
we're down some levels in a recursive call -- want to unwind.
*/
return( MS_OK );
}
return( MS_FAIL );
}
/*
* BreakRet -- put a break point at the return address of a routine
*/
static void BreakRet( mad_trace_data *td, mad_disasm_data *dd, const mad_registers *mr )
{
address sp;
union {
addr32_off off32;
addr48_off off48;
} off;
sp = GetRegSP( mr );
if( dd->characteristics & X86AC_BIG ) {
MCReadMem( sp, sizeof( off.off48 ), &off.off48 );
sp.mach.offset += sizeof( off.off48 );
td->brk.mach.offset = off.off48;
} else {
MCReadMem( sp, sizeof( off.off32 ), &off.off32 );
sp.mach.offset += sizeof( off.off32 );
td->brk.mach.offset = off.off32;
}
switch( td->prev_ins_type ) {
case DI_X86_call:
case DI_X86_call2:
case DI_X86_ret:
case DI_X86_ret2:
td->brk.mach.segment = mr->x86.cpu.cs;
break;
case DI_X86_call3:
case DI_X86_call4:
case DI_X86_int:
case DI_X86_into:
case DI_X86_iret:
case DI_X86_iretd:
case DI_X86_retf:
case DI_X86_retf2:
MCReadMem( sp, sizeof( td->brk.mach.segment ), &td->brk.mach.segment );
sp.mach.offset += sizeof( td->brk.mach.segment );
break;
default:
break;
}
MCAddrSection( &td->brk );
}
/*
* BreakNext -- put a break point at the next instruction
*/
static void BreakNext( mad_trace_data *td, mad_disasm_data *dd )
{
td->brk = dd->addr;
td->brk.mach.offset += dd->ins.size;
}
static mad_trace_how DoTraceOne( mad_trace_data *td, mad_disasm_data *dd, mad_trace_kind tk, const mad_registers *mr )
{
switch( tk ) {
case MTRK_OUT:
BreakRet( td, dd, mr );
return( MTRH_BREAK );
case MTRK_INTO:
return( MTRH_STEP );
case MTRK_OVER:
switch( dd->ins.type ) {
case DI_X86_call:
/* Handle special case of a call to the next instruction, which is
* used under Linux to get the GOT pointer when compiled for
* 386 processors.
*/
if( dd->ins.op[0].value == dd->ins.size )
return( MTRH_STEP );
/* Fall through for normal handling */
case DI_X86_call2:
case DI_X86_call3:
case DI_X86_call4:
case DI_X86_int:
case DI_X86_into:
BreakNext( td, dd );
return( MTRH_BREAK );
case DI_X86_movs:
case DI_X86_cmps:
case DI_X86_scas:
case DI_X86_lods:
case DI_X86_stos:
case DI_X86_outs:
case DI_X86_ins:
if( dd->ins.flags & (DIF_X86_REPE|DIF_X86_REPNE|DIF_X86_FWAIT) ) {
BreakNext( td, dd );
return( MTRH_BREAK );
}
return( MTRH_STEP );
default:
break;
}
return( MTRH_STEP );
case MTRK_NEXT:
BreakNext( td, dd );
return( MTRH_BREAK );
}
return( MTRH_STOP );
}
/*
* CheckSpecial - check for instructions we have to handle specially or
* we'll have problems
*/
static mad_trace_how CheckSpecial( mad_trace_data *td, mad_disasm_data *dd, const mad_registers *mr, mad_trace_how th )
{
if( th != MTRH_STEP ) return( th );
switch( dd->ins.type ) {
case DI_X86_int:
if( dd->ins.flags & DIF_X86_EMU_INT )
break;
/* fall through */
case DI_X86_into:
if( !( dd->characteristics & X86AC_REAL ) )
break;
return( MTRH_SIMULATE );
case DI_X86_iret:
case DI_X86_iretd:
BreakRet( td, dd, mr );
return( MTRH_STEPBREAK );
case DI_X86_pop:
case DI_X86_pop2:
case DI_X86_pop3d:
case DI_X86_pop3e:
case DI_X86_pop3s:
case DI_X86_pop4f:
case DI_X86_pop4g:
case DI_X86_mov:
case DI_X86_mov2:
case DI_X86_mov3:
case DI_X86_mov4:
case DI_X86_mov5:
case DI_X86_mov6:
case DI_X86_mov7:
if( dd->ins.op[0].type != DO_REG )
return( MTRH_STEP );
switch( dd->ins.op[0].base ) {
case DR_X86_es:
case DR_X86_ds:
if( ( MCSystemConfig()->cpu & X86_CPU_MASK ) < X86_386 )
break;
/* fall through */
default:
return( MTRH_STEP );
}
break;
case DI_X86_pushf:
case DI_X86_pushfd:
case DI_X86_popf:
case DI_X86_popfd:
break;
case DI_X86_fwait:
if( MCSystemConfig()->fpu != X86_EMU )
return( MTRH_STEP );
break;
default:
if( dd->ins.flags & DIF_X86_EMU_INT ) break;
if( ( dd->ins.flags & DIF_X86_FP_INS )
&& ( ( dd->ins.flags & DIF_X86_FWAIT ) || ( MCSystemConfig()->fpu == X86_EMU ) ) )
break;
return( MTRH_STEP );
}
BreakNext( td, dd );
return( MTRH_STEPBREAK );
}
static walk_result TouchesScreenBuff( address a, mad_type_handle th, mad_memref_kind mk, void *d )
{
const mad_registers *mr = d;
th = th;
if( mk & MMK_IMPLICIT )
return( WR_CONTINUE );
switch( MCSystemConfig()->os ) {
case OS_DOS:
if( a.mach.segment < 0xa000 || a.mach.segment >= 0xc000 )
return( WR_CONTINUE );
break;
case OS_RATIONAL:
if( a.mach.segment != mr->x86.cpu.cs && a.mach.segment != mr->x86.cpu.ds )
return( WR_CONTINUE );
if( a.mach.offset < 0xa0000UL || a.mach.offset >= 0xc0000UL )
return( WR_CONTINUE );
break;
case OS_AUTOCAD:
case OS_PHARLAP:
case OS_ECLIPSE:
if( a.mach.segment == mr->x86.cpu.cs
|| a.mach.segment == mr->x86.cpu.ds )
return( WR_CONTINUE );
break;
}
MCNotify( MNT_EXECUTE_TOUCH_SCREEN_BUFF, NULL );
return( WR_STOP );
}
mad_trace_how DIGENTRY MITraceOne( mad_trace_data *td, mad_disasm_data *dd, mad_trace_kind tk, const mad_registers *mr, address *brk )
{
mad_trace_how th;
th = DoTraceOne( td, dd, tk, mr );
th = CheckSpecial( td, dd, mr, th );
switch( MCSystemConfig()->os ) {
case OS_OS2:
case OS_NW386:
case OS_QNX:
case OS_WINDOWS:
case OS_NT:
break;
default:
DoDisasmMemRefWalk( dd, TouchesScreenBuff, mr, (void *)mr );
break;
}
td->prev_ins_type = dd->ins.type;
td->prev_ins_flags = dd->ins.flags;
switch( th ) {
case MTRH_BREAK:
switch( td->prev_ins_type ) {
case DI_X86_call:
case DI_X86_call2:
case DI_X86_call3:
case DI_X86_call4:
case DI_X86_int:
case DI_X86_into:
MCNotify( MNT_EXECUTE_LONG, NULL );
break;
default:
break;
}
/* fall through */
case MTRH_STEPBREAK:
*brk = td->brk;
break;
}
return( th );
}
mad_status DIGENTRY MITraceSimulate( mad_trace_data *td, mad_disasm_data *dd, const mad_registers *in, mad_registers *out )
{
address sp;
word value;
td = td;
switch( dd->ins.type ) {
case DI_X86_into:
if( !( in->x86.cpu.efl & FLG_O ) ) {
out->x86 = in->x86;
out->x86.cpu.eip += dd->ins.size;
return( MS_OK );
}
/* fall through */
case DI_X86_int:
/* only in real mode */
if( !( dd->characteristics & X86AC_REAL ) )
break;
out->x86 = in->x86;
sp = GetRegSP( out );
sp.mach.offset -= sizeof( word );
value = out->x86.cpu.efl;
MCWriteMem( sp, sizeof( value ), &value );
out->x86.cpu.efl &= ~FLG_I;
value = out->x86.cpu.cs;
MCWriteMem( sp, sizeof( value ), &value );
value = out->x86.cpu.eip;
MCWriteMem( sp, sizeof( value ), &value );
out->x86.cpu.esp = sp.mach.offset;
return( MS_OK );
default:
break;
}
return( MS_UNSUPPORTED );
}
void DIGENTRY MITraceFini( mad_trace_data *td )
{
td = td;
}
#define JMP_SHORT ((unsigned char)0XEB)
#define BRK_POINT ((unsigned char)0XCC)
mad_status DIGENTRY MIUnexpectedBreak( mad_registers *mr, unsigned *maxp, char *buff )
{
address a;
union {
byte b[9];
addr32_ptr a32;
addr48_ptr a48;
} data;
unsigned max;
unsigned len;
max = *maxp;
*maxp = 0;
if( max > 0 )
buff[0] = '\0';
a = GetRegIP( mr );
memset( &data, 0, sizeof( data ) );
MCReadMem( a, sizeof( data.b ), &data );
if( data.b[0] != BRK_POINT )
return( MS_FAIL );
mr->x86.cpu.eip += 1;
if( data.b[1] != JMP_SHORT )
return( MS_OK );
if( memcmp( &data.b[3], "WVIDEO", 6 ) != 0 )
return( MS_OK );
a = GetRegSP( mr );
MCReadMem( a, sizeof( addr_ptr ), &data );
if( BIG_SEG( a ) ) {
a.mach = data.a48;
} else {
ConvAddr32ToAddr48( data.a32, a.mach );
}
len = 0;
for( ;; ) {
if( MCReadMem( a, sizeof( data.b[0] ), &data.b[0] ) == 0 )
break;
a.mach.offset++;
if( len < max )
buff[len] = data.b[0];
if( data.b[0] == '\0' )
break;
++len;
}
if( max > 0 )
buff[max] = '\0';
*maxp = len;
return( MS_OK );
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?