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 + -
显示快捷键?