2020-09-30 17:12:29 +02:00

1080 lines
39 KiB
C

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
disasm.c
Abstract:
This file provides support disassembly ( mips ).
Author:
Gerd Immeyer 19-Oct-1989
Wesley Witt (wesw) 1-May-1993 ( ported from ntsd to drwatson)
Environment:
User Mode
--*/
#include <windows.h>
#include <stddef.h>
#include <string.h>
#include "regs.h"
#include "disasm.h"
#include "drwatson.h"
#include "proto.h"
#define OPCODE 18
#define OPSTART 26
typedef struct optabentry {
PUCHAR pszOpcode;
ULONG fInstruction;
} OPTABENTRY, *POPTABENTRY;
INSTR disinstr;
ULONG EAaddr = 0;
DWORD 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 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 pszDiv[] = "div";
UCHAR pszDivu[] = "divu";
UCHAR pszDiv_s[] = "div.s";
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 pszLh[] = "lh";
UCHAR pszLhu[] = "lhu";
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 pszSdc1[] = "sdc1";
UCHAR pszSdc2[] = "sdc2";
UCHAR pszSdc3[] = "sdc3";
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
{ pszUndef, 0 }, // 18
{ pszUndef, 0 }, // 19
{ pszUndef, 0 }, // 1a
{ pszUndef, 0 }, // 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
{ pszUndef, 0 }, // 2c
{ pszUndef, 0 }, // 2d
{ pszSwr, opnRtRightIndex }, // 2e
{ pszCache, opnCacheRightIndex + opnR4000 }, // 2f
{ pszLwc0, opnRtDwordIndex }, // 30
{ pszLwc1, opnFtDwordIndex }, // 31
{ pszLwc2, opnRtDwordIndex }, // 32
{ pszLwc3, opnRtDwordIndex }, // 33
{ pszUndef, 0 }, // 34
{ pszLdc1, opnFtDwordIndex + opnR4000 }, // 35 Qword?
{ pszLdc2, opnRtDwordIndex + opnR4000 }, // 36 Qword?
{ pszLdc3, opnRtDwordIndex + opnR4000 }, // 37 Qword?
{ pszSwc0, opnRtDwordIndex }, // 38
{ pszSwc1, opnFtDwordIndex }, // 39
{ pszSwc2, opnRtDwordIndex }, // 3a
{ pszSwc3, opnRtDwordIndex }, // 3b
{ pszUndef, 0 }, // 3c
{ pszSdc1, opnFtDwordIndex + opnR4000 }, // 3d Qword?
{ pszSdc2, opnRtDwordIndex + opnR4000 }, // 3e Qword?
{ pszSdc3, 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
{ pszUndef, 0 }, // 14
{ pszUndef, 0 }, // 15
{ pszUndef, 0 }, // 16
{ pszUndef, 0 }, // 17
{ pszMult, opnRsRt }, // 18
{ pszMultu, opnRsRt }, // 19
{ pszDiv, opnRsRt }, // 1a
{ pszDivu, opnRsRt }, // 1b
{ pszUndef, 0 }, // 1c
{ pszUndef, 0 }, // 1d
{ pszUndef, 0 }, // 1e
{ pszUndef, 0 }, // 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
{ pszUndef, 0 }, // 2c
{ pszUndef, 0 }, // 2d
{ pszUndef, 0 }, // 2e
{ pszUndef, 0 }, // 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
{ pszUndef, 0 }, // 38
{ pszUndef, 0 }, // 39
{ pszUndef, 0 }, // 3a
{ pszUndef, 0 }, // 3b
{ pszUndef, 0 }, // 3c
{ pszUndef, 0 }, // 3d
{ pszUndef, 0 }, // 3e
{ pszUndef, 0 } // 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
{ pszUndef, 0 }, // 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'
};
//
// prototypes
//
void BlankFill(ULONG count);
void OutputHex (ULONG outvalue, ULONG length, BOOLEAN fSigned);
void OutputDisSymbol (PDEBUGPACKET dp, ULONG offset);
void OutputString (PUCHAR pStr);
void OutputReg (ULONG regnum);
void OutputFReg (ULONG regnum);
void GetNextOffset (PDEBUGPACKET dp, PULONG result, BOOLEAN fStep);
BOOLEAN fDelayInstruction (PDEBUGPACKET dp);
PUCHAR RegNameFromIndex (ULONG index);
BOOLEAN
disasm (PDEBUGPACKET dp, PDWORD poffset, PUCHAR bufptr, BOOLEAN fEAout)
{
ULONG opcode;
ULONG temp;
POPTABENTRY pEntry;
UCHAR chSuffix = '\0';
UCHAR EAsize = 0;
pBufStart = pBuf = bufptr;
OutputHex(*poffset, 8, 0); // output hex offset
*pBuf++ = ' ';
if (!DoMemoryRead( dp,
(LPVOID)*poffset,
(LPVOID)&disinstr.instruction,
sizeof(DWORD),
NULL
)) {
OutputString("???????? ????");
*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 != 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(dp,((long)(short)disinstr.immed_instr.Value << 2)
+ *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(dp,(disinstr.jump_instr.Target << 2)
+ (*poffset & 0xf0000000));
if (pEntry->fInstruction & opnAnyIndex) {
OutputHex((long)(short)disinstr.immed_instr.Value, 0, TRUE);
*pBuf++ = '(';
OutputReg(disinstr.immed_instr.RS);
*pBuf++ = ')';
if (fEAout) {
EAaddr = (DWORD)GetRegValue(dp, 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++ = '=';
if (!DoMemoryRead( dp,
(LPVOID)EAaddr,
(LPVOID)&temp,
EAsize,
NULL
)) {
while (EAsize--) {
*pBuf++ = '?';
*pBuf++ = '?';
}
}
}
else {
OutputHex(temp, (ULONG)(EAsize * 2), FALSE);
}
}
if (pEntry->fInstruction & opnShift)
OutputHex(disinstr.special_instr.RE, 2, FALSE);
*poffset += sizeof(ULONG);
*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 = (ULONG)(-(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: <symbol>(<offset>)
* if symbol, disp: <symbol>+<disp>(<offset>)
* if no symbol, no disp: <offset>
*
*************************************************************************/
void
OutputDisSymbol (PDEBUGPACKET dp, ULONG offset)
{
ULONG displacement;
PUCHAR pszTemp;
UCHAR ch;
if (SymGetSymFromAddr( dp->hProcess, offset, &displacement, sym )) {
pszTemp = sym->Name;
if (!pszTemp) {
pszTemp = sym->Name;
}
while (ch = *pszTemp++) {
*pBuf++ = ch;
}
if (displacement) {
*pBuf++ = '+';
OutputHex(displacement, 8, TRUE);
}
*pBuf++ = '(';
OutputHex(offset, 8, FALSE);
*pBuf++ = ')';
}
else {
OutputHex(offset, 8, FALSE);
}
}
/*** 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(RegNameFromIndex(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 (PDEBUGPACKET dp, PULONG result, BOOLEAN fStep)
{
ULONG returnvalue;
ULONG opcode;
ULONG firaddr;
firaddr = (DWORD)GetRegValue(dp,REGFIR);
DoMemoryRead( dp,
(LPVOID)firaddr,
(LPVOID)&disinstr.instruction,
sizeof(ULONG),
NULL
);
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 = (DWORD)GetRegValue(dp,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 = (DWORD)GetRegValue(dp,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(dp,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)((DWORD)GetRegValue(dp,disinstr.immed_instr.RS + REGBASE)
!= (DWORD)GetRegValue(dp,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(dp,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) == (DWORD)GetRegFlagValue(dp,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
*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 (PDEBUGPACKET dp)
{
BOOLEAN returnvalue;
ULONG opcode;
ULONG firaddr = (DWORD)GetRegValue(dp,REGFIR);
DoMemoryRead( dp,
(LPVOID)firaddr,
(LPVOID)&disinstr.instruction,
sizeof(ULONG),
NULL
);
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;
}