x86disas.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 969 行 · 第 1/2 页

C
969
字号
        th = X86T_DOUBLE;
        break;
    case DRT_X86_QWORD:
        th = X86T_QWORD;
        break;
    case DRT_X86_WORD:
        th = X86T_WORD;
        break;
    case DRT_X86_BYTE:
        th = X86T_BYTE;
        break;
    case DRT_X86_TBYTE:
        th = X86T_EXTENDED;
        break;
    case DRT_X86_FARPTR48:
        th = X86T_F32_PTR;
        break;
    case DRT_X86_FARPTR32:
        th = X86T_F16_PTR;
        break;
    default:
        th = X86T_BYTE;
        break;
    }
    addr.sect_id = 0;
    addr.indirect = 0;
    addr.mach.offset = op->value;
    if( op->base != DR_NONE ) {
        addr.mach.offset += RegValue( mr, op->base );
    }
    if( op->index != DR_NONE ) {
        addr.mach.offset += RegValue( mr, op->index ) * op->scale;
    }
    if( op->type & DO_NO_SEG_OVR ) {
        addr.mach.segment = RegValue( mr, DR_X86_es );
    } else {
        addr.mach.segment = RegValue( mr, GetSegRegOverride( dd, op ) );
    }
    if( dd->ins.flags & DIF_X86_ADDR_LONG ) {
        addr.mach.offset &= ~(dword)0;
    } else {
        addr.mach.offset &= ~(word)0;
    }
    mmk = MMK_READ;
    switch( dd->ins.type ) {
    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_ins:
    case DI_X86_stos:
        mmk = MMK_WRITE;
        break;
    case DI_X86_xchg:
    case DI_X86_xchg2:
    case DI_X86_inc:
    case DI_X86_inc2:
    case DI_X86_dec:
    case DI_X86_dec2:
        mmk |= MMK_WRITE;
        break;
    case DI_X86_cmps:
    case DI_X86_lods:
    case DI_X86_outs:
    case DI_X86_scas:
        break;
    case DI_X86_movzx:
    case DI_X86_movsx:
    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:
    case DI_X86_movs:
        if( opnd == OP_1 ) {
            mmk = MMK_WRITE;
        }
        break;
    default:
        if( dd->ins.num_ops >= 2 && opnd == OP_1 ) {
            mmk |= MMK_WRITE;
        }
        break;
    }
    return( wk( addr, th, mmk, d ) );
}

walk_result DoDisasmMemRefWalk( mad_disasm_data *dd, MEMREF_WALKER *wk, const mad_registers *mr, void *d )
{
    walk_result         wr;
    mad_type_handle     th;
    int                 i;

    th = (mad_type_handle)-1;
    switch( dd->ins.type ) {
    case DI_X86_ret:
    case DI_X86_ret2:
        th = (dd->ins.flags & DIF_X86_OPND_LONG) ? X86T_N32_PTR : X86T_N16_PTR;
        break;
    case DI_X86_retf:
    case DI_X86_retf2:
        th = (dd->ins.flags & DIF_X86_OPND_LONG) ? X86T_F32_PTR : X86T_F16_PTR;
        break;
    case DI_X86_iret:
    case DI_X86_iretd:
        th = (dd->ins.flags & DIF_X86_OPND_LONG) ? X86T_IRET32 : X86T_IRET16;
        break;
    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_popf:
    case DI_X86_popfd:
    case DI_X86_leave:
        th = (dd->ins.flags & DIF_X86_OPND_LONG) ? X86T_DWORD : X86T_WORD;
        break;
    case DI_X86_popa:
    case DI_X86_popad:
        th = (dd->ins.flags & DIF_X86_OPND_LONG) ? X86T_POPAD : X86T_POPA;
        break;
    default:
        break;
    }
    if( th != (mad_type_handle)-1 ) {
        wr = wk( GetRegSP( mr ), th, MMK_VOLATILE|MMK_IMPLICIT|MMK_READ, d );
        if( wr != WR_CONTINUE ) {
            return( wr );
        }
    }
    for( i = 0; i < dd->ins.num_ops; i++ ) {
        if( ( dd->ins.op[i].type & ( DO_MASK | DO_HIDDEN ) ) == DO_MEMORY_ABS ) {
            wr = MemReference( i, dd, wk, mr, d );
            if( wr != WR_CONTINUE ) {
                return( wr );
            }
        }
    }
    return( WR_CONTINUE );
}

struct memref_glue {
    MI_MEMREF_WALKER    *wk;
    void                *d;
};

static walk_result MemRefGlue( address a, mad_type_handle th, mad_memref_kind mk, void *d )
{
    struct memref_glue  *gd = d;

    return( gd->wk( a, th, mk, gd->d ) );
}

