disentry.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 375 行

C
375
字号
/****************************************************************************
*
*                            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:  CPU independent instruction decoding core.
*
****************************************************************************/


#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "distypes.h"
#include "dis.h"
#include "distbls.gh"

#if DISCPU & DISCPU_axp
extern const dis_cpu_data       AXPData;
#endif
#if DISCPU & DISCPU_ppc
extern const dis_cpu_data       PPCData;
#endif
#if DISCPU & DISCPU_x86
extern const dis_cpu_data       X86Data;
#endif
#if DISCPU & DISCPU_x64
extern const dis_cpu_data       X64Data;
#endif
#if DISCPU & DISCPU_jvm
extern const dis_cpu_data       JVMData;
#endif
#if DISCPU & DISCPU_sparc
extern const dis_cpu_data       SPARCData;
#endif
#if DISCPU & DISCPU_mips
extern const dis_cpu_data       MIPSData;
#endif

long SEX( unsigned long v, unsigned bit )
{
    unsigned long chk;

    chk = 1UL << bit;
    if( v & chk ) {
        v |= ~(chk - 1);
    }
    return( v );
}

#define LENGTH_BIT      0x80

unsigned DisGetString( unsigned index, char *buff, int upper )
{
    unsigned            len;
    unsigned            i;
    const unsigned char *src;
    unsigned char       c;

    src = &DisStringTable[index];
    len = *src++ & ~LENGTH_BIT;
    i = len;
    for( ;; ) {
        if( i == 0 ) break;
        c = *src++;
        if( !(c & LENGTH_BIT) ) {
            if( upper ) c = toupper( c );
            *buff++ = c;
            --i;
        }
    }
    *buff = '\0';
    return( len );
}

dis_handler_return DisDummyHandler( dis_handle *h, void *d, dis_dec_ins *ins )
{
    return( DHR_INVALID );
}

dis_return DisInit( dis_cpu cpu, dis_handle *h, bool swap_bytes )
// Perform all setup required
{
    h->cpu = cpu;
    switch( cpu ) {
#if DISCPU & DISCPU_axp
    case DISCPU_axp:
        h->d = &AXPData;
        break;
#endif
#if DISCPU & DISCPU_ppc
    case DISCPU_ppc:
        h->d = &PPCData;
        break;
#endif
#if DISCPU & DISCPU_x86
    case DISCPU_x86:
        h->d = &X86Data;
        break;
#endif
#if DISCPU & DISCPU_x64
    case DISCPU_x64:
        h->d = &X64Data;
        break;
#endif
#if DISCPU & DISCPU_jvm
    case DISCPU_jvm:
        h->d = &JVMData;
        break;
#endif
#if DISCPU & DISCPU_sparc
    case DISCPU_sparc:
        h->d = &SPARCData;
        break;
#endif
#if DISCPU & DISCPU_mips
    case DISCPU_mips:
        h->d = &MIPSData;
        break;
#endif
    default:
        return( DR_FAIL );
    }
    if( h->d->range == NULL ) return( DR_FAIL );
    h->need_bswap = swap_bytes;
    return( DR_OK );
}

void DisFini( dis_handle *h )
// Perform all shutdown required
{
    h = h;
}

void DisDecodeInit( dis_handle *h, dis_dec_ins *ins )
// Initialize a decoded instruction structure
{
    memset( ins, 0, sizeof( *ins ) );
    ins->num_ops = MAX_NUM_OPERANDS + 1;
    switch( h->cpu ) {
    case DISCPU_axp:
    case DISCPU_ppc:
    case DISCPU_sparc:
    case DISCPU_mips:
        ins->size = sizeof( unsigned_32 );
        break;
    }
}

static void BadOpcode( dis_handle *h, dis_dec_ins *ins )
{
    DisDecodeInit( h, ins );
    ins->type = DI_INVALID;
    ins->size = h->d->inssize_inc;
    ins->num_ops = 0;
}

dis_return DisDecode( dis_handle *h, void *d, dis_dec_ins *ins )
// Decode an instruction
{
    int                     curr;
    const dis_range        *table;
    dis_return              dr;
    unsigned                idx;
    unsigned                start;
    dis_handler_return      hr;
    int                     page;
    int const              *pos;
    int                     offs;

    start = 0;
    curr  = 0;
    table = h->d->range;
    for( ;; ) {
        dr = DisCliGetData( d, start, sizeof( ins->opcode ), &ins->opcode );
        if( dr != DR_OK ) {
            ins->num_ops = 0;   /* must reset num_ops before returning! */
            return( dr );
        }
        h->d->preproc_hook( h, d, ins );
        page = 0;
        for( pos = h->d->range_pos ; *pos != -1 ; ++pos, ++page ) {
            if( h->d->decode_check( page, ins ) != DHR_DONE )
                continue;
            offs = *pos;
            curr = 0;
            for( ;; ) {
                idx = (ins->opcode >> table[curr+offs].shift) & table[curr+offs].mask;
                curr = DisSelectorTable[idx + table[curr+offs].index];
                if( curr >= 0 ) break;
                curr = -curr;
            }
            if( (DisInstructionTable[curr].mask & ins->opcode) == DisInstructionTable[curr].opcode ) {
                break;
            }
        }
        if( *pos == -1 ) {
            BadOpcode( h, ins );
            break;
        }
        ins->type = curr;
        hr = DisInstructionTable[curr].handler( h, d, ins );
        if( hr == DHR_DONE ) break;
        if( hr == DHR_INVALID ) {
            BadOpcode( h, ins );
            break;
        }
        start = ins->size;
    }
    if( ins->num_ops > MAX_NUM_OPERANDS ) {
        /* nobody's set the number of operands */
        for( idx = 0; idx < MAX_NUM_OPERANDS; ++idx ) {
            if( ins->op[idx].type == DO_NONE ) break;
        }
        ins->num_ops = idx;
    }
    return( DR_OK );
}

