#include #include "ntsdp.h" #include "ntdis.h" #include "ntreg.h" #define OPCODE 18 #define OPSTART 26 typedef struct optabentry { PUCHAR pszOpcode; ULONG fInstruction; } OPTABENTRY, *POPTABENTRY; BOOLEAN disasm(PADDR, PUCHAR, BOOLEAN); void BlankFill(ULONG); void OutputHex(ULONG, ULONG, BOOLEAN); void OutputDisSymbol(ULONG); void OutputString(PUCHAR); void OutputReg(ULONG); void OutputFReg(ULONG); void GetNextOffset(PADDR, BOOLEAN); BOOLEAN fDelayInstruction(void); INSTR disinstr; ULONG EAaddr = 0; ADDR EA; UCHAR pszUndef[] = "????"; UCHAR pszNull[] = ""; UCHAR pszAbs_s[] = "abs.s"; UCHAR pszAdd[] = "add"; UCHAR pszAdd_s[] = "add.s"; UCHAR pszAddi[] = "addi"; UCHAR pszAddiu[] = "addiu"; UCHAR pszAddu[] = "addu"; UCHAR pszAnd[] = "and"; UCHAR pszAndi[] = "andi"; UCHAR pszBc0f[] = "bc0f"; UCHAR pszBc0fl[] = "bc0fl"; UCHAR pszBc0t[] = "bc0t"; UCHAR pszBc0tl[] = "bc0tl"; UCHAR pszBc1f[] = "bc1f"; UCHAR pszBc1fl[] = "bc1fl"; UCHAR pszBc1t[] = "bc1t"; UCHAR pszBc1tl[] = "bc1tl"; UCHAR pszBc2f[] = "bc2f"; UCHAR pszBc2fl[] = "bc2fl"; UCHAR pszBc2t[] = "bc2t"; UCHAR pszBc2tl[] = "bc2tl"; UCHAR pszBc3f[] = "bc3f"; UCHAR pszBc3fl[] = "bc3fl"; UCHAR pszBc3t[] = "bc3t"; UCHAR pszBc3tl[] = "bc3tl"; UCHAR pszBgez[] = "bgez"; UCHAR pszBgezal[] = "bgezal"; UCHAR pszBgezall[] = "bgezall"; UCHAR pszBgezl[] = "bgezl"; UCHAR pszBgtz[] = "bgtz"; UCHAR pszBgtzl[] = "bgtzl"; UCHAR pszBeq[] = "beq"; UCHAR pszBeql[] = "beql"; UCHAR pszBlez[] = "blez"; UCHAR pszBlezl[] = "blezl"; UCHAR pszBltz[] = "bltz"; UCHAR pszBltzal[] = "bltzal"; UCHAR pszBltzall[] = "bltzall"; UCHAR pszBltzl[] = "bltzl"; UCHAR pszBne[] = "bne"; UCHAR pszBnel[] = "bnel"; UCHAR pszBreak[] = "break"; UCHAR pszCache[] = "cache"; UCHAR pszCeil_w_s[] = "ceil.w.s"; UCHAR pszCeil_l_s[] = "ceil.l.s"; UCHAR pszCfc0[] = "cfc0"; UCHAR pszCfc1[] = "cfc1"; UCHAR pszCfc2[] = "cfc2"; UCHAR pszCfc3[] = "cfc3"; UCHAR pszCtc0[] = "ctc0"; UCHAR pszCtc1[] = "ctc1"; UCHAR pszCtc2[] = "ctc2"; UCHAR pszCtc3[] = "ctc3"; UCHAR pszCop0[] = "cop0"; UCHAR pszCop1[] = "cop1"; UCHAR pszCop2[] = "cop2"; UCHAR pszCop3[] = "cop3"; UCHAR pszCvt_d_s[] = "cvt.d.s"; UCHAR pszCvt_e_s[] = "cvt.e.s"; UCHAR pszCvt_q_s[] = "cvt.q.s"; UCHAR pszCvt_s_s[] = "cvt.s.s"; UCHAR pszCvt_w_s[] = "cvt.w.s"; UCHAR pszC_eq_s[] = "c.eq.s"; UCHAR pszC_f_s[] = "c.f.s"; UCHAR pszC_le_s[] = "c.le.s"; UCHAR pszC_lt_s[] = "c.lt.s"; UCHAR pszC_nge_s[] = "c.nge.s"; UCHAR pszC_ngl_s[] = "c.ngl.s"; UCHAR pszC_ngle_s[] = "c.ngle.s"; UCHAR pszC_ngt_s[] = "c.ngt.s"; UCHAR pszC_ole_s[] = "c.ole.s"; UCHAR pszC_olt_s[] = "c.olt.s"; UCHAR pszC_seq_s[] = "c.seq.s"; UCHAR pszC_sf_s[] = "c.sf.s"; UCHAR pszC_ueq_s[] = "c.ueq.s"; UCHAR pszC_ule_s[] = "c.ule.s"; UCHAR pszC_ult_s[] = "c.ult.s"; UCHAR pszC_un_s[] = "c.un.s"; UCHAR pszDadd[] = "dadd"; UCHAR pszDaddi[] = "daddi"; UCHAR pszDaddiu[] = "daddiu"; UCHAR pszDaddu[] = "daddu"; UCHAR pszDdiv[] = "ddiv"; UCHAR pszDdivu[] = "ddivu"; UCHAR pszDiv[] = "div"; UCHAR pszDivu[] = "divu"; UCHAR pszDiv_s[] = "div.s"; UCHAR pszDmfc0[] = "dmfc0"; UCHAR pszDmtc0[] = "dmtc0"; UCHAR pszDmult[] = "dmult"; UCHAR pszDmultu[] = "dmultu"; UCHAR pszDsll[] = "dsll"; UCHAR pszDsllv[] = "dsllv"; UCHAR pszDsll32[] = "dsll32"; UCHAR pszDsra[] = "dsra"; UCHAR pszDsrav[] = "dsrav"; UCHAR pszDsra32[] = "dsra32"; UCHAR pszDsrl[] = "dsrl"; UCHAR pszDsrlv[] = "dsrlv"; UCHAR pszDsrl32[] = "dsrl32"; UCHAR pszDsub[] = "dsub"; UCHAR pszDsubu[] = "dsubu"; UCHAR pszEret[] = "eret"; UCHAR pszFloor_w_s[] = "floor.w.s"; UCHAR pszJ[] = "j"; UCHAR pszJal[] = "jal"; UCHAR pszJalr[] = "jalr"; UCHAR pszJr[] = "jr"; UCHAR pszLb[] = "lb"; UCHAR pszLbu[] = "lbu"; UCHAR pszLdc1[] = "ldc1"; UCHAR pszLdc2[] = "ldc2"; UCHAR pszLdc3[] = "ldc3"; UCHAR pszLd[] = "ld"; UCHAR pszLdl[] = "ldl"; UCHAR pszLdr[] = "ldr"; UCHAR pszLh[] = "lh"; UCHAR pszLhu[] = "lhu"; UCHAR pszLld[] = "lld"; UCHAR pszLui[] = "lui"; UCHAR pszLw[] = "lw"; UCHAR pszLwc0[] = "lwc0"; UCHAR pszLwc1[] = "lwc1"; UCHAR pszLwc2[] = "lwc2"; UCHAR pszLwc3[] = "lwc3"; UCHAR pszLwl[] = "lwl"; UCHAR pszLwr[] = "lwr"; UCHAR pszMfc0[] = "mfc0"; UCHAR pszMfc1[] = "mfc1"; UCHAR pszMfc2[] = "mfc2"; UCHAR pszMfc3[] = "mfc3"; UCHAR pszMfhi[] = "mfhi"; UCHAR pszMflo[] = "mflo"; UCHAR pszMov_s[] = "mov.s"; UCHAR pszMtc0[] = "mtc0"; UCHAR pszMtc1[] = "mtc1"; UCHAR pszMtc2[] = "mtc2"; UCHAR pszMtc3[] = "mtc3"; UCHAR pszMthi[] = "mthi"; UCHAR pszMtlo[] = "mtlo"; UCHAR pszMul_s[] = "mul.s"; UCHAR pszMult[] = "mult"; UCHAR pszMultu[] = "multu"; UCHAR pszNeg_s[] = "neg.s"; UCHAR pszNop[] = "nop"; UCHAR pszNor[] = "nor"; UCHAR pszOr[] = "or"; UCHAR pszOri[] = "ori"; UCHAR pszRfe[] = "rfe"; UCHAR pszRound_w_s[] = "round.w.s"; UCHAR pszSb[] = "sb"; UCHAR pszScd[] = "scd"; UCHAR pszSd[] = "sd"; UCHAR pszSdc1[] = "sdc1"; UCHAR pszSdc2[] = "sdc2"; UCHAR pszSdc3[] = "sdc3"; UCHAR pszSdl[] = "sdl"; UCHAR pszSdr[] = "sdr"; UCHAR pszSh[] = "sh"; UCHAR pszSll[] = "sll"; UCHAR pszSllv[] = "sllv"; UCHAR pszSlt[] = "slt"; UCHAR pszSlti[] = "slti"; UCHAR pszSltiu[] = "sltiu"; UCHAR pszSltu[] = "sltu"; UCHAR pszSqrt_s[] = "sqrt.s"; UCHAR pszSra[] = "sra"; UCHAR pszSrav[] = "srav"; UCHAR pszSrl[] = "srl"; UCHAR pszSrlv[] = "srlv"; UCHAR pszSub[] = "sub"; UCHAR pszSub_s[] = "sub.s"; UCHAR pszSubu[] = "subu"; UCHAR pszSw[] = "sw"; UCHAR pszSwc0[] = "swc0"; UCHAR pszSwc1[] = "swc1"; UCHAR pszSwc2[] = "swc2"; UCHAR pszSwc3[] = "swc3"; UCHAR pszSwl[] = "swl"; UCHAR pszSwr[] = "swr"; UCHAR pszSync[] = "sync"; UCHAR pszSyscall[] = "syscall"; UCHAR pszTeq[] = "teq"; UCHAR pszTeqi[] = "teqi"; UCHAR pszTge[] = "tge"; UCHAR pszTgei[] = "tgei"; UCHAR pszTgeiu[] = "tgeiu"; UCHAR pszTgeu[] = "tgeu"; UCHAR pszTlbp[] = "tlbp"; UCHAR pszTlbr[] = "tlbr"; UCHAR pszTlbwi[] = "tlbwi"; UCHAR pszTlbwr[] = "tlbwr"; UCHAR pszTlt[] = "tlt"; UCHAR pszTlti[] = "tlti"; UCHAR pszTltiu[] = "tltiu"; UCHAR pszTltu[] = "tltu"; UCHAR pszTne[] = "tne"; UCHAR pszTnei[] = "tnei"; UCHAR pszTrunc_w_s[] = "trunc.w.s"; UCHAR pszXor[] = "xor"; UCHAR pszXori[] = "xori"; OPTABENTRY opTable[] = { { pszNull, 0 }, // 00 { pszNull, 0 }, // 01 { pszJ, opnAddr26 }, // 02 { pszJal, opnAddr26 }, // 03 { pszBeq, opnRsRtRel16 }, // 04 { pszBne, opnRsRtRel16 }, // 05 { pszBlez, opnRsRel16 }, // 06 { pszBgtz, opnRsRel16 }, // 07 { pszAddi, opnRtRsImm16 }, // 08 { pszAddiu, opnRtRsImm16 }, // 09 { pszSlti, opnRtRsImm16 }, // 0a { pszSltiu, opnRtRsImm16 }, // 0b { pszAndi, opnRtRsImm16 }, // 0c { pszOri, opnRtRsImm16 }, // 0d { pszXori, opnRtRsImm16 }, // 0e { pszLui, opnRtImm16 }, // 0f { pszCop0, opnImm26 }, // 10 { pszCop1, opnImm26 }, // 11 { pszCop2, opnImm26 }, // 12 { pszCop3, opnImm26 }, // 13 { pszBeql, opnRsRtRel16 + opnR4000 }, // 14 { pszBnel, opnRsRtRel16 + opnR4000 }, // 15 { pszBlezl, opnRsRel16 + opnR4000 }, // 16 { pszBgtzl, opnRsRel16 + opnR4000 }, // 17 { pszDaddi, opnRtRsImm16 }, // 18 { pszDaddiu, opnRtRsImm16 }, // 19 { pszLdl, opnRtDwordIndex }, // 1a { pszLdr, opnRtDwordIndex }, // 1b { pszUndef, 0 }, // 1c { pszUndef, 0 }, // 1d { pszUndef, 0 }, // 1e { pszUndef, 0 }, // 1f { pszLb, opnRtByteIndex }, // 20 { pszLh, opnRtWordIndex }, // 21 { pszLwl, opnRtLeftIndex }, // 22 { pszLw, opnRtDwordIndex }, // 23 { pszLbu, opnRtByteIndex }, // 24 { pszLhu, opnRtWordIndex }, // 25 { pszLwr, opnRtRightIndex }, // 26 { pszUndef, 0 }, // 27 { pszSb, opnRtByteIndex }, // 28 { pszSh, opnRtWordIndex }, // 29 { pszSwl, opnRtLeftIndex }, // 2a { pszSw, opnRtDwordIndex }, // 2b { pszSdl, opnRtDwordIndex }, // 2c { pszSdr, opnRtDwordIndex }, // 2d { pszSwr, opnRtRightIndex }, // 2e { pszCache, opnCacheRightIndex + opnR4000 }, // 2f { pszLwc0, opnRtDwordIndex }, // 30 { pszLwc1, opnFtDwordIndex }, // 31 { pszLwc2, opnRtDwordIndex }, // 32 { pszLwc3, opnRtDwordIndex }, // 33 { pszLld, opnRtDwordIndex }, // 34 { pszLdc1, opnFtDwordIndex + opnR4000 }, // 35 Qword? { pszLdc2, opnRtDwordIndex + opnR4000 }, // 36 Qword? { pszLd, opnRtDwordIndex + opnR4000 }, // 37 Qword? { pszSwc0, opnRtDwordIndex }, // 38 { pszSwc1, opnFtDwordIndex }, // 39 { pszSwc2, opnRtDwordIndex }, // 3a { pszSwc3, opnRtDwordIndex }, // 3b { pszScd, opnRtDwordIndex }, // 3c { pszSdc1, opnFtDwordIndex + opnR4000 }, // 3d Qword? { pszSdc2, opnRtDwordIndex + opnR4000 }, // 3e Qword? { pszSd, opnRtDwordIndex + opnR4000 }, // 3f Qword? }; OPTABENTRY opSpecialTable[] = { { pszSll, opnRdRtShift }, // 00 { pszUndef, 0 }, // 01 { pszSrl, opnRdRtShift }, // 02 { pszSra, opnRdRtShift }, // 03 { pszSllv, opnRdRtRs }, // 04 { pszUndef, 0 }, // 05 { pszSrlv, opnRdRtRs }, // 06 { pszSrav, opnRdRtRs }, // 07 { pszJr, opnRs }, // 08 { pszJalr, opnRdOptRs }, // 09 { pszUndef, 0 }, // 0a { pszUndef, 0 }, // 0b { pszSyscall, opnNone }, // 0c { pszBreak, opnImm20 }, // 0d { pszUndef, 0 }, // 0e { pszSync, opnNone + opnR4000 }, // 0f { pszMfhi, opnRd }, // 10 { pszMthi, opnRs }, // 11 { pszMflo, opnRd }, // 12 { pszMtlo, opnRs }, // 13 { pszDsllv, opnRdRtRs }, // 14 { pszUndef, 0 }, // 15 { pszDsrlv, opnRdRtRs }, // 16 { pszDsrav, opnRdRtRs }, // 17 { pszMult, opnRsRt }, // 18 { pszMultu, opnRsRt }, // 19 { pszDiv, opnRsRt }, // 1a { pszDivu, opnRsRt }, // 1b { pszDmult, opnRsRt }, // 1c { pszDmultu, opnRsRt }, // 1d { pszDdiv, opnRsRt }, // 1e { pszDdivu, opnRsRt }, // 1f { pszAdd, opnRdRsRt }, // 20 { pszAddu, opnRdRsRt }, // 21 { pszSub, opnRdRsRt }, // 22 { pszSubu, opnRdRsRt }, // 23 { pszAnd, opnRdRsRt }, // 24 { pszOr, opnRdRsRt }, // 25 { pszXor, opnRdRsRt }, // 26 { pszNor, opnRdRsRt }, // 27 { pszUndef, 0 }, // 28 { pszUndef, 0 }, // 29 { pszSlt, opnRdRsRt }, // 2a { pszSltu, opnRdRsRt }, // 2b { pszDadd, opnRdRsRt }, // 2c { pszDaddu, opnRdRsRt }, // 2d { pszDsub, opnRdRtRs }, // 2e { pszDsubu, opnRdRtRs }, // 2f { pszTge, opnRsRtImm10 + opnR4000 }, // 30 { pszTgeu, opnRsRtImm10 + opnR4000 }, // 31 { pszTlt, opnRsRtImm10 + opnR4000 }, // 32 { pszTltu, opnRsRtImm10 + opnR4000 }, // 33 { pszTeq, opnRsRtImm10 + opnR4000 }, // 34 { pszUndef, 0 }, // 35 { pszTne, opnRsRtImm10 + opnR4000 }, // 36 { pszUndef, 0 }, // 37 { pszDsll, opnRdRtShift }, // 38 { pszUndef, 0 }, // 39 { pszDsrl, opnRdRtShift }, // 3a { pszDsra, opnRdRtShift }, // 3b { pszDsll32, opnRdRtShift }, // 3c { pszUndef, 0 }, // 3d { pszDsrl32, opnRdRtShift }, // 3e { pszDsra32, opnRdRtShift } // 3f }; OPTABENTRY opBcondTable[] = { { pszBltz, opnRsRel16 }, // 00 { pszBgez, opnRsRel16 }, // 01 { pszBltzl, opnRsRel16 + opnR4000 }, // 02 { pszBgezl, opnRsRel16 + opnR4000 }, // 03 { pszUndef, 0 }, // 04 { pszUndef, 0 }, // 05 { pszUndef, 0 }, // 06 { pszUndef, 0 }, // 07 { pszTgei, opnRsImm16 + opnR4000 }, // 08 { pszTgeiu, opnRsImm16 + opnR4000 }, // 09 { pszTlti, opnRsImm16 + opnR4000 }, // 0a { pszTltiu, opnRsImm16 + opnR4000 }, // 0b { pszTeqi, opnRsImm16 + opnR4000 }, // 0c { pszUndef, 0 }, // 0d { pszTnei, opnRsImm16 + opnR4000 }, // 0e { pszUndef, 0 }, // 0f { pszBltzal, opnRsRel16 }, // 10 { pszBgezal, opnRsRel16 }, // 11 { pszBltzall, opnRsRel16 + opnR4000 }, // 12 { pszBgezall, opnRsRel16 + opnR4000 } // 13 }; OPTABENTRY opCopnTable[] = { { pszMfc0, opnRtRd }, // 00 { pszMfc1, opnRtFs }, // 01 { pszMfc2, opnRtRd }, // 02 { pszMfc3, opnRtRd }, // 03 { pszCfc0, opnRtRd }, // 04 { pszCfc1, opnRtFs }, // 05 { pszCfc2, opnRtRd }, // 06 { pszCfc3, opnRtRd }, // 07 { pszMtc0, opnRtRd }, // 08 { pszMtc1, opnRtFs }, // 09 { pszMtc2, opnRtRd }, // 0a { pszMtc3, opnRtRd }, // 0b { pszCtc0, opnRtRd }, // 0c { pszCtc1, opnRtFs }, // 0d { pszCtc2, opnRtRd }, // 0e { pszCtc3, opnRtRd }, // 0f { pszBc0f, opnRel16 }, // 10 { pszBc1f, opnRel16 }, // 11 { pszBc2f, opnRel16 }, // 12 { pszBc3f, opnRel16 }, // 13 { pszBc0t, opnRel16 }, // 14 { pszBc1t, opnRel16 }, // 15 { pszBc2t, opnRel16 }, // 16 { pszBc3t, opnRel16 }, // 17 { pszBc0fl, opnRel16 + opnR4000 }, // 18 { pszBc1fl, opnRel16 + opnR4000 }, // 19 { pszBc2fl, opnRel16 + opnR4000 }, // 1a { pszBc3fl, opnRel16 + opnR4000 }, // 1b { pszBc0tl, opnRel16 + opnR4000 }, // 1c { pszBc1tl, opnRel16 + opnR4000 }, // 1d { pszBc2tl, opnRel16 + opnR4000 }, // 1e { pszBc3tl, opnRel16 + opnR4000 } // 1f }; OPTABENTRY opFloatTable[] = { { pszAdd_s, opnFdFsFt }, // 00 { pszSub_s, opnFdFsFt }, // 01 { pszMul_s, opnFdFsFt }, // 02 { pszDiv_s, opnFdFsFt }, // 03 { pszSqrt_s, opnFdFs + opnR4000 }, // 04 { pszAbs_s, opnFdFs }, // 05 { pszMov_s, opnFdFs }, // 06 { pszNeg_s, opnFdFs }, // 07 { pszUndef, 0 }, // 08 { pszUndef, 0 }, // 09 { pszCeil_l_s, opnFdFs + opnR4000 }, // 0a { pszUndef, 0 }, // 0b { pszRound_w_s, opnFdFs + opnR4000 }, // 0c { pszTrunc_w_s, opnFdFs + opnR4000 }, // 0d { pszCeil_w_s, opnFdFs + opnR4000 }, // 0e { pszFloor_w_s, opnFdFs + opnR4000 }, // 0f { pszUndef, 0 }, // 10 { pszUndef, 0 }, // 11 { pszUndef, 0 }, // 12 { pszUndef, 0 }, // 13 { pszUndef, 0 }, // 14 { pszUndef, 0 }, // 15 { pszUndef, 0 }, // 16 { pszUndef, 0 }, // 17 { pszUndef, 0 }, // 18 { pszUndef, 0 }, // 19 { pszUndef, 0 }, // 1a { pszUndef, 0 }, // 1b { pszUndef, 0 }, // 1c { pszUndef, 0 }, // 1d { pszUndef, 0 }, // 1e { pszUndef, 0 }, // 1f { pszCvt_s_s, opnFdFs }, // 20 { pszCvt_d_s, opnFdFs }, // 21 { pszCvt_e_s, opnFdFs + opnR4000 }, // 22 { pszCvt_q_s, opnFdFs + opnR4000 }, // 23 { pszCvt_w_s, opnFdFs }, // 24 { pszUndef, 0 }, // 25 { pszUndef, 0 }, // 26 { pszUndef, 0 }, // 27 { pszUndef, 0 }, // 28 { pszUndef, 0 }, // 29 { pszUndef, 0 }, // 2a { pszUndef, 0 }, // 2b { pszUndef, 0 }, // 2c { pszUndef, 0 }, // 2d { pszUndef, 0 }, // 2e { pszUndef, 0 }, // 2f { pszC_f_s, opnFsFt }, // 30 { pszC_un_s, opnFsFt }, // 31 { pszC_eq_s, opnFsFt }, // 32 { pszC_ueq_s, opnFsFt }, // 33 { pszC_olt_s, opnFsFt }, // 34 { pszC_ult_s, opnFsFt }, // 35 { pszC_ole_s, opnFsFt }, // 36 { pszC_ule_s, opnFsFt }, // 37 { pszC_sf_s, opnFsFt }, // 38 { pszC_ngle_s, opnFsFt }, // 39 { pszC_seq_s, opnFsFt }, // 3a { pszC_ngl_s, opnFsFt }, // 3b { pszC_lt_s, opnFsFt }, // 3c { pszC_nge_s, opnFsFt }, // 3d { pszC_le_s, opnFsFt }, // 3e { pszC_ngt_s, opnFsFt } // 3f }; OPTABENTRY TlbrEntry = { pszTlbr, opnNone }; OPTABENTRY TlbwiEntry = { pszTlbwi, opnNone }; OPTABENTRY TlbwrEntry = { pszTlbwr, opnNone }; OPTABENTRY TlbpEntry = { pszTlbp, opnNone }; OPTABENTRY RfeEntry = { pszRfe, opnNone }; OPTABENTRY EretEntry = { pszEret, opnNone }; OPTABENTRY UndefEntry = { pszUndef, 0 }; OPTABENTRY NopEntry = { pszNop, opnNone }; static PUCHAR pBufStart; static PUCHAR pBuf; static ULONG InstrOffset; UCHAR HexDigit[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; BOOLEAN disasm (PADDR poffset, PUCHAR bufptr, BOOLEAN fEAout) { ULONG opcode; ULONG temp; POPTABENTRY pEntry; UCHAR chSuffix = '\0'; UCHAR EAsize = 0; pBufStart = pBuf = bufptr; OutputHex(Flat(*poffset), 8, 0); // output hex offset *pBuf++ = ' '; if (!GetMemDword(poffset, &disinstr.instruction)) { OutputString("???????? ????\n"); *pBuf = '\0'; return FALSE; } OutputHex(disinstr.instruction, 8, 0); // output hex contents *pBuf++ = ' '; // output the opcode in the table entry opcode = disinstr.jump_instr.Opcode; pEntry = &opTable[opcode]; // default value if (opcode == 0x00) // special opcodes if (disinstr.instruction) pEntry = &opSpecialTable[disinstr.special_instr.Funct]; else pEntry = &NopEntry; // special opcode for no-op else if (opcode == 0x01) { // bcond opcodes opcode = disinstr.immed_instr.RT; if (opcode < 0x14) pEntry = &opBcondTable[opcode]; else pEntry = &UndefEntry; } else if ((opcode & ~0x3) == 0x10) { // coprocessor opcodes temp = disinstr.immed_instr.RS; if (temp & 0x10) { // test for CO bit if (opcode == 0x10) { // test if COP0 temp = disinstr.special_instr.Funct; if (temp == 0x01) pEntry = &TlbrEntry; else if (temp == 0x02) pEntry = &TlbwiEntry; else if (temp == 0x06) pEntry = &TlbwrEntry; else if (temp == 0x08) pEntry = &TlbpEntry; else if (temp == 0x10) pEntry = &RfeEntry; else if (temp == 0x18) pEntry = &EretEntry; } else if (opcode == 0x11) { // coprocessor operations opcode = disinstr.float_instr.Funct; pEntry = &opFloatTable[opcode]; // get opcode if (temp == 0x11) chSuffix = 'd'; else if (temp == 0x12) { chSuffix = 'e'; pEntry->fInstruction |= opnR4000; } else if (temp == 0x13) { chSuffix = 'q'; pEntry->fInstruction |= opnR4000; } else if (temp == 0x14) chSuffix = 'w'; else if (temp == 0x15) chSuffix = 'l'; else if (temp != 0x10) pEntry = &UndefEntry; } } else { // no CO bit, general COPz ops if (!(temp & ~0x06)) // rs = 0, 2, 4, 6 pEntry = &opCopnTable[temp * 2 + (opcode - 0x10)]; else if ((temp & ~0x04) == 0x08) // rs = 8 or 0xc, rt = 0 to 3 pEntry = &opCopnTable[(4 + (disinstr.immed_instr.RT & 3)) * 4 + (opcode - 0x10)]; } } // pEntry has the opcode string and operand template needed to // output the instruction. OutputString(pEntry->pszOpcode); if (*(pBuf - 1) != '?' && chSuffix) *(pBuf - 1) = chSuffix; // change xxx.s to xxx.d, xxx.w, // xxx.e, or xxx.q (R4000 for e, q) BlankFill(OPSTART); // cache instruction has special codes for RT field value: // 0 = 'i'; 1 = 'd'; 2 = 'si'; 3 = 'sd' if (pEntry->fInstruction & opnCache) { temp = disinstr.special_instr.RT; if (temp > 3) *pBuf++ = '?'; else { if (temp > 1) { *pBuf++ = 's'; temp -= 2; } if (temp == 0) *pBuf++ = 'i'; else *pBuf++ = 'd'; } *pBuf++ = ','; } if (pEntry->fInstruction & opnPreRt) { OutputReg(disinstr.special_instr.RT); *pBuf++ = ','; } if (pEntry->fInstruction & opnRd) OutputReg(disinstr.special_instr.RD); if (pEntry->fInstruction & opnFd) OutputFReg(disinstr.float_instr.FD); if (pEntry->fInstruction & opnRdOptRs) { if (disinstr.special_instr.RD != 0x1f) { OutputReg(disinstr.special_instr.RD); *pBuf++ = ','; } OutputReg(disinstr.immed_instr.RS); } if (pEntry->fInstruction & opnRdComma) *pBuf++ = ','; if (pEntry->fInstruction & opnRs) OutputReg(disinstr.immed_instr.RS); if (pEntry->fInstruction & opnFs) OutputFReg(disinstr.float_instr.FS); if (pEntry->fInstruction & opnRsComma) *pBuf++ = ','; if (pEntry->fInstruction & opnRt) OutputReg(disinstr.immed_instr.RT); if (pEntry->fInstruction & opnFt) OutputFReg(disinstr.float_instr.FT); if (pEntry->fInstruction & opnRtComma) *pBuf++ = ','; if (pEntry->fInstruction & opnPostRs) OutputReg(disinstr.immed_instr.RS); if (pEntry->fInstruction & opnImm10) OutputHex((long)(short)disinstr.trap_instr.Value, 0, TRUE); if (pEntry->fInstruction & opnImm16) OutputHex((long)(short)disinstr.immed_instr.Value, 0, TRUE); if (pEntry->fInstruction & opnRel16) OutputDisSymbol(((long)(short)disinstr.immed_instr.Value << 2) + Flat(*poffset) + sizeof(ULONG)); if (pEntry->fInstruction & opnImm20) OutputHex(disinstr.break_instr.Value, 0, TRUE); if (pEntry->fInstruction & opnImm26) OutputHex(disinstr.jump_instr.Target, 0, TRUE); if (pEntry->fInstruction & opnAddr26) OutputDisSymbol((disinstr.jump_instr.Target << 2) + (Flat(*poffset) & 0xf0000000)); if (pEntry->fInstruction & opnAnyIndex) { OutputHex((long)(short)disinstr.immed_instr.Value, 0, TRUE); *pBuf++ = '('; OutputReg(disinstr.immed_instr.RS); *pBuf++ = ')'; // if instruction is for R4000 only, output " (4) " if (fEAout) { EAaddr = (ULONG)GetRegValue(disinstr.immed_instr.RS + REGBASE) + (long)(short)disinstr.immed_instr.Value; if (pEntry->fInstruction & opnByteIndex) EAsize = 1; else if (pEntry->fInstruction & opnWordIndex) EAsize = 2; else if (pEntry->fInstruction & opnDwordIndex) EAsize = 4; else if (pEntry->fInstruction & opnLeftIndex) EAsize = (UCHAR)(4 - (EAaddr & 3)); else // if (pEntry->fInstruction & opnRightIndex) EAsize = (UCHAR)((EAaddr & 3) + 1); BlankFill(79 - 12 - (EAsize * 2)); OutputString("EA:"); OutputHex(EAaddr, 8, FALSE); *pBuf++ = '='; ADDR32(&EA, EAaddr); if (GetMemString(&EA, (PUCHAR)&temp, (ULONG)EAsize) == (ULONG)EAsize) OutputHex(temp, (ULONG)(EAsize * 2), FALSE); else { while (EAsize--) { *pBuf++ = '?'; *pBuf++ = '?'; } } } } if (pEntry->fInstruction & opnShift) OutputHex(disinstr.special_instr.RE, 2, FALSE); Off(*poffset) += sizeof(ULONG); NotFlat(*poffset); ComputeFlatAddress(poffset, NULL); *pBuf++ = '\n'; *pBuf = '\0'; return TRUE; } /*** BlankFill - blank-fill buffer * * Purpose: * To fill the buffer at *pBuf with blanks until * position count is reached. * * Input: * None. * * Output: * None. * *************************************************************************/ void BlankFill(ULONG count) { do *pBuf++ = ' '; while (pBuf < pBufStart + count); } /*** OutputHex - output hex value * * Purpose: * Output the value in outvalue into the buffer * pointed by *pBuf. The value may be signed * or unsigned depending on the value fSigned. * * Input: * outvalue - value to output * length - length in digits * fSigned - TRUE if signed else FALSE * * Output: * None. * *************************************************************************/ void OutputHex (ULONG outvalue, ULONG length, BOOLEAN fSigned) { UCHAR digit[8]; LONG index = 0; if (fSigned && (long)outvalue < 0) { *pBuf++ = '-'; outvalue = - (LONG)outvalue; } if (fSigned) { *pBuf++ = '0'; *pBuf++ = 'x'; } do { digit[index++] = HexDigit[outvalue & 0xf]; outvalue >>= 4; } while ((fSigned && outvalue) || (!fSigned && index < (LONG)length)); while (--index >= 0) *pBuf++ = digit[index]; } /*** OutputDisSymbol - output symbol for disassembly * * Purpose: * Access symbol table with given offset and put string into buffer. * * Input: * offset - offset of address to output * * Output: * buffer pointed by pBuf updated with string: * if symbol, no disp: () * if symbol, disp: +() * if no symbol, no disp: * *************************************************************************/ void OutputDisSymbol (ULONG offset) { UCHAR chAddrBuffer[SYMBOLSIZE + 16]; ULONG displacement; PUCHAR pszTemp; UCHAR ch; GetSymbolStdCall(offset, chAddrBuffer, &displacement, NULL); if (chAddrBuffer[0]) { pszTemp = chAddrBuffer; while (ch = *pszTemp++) *pBuf++ = ch; if (displacement) { *pBuf++ = '+'; OutputHex(displacement, 8, TRUE); } *pBuf++ = '('; } OutputHex(offset, 8, FALSE); if (chAddrBuffer[0]) *pBuf++ = ')'; } /*** OutputString - output string * * Purpose: * Copy the string into the buffer pointed by pBuf. * * Input: * *pStr - pointer to string * * Output: * None. * *************************************************************************/ void OutputString (PUCHAR pStr) { while (*pStr) *pBuf++ = *pStr++; } void OutputReg (ULONG regnum) { OutputString(pszReg[regnum + REGBASE]); } void OutputFReg (ULONG regnum) { *pBuf++ = 'f'; if (regnum > 9) *pBuf++ = (UCHAR)('0' + regnum / 10); *pBuf++ = (UCHAR)('0' + regnum % 10); } /*** GetNextOffset - compute offset for trace or step * * Purpose: * From a limited disassembly of the instruction pointed * by the FIR register, compute the offset of the next * instruction for either a trace or step operation. * * Input: * fStep - TRUE for step offset; FALSE for trace offset * * Returns: * step or trace offset if input is TRUE or FALSE, respectively * *************************************************************************/ void GetNextOffset (PADDR result, BOOLEAN fStep) { ULONG returnvalue; ULONG opcode; ULONG firaddr; ADDR fir; firaddr = (ULONG)GetRegValue(REGFIR); ADDR32( &fir, firaddr ); GetMemDword(&fir, &(disinstr.instruction)); opcode = disinstr.jump_instr.Opcode; returnvalue = firaddr + sizeof(ULONG) * 2; // assume delay slot if (disinstr.instruction == 0x0000000c) { // stepping over a syscall instruction must set the breakpoint // at the caller's return address, not the inst after the syscall returnvalue = (ULONG)GetRegValue(REGRA); } else if (opcode == 0x00L // SPECIAL && (disinstr.special_instr.Funct & ~0x01L) == 0x08L) { // jr/jalr only if (disinstr.special_instr.Funct == 0x08L || !fStep) // jr or trace returnvalue = (ULONG)GetRegValue(disinstr.special_instr.RS + REGBASE); } else if (opcode == 0x01L) { // For BCOND opcode, RT values 0x00 - 0x03, 0x10 - 0x13 // are defined as conditional jumps. A 16-bit relative // offset is taken if: // // (RT is even and (RS) < 0 (0x00 = BLTZ, 0x02 = BLTZL, // 0x10 = BLTZAL, 0x12 = BLTZALL) // OR // RT is odd and (RS) >= 0 (0x01 = BGEZ, 0x03 = BGEZL // 0x11 = BGEZAL, 0x13 = BGEZALL)) // AND // (RT is 0x00 to 0x03 (BLTZ BGEZ BLTZL BGEZL non-linking) // OR // fStep is FALSE (linking and not stepping over)) // if (((disinstr.immed_instr.RT & ~0x13) == 0x00) && (((LONG)GetRegValue(disinstr.immed_instr.RS + REGBASE) >= 0) == (BOOLEAN)(disinstr.immed_instr.RT & 0x01)) && (((disinstr.immed_instr.RT & 0x10) == 0x00) || !fStep)) returnvalue = ((LONG)(SHORT)disinstr.immed_instr.Value << 2) + firaddr + sizeof(ULONG); } else if ((opcode & ~0x01L) == 0x02) { // J and JAL opcodes (0x02 and 0x03). Target is // 26-bit absolute offset using high four bits of the // instruction location. Return target if J opcode or // not stepping over JAL. // if (opcode == 0x02 || !fStep) returnvalue = (disinstr.jump_instr.Target << 2) + (firaddr & 0xf0000000); } else if ((opcode & ~0x11L) == 0x04) { // BEQ, BNE, BEQL, BNEL opcodes (0x04, 0x05, 0x14, 0x15). // Target is 16-bit relative offset to next instruction. // Return target if (BEQ or BEQL) and (RS) == (RT), // or (BNE or BNEL) and (RS) != (RT). // if ((BOOLEAN)(opcode & 0x01) == (BOOLEAN)(GetRegValue(disinstr.immed_instr.RS + REGBASE) != GetRegValue(disinstr.immed_instr.RT + REGBASE))) returnvalue = ((long)(short)disinstr.immed_instr.Value << 2) + firaddr + sizeof(ULONG); } else if ((opcode & ~0x11L) == 0x06) { // BLEZ, BGTZ, BLEZL, BGTZL opcodes (0x06, 0x07, 0x16, 0x17). // Target is 16-bit relative offset to next instruction. // Return target if (BLEZ or BLEZL) and (RS) <= 0, // or (BGTZ or BGTZL) and (RS) > 0. // if ((BOOLEAN)(opcode & 0x01) == (BOOLEAN)((long)GetRegValue(disinstr.immed_instr.RS + REGBASE) > 0)) returnvalue = ((long)(short)disinstr.immed_instr.Value << 2) + firaddr + sizeof(ULONG); } else if (opcode == 0x11L && (disinstr.immed_instr.RS & ~0x04L) == 0x08L && (disinstr.immed_instr.RT & ~0x03L) == 0x00L) { // COP1 opcode (0x11) with (RS) == 0x08 or (RS) == 0x0c and // (RT) == 0x00 to 0x03, producing BC1F, BC1T, BC1FL, BC1TL // instructions. Return target if (BC1F or BC1FL) and floating // point condition is FALSE or if (BC1T or BC1TL) and condition TRUE. // if ((disinstr.immed_instr.RT & 0x01) == GetRegFlagValue(FLAGFPC)) returnvalue = ((long)(short)disinstr.immed_instr.Value << 2) + firaddr + sizeof(ULONG); } else if ((opcode == 0x38) && (fStep)) { // // stepping over an SC instruction, so skip the immediately following // BEQ instruction. The SC will fail because we are tracing over it, // the branch will be taken, and we will run through the LL/SC again // until the SC succeeds. Then the branch won't be taken, and we // will hit our breakpoint. // returnvalue += sizeof(ULONG); // skip BEQ and BEQ's delay slot } else returnvalue -= sizeof(ULONG); // remove delay slot ADDR32( result, returnvalue ); } /*** fDelayInstruction - returns flag TRUE if delayed instruction * * Purpose: * From a limited disassembly of the instruction pointed * by the FIR register, return TRUE if delayed, else FALSE. * * Input: * None. * * Returns: * set if instruction is delayed execution * *************************************************************************/ BOOLEAN fDelayInstruction (void) { BOOLEAN returnvalue; ULONG opcode; ULONG firaddr = (ULONG)GetRegValue(REGFIR); ADDR fir; ADDR32( &fir, firaddr ); GetMemDword(&fir, &(disinstr.instruction)); opcode = disinstr.jump_instr.Opcode; if (opcode == 0x00) // for SPECIAL opcode, JR and JALR use a delay slot // returnvalue = (BOOLEAN)((disinstr.special_instr.Funct & ~1L) == 0x08); else if (opcode == 0x01) // for BCOND opcode, RT == 0x00 to 0x03 or 0x10 to 0x13 have slot // BLTZ, BGEZ, BLTZL, BGEZL, BLTZAL, BGEZAL, BLTZALL, BGEZALL // returnvalue = (BOOLEAN)((disinstr.special_instr.RT & ~0x13L) == 0x00); else if ((opcode & ~0x07L) == 0x00) // opcodes 0x02 to 0x07 have delay slot (0x00 and 0x01 tested above) // J, JAL, BEQ, BNE, BLEZ, BGTZ // returnvalue = TRUE; else if ((opcode & ~0x03L) == 0x14) // opcodes 0x14 to 0x17 have delay slot - BEQL, BNEL, BLEZL, BGTZL // returnvalue = TRUE; else // opcodes 0x10 to 0x13 - COPn - BCxF, BCxT, BCxFL, BCxTL // returnvalue = (BOOLEAN)((opcode & ~0x03L) == 0x10 && (disinstr.special_instr.RS & ~0x04L) == 0x08 && (disinstr.special_instr.RT & ~0x03L) == 0x00); return returnvalue; }