walk_result DIGENTRY MIDisasmMemRefWalk( mad_disasm_data *dd, MI_MEMREF_WALKER *wk, const mad_registers *mr, void *d )
{
    struct memref_glue  glue;

    glue.wk = wk;
    glue.d  = d;
    return( DoDisasmMemRefWalk( dd, MemRefGlue, mr, &glue ) );
}

const mad_toggle_strings *DIGENTRY MIDisasmToggleList( void )
{
    static const mad_toggle_strings list[] = {
        { MSTR_MUPPER, MSTR_UPPER, MSTR_LOWER },
        { MSTR_MINSIDE, MSTR_INSIDE, MSTR_OUTSIDE },
        { MSTR_NIL, MSTR_NIL, MSTR_NIL }
    };
    return( list );
}

unsigned DIGENTRY MIDisasmToggle( unsigned on, unsigned off )
{
    unsigned    toggle;

    toggle = (on & off);
    MADState->disasm_state ^= toggle;
    MADState->disasm_state |= on & ~toggle;
    MADState->disasm_state &= ~off | toggle;
    return( MADState->disasm_state );
}


static int RegAt( char *from, char *reg )
{
    unsigned    len;

    ++from;
    switch( *from ) {
    case 'e':
    case 'E':
        ++from;
    }
    len = strlen( reg );
    if( strnicmp( from, reg, len ) != 0 )
        return( 0 );
    if( isalnum( from[len] ) || from[len] == '_' )
        return( 0 );
    return( 1 );
}

static char *StrCopy( const char *s, char *d )
{
    for( ;; ) {
        *d = *s;
        if( *d == '\0' ) break;
        ++s;
        ++d;
    }
    return( d );
}

mad_status DIGENTRY MIDisasmInspectAddr( char *from, unsigned len, unsigned radix, const mad_registers *mr, address *a )
{
    char        *buff = __alloca( len * 2 );
    char        *to;
    int         parens;

    mr = mr;
    to = buff;
    parens = 0;
    while( len != 0 ) {
        switch( *from ) {
        case '[':
            *to++ = '+';
            *to++ = '(';
            if( RegAt( from, "bp" ) || RegAt( from, "sp" ) ) {
                to = StrCopy( "ss", to );
            } else {
                to = StrCopy( "ds", to );
            }
            to = StrCopy( ":(", to );
            break;
        case ']':
            to = StrCopy( "))", to );
            break;
        case ':':
            to = StrCopy( "):(", to );
            ++parens;
            break;
        default:
            *to++ = *from;
        }
        ++from;
        --len;
    }
    while( --parens >= 0 ) {
        memmove( buff+1, buff, to - buff + 1 );
        buff[0] = '(';
        ++to;
        *to++ = ')';
    }
    return( MCMemExpr( buff, to - buff, radix, a ) );
}

/*
 * CnvRadix -- convert an unsigned number of a given radix to a string
 */

char *CnvRadix( unsigned long value, unsigned radix, char base,
                char *buff, int len )
{
    char        internal[ 33 ];
    char        *ptr;
    unsigned    dig;

    ptr = &internal[ 32 ];
    for( ; len > 0 || value != 0; value /= radix ) {
        dig = value % radix;
        *ptr = (dig <= 9) ? dig + '0' : dig - 10 + base;
        --ptr;
        --len;
    }
    len = &internal[32] - ptr;
    memcpy( buff, ptr + 1, len );
    buff[ len ] = '\0';
    return( buff + len );
}

/****************** DISASSEMBLER INTERFACE **************************************/

/*
 * JmpLabel -- process a label
 */

char *JmpLabel( unsigned long addr, addr_off off )
{
    address             memaddr;
    mad_type_handle     th;
    char                *p;

    memaddr = DbgAddr;
    memaddr.mach.offset = addr;
    th = ( BIG_SEG( memaddr ) ) ? X86T_N32_PTR : X86T_N16_PTR;
    #define PREFIX_STR "CS:"
    #define PREFIX_LEN (sizeof(PREFIX_STR)-1)
    p = &ScratchBuff[ PREFIX_LEN ];
    if( MCAddrToString( memaddr, th, MLK_CODE, sizeof( ScratchBuff ) - 1 - PREFIX_LEN, p ) != MS_OK ) {
        p -= PREFIX_LEN;
        memcpy( p, PREFIX_STR, PREFIX_LEN );
    }
    return( p );
}

/*
 * ToSegStr -- convert to segment string
 */

char *ToSegStr( addr_off value, addr_seg seg, addr_off addr )
{
    address             memaddr;
    mad_type_handle     th;

    memaddr.mach.segment = seg;
    memaddr.mach.offset  = value;
    MCAddrSection( &memaddr );
    th = BIG_SEG( memaddr ) ? X86T_F32_PTR : X86T_F16_PTR;
    MCAddrToString( memaddr, th, MLK_MEMORY, sizeof( ScratchBuff ) - 1, ScratchBuff );
    return( ScratchBuff );
}


