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;
}
Exemple #5
0
//----------------------------------------------------------------------
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);
        }
      }