int idaapi emu( void ) { uint32 Feature = cmd.get_canon_feature(); flow = ((Feature & CF_STOP) == 0); if( Feature & CF_USE1 ) TouchArg( cmd.Op1, 1 ); if( Feature & CF_USE2 ) TouchArg( cmd.Op2, 1 ); if( Feature & CF_USE3 ) TouchArg( cmd.Op3, 1 ); if( Feature & CF_JUMP ) QueueSet( Q_jumps, cmd.ea ); if( Feature & CF_CHG1 ) TouchArg( cmd.Op1, 0 ); if( Feature & CF_CHG2 ) TouchArg( cmd.Op2, 0 ); if( Feature & CF_CHG3 ) TouchArg( cmd.Op3, 0 ); switch ( cmd.itype ) { case I196_popa: split_srarea(cmd.ea, WSR, BADSEL, SR_auto); split_srarea(cmd.ea, WSR1, BADSEL, SR_auto); break; } if( flow ) ua_add_cref( 0, cmd.ea+cmd.size, fl_F ); return 1; }
//---------------------------------------------------------------------- static void TouchArg( op_t &x, int isload ) { switch( x.type ) { case o_imm: doImmd(cmd.ea); if ( op_adds_xrefs(uFlag, x.n) ) ua_add_off_drefs2(x, dr_O, OOF_SIGNED); break; case o_indexed: // addr[value] doImmd(cmd.ea); if ( x.value == 0 && !isDefArg(uFlag, x.n) ) set_offset(cmd.ea, x.n, toEA(cmd.cs, 0)); if ( op_adds_xrefs(uFlag, x.n) ) // xref to addr { uval_t saved = x.value; x.value = x.addr; ua_add_off_drefs2(x, saved ? dr_O : isload ? dr_R : dr_W, OOF_SIGNED|OOF_ADDR); x.value = saved; } if ( x.value != 0 ) // xref to value { // no references to ZERO_REG ea_t ea = toEA(cmd.cs, x.value); ua_add_dref(x.offb, ea, isload ? dr_R : dr_W ); ua_dodata2(x.offb, ea, x.dtyp); } break; case o_indirect: case o_indirect_inc: case o_mem: { ea_t dea = toEA( cmd.cs, x.addr ); ua_dodata2(x.offb, dea, x.dtyp); if( !isload ) doVar(dea); ua_add_dref( x.offb, dea, isload ? dr_R : dr_W ); if ( !isload && (x.addr == 0x14 || x.addr == 0x15) ) { sel_t wsrval = BADSEL; if ( cmd.Op2.type == o_imm ) wsrval = sel_t(cmd.Op2.value); split_srarea(cmd.ea, x.addr == 0x14 ? WSR : WSR1, wsrval, SR_auto); } } break; case o_near: ea_t ea = toEA( cmd.cs, x.addr ); int iscall = InstrIsSet( cmd.itype, CF_CALL ); ua_add_cref( x.offb, ea, iscall ? fl_CN : fl_JN ); if ( flow && iscall ) flow = func_does_return(ea); } }
bool handle_operand(const op_t &op, enum opRefType ref_type) { ea_t ea; sel_t data_selector; bool flow = true; switch ( op.type ) { case o_reg: // // Register operand. // // // Nothing needs to be calculated or examined for this // operand. // break; case o_imm: // // Immediate operand. // // Make sure that this operand reference isn't a write reference. // (Writing to an immediate value is not allowed and is a sure // sign of a badly decoded instruction). // if ( ref_type == hop_WRITE ) { // // Attempt to write to an immediate value. // Error. // warning("%a: %s,%d: bad optype %d", cmd.ea, cmd.get_canon_mnem(), op.n, op.type); break; } // // SPECIAL INSTRUCTION CASE: // // The LDPK instruction is decoded by ana() to have an immediate // value as an operand. However, this immediate value is to be // the new data page pointer, which we must track for proper // memory referencing. // if ( cmd.itype == I_LDPK ) { // // This is an LDPK instruction. Let the kernel know that // we are changing the current data page pointer. We track // this bit as though it were a virtual segment register named // I_VDS, although it is not a true register in the CPU. // // Determine into which data page the instruction is attempting // to point. // if ( op.value == 0 ) { // // Data page 0 is being loaded. // data_selector = tms320c1x_dpage0; } else { // // Data page 1 is being loaded. // data_selector = tms320c1x_dpage1; } // // Notify the IDA kernel of the change. // split_srarea( cmd.ea, // The current instruction's address IREG_VDS, // The segment register being modified data_selector, // The new selector value being loaded SR_auto // How the new value was determined ); } // // Let the kernel know that the instruction's address should // be marked with a 'has immediate value' flag. // (Useful during search?) // doImmd(cmd.ea); break; case o_phrase: // // Processor-specific phrase. // // These operands have no currently trackable side effect. // break; case o_mem: // // Direct memory reference. // // // Ask the IDA kernel for the current data page pointer selector. // data_selector = get_segreg(cmd.ea, IREG_VDS); // // Is it known? // if ( data_selector == BADSEL ) { // // The current data page pointer is unknown. // There is nothing to do. // } else { // // The current data page pointer is known. // Calculate the full effective address being referenced // by this operand. // ea = sel2ea(data_selector) + op.addr; // // Generate a data cross reference from this instruction // to the target address. // ua_add_dref(op.offb, ea, ref_type == hop_READ ? dr_R : dr_W); } // // TODO: DMOV, ... // These instructions read from the address in their operands // and write to the address ADJACENT to it. // break; case o_near: // // Code reference in current segment. // // // Determine the effective address of the reference. // ea = toEA(cmd.cs, op.addr); // // Is this a 'CALL' type reference, or a branch type reference? // if ( InstrIsSet(cmd.itype, CF_CALL) ) { // // This is a CALL type reference. Make a cross reference // that notes it. // ua_add_cref(op.offb, ea, fl_CN); if ( !func_does_return(ea) ) flow = false; } else { // // This is a branch type reference. Make a cross reference // that notes it. // ua_add_cref(op.offb, ea, fl_JN); } break; default: // // Unhandled operand type. // Error. // warning("%a: %s,%d: bad optype %d", cmd.ea, cmd.get_canon_mnem(), op.n, op.type); break; } return flow; }
//---------------------------------------------------------------------- int idaapi emu(void) { uint32 Feature = cmd.get_canon_feature(); int flag1 = is_forced_operand(cmd.ea, 0); int flag2 = is_forced_operand(cmd.ea, 1); int flag3 = is_forced_operand(cmd.ea, 2); flow = ((Feature & CF_STOP) == 0); if ( Feature & CF_USE1 ) process_operand(cmd.Op1, flag1, 1); if ( Feature & CF_USE2 ) process_operand(cmd.Op2, flag2, 1); if ( Feature & CF_USE3 ) process_operand(cmd.Op3, flag3, 1); if ( Feature & CF_CHG1 ) process_operand(cmd.Op1, flag1, 0); if ( Feature & CF_CHG2 ) process_operand(cmd.Op2, flag2, 0); if ( Feature & CF_CHG3 ) process_operand(cmd.Op3, flag3, 0); // // Determine if the next instruction should be executed // if ( segtype(cmd.ea) == SEG_XTRN ) flow = false; // // Handle loads to segment registers // sel_t v = BADSEL; switch ( cmd.itype ) { case H8500_andc: if ( cmd.Op1.value == 0 ) v = 0; goto SPLIT; case H8500_orc: if ( cmd.Op1.value == 0xFF ) v = 0xFF; goto SPLIT; case H8500_ldc: if ( cmd.Op1.type == o_imm ) v = cmd.Op1.value; case H8500_xorc: SPLIT: if ( cmd.Op2.reg >= BR && cmd.Op2.reg <= TP ) split_srarea(cmd.ea+cmd.size, cmd.Op2.reg, v, SR_auto); break; } if ( (Feature & CF_CALL) != 0 ) { ea_t callee = find_callee(); if ( !handle_function_call(callee) ) flow = false; } // // Handle SP modifications // if ( may_trace_sp() ) { func_t *pfn = get_func(cmd.ea); if ( pfn != NULL ) { if ( (pfn->flags & FUNC_USERFAR) == 0 && (pfn->flags & FUNC_FAR) == 0 && is_far_ending() ) { pfn->flags |= FUNC_FAR; update_func(pfn); reanalyze_callers(pfn->startEA, 0); } if ( !flow ) recalc_spd(cmd.ea); // recalculate SP register for the next insn else trace_sp(); } } if ( flow ) ua_add_cref(0, cmd.ea+cmd.size, fl_F); return 1; }
//---------------------------------------------------------------------- int idaapi emu(void) { uint32 Feature = cmd.get_canon_feature(); flow = ((Feature & CF_STOP) == 0); if ( Feature & CF_USE1 ) handle_operand(cmd.Op1, 1); if ( Feature & CF_USE2 ) handle_operand(cmd.Op2, 1); if ( Feature & CF_CHG1 ) handle_operand(cmd.Op1, 0); if ( Feature & CF_CHG2 ) handle_operand(cmd.Op2, 0); if ( Feature & CF_JUMP ) QueueSet(Q_jumps, cmd.ea); if ( flow ) ua_add_cref(0,cmd.ea+cmd.size,fl_F); uint8 code = get_byte(cmd.ea); const struct opcode_info_t &opinfo = get_opcode_info(code); if ( opinfo.itype == M65816_jmp || opinfo.itype == M65816_jsr ) { if ( opinfo.addr == ABS_INDIR || opinfo.addr == ABS_INDIR_LONG || opinfo.addr == ABS_IX_INDIR ) { QueueSet(Q_jumps,cmd.ea); } } #if 0 switch ( opinfo.addr ) { case ABS_LONG_IX: { ea_t orig_ea = cmd.Op1.addr; ea_t ea = xlat(orig_ea); bool read_access; if ( cmd.itype == M65816_sta ) read_access = false; else read_access = true; if ( !read_access ) doVar(ea); ua_add_dref(cmd.Op1.offb, ea, read_access ? dr_R : dr_W); break; } case DP: { bool read_access; if ( cmd.itype == M65816_tsb || cmd.itype == M65816_asl || cmd.itype == M65816_trb || cmd.itype == M65816_rol || cmd.itype == M65816_lsr || cmd.itype == M65816_ror || cmd.itype == M65816_dec || cmd.itype == M65816_inc ) read_access = false; else read_access = true; int32 val = backtrack_value(cmd.ea, 2, BT_DP); if ( val != -1 ) { ea_t orig_ea = val + cmd.Op1.addr; ea_t ea = xlat(orig_ea); ua_dodata2(cmd.Op1.offb, ea, cmd.Op1.dtyp); if ( !read_access ) doVar(ea); ua_add_dref(cmd.Op1.offb, ea, read_access ? dr_R : dr_W); } } break; } #endif switch ( cmd.itype ) { case M65816_sep: case M65816_rep: { // Switching 8 -> 16 bits modes. uint8 flag_data = get_byte(cmd.ea + 1); uint8 m_flag = flag_data & 0x20; uint8 x_flag = flag_data & 0x10; uint8 val = (cmd.itype == M65816_rep) ? 0 : 1; if ( m_flag ) split_srarea(cmd.ea + 2, rFm, val, SR_auto); if ( x_flag ) split_srarea(cmd.ea + 2, rFx, val, SR_auto); } break; case M65816_xce: { // Switching to native mode? uint8 prev = get_byte(cmd.ea - 1); const struct opcode_info_t &opinf = get_opcode_info(prev); if ( opinf.itype == M65816_clc ) split_srarea(cmd.ea + 1, rFe, 0, SR_auto); else if ( opinf.itype == M65816_sec ) split_srarea(cmd.ea + 1, rFe, 1, SR_auto); } break; case M65816_jmp: case M65816_jml: case M65816_jsl: case M65816_jsr: { if ( cmd.Op1.full_target_ea ) { ea_t ftea = cmd.Op1.full_target_ea; if ( cmd.itype != M65816_jsl && cmd.itype != M65816_jml ) ftea = toEA(codeSeg(ftea, 0), ftea); else ftea = xlat(ftea); split_srarea(ftea, rFm, get_segreg(cmd.ea, rFm), SR_auto); split_srarea(ftea, rFx, get_segreg(cmd.ea, rFx), SR_auto); split_srarea(ftea, rFe, get_segreg(cmd.ea, rFe), SR_auto); split_srarea(ftea, rPB, ftea >> 16, SR_auto); split_srarea(ftea, rB, get_segreg(cmd.ea, rB), SR_auto); split_srarea(ftea, rDs, get_segreg(cmd.ea, rDs), SR_auto); split_srarea(ftea, rD, get_segreg(cmd.ea, rD), SR_auto); } } break; case M65816_plb: { int32 val = backtrack_value(cmd.ea, 1, BT_STACK); if ( val != -1 ) { split_srarea(cmd.ea + cmd.size, rB, val, SR_auto); split_srarea(cmd.ea + cmd.size, rDs, val << 12, SR_auto); } } break; case M65816_pld: { int32 val = backtrack_value(cmd.ea, 2, BT_STACK); if ( val != -1 ) split_srarea(cmd.ea + cmd.size, rD, val, SR_auto); } break; case M65816_plp: { // Ideally, should pass another parameter, specifying when to stop // backtracking. // For example, in order to avoid this: // PHP // PLP <-- this one is causing interference // (dunno if that even happens, though) // PLP ea_t ea = backtrack_prev_ins(cmd.ea, M65816_php); if ( ea != BADADDR ) { uint16 p = get_cpu_status(ea); split_srarea(cmd.ea + cmd.size, rFm, (p >> 5) & 0x1, SR_auto); split_srarea(cmd.ea + cmd.size, rFx, (p >> 4) & 0x1, SR_auto); } }