static void ReadMem( address a, unsigned s, void *d )
{

    if( a.sect_id == Cache.start.sect_id
     && a.mach.segment == Cache.start.mach.segment
     && a.mach.offset >= Cache.start.mach.offset
     && ( a.mach.offset + s ) < ( Cache.start.mach.offset + Cache.len ) ) {
        memcpy( d, &Cache.data[a.mach.offset-Cache.start.mach.offset], s );
        return;
    }
#if 0
    InitCache( a, Cache.want );
    if( a.sect_id == Cache.start.sect_id
     && a.mach.segment == Cache.start.mach.segment
     && a.mach.offset >= Cache.start.mach.offset
     && (a.mach.offset+s) < (Cache.start.mach.offset+Cache.len) ) {
        memcpy( d, &Cache.data[a.mach.offset-Cache.start.mach.offset], s );
        return;
    }
#endif
    MCReadMem( a, s, d );
}

signed_16 GetDataWord( void )
{
    signed_16   d;

    ReadMem( DbgAddr, sizeof( d ), &d );
    DbgAddr.mach.offset += sizeof( d );
    return( d );
}


signed_32 GetDataLong( void )
{
    signed_32   d;

    ReadMem( DbgAddr, sizeof( d ), &d );
    DbgAddr.mach.offset += sizeof( d );
    return( d );
}

void InitCache( address start, unsigned len )
{
    Cache.start = start;
    if( len > sizeof( Cache.data ) ) len = sizeof( Cache.data );
    Cache.want = len;
    Cache.len = MCReadMem( start, len, Cache.data );
}

dis_return DisCliGetData( void *d, unsigned off, unsigned int size, void *data )
{
    mad_disasm_data     *dd = d;
    address             addr;

    addr = dd->addr;
    addr.mach.offset += off;
    if( MCReadMem( addr, size, data ) == 0 ) return( DR_FAIL );
    return( DR_OK );
}

static int GetValueByteSize( unsigned long value )
{
    int                 size;

    for( size = 4; size > 1; size-- ) {
        if( value & 0xFF000000 )
            break;
        value <<= 8;
    }
    return( size );
}

unsigned DisCliValueString( void *d, dis_dec_ins *ins, unsigned opnd, char *buff )
{
    mad_disasm_data     *dd = d;
    char                *p;
    unsigned            max = 40;
    mad_type_info       mti;
    address             val;
    dis_operand         *op;
    int                 size;

    op = &ins->op[opnd];
    p = buff;
    p[0] = '\0';
    val = dd->addr;
    switch( op->type & DO_MASK ) {
    case DO_IMMED:
        switch( op->ref_type ) {
        case DRT_X86_BYTE:
            size = 1;
            break;
        case DRT_X86_WORD:
            size = 2;
            break;
        case DRT_X86_DWORD:
        case DRT_X86_DWORDF:
            size = 4;
            break;
        default:
            size = (ins->flags & DIF_X86_OPND_LONG) ? 4 : 2;
        }
        MCTypeInfoForHost( MTK_INTEGER, size , &mti );
        MCTypeToString( dd->radix, &mti, &op->value, &max, p );
        break;
    case DO_RELATIVE:
        val.mach.offset += op->value;
        MCAddrToString( val, (ins->flags & DIF_X86_OPND_LONG) ? X86T_N32_PTR : X86T_N16_PTR , MLK_CODE, max, p );
        break;
    case DO_ABSOLUTE:
        if( op->type & DO_EXTRA ) {
            val.mach.offset = op->value;
            val.mach.segment = op->extra;
            MCAddrToString( val, (ins->flags & DIF_X86_OPND_LONG) ? X86T_F32_PTR : X86T_F16_PTR , MLK_CODE, max, p );
            break;
        }
        /* fall through for LEA instruction */
    case DO_MEMORY_ABS:
    case DO_MEMORY_REL:
        if( op->base == DR_NONE && op->index == DR_NONE ) {
            // direct memory address
            MCTypeInfoForHost( MTK_INTEGER, (ins->flags & DIF_X86_ADDR_LONG) ? 4 : 2 , &mti );
            MCTypeToString( dd->radix, &mti, &op->value, &max, p );
        } else if( op->value == 0 ) {
            // don't output zero disp in indirect memory address
        } else {
            // indirect memory address with displacement
            if( op->value < 0 ) {
                *(p++) = '-';
                op->value = - op->value;
            }
            size = GetValueByteSize( op->value );
            MCTypeInfoForHost( MTK_INTEGER, size , &mti );
            MCTypeToString( dd->radix, &mti, &op->value, &max, p );
        }
        break;
    }
    return( strlen( buff ) );
}

mad_status DisasmInit()
{
    if( DisInit( DISCPU_x86, &DH, FALSE ) != DR_OK ) {
        return( MS_ERR | MS_FAIL );
    }
    return( MS_OK );
}

void DisasmFini()
{
    DisFini( &DH );
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?