char *DisAddReg( dis_register reg, char *dst, dis_format_flags flags )
{
    return( &dst[ DisGetString( DisRegisterTable[reg], dst,
                        (flags & DFF_REG_UP) ) ] );
}

char *DisOpFormat( dis_handle *h, void *d, dis_dec_ins *ins, dis_format_flags flags,
                        unsigned i, char *p )
{
    const char chLbrac = ( h->cpu == DISCPU_sparc ) ? '[' : '(';
    const char chRbrac = ( h->cpu == DISCPU_sparc ) ? ']' : ')';

    
    // BartoszP 23.10.2005
    // for SPARC architecture DO_IMMED value could not be emited before
    // other arguments (registers) so we should dissassembly like:
    //   [ %reg + offset ]
    // not like x86:
    //   offset[reg]
    if( h->cpu != DISCPU_sparc ) {
        p += DisCliValueString( d, ins, i, p );
    }
    switch( ins->op[i].type & DO_MASK ) {
    case DO_IMMED:
        if( h->cpu == DISCPU_sparc ) {
            p += DisCliValueString( d, ins, i, p );
        }
        break;
    case DO_REG:
        p = DisAddReg( ins->op[i].base, p, flags );
        break;
    case DO_ABSOLUTE:
    case DO_RELATIVE:
        if( h->cpu == DISCPU_sparc ) {
            p += DisCliValueString( d, ins, i, p );
            break;
        }
    case DO_MEMORY_ABS:
    case DO_MEMORY_REL:
        if( ins->op[i].base != DR_NONE || ins->op[i].index != DR_NONE ) {
            *p++ = chLbrac;
            p = DisAddReg( ins->op[i].base, p, flags );
            if( h->cpu != DISCPU_sparc ) {
                if( ins->op[i].index != DR_NONE ) {
                    *p++ = ',';
                    p = DisAddReg( ins->op[i].index, p, flags );
                    if( ins->op[i].scale != 1 ) {
                        *p++ = ',';
                        *p++ = '0' + ins->op[i].scale;
                    }
                }
            } else {
                // SPARC stuff
                if( ins->op[i].index != DR_NONE 
                     && ( DO_MEMORY_ABS == (ins->op[i].type & DO_MASK ) ) ) {
                    // ASI stuff
                } else if( ins->op[i].index == DR_NONE
                            && ins->op[i].value != 0 ) {
                    // always add offset to base reg
                    // offset > 0 dissassembles like %reg + offset
                    // offset < 0 dissassembles like %reg + -offset
                    *p++ = ' '; *p++ = '+'; *p++ = ' ';
                    p += DisCliValueString( d, ins, i, p );
                } else {
                    // who knows ??
                    *p++ = '/'; *p++ = '*';
                    *p++ = '?'; *p++ = '?'; *p++ = '?';
                    *p++ = '*'; *p++ = '/';
                }
            }
            *p++ = chRbrac;
        }
        break;
    }
    return( p );
}

dis_return DisFormat( dis_handle *h, void *d, dis_dec_ins *ins_p,
                dis_format_flags flags, char *name, char *opers )
// Format up an instruction name or operands or both
{
    unsigned    i;
    dis_dec_ins ins;
    char        *p;
    unsigned    len;

    ins = *ins_p;       /* so we can fiddle it around */

    if( name != NULL ) name[0] = '\0';
    len = h->d->ins_hook( h, d, &ins, flags, name );
    if( name != NULL ) {
        if( len == 0 ) {
            DisGetString( DisInstructionTable[ins.type].name, name, 0 );
        }
        p = &name[ strlen( name ) ];
        h->d->flag_hook( h, d, &ins, flags, p );
        if( flags & DFF_INS_UP ) {
            strupr( name );
        }
    }
    if( opers != NULL ) {
        p = opers;
        for( i = 0; i < ins.num_ops; ++i ) {
            if( !(ins.op[i].type & DO_HIDDEN) ) {
                if( p != opers )
                    *p++ = ',';
                len = h->d->op_hook( h, d, &ins, flags, i, p );
                p += len;
                if( len == 0 ) {
                    p = DisOpFormat( h, d, &ins, flags, i, p );
                }
            }
        }
        if( p != opers )
            *p++ = ' ';
        len = h->d->post_op_hook( h, d, &ins, flags, i, p );
        p += len;
        *p = '\0';
    }
    return( DR_OK );
}

unsigned DisInsNameMax( dis_handle *h )
// Return how long (character length) the longest instruction name is
{
    return( *(h->d->max_insnamep) );
}

unsigned DisInsSizeInc( dis_handle *h )
// Return the number of bytes an instruction can grow by
// (LCM of instruction sizes).
{
    return( h->d->inssize_inc );
}

⌨️ 快捷键说明

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