Пример #1
0
 DWORD get_id() const
 {
   DWORD id;
   if ( get_dword(t_symIndexId, &id) != S_OK )
     INTERR(30211);
   return id;
 }
Пример #2
0
// output an operand
bool idaapi outop(op_t &op) {
    switch ( op.type ) {
        // register
        case o_reg:
            outreg(op.reg);
            break;

        // immediate
        case o_imm:
            if ( (op.specflag1 & OP_IMM_BIT) == 0 )
              out_symbol('#');
            OutValue(op, OOFW_IMM);
            break;

        // data / code memory address
        case o_near:
        case o_mem:
            outaddr(op);
            break;

        // displ
        case o_displ:
            outdispl();
            break;

        // ignore void operands
        case o_void:
            break;

        default:
            INTERR(10024);
    }
    return 1;
}
Пример #3
0
static void out_reglist(op_t &op) {
    static const uint16 regs_ldm0[] = { rR7,  rR6,  rR5,  rR4,  rR3,  rR2,  rR1,  rR0  };
    static const uint16 regs_stm0[] = { rR0,  rR1,  rR2,  rR3,  rR4,  rR5,  rR6,  rR7  };
    static const uint16 regs_ldm1[] = { rR15, rR14, rR13, rR12, rR11, rR10, rR9,  rR8  };
    static const uint16 regs_stm1[] = { rR8,  rR9,  rR10, rR11, rR12, rR13, rR14, rR15 };
    const uint16 *regs;
    bool left;

    switch ( cmd.itype ) {
        case fr_ldm0:   regs = regs_ldm0; left = false; break;
        case fr_stm0:   regs = regs_stm0; left = true;  break;
        case fr_ldm1:   regs = regs_ldm1; left = false; break;
        case fr_stm1:   regs = regs_stm1; left = true;  break;
        default:
            INTERR(10018);
    }

    print_comma = false;

    out_symbol('(');
    if ( left ) {
        for (int i = 0, bit = 128; bit != 0; bit >>= 1, i++)
            out_reg_if_bit(regs[i], op.value, bit);
    }
    else {
        for (int i = 7, bit = 1; bit <= 128; bit <<= 1, i--)
Пример #4
0
// output a displacement
static void outdispl(void) {
    if ( is_displ_indx() ) {
        out_symbol('(');
        outaddr(cmd.Op1, false);
        out_symbol(',');
        if ( !(ash.uflag & UAS_INDX_NOSPACE)) OutChar(' ' );
        outreg(cmd.Op1.reg);
        out_symbol(')');
        return;
    }
    if ( is_displ_indy() ) {
        out_symbol('(');
        outaddr(cmd.Op1, false);
        out_symbol(')');
        out_symbol(',');
        OutChar(' ');
        outreg(cmd.Op1.reg);
        return;
    }
    if ( is_displ_zpx() || is_displ_zpy() || is_displ_absx() || is_displ_absy() ) {
        outaddr(cmd.Op1, false);
        out_symbol(',');
        OutChar(' ');
        outreg(cmd.Op1.reg);
        return;
    }
    INTERR(10023);
}
Пример #5
0
static int idaapi options_cb(int fid, form_actions_t &fa)
{
  if ( fid == 2 || fid == -1 )
  {
    ushort opt;
    if ( !fa.get_field_value(3, &opt) )
      INTERR(30001);
    // hide recursion level textbox
    fa.show_field(4, (opt & FWO_RECURSE_UNLIM) == 0);
  }
  return 1;
}
Пример #6
0
//--------------------------------------------------------------------------
static int idaapi modcb(int fid, form_actions_t &fa)
{
    switch ( fid )
    {
    case -1:
        msg("initializing\n");
        break;
    case -2:
        msg("terminating\n");
        break;
    case 5:     // operand
        msg("changed operand\n");
        break;
    case 6:     // check
        msg("changed check\n");
        break;
    case 7:     // button
        msg("changed button\n");
        break;
    case 8:     // color button
        msg("changed color button\n");
        break;
    default:
        msg("unknown id %d\n", fid);
        break;

    }
    bool is_gui = callui(ui_get_hwnd).vptr != NULL;

    char buf0[MAXSTR];
    if ( !fa.get_field_value(5, buf0) )
        INTERR();
    if ( strcmp(buf0, "on") == 0 )
        fa.enable_field(12, true);
    if ( strcmp(buf0, "off") == 0 )
        fa.enable_field(12, false);

    ushort buf1;
    if ( !fa.get_field_value(12, &buf1) )
        INTERR();

    fa.show_field(7, (buf1 & 1) != 0);
    fa.enable_field(8, (buf1 & 2) != 0);


    ushort c13;
    if ( !fa.get_field_value(13, &c13) )
        INTERR();
    fa.enable_field(10, c13);

    ushort c14;
    if ( !fa.get_field_value(14, &c14) )
        INTERR();
    fa.enable_field(5, c14);

    ushort c15;
    if ( !fa.get_field_value(15, &c15) )
        INTERR();

    if ( (buf1 & 8) != 0 )
    {
        uval_t x, y, w, h;
        fa.get_field_value(4, &x);
        fa.get_field_value(3, &y);
        fa.get_field_value(2, &w);
        fa.get_field_value(1, &h);
        fa.move_field(5, x, y, w, h);
        if ( x != -1 && c15 )
            fa.move_field(-5, x-7, y, w, h);
    }

    if ( fa.get_field_value(7, NULL) )
        INTERR();

    bgcolor_t bgc = -1;
    if ( is_gui && !fa.get_field_value(8, &bgc) )
        INTERR();
    msg("  op=%s change=%x color=%x\n", buf0, buf1, bgc);

    fa.set_field_value(9, buf0);
    return 1;
}
Пример #7
0
//----------------------------------------------------------------------
static void process_operand(op_t &x,int isAlt,int isload)
{
  switch ( x.type )
  {
    case o_reg:
    case o_reglist:
      return;
    case o_imm:
      QASSERT(10090, isload);
      process_immediate_number(x.n);
      if ( op_adds_xrefs(uFlag, x.n) )
        ua_add_off_drefs2(x, dr_O, calc_opimm_flags());
      break;
    case o_phrase:
    case o_displ:
      process_immediate_number(x.n);
      if ( isAlt ) break;
      if ( op_adds_xrefs(uFlag, x.n) )
      {
        ea_t ea = ua_add_off_drefs2(x, isload ? dr_R : dr_W, calc_opdispl_flags());
        if ( ea != BADADDR )
        {
          ua_dodata2(x.offb, ea, x.dtyp);
          if ( !isload )
            doVar(ea);
        }
      }
      // create stack variables if required
      if ( x.type == o_displ
        && may_create_stkvars()
        && !isDefArg(uFlag, x.n) )
      {
        func_t *pfn = get_func(cmd.ea);
        if ( pfn != NULL
          && (issp(x.phrase)
              || isbp(x.phrase) && (pfn->flags & FUNC_FRAME) != 0) )
        {
          if ( ua_stkvar2(x, x.addr, STKVAR_VALID_SIZE) )
            op_stkvar(cmd.ea, x.n);
        }
      }
      break;
    case o_near:
    case o_far:
      {
        cref_t ftype = x.type == o_near ? fl_JN : fl_JF;
        ea_t ea = calc_mem(x);
        if ( InstrIsSet(cmd.itype, CF_CALL) )
        {
          if ( !func_does_return(ea) )
            flow = false;
          ftype = x.type == o_near ? fl_CN : fl_CF;
        }
        ua_add_cref(x.offb, ea, ftype);
      }
      break;
    case o_mem:
      {
        ea_t ea = calc_mem(x);
        ua_add_dref(x.offb, ea, isload ? dr_R : dr_W);
        ua_dodata2(x.offb, ea, x.dtyp);
        if ( !isload ) doVar(ea);
      }
      break;
    default:
      INTERR(10091);
  }
}
Пример #8
0
 void assert_token(sym_token_t token) const
 {
   if ( !token_present(token) )
     INTERR(30210);
 }
Пример #9
0
//----------------------------------------------------------------------
static void process_operand(op_t &x,int isAlt,int isload)
{
  switch ( x.type )
  {
    case o_reg:
    case o_phrase:
    case o_reglist:
      return;
    case o_imm:
      QASSERT(10094, isload);
      process_immediate_number(x.n);
      if ( op_adds_xrefs(uFlag, x.n) )
        ua_add_off_drefs2(x, dr_O, OOFS_IFSIGN|OOFW_IMM);
      break;
    case o_displ:
      process_immediate_number(x.n);
      if ( isAlt )
        break;
      if ( op_adds_xrefs(uFlag, x.n) )
      {
        ea_t ea = ua_add_off_drefs2(x, isload ? dr_R : dr_W, get_displ_outf(x));
        if ( ea != BADADDR )
        {
          ua_dodata2(x.offb, ea, x.dtyp);
          if ( !isload )
            doVar(ea);
        }
      }
      // create stack variables if required
      if ( may_create_stkvars() && !isDefArg(uFlag, x.n) )
      {
        func_t *pfn = get_func(cmd.ea);
        if ( pfn != NULL
          && (issp(x.phrase)
              || isbp(x.phrase) && (pfn->flags & FUNC_FRAME) != 0) )
        {
          if ( ua_stkvar2(x, x.addr, STKVAR_VALID_SIZE) )
            op_stkvar(cmd.ea, x.n);
        }
      }
      break;
    case o_near:
      add_code_xref(x, calc_mem(x.addr));
      break;
    case o_mem:
    case o_memind:
      {
        ea_t ea = calc_mem(x.addr);
        if ( !isEnabled(ea) && find_sym(ea) ) break;    // address not here
        ua_add_dref(x.offb, ea, isload ? dr_R : dr_W);
        ua_dodata2(x.offb, ea, x.dtyp);
        if ( x.type == o_memind )
        {
          ssize_t size = get_dtyp_size(x.dtyp);
          flags_t F = getFlags(ea);
          if ( (isWord(F) || isDwrd(F))
            && (!isDefArg0(F) || isOff0(F)) )
          {
            ea_t target = calc_mem(size == 2
                                ? get_word(ea)
                                : (get_long(ea) & 0xFFFFFFL));
            if ( isEnabled(target) ) add_code_xref(x, target);
            if ( !isOff0(F) )
              set_offset(ea, 0, calc_mem(0));
          }
          break;
        }
        if ( !isload ) doVar(ea);
      }
      break;
    default:
      INTERR(10095);
  }
}
Пример #10
0
//--------------------------------------------------------------------------
int idaapi rpc_debmod_t::dbg_add_bpt(bpttype_t, ea_t, int)
{
  INTERR(30114);
}
Пример #11
0
//--------------------------------------------------------------------------
int idaapi rpc_debmod_t::dbg_del_bpt(bpttype_t, ea_t, const uchar *, int)
{
  INTERR(30115);
}
Пример #12
0
// Emulate an operand.
static void handle_operand(op_t &op, bool write) {
    switch ( op.type ) {
        // Code address
        case o_near:
            {
                cref_t mode;
                ea_t ea = toEA(cmd.cs, op.addr);

                // call or jump ?
                if ( cmd.itype == st9_call || cmd.itype == st9_calls )
                {
                  if ( !func_does_return(ea) )
                    flow = false;
                  mode = fl_CN;
                }
                else
                {
                  mode = fl_JN;
                }
                ua_add_cref(op.offb, ea, mode);
            }
            break;

        // Memory address
        case o_mem:
            {
                enum dref_t mode;

                mode = write ? dr_W: dr_R;

                ua_add_dref(op.offb, toEA(cmd.cs, op.addr), mode);
                ua_dodata2(op.offb, op.addr, op.dtyp);
            }
            break;

        // Immediate value
        case o_imm:
            doImmd(cmd.ea);
            // 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(uFlag) ) {
                    set_cmt(cmd.ea, port->cmt, false);
                }
            }
            // if the value was converted to an offset, then create a data xref:
            if ( op_adds_xrefs(uFlag, op.n) )
              ua_add_off_drefs2(op, dr_O, 0);
            break;

        // Displacement
        case o_displ:
            doImmd(cmd.ea);
            if ( op_adds_xrefs(uFlag, op.n) )
            {
                ea_t ea = ua_add_off_drefs2(op, dr_O, OOF_ADDR);
                ua_dodata2(op.offb, ea, op.dtyp);
            }

            // create stack variables if required
            if ( may_create_stkvars() && !isDefArg(uFlag, op.n) )
            {
                func_t *pfn = get_func(cmd.ea);
                if ( pfn != NULL && pfn->flags & FUNC_FRAME )
                {
                    if ( ua_stkvar2(op, op.addr, STKVAR_VALID_SIZE) )
                    {
                        op_stkvar(cmd.ea, op.n);
                        if ( cmd.Op2.type == o_reg )
                        {
                            regvar_t *r = find_regvar(pfn, cmd.ea, ph.regNames[cmd.Op2.reg]);
                            if ( r != NULL )
                            {
                                struc_t *s = get_frame(pfn);
                                member_t *m = get_stkvar(op, op.addr, NULL);
                                if ( s != NULL && m != NULL )
                                {
                                  char b[20];
                                  qsnprintf(b, sizeof b, "%scopy", r->user);
                                  set_member_name(s, m->soff, b);
                                }
                            }
                        }
                    }
                }
            }
            break;

        // Register - Phrase - Void: do nothing
        case o_reg:
        case o_phrase:
        case o_void:
            break;

        default:
            INTERR(10076);
    }
}
Пример #13
0
//----------------------------------------------------------------------
static void handle_operand(op_t &x, bool read_access)
{
  ea_t ea;
  dref_t dreftype;
  switch ( x.type )
  {
    case o_void:
    case o_reg:
      break;

    case o_imm:
      QASSERT(557, read_access);
      dreftype = dr_O;
MAKE_IMMD:
      doImmdValue();
      if ( isOff(uFlag, x.n) )
        ua_add_off_drefs(x, dreftype);
      break;

    case o_displ:
      dreftype = read_access ? dr_R : dr_W;
      switch ( x.phrase )
      {
        case rD:        // "dp"
        case rDX:       // "dp, X"
        case rDY:       // "dp, Y"
        case riDX:      // "(dp, X)"
        case rDi:       // "(dp,n)"
        case rDiL:      // "long(dp,n)"
        case rDiY:      // "(dp,n), Y"
        case rDiLY:     // "long(dp,n), Y"
          {
            sel_t dp = get_segreg(cmd.ea, rD);
            if ( dp != BADSEL )
            {
              ea_t orig_ea = dp + x.addr;
              ea = xlat(orig_ea);
              goto MAKE_DREF;
            }
            else
            {
              goto MAKE_IMMD;
            }
          }

        case rAbsi:     // "(abs)"
        case rAbsX:     // "abs, X"
        case rAbsY:     // "abs, Y"
        case rAbsiL:    // "long(abs)"
          ea = toEA(dataSeg_op(x.n), x.addr);
          goto MAKE_DREF;

        case rAbsXi:    // "(abs,X)"
          ea = toEA(codeSeg(cmd.ea, x.n), x.addr); // jmp, jsr
          goto MAKE_DREF;

        case rAbsLX:    // "long abs, X"
          ea = x.addr;
          goto MAKE_DREF;

        default:
          goto MAKE_IMMD;
      }

    case o_mem:
    case o_mem_far:
      ea = calc_addr(x);
MAKE_DREF:
      ua_dodata2(x.offb, ea, x.dtyp);
      if ( !read_access )
        doVar(ea);
      ua_add_dref(x.offb, ea, read_access ? dr_R : dr_W);
      break;

    case o_near:
    case o_far:
      {
        ea_t orig_ea;
        ea = calc_addr(x, &orig_ea);
        if ( cmd.itype == M65816_per )
        {
          ua_add_dref(x.offb, ea, dr_O);
        }
        else
        {
          bool iscall = InstrIsSet(cmd.itype, CF_CALL);
          cref_t creftype = x.type == o_near
                          ? iscall ? fl_CN : fl_JN
                          : iscall ? fl_CF : fl_JF;
          ua_add_cref(x.offb, ea, creftype);
          if ( flow && iscall )
            flow = func_does_return(ea);
        }
      }
      break;

    default:
      INTERR(558);
  }
}
Пример #14
0
// Emulate an operand.
static void handle_operand(op_t &op) {
    bool offset = false;
    switch ( op.type ) {
        case o_near:
            ua_add_cref(op.offb, toEA(cmd.cs, op.addr), (cmd.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 = toEA(cmd.cs, op.addr);
                ua_add_dref(op.offb, ea, mode);
                ua_dodata2(op.offb, ea, op.dtyp);
            }
            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 (cmd.itype == fr_ldi_32 &&
                cmd.Op1.type == o_imm &&
                cmd.Op2.type == o_reg)
            {
                const int callreg = cmd.Op2.reg;
                insn_t cmd_backup = cmd;
                if ( next_insn(cmd.ea + cmd.size ) > 0 &&
                    cmd.itype == fr_call &&
                    cmd.Op1.type == o_phrase &&
                    cmd.Op1.specflag2 == fIGR &&
                    cmd.Op1.reg == callreg)
                {
                    offset = true;
                }
                const ea_t from = cmd.ea;
                cmd = cmd_backup;
                if ( !isDefArg(uFlag, 0) && offset && set_offset(cmd.ea, 0, 0) )
                    add_cref(from, toEA(cmd.cs, cmd.Op1.value), fl_CN);
            }
            doImmd(cmd.ea);
            if ( !offset )
                // if the value was converted to an offset, then create a data xref:
                if ( isOff(uFlag, op.n) )
                  ua_add_off_drefs2(op, dr_O, 0);

            // create stack variables if necessary
            {
                bool ok = false;
                // ldi8 #our_value, R1
                // extsb R1
                // addn R14, R1
                if (cmd.itype == fr_ldi_8 &&
                    cmd.Op2.type == o_reg &&
                    cmd.Op2.reg == rR1)
                {
                    insn_t current_insn = cmd;
                    next_insn(cmd.ea + cmd.size);
                    if (cmd.itype == fr_extsb &&
                        cmd.Op1.type == o_reg &&
                        cmd.Op1.reg == rR1)
                    {
                        ok = true;
                    }
                    if ( ok ) {
                        ok = false;
                        next_insn(cmd.ea + cmd.size);
                        if (cmd.itype == fr_addn &&
                            cmd.Op1.type == o_reg &&
                            cmd.Op1.reg == rR14 &&
                            cmd.Op2.type == o_reg &&
                            cmd.Op2.reg == rR1)
                        {
                            ok = true;
                        }
                    }
                    cmd = current_insn;
                }
                // ldi32 #our_value, Ri
                // addn R14, Ri
                //
                // (where Ri is either R1 or R2)
                else if (cmd.itype == fr_ldi_32 &&
                    cmd.Op2.type == o_reg &&
                    (cmd.Op2.reg == rR1 || cmd.Op2.reg == rR2))
                {
                    ushort the_reg = cmd.Op2.reg;
                    insn_t current_insn = cmd;
                    next_insn(cmd.ea + cmd.size);
                    if (cmd.itype == fr_addn &&
                        cmd.Op1.type == o_reg &&
                        cmd.Op1.reg == rR14 &&
                        cmd.Op2.type == o_reg &&
                        cmd.Op2.reg == the_reg)
                    {
                        ok = true;
                    }
                    cmd = current_insn;
                }

                if ( ok && may_create_stkvars() && !isDefArg(uFlag, op.n) ) {
                    func_t *pfn = get_func(cmd.ea);
                    if ( pfn != NULL && pfn->flags & FUNC_FRAME ) {
                        if ( ua_stkvar2(op, op.value, 0) ) {
                            op_stkvar(cmd.ea, op.n);
                        }
                    }
                }
            }
            break;

        case o_displ:
        case o_phrase:  // XXX
        case o_reglist:
        case o_void:
        case o_reg:
            break;

        default:
            INTERR(10017);
    }
}
Пример #15
0
// Output an operand
bool idaapi outop(op_t &op) {
    switch ( op.type ) {
        // Data / Code memory address
        case o_near:
        case o_mem:
            BEG_TAG(op);
            out_addr(op);
            END_TAG(op);
            break;

        // Immediate value
        case o_imm:
            BEG_TAG(op);
            {
                const ioport_t * port = find_sym(op.value);

                // this immediate is represented in the .cfg file
                if ( port != NULL )
                    // output the port name instead of the numeric value
                    out_line(port->name, COLOR_IMPNAME);
                // otherwise, simply print the value
                else
                    out_imm(op);
            }
            END_TAG(op);
            break;

        // Displacement
        case o_displ:
            out_addr(op, false);
            out_symbol('(');
            out_reg(op);
            out_symbol(')');
            break;

        // Register
        case o_reg:
            BEG_TAG(op);
            out_reg(op);
            END_TAG(op);
            if ( is_reg_with_bit(op) ) {
                out_symbol('.');
                if ( is_bit_compl(op) )
                    out_symbol('!');
                out_imm(op, true);
            }
            break;

        // Phrase
        case o_phrase:
            switch ( op.specflag2 ) {
                case fPI:   // post increment
                    out_symbol('(');
                    out_reg(op);
                    out_symbol(')');
                    out_symbol('+');
                    break;

                case fPD:   // pre decrement
                    out_symbol('-');
                    out_symbol('(');
                    out_reg(op);
                    out_symbol(')');
                    break;

                case fDISP: // displacement
                    out_reg(op);
                    out_symbol('(');
                    {
                        ushort reg = op.specflag2 << 8;
                        reg |= op.specflag3;
                        out_reg(reg);
                    }
                    out_symbol(')');
                    break;

                default:
                    INTERR(10077);
            }
            break;

        // No operand
        case o_void:
            break;

        default:
            INTERR(10078);
    }

    return 1;
}
Пример #16
0
//-------------------------------------------------------------------------
// Converts an IDC variable to a Python variable
// If py_var points to an existing object then the object will be updated
// If py_var points to an existing immutable object then ZERO is returned
// Returns one of CIP_xxxx. Check pywraps.hpp
int idcvar_to_pyvar(
  const idc_value_t &idc_var,
  ref_t *py_var)
{
  PYW_GIL_CHECK_LOCKED_SCOPE();
  switch ( idc_var.vtype )
  {
  case VT_PVOID:
    if ( *py_var == NULL )
    {
      newref_t nr(PyCObject_FromVoidPtr(idc_var.pvoid, NULL));
      *py_var = nr;
    }
    else
    {
      return CIP_IMMUTABLE;
    }
    break;

  case VT_INT64:
    {
      // Recycle?
      if ( *py_var != NULL )
      {
        // Recycling an int64 object?
        int t = get_pyidc_cvt_type(py_var->o);
        if ( t != PY_ICID_INT64 )
          return CIP_IMMUTABLE; // Cannot recycle immutable object
        // Update the attribute
        PyObject_SetAttrString(py_var->o, S_PY_IDCCVT_VALUE_ATTR, PyLong_FromLongLong(idc_var.i64));
        return CIP_OK;
      }
      ref_t py_cls(get_idaapi_attr_by_id(PY_CLSID_CVT_INT64));
      if ( py_cls == NULL )
        return CIP_FAILED;
      *py_var = newref_t(PyObject_CallFunctionObjArgs(py_cls.o, PyLong_FromLongLong(idc_var.i64), NULL));
      if ( PyW_GetError() || *py_var == NULL )
        return CIP_FAILED;
      break;
    }

#if !defined(NO_OBSOLETE_FUNCS) || defined(__EXPR_SRC)
  case VT_STR:
    *py_var = newref_t(PyString_FromString(idc_var.str));
    break;

#endif
  case VT_STR2:
    if ( *py_var == NULL )
    {
      const qstring &s = idc_var.qstr();
      *py_var = newref_t(PyString_FromStringAndSize(s.begin(), s.length()));
      break;
    }
    else
      return CIP_IMMUTABLE; // Cannot recycle immutable object
  case VT_LONG:
    // Cannot recycle immutable objects
    if ( *py_var != NULL )
      return CIP_IMMUTABLE;
    *py_var = newref_t(cvt_to_pylong(idc_var.num));
    break;
  case VT_FLOAT:
    if ( *py_var == NULL )
    {
      double x;
      if ( ph.realcvt(&x, (uint16 *)idc_var.e, (sizeof(x)/2-1)|010) != 0 )
        INTERR(30160);

      *py_var = newref_t(PyFloat_FromDouble(x));
      break;
    }
    else
      return CIP_IMMUTABLE;

  case VT_REF:
    {
      if ( *py_var == NULL )
      {
        ref_t py_cls(get_idaapi_attr_by_id(PY_CLSID_CVT_BYREF));
        if ( py_cls == NULL )
          return CIP_FAILED;

        // Create a byref object with None value. We populate it later
        *py_var = newref_t(PyObject_CallFunctionObjArgs(py_cls.o, Py_None, NULL));
        if ( PyW_GetError() || *py_var == NULL )
          return CIP_FAILED;
      }
      int t = get_pyidc_cvt_type(py_var->o);
      if ( t != PY_ICID_BYREF )
        return CIP_FAILED;

      // Dereference
      // (Since we are not using VREF_COPY flag, we can safely const_cast)
      idc_value_t *dref_v = VarDeref(const_cast<idc_value_t *>(&idc_var), VREF_LOOP);
      if ( dref_v == NULL )
        return CIP_FAILED;

      // Can we recycle the object?
      ref_t new_py_val(PyW_TryGetAttrString(py_var->o, S_PY_IDCCVT_VALUE_ATTR));
      if ( new_py_val != NULL )
      {
        // Recycle
        t = idcvar_to_pyvar(*dref_v, &new_py_val);

        // Success? Nothing more to be done
        if ( t == CIP_OK )
          return CIP_OK;

        // Clear it so we don't recycle it
        new_py_val = ref_t();
      }
      // Try to convert (not recycle)
      if ( idcvar_to_pyvar(*dref_v, &new_py_val) != CIP_OK )
        return CIP_FAILED;

      // Update the attribute
      PyObject_SetAttrString(py_var->o, S_PY_IDCCVT_VALUE_ATTR, new_py_val.o);
      break;
    }

    // Can convert back into a Python object or Python dictionary
    // (Depending if py_var will be recycled and it was a dictionary)
  case VT_OBJ:
    {
      // Check if this IDC object has __cvt_id__ and the __idc_cvt_value__ fields
      idc_value_t idc_val;
      if (    VarGetAttr(&idc_var, S_PY_IDCCVT_ID_ATTR, &idc_val) == eOk
        && VarGetAttr(&idc_var, S_PY_IDCCVT_VALUE_ATTR, &idc_val) == eOk )
      {
        // Extract the object
        *py_var = borref_t((PyObject *) idc_val.pvoid);
        return CIP_OK_OPAQUE;
      }
      ref_t obj;
      bool is_dict = false;

      // Need to create a new object?
      if ( *py_var == NULL )
      {
        // Get skeleton class reference
        ref_t py_cls(get_idaapi_attr_by_id(PY_CLSID_APPCALL_SKEL_OBJ));
        if ( py_cls == NULL )
          return CIP_FAILED;

        // Call constructor
        obj = newref_t(PyObject_CallFunctionObjArgs(py_cls.o, NULL));
        if ( PyW_GetError() || obj == NULL )
          return CIP_FAILED;
      }
      else
      {
        // Recycle existing variable
        obj = *py_var;
        if ( PyDict_Check(obj.o) )
          is_dict = true;
      }

      // Walk the IDC attributes and store into python
      for (const char *attr_name = VarFirstAttr(&idc_var);
        attr_name != NULL;
        attr_name = VarNextAttr(&idc_var, attr_name) )
      {
        // Get the attribute
        idc_value_t v;
        VarGetAttr(&idc_var, attr_name, &v, true);

        // Convert attribute to a python value (recursively)
        ref_t py_attr;
        int cvt = idcvar_to_pyvar(v, &py_attr);
        if ( cvt <= CIP_IMMUTABLE )
          return CIP_FAILED;
        if ( is_dict )
          PyDict_SetItemString(obj.o, attr_name, py_attr.o);
        else
          PyObject_SetAttrString(obj.o, attr_name, py_attr.o);
      }
      *py_var = obj;
      break;
    }
    // Unhandled type
  default:
    *py_var = ref_t();
    return CIP_FAILED;
  }
  return CIP_OK;
}