x86disas.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 969 行 · 第 1/2 页
C
969 行
/****************************************************************************
*
* 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: MAD interface to x86 disassembler.
*
****************************************************************************/
#include <string.h>
#include <stddef.h>
#include <ctype.h>
#include "walloca.h"
#include "x86.h"
#include "x86types.h"
#include "madregs.h"
#define OP_1 0
static dis_handle DH;
address DbgAddr;
static dword RegValue( const mad_registers *mr, int idx );
static char ScratchBuff[40];
static struct {
address start;
unsigned len;
unsigned want;
unsigned_8 data[0x80];
} Cache;
unsigned DIGENTRY MIDisasmDataSize( void )
{
return( sizeof( mad_disasm_data ) );
}
unsigned DIGENTRY MIDisasmNameMax( void )
{
return( DisInsNameMax( &DH ) );
}
void DoCode( mad_disasm_data *dd, int big )
{
DisDecodeInit( &DH, &dd->ins );
dd->addr = DbgAddr;
dd->ins.flags = ( big ) ? DIF_X86_USE32_FLAGS : 0;
DisDecode( &DH, dd, &dd->ins );
}
void DecodeIns( address *a, mad_disasm_data *dd, int big )
{
DbgAddr = *a;
InitCache( DbgAddr, 0x8 );
DoCode( dd, big );
a->mach.offset += dd->ins.size;
}
mad_status GetDisasmPrev( address *a )
{
mad_disasm_data dd;
addr_off start;
addr_off curr_off;
addr_off prev;
unsigned backup;
int big;
DbgAddr = *a;
big = BIG_SEG( DbgAddr );
backup = ( big ) ? 0x40 : 0x20;
curr_off = DbgAddr.mach.offset;
DbgAddr.mach.offset = (curr_off <= backup) ? 0 : (curr_off - backup);
InitCache( DbgAddr, curr_off - DbgAddr.mach.offset );
for( start = DbgAddr.mach.offset; start < curr_off; ++start ) {
DbgAddr.mach.offset = start;
for( ;; ) {
prev = DbgAddr.mach.offset;
DoCode( &dd, big );
if( dd.ins.size == 0 )
break; /* invalid address */
DbgAddr.mach.offset += dd.ins.size;
if( DbgAddr.mach.offset == curr_off ) {
a->mach.offset = prev;
return( MS_OK );
}
if( DbgAddr.mach.offset > curr_off ) break;
if( DbgAddr.mach.offset < start ) break; /* wrapped around segment */
}
}
/* Couldn't sync instruction stream */
return( MS_FAIL );
}
mad_status DIGENTRY MIDisasm( mad_disasm_data *dd, address *a, int adj )
{
mad_status ms;
dd->characteristics = AddrCharacteristics( *a );
while( adj < 0 ) {
ms = GetDisasmPrev( a );
if( ms != MS_OK ) return( ms );
++adj;
}
while( adj >= 0 ) {
DecodeIns( a, dd, dd->characteristics & X86AC_BIG );
--adj;
}
return( MS_OK );
}
unsigned DIGENTRY MIDisasmFormat( mad_disasm_data *dd, mad_disasm_piece dp, unsigned radix, unsigned max, char *buff )
{
char nbuff[20];
char obuff[256];
char *np;
char *op;
unsigned nlen;
unsigned olen;
unsigned len;
dis_format_flags ff;
nbuff[0] = '\0';
obuff[0] = '\0';
np = (dp & MDP_INSTRUCTION) ? nbuff : NULL;
op = (dp & MDP_OPERANDS) ? obuff : NULL;
ff = DFF_ASM;
if( MADState->disasm_state & DT_UPPER ) ff |= DFF_INS_UP | DFF_REG_UP;
if( MADState->disasm_state & DT_INSIDE ) ff |= DFF_X86_ALT_INDEXING;
dd->radix = radix;
if( DisFormat( &DH, dd, &dd->ins, ff, np, op ) != DR_OK ) {
return( 0 );
}
olen = strlen( obuff );
nlen = strlen( nbuff );
if( dp == MDP_ALL ) nbuff[ nlen++ ] = ' ';
len = nlen + olen;
if( max > 0 ) {
--max;
if( max > len ) max = len;
if( nlen > max ) nlen = max;
memcpy( buff, nbuff, nlen );
buff += nlen;
max -= nlen;
if( olen > max ) olen = max;
memcpy( buff, obuff, olen );
buff[max] = '\0';
}
return( len );
}
unsigned DIGENTRY MIDisasmInsSize( mad_disasm_data *dd )
{
return( dd->ins.size );
}
mad_status DIGENTRY MIDisasmInsUndoable( mad_disasm_data *dd )
{
switch( dd->ins.type ) {
case DI_X86_bound:
case DI_X86_int:
case DI_X86_into:
case DI_X86_in:
case DI_X86_in2:
case DI_X86_ins:
case DI_X86_lgdt:
case DI_X86_lidt:
case DI_X86_lldt:
case DI_X86_lmsw:
case DI_X86_out:
case DI_X86_out2:
case DI_X86_outs:
return( MS_FAIL );
default:
break;
}
return( MS_OK );
}
static unsigned Adjustment( mad_disasm_data *dd )
{
switch( dd->ins.op[ OP_1 ].type & DO_MASK ) {
case DO_IMMED:
case DO_RELATIVE:
if( dd->ins.op[ OP_1 ].value < dd->addr.mach.offset ) return( MDC_TAKEN_BACK );
return( MDC_TAKEN_FORWARD );
}
return( MDC_TAKEN );
}
static mad_disasm_control Cond( mad_disasm_data *dd, int taken )
{
if( !taken )
return( MDC_JUMP | MDC_CONDITIONAL | MDC_TAKEN_NOT );
return( (MDC_JUMP | MDC_CONDITIONAL) + Adjustment( dd ) );
}
mad_disasm_control DisasmControl( mad_disasm_data *dd, const mad_registers *mr )
{
char xor;
unsigned long val;
xor = 0;
switch( dd->ins.type ) {
case DI_X86_int:
return( MDC_SYSCALL | MDC_TAKEN );
case DI_X86_call:
case DI_X86_call2:
case DI_X86_call3:
case DI_X86_call4:
return( MDC_CALL | MDC_TAKEN );
case DI_X86_jmp:
case DI_X86_jmp1:
return( MDC_JUMP + Adjustment( dd ) );
case DI_X86_iret:
case DI_X86_iretd:
return( MDC_SYSRET | MDC_TAKEN );
case DI_X86_ret:
case DI_X86_ret2:
case DI_X86_retf:
case DI_X86_retf2:
return( MDC_RET | MDC_TAKEN );
case DI_X86_jmp2:
case DI_X86_jmp3:
case DI_X86_jmp4:
return( MDC_JUMP | MDC_TAKEN );
case DI_X86_bound:
return( MDC_OPER | MDC_TAKEN_NOT ); /* not supported yet */
case DI_X86_jno:
case DI_X86_jno2:
xor = 1;
case DI_X86_jo:
case DI_X86_jo2:
return Cond( dd, ( ( mr->x86.cpu.efl & FLG_O ) != 0 ) ^ xor );
case DI_X86_jae:
case DI_X86_jae2:
xor = 1;
case DI_X86_jb:
case DI_X86_jb2:
return Cond( dd, ( ( mr->x86.cpu.efl & FLG_C ) != 0 ) ^ xor );
case DI_X86_jne:
case DI_X86_jne2:
xor = 1;
case DI_X86_je:
case DI_X86_je2:
return Cond( dd, ( ( mr->x86.cpu.efl & FLG_Z ) != 0 ) ^ xor );
case DI_X86_ja:
case DI_X86_ja2:
xor = 1;
case DI_X86_jbe:
case DI_X86_jbe2:
return Cond( dd, ( ( mr->x86.cpu.efl & ( FLG_C | FLG_Z ) ) != 0 ) ^ xor );
case DI_X86_jns:
case DI_X86_jns2:
xor = 1;
case DI_X86_js:
case DI_X86_js2:
return Cond( dd, ( ( mr->x86.cpu.efl & FLG_S ) != 0 ) ^ xor );
case DI_X86_jpo:
case DI_X86_jpo2:
xor = 1;
case DI_X86_jp:
case DI_X86_jp2:
return Cond( dd, ( ( mr->x86.cpu.efl & FLG_P ) != 0 ) ^ xor );
case DI_X86_jge:
case DI_X86_jge2:
xor = 1;
case DI_X86_jl:
case DI_X86_jl2:
return Cond( dd, ( ( mr->x86.cpu.efl & FLG_S ) != 0 )
^ ( ( mr->x86.cpu.efl & FLG_O ) !=0 )
^ xor );
case DI_X86_jg:
case DI_X86_jg2:
xor = 1;
case DI_X86_jle:
case DI_X86_jle2:
return Cond( dd, ( ( ( ( mr->x86.cpu.efl & FLG_S ) != 0 )
^ ( ( mr->x86.cpu.efl & FLG_O ) != 0 ) )
| ( ( mr->x86.cpu.efl & FLG_Z ) != 0 ) )
^ xor );
case DI_X86_into:
return( ( mr->x86.cpu.efl & FLG_O ) != 0
? ( MDC_SYSCALL|MDC_CONDITIONAL|MDC_TAKEN )
: ( MDC_SYSCALL|MDC_CONDITIONAL|MDC_TAKEN_NOT ) );
case DI_X86_loopnz:
val= mr->x86.cpu.ecx;
if( !( dd->ins.flags & DIF_X86_OPND_LONG ) )
val &= 0xffff;
return Cond( dd, ( mr->x86.cpu.efl & FLG_Z ) == 0 && val != 1 );
case DI_X86_loopz:
val= mr->x86.cpu.ecx;
if( !( dd->ins.flags & DIF_X86_OPND_LONG ) )
val &= 0xffff;
return Cond( dd, ( mr->x86.cpu.efl & FLG_Z ) != 0 && val != 1 );
case DI_X86_loop:
val= mr->x86.cpu.ecx;
if( !( dd->ins.flags & DIF_X86_OPND_LONG ) )
val &= 0xffff;
return Cond( dd, val != 1 );
case DI_X86_jcxz:
case DI_X86_jecxz:
val= mr->x86.cpu.ecx;
if( !( dd->ins.flags & DIF_X86_OPND_LONG ) )
val &= 0xffff;
return Cond( dd, val == 0 );
default:
break;
}
return( MDC_OPER | MDC_TAKEN_NOT );
}
mad_disasm_control DIGENTRY MIDisasmControl( mad_disasm_data *dd, const mad_registers *mr )
{
return( DisasmControl( dd, mr ) );
}
static walk_result FindCallTarget( address a, mad_type_handle th, mad_memref_kind mk, void *d )
{
*(address *)d = a;
return( WR_STOP );
}
mad_status DIGENTRY MIDisasmInsNext( mad_disasm_data *dd, const mad_registers *mr, address *next )
{
mad_disasm_control dc;
*next = GetRegIP( mr );
next->mach.offset += dd->ins.size;
dc = DisasmControl( dd, mr );
if( (dc & MDC_TAKEN_MASK) == MDC_TAKEN_NOT ) {
return( MS_OK );
}
switch( dc & MDC_TYPE_MASK ) {
case MDC_SYSCALL:
return( MS_FAIL );
case MDC_JUMP:
case MDC_CALL:
switch( dd->ins.op[ OP_1 ].type & DO_MASK ) {
case DO_ABSOLUTE:
next->mach.segment = dd->ins.op[ OP_1 ].extra;
/* fall through */
case DO_RELATIVE:
next->mach.offset = dd->ins.op[ OP_1 ].value;
break;
case DO_REG:
next->mach.offset = RegValue( mr, dd->ins.op[ OP_1 ].base );
break;
default:
/* memory indirect jump/call */
DoDisasmMemRefWalk( dd, FindCallTarget, mr, &DbgAddr );
if( dd->ins.flags & DIF_X86_OPND_LONG ) {
next->mach.offset = GetDataLong();
if( dd->ins.op[ OP_1 ].ref_type == DRT_X86_FARPTR48 ) {
next->mach.segment = (unsigned_16)GetDataWord();
}
} else {
next->mach.offset = (unsigned_16)GetDataWord();
if( dd->ins.op[ OP_1 ].ref_type == DRT_X86_FARPTR32 ) {
next->mach.segment = (unsigned_16)GetDataWord();
}
}
break;
}
break;
case MDC_SYSRET:
case MDC_RET:
DbgAddr = GetRegSP( mr );
if( dd->ins.flags & DIF_X86_OPND_LONG ) {
next->mach.offset = GetDataLong();
} else {
next->mach.offset = (unsigned_16)GetDataWord();
}
switch( dd->ins.type ) {
case DI_X86_retf:
case DI_X86_retf2:
next->mach.segment = (unsigned_16)GetDataWord();
break;
default:
break;
}
break;
}
return( MS_OK );
}
static const unsigned_8 RegIndex[] = {
offsetof( mad_registers, x86.cpu.eax ),
offsetof( mad_registers, x86.cpu.ecx ),
offsetof( mad_registers, x86.cpu.edx ),
offsetof( mad_registers, x86.cpu.ebx ),
offsetof( mad_registers, x86.cpu.esp ),
offsetof( mad_registers, x86.cpu.ebp ),
offsetof( mad_registers, x86.cpu.esi ),
offsetof( mad_registers, x86.cpu.edi ),
offsetof( mad_registers, x86.cpu.es ),
offsetof( mad_registers, x86.cpu.cs ),
offsetof( mad_registers, x86.cpu.ss ),
offsetof( mad_registers, x86.cpu.ds ),
offsetof( mad_registers, x86.cpu.fs ),
offsetof( mad_registers, x86.cpu.gs ),
};
static dword RegValue( const mad_registers *mr, int idx )
{
dword *reg;
dword mask;
if( idx >= DR_X86_es && idx <= DR_X86_gs ) {
idx -= DR_X86_es - 8;
mask = 0xffff;
} else if( idx >= DR_X86_ax && idx <= DR_X86_di ) {
idx -= DR_X86_ax;
mask = 0xffff;
} else {
idx -= DR_X86_eax;
mask = 0xffffffff;
}
reg = (dword *)( (unsigned_8 *)mr + RegIndex[ idx ] );
return( *reg & mask );
}
int GetSegRegOverride( mad_disasm_data *dd, dis_operand *op )
{
if( dd->ins.flags & DIF_X86_CS ) {
return( DR_X86_cs );
} else if( dd->ins.flags & DIF_X86_DS ) {
return( DR_X86_ds );
} else if( dd->ins.flags & DIF_X86_ES ) {
return( DR_X86_es );
} else if( dd->ins.flags & DIF_X86_FS ) {
return( DR_X86_fs );
} else if( dd->ins.flags & DIF_X86_GS ) {
return( DR_X86_gs );
} else if( dd->ins.flags & DIF_X86_SS ) {
return( DR_X86_ss );
} else {
switch( op->base ) {
case DR_X86_sp:
case DR_X86_esp:
case DR_X86_bp:
case DR_X86_ebp:
return( DR_X86_ss );
default:
return( DR_X86_ds );
}
}
}
walk_result MemReference( int opnd, mad_disasm_data *dd, MEMREF_WALKER *wk, const mad_registers *mr, void *d )
{
mad_type_handle th;
address addr;
dis_operand *op;
mad_memref_kind mmk;
op = &dd->ins.op[opnd];
switch( op->ref_type ) {
case DRT_X86_DWORDF:
th = X86T_FLOAT;
break;
case DRT_X86_DWORD:
th = X86T_DWORD;
break;
case DRT_X86_QWORDF:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?