update to ida 7.6, add builds
This commit is contained in:
393
idasdk76/module/m32r/emu.cpp
Normal file
393
idasdk76/module/m32r/emu.cpp
Normal file
@@ -0,0 +1,393 @@
|
||||
|
||||
#include "m32r.hpp"
|
||||
|
||||
// handle immediate values
|
||||
static void handle_imm(const insn_t &insn)
|
||||
{
|
||||
set_immd(insn.ea);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// handle the custom switch format
|
||||
// ....
|
||||
// bl.s next || nop <- insn_ea
|
||||
// next:
|
||||
// add lr, R0
|
||||
// jmp lr
|
||||
// si.jumps:
|
||||
// bra.s case0 || nop
|
||||
// bra.l case1
|
||||
// ...
|
||||
int m32r_create_switch_xrefs(ea_t insn_ea, const switch_info_t &si)
|
||||
{
|
||||
if ( (si.flags & SWI_CUSTOM) != 0 )
|
||||
{
|
||||
insn_t insn;
|
||||
decode_insn(&insn, insn_ea);
|
||||
ea_t ea = si.jumps;
|
||||
for ( int i = 0; i < si.ncases; i++, ea += insn.size )
|
||||
{
|
||||
add_cref(insn_ea, ea, fl_JN);
|
||||
decode_insn(&insn, ea);
|
||||
if ( insn.Op1.type == o_near )
|
||||
{
|
||||
ea_t target = to_ea(insn.cs, insn.Op1.addr);
|
||||
// xrefs are from "bl" -> branch target.
|
||||
add_cref(insn_ea, target, fl_JN);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1; // ok
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
int m32r_calc_switch_cases(casevec_t *casevec, eavec_t *targets, ea_t insn_ea, const switch_info_t &si)
|
||||
{
|
||||
if ( (si.flags & SWI_CUSTOM) == 0 )
|
||||
return 0;
|
||||
|
||||
insn_t insn;
|
||||
decode_insn(&insn, insn_ea);
|
||||
|
||||
ea_t ea = si.jumps;
|
||||
svalvec_t vals;
|
||||
vals.push_back(0); // add one item
|
||||
for ( int i=0; i < si.ncases; i++, ea += insn.size )
|
||||
{
|
||||
decode_insn(&insn, ea);
|
||||
if ( targets != NULL )
|
||||
{
|
||||
if ( insn.itype == m32r_bra && insn.Op1.type == o_near )
|
||||
targets->push_back(insn.Op1.addr);
|
||||
else
|
||||
targets->push_back(insn.ea);
|
||||
}
|
||||
if ( casevec != NULL )
|
||||
{
|
||||
vals[0] = i;
|
||||
casevec->push_back(vals);
|
||||
}
|
||||
}
|
||||
return 1; // ok
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static bool handle_switch(const insn_t &insn)
|
||||
{
|
||||
switch_info_t si;
|
||||
bool was_switch = (get_flags(insn.ea) & FF_JUMP) != 0
|
||||
&& get_switch_info(&si, insn.ea) > 0;
|
||||
// do not overwrite the existing switch
|
||||
// FIXME: reanalyze non user defined switches
|
||||
if ( was_switch )
|
||||
return true;
|
||||
|
||||
// ldi8 R1, #0x21 ; '!'
|
||||
// cmpu R1, R0
|
||||
// bc.l loc_67F8C
|
||||
// slli R0, #2
|
||||
// addi R0, #4
|
||||
// bl.s next || nop
|
||||
// next:
|
||||
// add lr, R0
|
||||
// jmp lr
|
||||
// bra.s loc_67CDC || nop
|
||||
// bra.s loc_67D34 || nop
|
||||
// bra.l loc_67F8C
|
||||
// ...
|
||||
if ( insn.itype != m32r_bl )
|
||||
return false;
|
||||
|
||||
// bl should be to next address
|
||||
ea_t tgt = to_ea(insn.cs, insn.Op1.addr);
|
||||
if ( tgt != insn.ea + insn.size )
|
||||
return false;
|
||||
|
||||
insn_t insn2;
|
||||
// check for add lr, R0; jmp lr
|
||||
if ( decode_insn(&insn2, tgt) == 0
|
||||
|| insn2.itype != m32r_add
|
||||
|| !insn2.Op1.is_reg(rLR)
|
||||
|| insn2.Op2.type != o_reg )
|
||||
{
|
||||
BAD_MATCH:
|
||||
return false;
|
||||
}
|
||||
|
||||
int switch_reg = insn2.Op2.reg;
|
||||
|
||||
// jmp lr
|
||||
if ( decode_insn(&insn2, insn2.ea + insn2.size) == 0
|
||||
|| insn2.itype != m32r_jmp
|
||||
|| !insn2.Op1.is_reg(rLR) )
|
||||
{
|
||||
goto BAD_MATCH;
|
||||
}
|
||||
|
||||
// addi R0, #4
|
||||
if ( decode_prev_insn(&insn2, insn.ea) == BADADDR
|
||||
|| insn2.itype != m32r_addi
|
||||
|| !insn2.Op1.is_reg(switch_reg)
|
||||
|| insn2.Op2.type != o_imm )
|
||||
{
|
||||
goto BAD_MATCH;
|
||||
}
|
||||
|
||||
ea_t jumps = insn.ea + insn.size + insn2.Op2.value;
|
||||
|
||||
// slli R0, #2
|
||||
if ( decode_prev_insn(&insn2, insn2.ea) == BADADDR
|
||||
|| insn2.itype != m32r_slli
|
||||
|| !insn2.Op1.is_reg(switch_reg)
|
||||
|| !insn2.Op2.is_imm(2) )
|
||||
{
|
||||
goto BAD_MATCH;
|
||||
}
|
||||
|
||||
// bc.l default
|
||||
if ( decode_prev_insn(&insn2, insn2.ea) == BADADDR
|
||||
|| insn2.itype != m32r_bc )
|
||||
{
|
||||
goto BAD_MATCH;
|
||||
}
|
||||
|
||||
ea_t defea = to_ea(insn2.cs, insn2.Op1.addr);
|
||||
|
||||
// cmpu R1, R0
|
||||
if ( decode_prev_insn(&insn2, insn2.ea) == BADADDR
|
||||
|| insn2.itype != m32r_cmpu
|
||||
|| !insn2.Op2.is_reg(switch_reg)
|
||||
|| insn2.Op1.type != o_reg )
|
||||
{
|
||||
goto BAD_MATCH;
|
||||
}
|
||||
|
||||
int cmpreg = insn2.Op1.reg;
|
||||
|
||||
// ldi8 R1, #max
|
||||
if ( decode_prev_insn(&insn2, insn2.ea) == BADADDR
|
||||
|| insn2.itype != m32r_ldi
|
||||
|| !insn2.Op1.is_reg(cmpreg)
|
||||
|| insn2.Op2.type != o_imm )
|
||||
{
|
||||
goto BAD_MATCH;
|
||||
}
|
||||
|
||||
// looks good
|
||||
|
||||
si.flags |= SWI_CUSTOM | SWI_J32;
|
||||
si.ncases = insn2.Op2.value + 1;
|
||||
si.jumps = jumps;
|
||||
si.lowcase = 0;
|
||||
si.startea = insn2.ea;
|
||||
si.set_expr(switch_reg, dt_dword);
|
||||
si.defjump = defea;
|
||||
set_switch_info(insn.ea, si);
|
||||
create_switch_table(insn.ea, si);
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// emulate operand
|
||||
void m32r_t::handle_operand(const insn_t &insn, const op_t &op, bool loading)
|
||||
{
|
||||
flags_t F = get_flags(insn.ea);
|
||||
switch ( op.type )
|
||||
{
|
||||
// Address
|
||||
case o_near:
|
||||
// branch label - create code reference (call or jump
|
||||
// according to the instruction)
|
||||
{
|
||||
ea_t ea = to_ea(insn.cs, op.addr);
|
||||
cref_t ftype = fl_JN;
|
||||
if ( insn.itype == m32r_bl && !handle_switch(insn) )
|
||||
{
|
||||
if ( !func_does_return(ea) )
|
||||
flow = false;
|
||||
ftype = fl_CN;
|
||||
}
|
||||
insn.add_cref(ea, op.offb, ftype);
|
||||
}
|
||||
break;
|
||||
|
||||
// Immediate
|
||||
case o_imm:
|
||||
QASSERT(10135, loading);
|
||||
handle_imm(insn);
|
||||
// if the value was converted to an offset, then create a data xref:
|
||||
if ( op_adds_xrefs(F, op.n) )
|
||||
insn.add_off_drefs(op, dr_O, OOFW_IMM|OOF_SIGNED);
|
||||
|
||||
// create a comment if this immediate is represented in the .cfg file
|
||||
{
|
||||
const ioport_t *port = find_sym(op.value);
|
||||
if ( port != NULL && !has_cmt(F) )
|
||||
set_cmt(insn.ea, port->cmt.c_str(), false);
|
||||
}
|
||||
break;
|
||||
|
||||
// Displ
|
||||
case o_displ:
|
||||
handle_imm(insn);
|
||||
// if the value was converted to an offset, then create a data xref:
|
||||
if ( op_adds_xrefs(F, op.n) )
|
||||
insn.add_off_drefs(op, loading ? dr_R : dr_W, OOF_SIGNED|OOF_ADDR|OOFW_32);
|
||||
|
||||
// create stack variables if required
|
||||
if ( may_create_stkvars() && !is_defarg(F, op.n) )
|
||||
{
|
||||
func_t *pfn = get_func(insn.ea);
|
||||
if ( pfn != NULL && (op.reg == rFP || op.reg == rSP) && pfn->flags & FUNC_FRAME )
|
||||
{
|
||||
if ( insn.create_stkvar(op, op.addr, STKVAR_VALID_SIZE) )
|
||||
op_stkvar(insn.ea, op.n);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case o_phrase:
|
||||
/* create stack variables if required */
|
||||
if ( op.specflag1 == fRI && may_create_stkvars() && !is_defarg(F, op.n) )
|
||||
{
|
||||
func_t *pfn = get_func(insn.ea);
|
||||
if ( pfn != NULL
|
||||
&& (op.reg == rFP || op.reg == rSP)
|
||||
&& (pfn->flags & FUNC_FRAME) != 0 )
|
||||
{
|
||||
if ( insn.create_stkvar(op, 0, STKVAR_VALID_SIZE) )
|
||||
op_stkvar(insn.ea, op.n);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Phrase - register - void : do nothing
|
||||
case o_reg:
|
||||
case o_void:
|
||||
break;
|
||||
|
||||
// Others types should never be called
|
||||
default:
|
||||
INTERR(10136);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// emulate an instruction
|
||||
int m32r_t::emu(const insn_t &insn)
|
||||
{
|
||||
uint32 feature = insn.get_canon_feature(ph);
|
||||
flow = ((feature & CF_STOP) == 0);
|
||||
|
||||
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 ( flow )
|
||||
add_cref(insn.ea, insn.ea + insn.size, fl_F);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool idaapi create_func_frame(func_t *pfn)
|
||||
{
|
||||
if ( pfn == NULL )
|
||||
return 0;
|
||||
|
||||
ea_t ea = pfn->start_ea;
|
||||
insn_t insn[4];
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < 4; i++ )
|
||||
{
|
||||
decode_insn(&insn[i], ea);
|
||||
ea += insn[i].size;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
ushort regsize = 0; // number of saved registers
|
||||
|
||||
// first insn is not either push fp OR st fp, @-sp
|
||||
if ( (insn[i].itype != m32r_push
|
||||
|| insn[i].Op1.reg != rFP)
|
||||
&& (insn[i].itype != m32r_st
|
||||
|| insn[i].Op1.reg != rFP
|
||||
|| insn[i].Op2.reg != rSP
|
||||
|| insn[i].Op2.specflag1 != fRIAS) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
regsize += 4;
|
||||
i++;
|
||||
|
||||
// next insn is push lr OR st lr, @-sp
|
||||
if ( (insn[i].itype == m32r_push
|
||||
&& insn[i].Op1.reg == rLR)
|
||||
|| (insn[i].itype == m32r_st
|
||||
&& insn[i].Op1.reg == rFP
|
||||
&& insn[i].Op2.reg == rLR
|
||||
&& insn[i].Op2.specflag1 != fRIAS) )
|
||||
{
|
||||
regsize += 4;
|
||||
i++;
|
||||
}
|
||||
|
||||
// next insn is not addi sp, #imm
|
||||
if ( insn[i].itype != m32r_addi || insn[i].Op1.reg != rSP )
|
||||
return 0;
|
||||
|
||||
sval_t offset = - (sval_t) insn[i].Op2.value;
|
||||
|
||||
// toggle to the negative sign of the immediate operand of the addi insn
|
||||
if ( !is_invsign(insn[i].ea, get_flags(insn[i].ea), 2) )
|
||||
toggle_sign(insn[i].ea, 2);
|
||||
|
||||
i++;
|
||||
|
||||
// next insn is not mv fp, sp
|
||||
if ( insn[i].itype != m32r_mv || insn[i].Op1.reg != rFP || insn[i].Op2.reg != rSP )
|
||||
return 0;
|
||||
|
||||
pfn->flags |= (FUNC_FRAME | FUNC_BOTTOMBP);
|
||||
return add_frame(pfn, offset, regsize, 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// should always returns 0
|
||||
int idaapi m32r_get_frame_retsize(const func_t *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// check is the specified operand is relative to the SP register
|
||||
int idaapi is_sp_based(const insn_t &/*insn*/, const op_t &op)
|
||||
{
|
||||
return OP_SP_ADD | (op.reg == rSP ? OP_SP_BASED : OP_FP_BASED);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool idaapi can_have_type(const op_t &x)
|
||||
{
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_imm:
|
||||
case o_displ:
|
||||
return 1;
|
||||
|
||||
case o_phrase:
|
||||
if ( x.specflag1 == fRI )
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user