//---------------------------------------------------------------------- // Calculate the target data address ea_t map_addr(asize_t off, int opnum, bool isdata) { if ( isdata ) { if ( isOff(uFlag, opnum) ) return get_offbase(cmd.ea, opnum) >> 4; return ((off >= 0x80 && off < 0x100) ? sfrmem : intmem) + off; } return toEA(codeSeg(off, opnum), off); }
//---------------------------------------------------------------------- // Calculate the target data address ea_t map_addr(asize_t off, int opnum, bool isdata) { if ( isdata ) { if ( isOff(uFlag, opnum) ) return get_offbase(cmd.ea, opnum) >> 4; return intmem + off; } return toEA(codeSeg(off, opnum), off); }
//---------------------------------------------------------------------- static int OutVarName(op_t &x, int iscode, int relative) { //char *ptr; ushort addr = ushort(x.addr); if(relative) { addr += (ushort)cmd.ip; addr += cmd.size; // ig: this is tested only for 6809 } //Получить линейный адресс ea_t toea = toEA((iscode || relative) ? codeSeg(addr,x.n) : dataSeg_op(x.n), addr); //Получть строку для данного лин. адресса return out_name_expr(x, toea, addr); }
static void OutVarNameVal(op_t &x) { ushort addr = x.value; ulong toea = toEA(codeSeg(addr,x.n), addr); #if IDP_INTERFACE_VERSION > 37 if(out_name_expr(x,toea,addr))return; #else const char *ptr; if((ptr=get_name_expr(cmd.ea+x.offb, toea, addr)) != NULL){ //вывод имен переменных и меток перехода OutLine(ptr); } #endif else OutValue(x, OOFW_16); }
static void OutVarName(op_t &x) { ea_t addr = x.addr; ea_t toea = toEA(codeSeg(addr,x.n), addr); #if IDP_INTERFACE_VERSION > 37 // msg("AT:%a target=%lx, segm=%lx, Result=%lx\n", // cmd.ea,addr, codeSeg(addr,x.n),toea); if ( out_name_expr(x,toea,addr) )return; #else const char *ptr; if ( (ptr=get_name_expr(cmd.ea+x.offb, toea, addr)) != NULL ){ //вывод имен переменных и меток перехода OutLine(ptr); } #endif else{ OutValue(x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_32); // пометим проблему - нет имени QueueMark(Q_noName,cmd.ea); } }
//---------------------------------------------------------------------- int i5_emu(void) { uint32 Feature = cmd.get_canon_feature(); flow = ((Feature & CF_STOP) == 0); if ( (Feature & CF_USE1) ) LoadArg(cmd.Op1); if ( (Feature & CF_USE2) ) LoadArg(cmd.Op2); if ( Feature & CF_JUMP ) QueueMark(Q_jumps,cmd.ea); switch ( cmd.itype ) { case I5_mov: case I5_mvi: case Z80_ld: // if ( ! fail ) R1.doInt( R2.value() ); // else R1.undef(); break; case Z80_jp: case Z80_jr: // Z80 case Z80_ret: // Z80 if ( cmd.Op1.Cond != oc_not ) break; case I5_jmp: if ( cmd.Op2.type == o_phrase ) QueueMark(Q_jumps,cmd.ea); case I5_ret: flow = 0; break; case I5_rstv: ua_add_cref(0,toEA(codeSeg(0x40,0),0x40),fl_CN); break; case I5_rst: { int mul = (isZ80() ? 1 : 8); ushort offset = ushort(cmd.Op1.value * mul); ua_add_cref(0,toEA(codeSeg(offset,0),offset),fl_CN); } case I5_call: case I5_cc: case I5_cnc: case I5_cz: case I5_cnz: case I5_cpe: case I5_cpo: case I5_cp: case I5_cm: case Z80_exx: // Z80 // i5_CPUregs.bc.undef(); // i5_CPUregs.de.undef(); // i5_CPUregs.hl.undef(); // i5_CPUregs.af.undef(); // i5_CPUregs.ix.undef(); // i5_CPUregs.iy.undef(); break; default: // R1.undef(); // R2.undef(); break; } if ( Feature & CF_CHG1 ) SaveArg(cmd.Op1); if ( Feature & CF_CHG2 ) SaveArg(cmd.Op2); if ( flow ) ua_add_cref(0,cmd.ea+cmd.size,fl_F); return 1; }
//---------------------------------------------------------------------- static void TouchArg(op_t &x,int isload) { ea_t ea; switch ( x.type ) { case o_phrase: // 2 registers or indirect addressing if ( cmd.itype != TMS_mar && cmd.itype != TMS2_mar && find_ar(&ea) ) goto set_dref; case o_reg: case o_bit: case o_cond: break; case o_imm: if ( ! isload ) goto badTouch; doImmdValue(); if ( isOff(uFlag, x.n) ) ua_add_off_drefs2(x, dr_O, is_mpy() ? OOF_SIGNED : 0); break; case o_mem: ea = toEA(dataSeg_op(x.n),x.addr); set_dref: ua_dodata2(x.offb, ea, x.dtyp); if ( ! isload ) doVar(ea); ua_add_dref(x.offb,ea,isload ? dr_R : dr_W); if ( x.type == o_mem ) if ( cmd.itype == TMS_dmov || cmd.itype == TMS_ltd || cmd.itype == TMS_macd || cmd.itype == TMS_madd || cmd.itype == TMS2_dmov || cmd.itype == TMS2_macd ) ua_add_dref(x.offb,ea+1,dr_W); break; case o_near: { ea_t segbase = codeSeg(x.addr, x.n); ea = toEA(segbase, x.addr); if ( cmd.itype == TMS_blpd || cmd.itype == TMS_mac || cmd.itype == TMS_macd || cmd.itype == TMS2_blkp || cmd.itype == TMS2_mac || cmd.itype == TMS2_macd ) goto set_dref; uval_t thisseg = cmd.cs; int iscall = InstrIsSet(cmd.itype,CF_CALL); if ( cmd.itype == TMS_rptb && isTail(get_flags_novalue(ea)) ) { // small hack to display end_loop-1 instead of before_end_loop+1 ea++; } ua_add_cref(x.offb, ea, iscall ? ((segbase == thisseg) ? fl_CN : fl_CF) : ((segbase == thisseg) ? fl_JN : fl_JF)); if ( iscall ) { if ( !func_does_return(ea) ) flow = false; } } break; default: badTouch: warning("%a: %s,%d: bad optype %d", cmd.ea, cmd.get_canon_mnem(), x.n, x.type); break; } }
//---------------------------------------------------------------------- // вывод одного операнда bool N78K_outop(op_t &x) { #if IDP_INTERFACE_VERSION <= 37 uFlag = getFlags(cmd.ea); #endif switch(x.type){ case o_void: return 0; case o_reg: if(x.FormOut & FORM_OUT_SKOBA) out_symbol('['); OutReg(x.reg); if(x.FormOut & FORM_OUT_PLUS) out_symbol('+'); if(x.FormOut & FORM_OUT_DISP){ if(isOff(uFlag, x.n)){ OutVarNameVal(x); } else OutValue(x, OOFW_IMM ); } if(x.FormOut & FORM_OUT_REG){ out_keyword( ph.regNames[x.SecondReg] ); } if(x.FormOut & FORM_OUT_SKOBA) out_symbol(']'); break; case o_bit: switch(x.FormOut){ case FORM_OUT_S_ADDR: case FORM_OUT_SFR: OutVarName(x); out_symbol('.'); #if IDP_INTERFACE_VERSION > 37 if( !nec_find_ioport_bit(x.addr, x.value) ) #endif { OutValue(x, OOFW_IMM); } break; case FORM_OUT_A: OutLine("A."); OutValue(x, OOFW_IMM); break; case FORM_OUT_PSW: OutLine("PSW."); switch(x.value){ case 0: OutLine("CY");break; case 1: OutLine("ISP");break; case 3: OutLine("RBS0");break; case 4: OutLine("AC");break; case 5: OutLine("RBS1");break; case 6: OutLine("Z");break; case 7: OutLine("IE");break; default:OutValue(x, OOFW_IMM); } break; case FORM_OUT_HL: out_symbol('['); OutReg(rHL); out_symbol(']'); out_symbol('.'); if(isOff(uFlag, x.n)){ OutVarNameVal(x); } else OutValue(x, OOFW_IMM ); break; } break; case o_imm: out_symbol('#'); if(isOff(uFlag, x.n)){ OutVarNameVal(x); } else OutValue(x, OOFW_IMM ); break; case o_mem: //выводит имя переменной из памяти(например byte_98) if(x.FormOut & FORM_OUT_VSK) out_symbol('!'); if(x.FormOut & FORM_OUT_SKOBA) out_symbol('['); //Вывод имени переменной OutVarName(x); if(x.FormOut & FORM_OUT_SKOBA) out_symbol(']'); break; case o_near: if(x.FormOut & FORM_OUT_VSK) out_symbol('!'); if(x.FormOut & FORM_OUT_SKOBA) out_symbol('['); { ulong adr; adr = toEA(codeSeg(x.addr,x.n),x.addr); #if IDP_INTERFACE_VERSION > 37 if( !out_name_expr(x, adr, x.addr)){ OutValue(x, OOF_ADDR | OOF_NUMBER | OOFW_16); QueueMark(Q_noName, cmd.ea); } #else {const char *ptr; ptr=get_name_expr(cmd.ea+x.offb, adr, x.addr); if( ptr == NULL ){ OutValue(x, OOF_ADDR | OOF_NUMBER | OOFW_16); QueueMark(Q_noName, cmd.ea); } else OutLine(ptr); } #endif } if(x.FormOut & FORM_OUT_SKOBA) out_symbol(']'); break; // неизвестный операнд default: warning("out: %lx: bad optype",cmd.ea,x.type); break; } return(1); }
//---------------------------------------------------------------------- static void TouchArg(op_t &x,int isAlt,int isload) { switch ( x.type ) { case o_phrase: //Добавляем в список ошибок(выводим сообщение) //ошибку и адресс где это случилось //QueueMark(Q_jumps, cmd.ea); case o_void: case o_reg: break; case o_sr: case o_displ: //Установить для данного байта признак immedia doImmd(cmd.ea); //Получить флаг для указанного линейного адресса if ( !isAlt ) { uint32 offb; ushort addr = ushort(x.addr); if ( x.type == o_displ ) { addr += (ushort)cmd.ip; addr += cmd.size; //Получить линейный адресс offb = (uint32)toEA(codeSeg(addr,x.n), 0); DataSet(x, offb+addr, isload); } else if ( isOff(uFlag, x.n) ) { reref: ua_add_off_drefs2(x, dr_O, x.type == o_displ ? OOF_ADDR : 0); if ( x.type == o_displ ) //Преобразовать данные по указанному линейному адрессу в указанный тип ua_dodata2(x.offb, calc_target(cmd.ea+x.offb, cmd.ea, x.n, x.addr), x.dtyp); } else if ( x.type == o_displ && !x.reg && !isDefArg(uFlag, x.n ) && set_offset(cmd.ea, x.n, toEA(cmd.cs,0))) goto reref; } break; case o_stk: case o_imm: { //Установить для данного байта признак immedia doImmd(cmd.ea); if ( isOff(get_flags_novalue(cmd.ea), x.n) ) ua_add_off_drefs2(x, dr_O, 0); } break; case o_ab: { if ( x.TypeOper == TAB_INDIRECTED_ABS_X ) { ea_t ea = toEA(cmd.cs, x.addr); ua_dodata2(x.offb, ea, dt_word); //добавить крос референсы для текущей инструкции ua_add_dref(x.offb, ea, isload ? dr_R : dr_W); //получить данные uint32 Addr; Addr = get_word(ea); Addr = uint32( Addr | (getPG<<16)); //добавить крос референсы для текущей инструкции ua_add_cref(2, Addr, fl_JF); } else DataSet(x, toEA(codeSeg(x.addr,x.n), x.addr), isload); } break; case o_mem: { // Конвертирование в данные(указан адресс) по указанному типу, //добавить крос референсы для текущей инструкции switch ( x.TypeOper ) { case TDIR_DIR_Y: case TDIR_DIR_X: case TDIR_DIR: case TDIR_INDIRECT_DIR: case TDIR_INDIRECT_DIR_X: case TDIR_INDIRECT_DIR_Y: case TDIR_L_INDIRECT_DIR: case TDIR_L_INDIRECT_DIR_Y: { if ( getDPReg == 1 ) { uint32 d = x.addr & 0xC; x.addr &= 0xFF3F; DataSet(x, toEA(codeSeg(x.addr,x.n), x.addr), isload); x.addr |=d; } else DataSet(x, toEA(codeSeg(x.addr,x.n), x.addr), isload); } break; default: DataSet(x, toEA(codeSeg(x.addr,x.n), x.addr), isload); }//end switch } break; case o_near: { //Получить линейный адресс ea_t ea = toEA(cmd.cs, x.addr); switch ( cmd.itype ) { case m7900_jsr: { //добавить крос референсы для текущей инструкции ua_add_cref(x.offb, ea, fl_CN ); if ( !func_does_return(ea) ) flow = false; } break; case m7900_jsrl: //добавить крос референсы для текущей инструкции ua_add_cref(x.offb, ea, fl_CF); if ( !func_does_return(ea) ) flow = false; break; case m7900_jmpl: //добавить крос референсы для текущей инструкции ua_add_cref(x.offb, ea, fl_JF); break; default: ua_add_cref(x.offb, ea, fl_JN); break; } } break; default: // warning("%a: %s,%d: bad optype %d", cmd.ea, cmd.get_canon_mnem(), x.n, x.type); break; } }
//---------------------------------------------------------------------- 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); } }
//---------------------------------------------------------------------- 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); } }
//---------------------------------------------------------------------- bool outop(op_t &x) { ea_t segadr; switch (x.type) { case o_void: return 0; case o_reg: OutReg(x.reg); break; case o_fpreg: OutReg(x.reg + 8); break; case o_imm: // 27 if(x.ill_imm) { out_symbol('('); OutReg(rPC); out_symbol(')'); out_symbol('+'); } else { out_symbol('#'); if(x.dtyp == dt_float || x.dtyp == dt_double) { char str[MAXSTR]; if(out_real(&x.value, 2, str, sizeof(str))) { register char *p = str; while(*p == ' ') p++; out_symbol('^'); out_symbol('F'); out_line(p, COLOR_NUMBER); } else out_long(x.value, 8); } else OutValue(x, OOF_SIGNED | OOFW_IMM); } break; case o_mem: // 37/67/77 case o_near: // jcc/ [jmp/call 37/67] case o_far: if(x.phrase != 0) { if(x.phrase == 077 || x.phrase == 037) out_symbol('@'); if(x.phrase == 037) out_symbol('#'); if(x.addr16 < m.asect_top && !isOff(uFlag,x.n)) { OutValue(x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_16); break; } } segadr = toEA(x.type == o_far ? x.segval : codeSeg(x.addr16,x.n), x.addr16); if(!out_name_expr(x, segadr, x.addr16)) { if(x.type == o_far || x.addr16 < 0160000) QueueMark(Q_noName, cmd.ea); OutValue(x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_16); } break; case o_number: //EMT/TRAP/MARK/SPL OutValue(x, OOF_NUMBER | OOFS_NOSIGN | OOFW_8); break; case o_displ: // 6x/7x (!67/!77) if(x.phrase >= 070) out_symbol('@'); OutValue(x, OOF_ADDR | OOF_SIGNED | OOFW_16); out_symbol('('); goto endregout; case o_phrase: // 1x/2x/3x/4x/5x (!27/!37) switch(x.phrase >> 3) { case 1: out_symbol('@'); OutReg(x.phrase & 7); break; case 3: out_symbol('@'); case 2: out_symbol('('); OutReg(x.phrase & 7); out_symbol(')'); out_symbol('+'); break; case 5: out_symbol('@'); case 4: out_symbol('-'); out_symbol('('); endregout: OutReg(x.phrase & 7); out_symbol(')'); break; } break; default: warning("out: %" FMT_EA "o: bad optype %d", cmd.ip, x.type); break; } return 1; }
//---------------------------------------------------------------------- static void TouchArg(op_t &x,int isAlt,int isload) { switch (x.type) { case o_phrase: //Добавляем в список ошибок(выводим сообщение) //ошибку и адресс где это случилось //QueueMark(Q_jumps, cmd.ea); case o_void: case o_reg: break; case o_imm: { //Установить для данного байта признак immedia doImmd(cmd.ea); //Получить флаг для указанного линейного адресса if(!isAlt) { uint32 offb; ushort addr = ushort(x.addr); if(x.type == o_displ ) { addr += (ushort)cmd.ip; addr += cmd.size; //Получить линейный адресс offb = (uint32)toEA(codeSeg(addr,x.n), 0); DataSet(x, offb+addr, isload); } else if ( isOff(uFlag, x.n) ) { reref: ua_add_off_drefs(x, dr_O); if ( x.type == o_displ ) //Преобразовать данные по указанному линейному адрессу в указанный тип ua_dodata2(x.offb, calc_target(cmd.ea+x.offb, cmd.ea, x.n, x.addr), x.dtyp); } else if(x.type == o_displ && !x.reg && !isDefArg(uFlag, x.n) && set_offset(cmd.ea, x.n, toEA(cmd.cs,0))) goto reref; } } break; case o_bit: case o_mem: // Конвертирование в данные(указан адресс) по указанному типу, //добавить крос референсы для текущей инструкции DataSet(x, toEA(codeSeg(x.addr,x.n), x.addr), isload); 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 ( iscall ) flow = func_does_return(ea); } break; default: warning("%a: %s,%d: bad optype %d", cmd.ea, cmd.get_canon_mnem(), x.n, x.type); break; } }
//---------------------------------------------------------------------- static int LoadArg(op_t &x) { dref_t xreftype; switch ( x.type ) { case o_reg: { if ( x.reg == R_sp ) goto Undefined; // AbstractRegister *in = &i5_getreg(x.reg); // if ( ! in->isDef() ) goto Undefined; // r.doInt(in->value()); return 1; } case o_imm: // r.doInt(unsigned(x.value)); xreftype = dr_O; MakeImm: doImmdValue(x.n); if ( isOff(uFlag, x.n) ) ua_add_off_drefs2(x, xreftype, 0); return 1; case o_displ: // r.undef(); xreftype = dr_R; goto MakeImm; case o_mem: { ea_t ea = toEA(dataSeg_op(x.n),x.addr); ua_add_dref(x.offb,ea,dr_R); ua_dodata2(x.offb, ea, x.dtyp); if ( !isVar(get_flags_novalue(ea)) && isLoaded(ea) ) { // r.doInt( x.dtyp != dt_byte ? get_word(ea) : char(get_byte(ea)) ); return 1; } } case o_phrase: Undefined: // r.undef(); break; case o_near: { ea_t segbase = codeSeg(x.addr,x.n); ea_t ea = toEA(segbase,x.addr); ea_t thisseg = cmd.cs; int iscall = InstrIsSet(cmd.itype,CF_CALL); ua_add_cref(x.offb, ea, iscall ? ((segbase == thisseg) ? fl_CN : fl_CF) : ((segbase == thisseg) ? fl_JN : fl_JF)); if ( iscall && !func_does_return(ea) ) flow = false; // r.doInt(unsigned(x.addr)); } return 1; default: // warning("%a: %s,%d: bad load optype %d", cmd.ea, cmd.get_canon_mnem(), x.n, x.type); break; } return 0; }
//------------------------------------------------------------------------ static void TouchArg(op_t &x,int isAlt,int isload) { ea_t jmpa; switch ( x.type ) { case o_near: // Jcc/ [jmp/call 37/67] case o_mem: // 37/67/77 case o_far: jmpa = toEA(x.type == o_far ? x.segval : codeSeg(x.addr16,x.n), x.addr16); if ( x.phrase == 0) { ua_add_cref(x.offb,jmpa,fl_JN ); break; } //Jcc extxref: if ( (x.phrase & 070) == 070 ) goto xrefset; if ( cmd.itype == pdp_jmp) ua_add_cref(x.offb,jmpa,fl_JF ); else if ( cmd.itype == pdp_jsr || cmd.itype == pdp_call ) { ua_add_cref(x.offb,jmpa,fl_CF); if ( !func_does_return(jmpa) ) flow = false; } else { xrefset: ua_dodata2(x.offb, jmpa, x.dtyp); ua_add_dref(x.offb, jmpa, isload ? dr_R : dr_W); } break; case o_displ: // 6x/7x (!67/!77) doImmdValue(); if ( !isload && x.phrase == (060 + rR0) && x.addr16 <= 1 ) loadR0data(&x, x.addr16); if ( !isAlt && isOff(emuFlg,x.n ) && (jmpa = get_offbase(cmd.ea, x.n)) != BADADDR) { jmpa += x.addr16; goto extxref; } break; case o_imm: // 27 if ( !x.ill_imm ) { doImmdValue(); if ( op_adds_xrefs(uFlag, x.n) ) ua_add_off_drefs2(x, dr_O, OOF_SIGNED); } break; case o_number: // EMT/TRAP/MARK/SPL if ( cmd.itype == pdp_emt && get_cmt(cmd.ea, false, NULL, 0) <= 0 ) { if ( x.value >= 0374 && x.value <= 0375 ) { cmd.Op2.value = (x.value == 0375) ? emuR0data.b[1] : (emuR0 >> 8); cmd.Op2.type = o_imm; } char buf[MAXSTR]; if ( get_predef_insn_cmt(cmd, buf, sizeof(buf)) > 0 ) set_cmt(cmd.ea, buf, false); cmd.Op2.type = o_void; } break; case o_reg: // 0 if ( x.reg == rR0 ) { if ( cmd.Op2.type == o_void ) { // one operand cmd if ( cmd.itype != pdp_clr ) { goto undefall; } else { if ( cmd.bytecmd ) emuR0 &= 0xFF00; else emuR0 = 0; goto undefdata; } } if ( &x == &cmd.Op2 ) { if ( cmd.itype != pdp_mov ) { if ( cmd.bytecmd ) { emuR0 |= 0xFF; goto undefdata; } else goto undefall; } if ( cmd.bytecmd ) goto undefall; if ( cmd.Op1.type == o_imm ) { if ( (emuR0 = (ushort)cmd.Op1.value) & 1 ) goto undefdata; emuR0data.w = get_word(toEA(cmd.cs, emuR0)); } else { undefall: emuR0 = 0xFFFF; undefdata: emuR0data.w = 0xFFFF; } } } break; case o_phrase: // 1x/2x/3x/4x/5x (!27/!37) if ( (x.phrase & 7) == rR0 ) { if ( !isload && x.phrase == (010 + rR0)) loadR0data(&x, 0 ); else if ( cmd.Op2.type == o_void || &x == &cmd.Op2 ) goto undefall; } case o_fpreg: // FPP break; default: warning("%" FMT_EA "o (%s): bad optype %d", cmd.ip, cmd.get_canon_mnem(), x.type); break; }
//---------------------------------------------------------------------- // поставим использование/изменение операндов static void near TouchArg(op_t &x,int isAlt,int isload) { ea_t ea = toEA(codeSeg(x.addr,x.n), x.addr); switch ( x.type ) { // эта часть не используется ! case o_void: break; // тут тоже нечего делать case o_reg: break; // непосредственный операнд case o_imm: // непосредственный не может меняться if ( ! isload ) goto badTouch; // поставим флажок непосредственного операнда doImmd(cmd.ea); // если не форсирован и помечен смещением if ( !isAlt && isOff(uFlag,x.n) ) // это смещение ! ua_add_dref(x.offb,ea,dr_O); break; // переход или вызов case o_near: // это вызов ? (или переход) if(InstrIsSet(cmd.itype,CF_CALL)){ // поставим ссылку на код ua_add_cref(x.offb,ea,fl_CN); // это функция без возврата ? #if IDP_INTERFACE_VERSION > 37 flow = func_does_return(ea); #else // получим описатель функции func_t *pfn = get_func(ea); // если функция описана и не имеет возврата - остановим if(pfn != NULL && (pfn->flags & FUNC_NORET) ) flow = false; #endif } else ua_add_cref(x.offb,ea,fl_JN); break; // ссылка на ячейку памяти case o_mem: // сделаем данные по указанному адресу ua_dodata2(x.offb, ea, x.dtyp); // если изменяется - поставим переменную if ( ! isload ) doVar(ea); // добавим ссылку на память ua_add_dref(x.offb,ea,isload ? dr_R : dr_W); break; // прочее - сообщим ошибку default: badTouch: #if IDP_INTERFACE_VERSION > 37 warning("%a %s,%d: bad optype %d", cmd.ea, cmd.get_canon_mnem(), #else warning("%08lX %s,%d: bad optype (%x)", cmd.ea,(char far *)Instructions[cmd.itype].name, #endif x.n, x.type); break; } }
LoadedModule* Loader::loadRPL(const std::string& name, const std::vector<uint8_t> data) { auto in = BigEndianView{ data.data(), data.size() }; std::map<std::string, void*> symbolsMap; // Read header auto header = elf::Header{}; if (!elf::readHeader(in, header)) { gLog->error("Failed elf::readHeader"); return nullptr; } // Check it is a CAFE abi rpl if (header.abi != elf::EABI_CAFE) { gLog->error("Unexpected elf abi found {:02x} expected {:02x}", header.abi, elf::EABI_CAFE); return nullptr; } // Read sections auto sections = std::vector<elf::XSection>{}; if (!elf::readSectionHeaders(in, header, sections)) { gLog->error("Failed elf::readSectionHeaders"); return nullptr; } // Read FileInfo data elf::FileInfo info; readFileInfo(in, sections, info); void *codeSegAddr = mCodeHeap->alloc(info.textSize, info.textAlign); assert(codeSegAddr); SequentialMemoryTracker codeSeg(codeSegAddr, info.textSize); void *dataSegAddr = nullptr; if (OSDynLoad_MemAlloc(info.dataSize, info.dataAlign, &dataSegAddr) != 0) { dataSegAddr = nullptr; } assert(dataSegAddr); SequentialMemoryTracker dataSeg(dataSegAddr, info.dataSize); void *loadSegAddr = mCodeHeap->alloc(info.loadSize, info.loadAlign); assert(loadSegAddr); SequentialMemoryTracker loadSeg(loadSegAddr, info.loadSize); // Allocate { std::vector<uint8_t> sectionData; for (auto& section : sections) { if (section.header.flags & elf::SHF_ALLOC) { if (section.header.type == elf::SHT_NOBITS) { sectionData.clear(); sectionData.resize(section.header.size, 0); } else { if (!elf::readSectionData(in, section.header, sectionData)) { gLog->error("Failed to decompressed allocatable section"); return nullptr; } } void *allocData = nullptr; if (section.header.type == elf::SHT_PROGBITS || section.header.type == elf::SHT_NOBITS) { if (section.header.flags & elf::SHF_EXECINSTR) { allocData = codeSeg.get(sectionData.size(), section.header.addralign); } else { allocData = dataSeg.get(sectionData.size(), section.header.addralign); } } else { allocData = loadSeg.get(sectionData.size(), section.header.addralign); } memcpy(allocData, sectionData.data(), sectionData.size()); section.virtAddress = allocData; section.virtSize = static_cast<uint32_t>(sectionData.size()); } } } // I am a bad person and I should feel bad std::map<void*, void*> trampolines; void * trampSegStart = codeSeg.getCurrentAddr(); auto getTramp = [&](void *target, const std::string& symbolName) { auto trampIter = trampolines.find(target); if (trampIter != trampolines.end()) { return trampIter->second; } uint32_t *trampAddr = static_cast<uint32_t*>(codeSeg.getCurrentAddr()); uint32_t *targetAddr = static_cast<uint32_t*>(target); intptr_t delta = reinterpret_cast<uint8_t*>(targetAddr) - reinterpret_cast<uint8_t*>(trampAddr); if (delta > -0x1fffffc && delta < 0x1fffffc) { trampAddr = static_cast<uint32_t*>(codeSeg.get(4)); // Short jump using b auto b = gInstructionTable.encode(InstructionID::b); b.li = delta >> 2; b.lk = 0; b.aa = 0; *trampAddr = byte_swap(b.value); } else if (gMemory.untranslate(targetAddr) < 0x03fffffc) {