256 lines
8.0 KiB
C++
256 lines
8.0 KiB
C++
/*
|
|
* Interactive disassembler (IDA).
|
|
* Copyright (c) 1990-98 by Ilfak Guilfanov.
|
|
* ALL RIGHTS RESERVED.
|
|
* E-mail: ig@estar.msk.su, ig@datarescue.com
|
|
* FIDO: 2:5020/209
|
|
*
|
|
*/
|
|
|
|
#include "i51.hpp"
|
|
#include <frame.hpp>
|
|
|
|
//------------------------------------------------------------------------
|
|
// Handle an operand with an immediate value:
|
|
// - mark it with FF_IMMD flag
|
|
// - for bit logical instructions specify the operand type as a number
|
|
// because such an operand is likely a plain number rather than
|
|
// an offset or of another type.
|
|
|
|
static flags_t set_immd_bit(const insn_t &insn, flags_t F)
|
|
{
|
|
if ( !has_immd(F) )
|
|
{
|
|
set_immd(insn.ea);
|
|
F = get_flags(insn.ea);
|
|
}
|
|
switch ( insn.itype )
|
|
{
|
|
case I51_anl:
|
|
case I51_orl:
|
|
case I51_xrl:
|
|
if ( !is_defarg1(F) )
|
|
{
|
|
op_num(insn.ea, 1);
|
|
F = get_flags(insn.ea);
|
|
}
|
|
break;
|
|
}
|
|
return F;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void i51_t::attach_bit_comment(const insn_t &insn, ea_t addr, int bit)
|
|
{
|
|
const ioport_bit_t *predef = find_bit(addr, bit);
|
|
if ( predef != NULL && get_cmt(NULL, insn.ea, false) <= 0 )
|
|
set_cmt(insn.ea, predef->cmt.c_str(), false);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Calculate the target data address
|
|
ea_t i51_t::i51_map_data_ea(const insn_t &insn, ea_t addr, int opnum) const
|
|
{
|
|
if ( is_off(get_flags(insn.ea), opnum) )
|
|
return get_offbase(insn.ea, opnum) >> 4;
|
|
return ((addr >= 0x80 && addr < 0x100) ? sfrmem : intmem) + addr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Handle an operand. What this function usually does:
|
|
// - creates cross-references from the operand
|
|
// (the kernel deletes all xrefs before calling emu())
|
|
// - creates permanent comments
|
|
// - if possible, specifies the operand type (for example, it may
|
|
// create stack variables)
|
|
// - anything else you might need to emulate or trace
|
|
|
|
void i51_t::handle_operand(const insn_t &insn, const op_t &x, bool loading)
|
|
{
|
|
ea_t addr = x.addr;
|
|
flags_t F = get_flags(insn.ea);
|
|
switch ( x.type )
|
|
{
|
|
case o_phrase: // no special hanlding for these types
|
|
case o_reg:
|
|
break;
|
|
|
|
case o_imm: // an immediate number as an operand
|
|
if ( !loading )
|
|
goto BAD_LOGIC; // this can't happen!
|
|
F = set_immd_bit(insn, F); // handle immediate number
|
|
|
|
// if the value was converted to an offset, then create a data xref:
|
|
if ( op_adds_xrefs(F, x.n) )
|
|
insn.add_off_drefs(x, dr_O, OOFS_IFSIGN);
|
|
|
|
break;
|
|
|
|
case o_displ:
|
|
F = set_immd_bit(insn, F); // handle immediate number
|
|
|
|
// if the value was converted to an offset, then create a data xref:
|
|
if ( op_adds_xrefs(F, x.n) )
|
|
insn.add_off_drefs(x, loading?dr_R:dr_W, OOFS_IFSIGN|OOF_ADDR);
|
|
break;
|
|
|
|
case o_bit: // 8051 specific operand types - bits
|
|
case o_bitnot:
|
|
addr = (x.reg & 0xF8);
|
|
if ( (addr & 0x80) == 0 )
|
|
addr = addr/8 + 0x20;
|
|
attach_bit_comment(insn, addr, x.reg & 7); // attach a comment if necessary
|
|
goto MEM_XREF;
|
|
|
|
case o_bit251:
|
|
attach_bit_comment(insn, addr, x.b251_bit);
|
|
/* no break */
|
|
|
|
case o_mem: // an ordinary memory data reference
|
|
MEM_XREF:
|
|
{
|
|
ea_t dea = i51_map_data_ea(insn, addr, x.n);
|
|
insn.create_op_data(dea, x);
|
|
insn.add_dref(dea, x.offb, loading ? dr_R : dr_W);
|
|
}
|
|
break;
|
|
|
|
case o_near: // a code reference
|
|
{
|
|
ea_t ea = map_code_ea(insn, x);
|
|
int iscall = has_insn_feature(insn.itype, CF_CALL);
|
|
insn.add_cref(ea, x.offb, iscall ? fl_CN : fl_JN);
|
|
if ( flow && iscall )
|
|
flow = func_does_return(ea);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
BAD_LOGIC:
|
|
warning("%a: %s,%d: bad optype %d", insn.ea, insn.get_canon_mnem(ph), x.n, x.type);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
static void add_stkpnt(const insn_t &insn, sval_t v)
|
|
{
|
|
if ( !may_trace_sp() )
|
|
return;
|
|
|
|
func_t *pfn = get_func(insn.ea);
|
|
if ( pfn == NULL )
|
|
return;
|
|
|
|
add_auto_stkpnt(pfn, insn.ea+insn.size, v);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Emulate an instruction
|
|
// This function should:
|
|
// - create all xrefs from the instruction
|
|
// - perform any additional analysis of the instruction/program
|
|
// and convert the instruction operands, create comments, etc.
|
|
// - create stack variables
|
|
// - analyze the delayed branches and similar constructs
|
|
// The kernel calls ana() before calling emu(), so you may be sure that
|
|
// the 'cmd' structure contains a valid and up-to-date information.
|
|
// You are not allowed to modify the 'cmd' structure.
|
|
// Upon entering this function, the 'uFlag' variable contains the flags of
|
|
// insn.ea. If you change the characteristics of the current instruction, you
|
|
// are required to refresh 'uFlag'.
|
|
// Usually the kernel calls emu() with consecutive addresses in insn.ea but
|
|
// you can't rely on this - for example, if the user asks to analyze an
|
|
// instruction at arbirary address, his request will be handled immediately,
|
|
// thus breaking the normal sequence of emulation.
|
|
// If you need to analyze the surroundings of the current instruction, you
|
|
// are allowed to save the contents of the 'cmd' structure and call ana().
|
|
// For example, this is a very common pattern:
|
|
// {
|
|
// insn_t saved = cmd;
|
|
// if ( decode_prev_insn(&cmd, insn.ea) != BADADDR )
|
|
// {
|
|
// ....
|
|
// }
|
|
// cmd = saved;
|
|
// }
|
|
//
|
|
// This sample emu() function is a very simple emulation engine.
|
|
|
|
int i51_t::emu(const insn_t &insn)
|
|
{
|
|
flags_t F = get_flags(insn.ea);
|
|
uint32 Feature = insn.get_canon_feature(ph);
|
|
flow = ((Feature & CF_STOP) == 0);
|
|
|
|
// you may emulate selected instructions with a greater care:
|
|
switch ( insn.itype )
|
|
{
|
|
case I51_mov:
|
|
if ( insn.Op1.type == o_mem && insn.Op1.addr == 0x81 ) // mov SP, #num
|
|
{
|
|
if ( insn.Op2.type == o_imm && !is_defarg(F,1) )
|
|
{
|
|
ea_t base = intmem;
|
|
if ( base == BADADDR )
|
|
base = calc_offset_base(insn.ea, 1);
|
|
if ( base != BADADDR )
|
|
op_plain_offset(insn.ea, 1, base); // convert it to an offset
|
|
}
|
|
}
|
|
break;
|
|
case I51_trap:
|
|
add_cref(insn.ea, 0x7B, fl_CN);
|
|
break;
|
|
case I51_pop:
|
|
add_stkpnt(insn, 1);
|
|
break;
|
|
case I51_push:
|
|
add_stkpnt(insn, -1);
|
|
break;
|
|
}
|
|
|
|
if ( Feature & CF_USE1 ) handle_operand(insn, insn.Op1, true);
|
|
if ( Feature & CF_USE2 ) handle_operand(insn, insn.Op2, true);
|
|
if ( Feature & CF_USE3 ) handle_operand(insn, insn.Op3, true);
|
|
if ( Feature & CF_JUMP )
|
|
remember_problem(PR_JUMP, insn.ea);
|
|
|
|
if ( Feature & CF_CHG1 ) handle_operand(insn, insn.Op1, false);
|
|
if ( Feature & CF_CHG2 ) handle_operand(insn, insn.Op2, false);
|
|
if ( Feature & CF_CHG3 ) handle_operand(insn, insn.Op3, false);
|
|
|
|
// if the execution flow is not stopped here, then create
|
|
// a xref to the next instruction.
|
|
// Thus we plan to analyze the next instruction.
|
|
|
|
if ( flow )
|
|
add_cref(insn.ea, insn.ea+insn.size, fl_F);
|
|
|
|
return 1; // actually the return value is unimportant, but let's it be so
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// reason meaning:
|
|
// 1: the instruction has no code refs to it.
|
|
// ida just tries to convert unexplored bytes
|
|
// to an instruction (but there is no other
|
|
// reason to convert them into an instruction)
|
|
// 0: the instruction is created because
|
|
// of some coderef, user request or another
|
|
// weighty reason.
|
|
bool is_sane_insn(const insn_t &insn, int reason)
|
|
{
|
|
if ( reason != 0 )
|
|
{
|
|
switch ( insn.itype )
|
|
{
|
|
case I51_mov:
|
|
if ( get_byte(insn.ea) == 0xFF )
|
|
return false;
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|