update to ida 7.6, add builds
This commit is contained in:
250
idasdk76/module/fr/emu.cpp
Normal file
250
idasdk76/module/fr/emu.cpp
Normal file
@@ -0,0 +1,250 @@
|
||||
|
||||
#include "fr.hpp"
|
||||
|
||||
// Analyze an instruction
|
||||
static ea_t next_insn(insn_t *insn, ea_t ea)
|
||||
{
|
||||
if ( decode_insn(insn, ea) == 0 )
|
||||
return 0;
|
||||
ea += insn->size;
|
||||
return ea;
|
||||
}
|
||||
|
||||
// Emulate an operand.
|
||||
static void handle_operand(const insn_t &insn, const op_t &op)
|
||||
{
|
||||
bool offset = false;
|
||||
switch ( op.type )
|
||||
{
|
||||
case o_near:
|
||||
insn.add_cref(to_ea(insn.cs, op.addr), op.offb, (insn.itype == fr_call) ? fl_CN : fl_JN);
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
{
|
||||
enum dref_t mode = dr_U;
|
||||
|
||||
if ( op.specflag1 & OP_ADDR_R )
|
||||
mode = dr_R;
|
||||
else if ( op.specflag1 & OP_ADDR_W )
|
||||
mode = dr_W;
|
||||
|
||||
ea_t ea = to_ea(insn.cs, op.addr);
|
||||
insn.add_dref(ea, op.offb, mode);
|
||||
insn.create_op_data(ea, op);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
// if current insn is ldi:32 #imm, r1
|
||||
// and next insn is call @r1,
|
||||
// replace the immediate value with an offset.
|
||||
if ( insn.itype == fr_ldi_32
|
||||
&& insn.Op1.type == o_imm
|
||||
&& insn.Op2.type == o_reg )
|
||||
{
|
||||
const int callreg = insn.Op2.reg;
|
||||
insn_t nexti;
|
||||
if ( next_insn(&nexti, insn.ea + insn.size ) > 0
|
||||
&& nexti.itype == fr_call
|
||||
&& nexti.Op1.type == o_phrase
|
||||
&& nexti.Op1.specflag2 == fIGR
|
||||
&& nexti.Op1.reg == callreg )
|
||||
{
|
||||
offset = true;
|
||||
}
|
||||
if ( !is_defarg(get_flags(insn.ea), 0) && offset )
|
||||
op_plain_offset(insn.ea, 0, 0);
|
||||
}
|
||||
set_immd(insn.ea);
|
||||
// if the value was converted to an offset, then create a data xref:
|
||||
if ( !offset && op_adds_xrefs(get_flags(insn.ea), op.n) )
|
||||
insn.add_off_drefs(op, dr_O, 0);
|
||||
|
||||
// create stack variables if necessary
|
||||
{
|
||||
bool ok = false;
|
||||
// ldi8 #our_value, R1
|
||||
// extsb R1
|
||||
// addn R14, R1
|
||||
if ( insn.itype == fr_ldi_8
|
||||
&& insn.Op2.type == o_reg
|
||||
&& insn.Op2.reg == rR1 )
|
||||
{
|
||||
insn_t nexti;
|
||||
next_insn(&nexti, insn.ea + insn.size);
|
||||
if ( nexti.itype == fr_extsb
|
||||
&& nexti.Op1.type == o_reg
|
||||
&& nexti.Op1.reg == rR1 )
|
||||
{
|
||||
ok = true;
|
||||
}
|
||||
if ( ok )
|
||||
{
|
||||
ok = false;
|
||||
next_insn(&nexti, nexti.ea + insn.size);
|
||||
if ( nexti.itype == fr_addn
|
||||
&& nexti.Op1.type == o_reg
|
||||
&& nexti.Op1.reg == rR14
|
||||
&& nexti.Op2.type == o_reg
|
||||
&& nexti.Op2.reg == rR1 )
|
||||
{
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ldi32 #our_value, Ri
|
||||
// addn R14, Ri
|
||||
//
|
||||
// (where Ri is either R1 or R2)
|
||||
else if ( insn.itype == fr_ldi_32
|
||||
&& insn.Op2.type == o_reg
|
||||
&& (insn.Op2.reg == rR1 || insn.Op2.reg == rR2) )
|
||||
{
|
||||
ushort the_reg = insn.Op2.reg;
|
||||
insn_t nexti;
|
||||
next_insn(&nexti, insn.ea + insn.size);
|
||||
if ( nexti.itype == fr_addn
|
||||
&& nexti.Op1.type == o_reg
|
||||
&& nexti.Op1.reg == rR14
|
||||
&& nexti.Op2.type == o_reg
|
||||
&& nexti.Op2.reg == the_reg )
|
||||
{
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ok && may_create_stkvars()
|
||||
&& !is_defarg(get_flags(insn.ea), op.n) )
|
||||
{
|
||||
func_t *pfn = get_func(insn.ea);
|
||||
if ( pfn != NULL && pfn->flags & FUNC_FRAME )
|
||||
{
|
||||
if ( insn.create_stkvar(op, op.value, 0) )
|
||||
op_stkvar(insn.ea, op.n);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case o_displ:
|
||||
case o_phrase: // XXX
|
||||
case o_reglist:
|
||||
case o_void:
|
||||
case o_reg:
|
||||
break;
|
||||
|
||||
default:
|
||||
INTERR(10017);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool fr_t::is_stop(const insn_t &insn) const
|
||||
{
|
||||
uint32 feature = insn.get_canon_feature(ph);
|
||||
return (feature & CF_STOP) != 0;
|
||||
}
|
||||
|
||||
// Emulate an instruction.
|
||||
int fr_t::emu(const insn_t &insn) const
|
||||
{
|
||||
bool flow = !is_stop(insn) || (insn.auxpref & INSN_DELAY_SHOT);
|
||||
if ( flow )
|
||||
{
|
||||
insn_t previ;
|
||||
if ( decode_prev_insn(&previ, insn.ea) != BADADDR )
|
||||
flow = !(is_stop(previ) && (previ.auxpref & INSN_DELAY_SHOT));
|
||||
}
|
||||
|
||||
if ( insn.Op1.type != o_void ) handle_operand(insn, insn.Op1);
|
||||
if ( insn.Op2.type != o_void ) handle_operand(insn, insn.Op2);
|
||||
if ( insn.Op3.type != o_void ) handle_operand(insn, insn.Op3);
|
||||
if ( insn.Op4.type != o_void ) handle_operand(insn, insn.Op4);
|
||||
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea + insn.size, fl_F);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create a function frame
|
||||
bool idaapi create_func_frame(func_t *pfn)
|
||||
{
|
||||
ushort savedreg_size = 0;
|
||||
uint32 args_size = 0;
|
||||
uint32 localvar_size;
|
||||
|
||||
ea_t ea = pfn->start_ea;
|
||||
|
||||
// detect multiple ``st Ri, @-R15'' instructions.
|
||||
insn_t insn;
|
||||
while ( (ea=next_insn(&insn, ea)) != 0
|
||||
&& insn.itype == fr_st
|
||||
&& insn.Op1.type == o_reg
|
||||
&& insn.Op2.type == o_phrase
|
||||
&& insn.Op2.reg == rR15
|
||||
&& insn.Op2.specflag2 == fIGRM )
|
||||
{
|
||||
savedreg_size += 4;
|
||||
#if defined(__DEBUG__)
|
||||
msg("0x%a: detected st Rx, @-R15\n", ea);
|
||||
#endif /* __DEBUG__ */
|
||||
}
|
||||
|
||||
// detect enter #nn
|
||||
if ( insn.itype == fr_enter )
|
||||
{
|
||||
// R14 is automatically pushed by fr_enter
|
||||
savedreg_size += 4;
|
||||
localvar_size = uint32(insn.Op1.value - 4);
|
||||
#if defined(__DEBUG__)
|
||||
msg("0x%a: detected enter #0x%a\n", ea, insn.Op1.value);
|
||||
#endif /* __DEBUG__ */
|
||||
}
|
||||
// detect mov R15, R14 + ldi #imm, R0 instructions
|
||||
else
|
||||
{
|
||||
if ( insn.itype != fr_mov
|
||||
|| insn.Op1.type != o_reg
|
||||
|| insn.Op1.reg != rR15
|
||||
|| insn.Op2.type != o_reg
|
||||
|| insn.Op2.reg != rR14 )
|
||||
{
|
||||
goto BAD_FUNC;
|
||||
}
|
||||
/*ea = */next_insn(&insn, ea);
|
||||
if ( (insn.itype == fr_ldi_20 || insn.itype == fr_ldi_32)
|
||||
&& insn.Op1.type == o_imm
|
||||
&& insn.Op2.type == o_reg
|
||||
&& insn.Op2.reg == rR0 )
|
||||
{
|
||||
localvar_size = uint32(insn.Op1.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
goto BAD_FUNC;
|
||||
}
|
||||
#if defined(__DEBUG__)
|
||||
msg("0x%a: detected ldi #0x%a, R0\n", ea, insn.Op1.value);
|
||||
#endif /* __DEBUG__ */
|
||||
}
|
||||
|
||||
// XXX we don't care about near/far functions, because currently
|
||||
// we don't know how to detect them ;-)
|
||||
|
||||
pfn->flags |= FUNC_FRAME;
|
||||
return add_frame(pfn, localvar_size, savedreg_size, args_size);
|
||||
|
||||
BAD_FUNC:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int idaapi is_sp_based(const insn_t &, const op_t &)
|
||||
{
|
||||
return OP_SP_ADD | OP_FP_BASED;
|
||||
}
|
||||
|
||||
int idaapi is_align_insn(ea_t ea)
|
||||
{
|
||||
return get_byte(ea) == 0;
|
||||
}
|
||||
Reference in New Issue
Block a user