update to ida 7.6, add builds
This commit is contained in:
255
idasdk76/module/i51/emu.cpp
Normal file
255
idasdk76/module/i51/emu.cpp
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user