1249 lines
48 KiB
C
1249 lines
48 KiB
C
/*
|
|
* NewOswan
|
|
* nec_debugger.c:
|
|
* Created by Manoël Trapier on 14/04/2021.
|
|
* Copyright (c) 2014-2021 986-Studio. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
|
|
#include "log.h"
|
|
#include "nec_debugger.h"
|
|
#include "necintrf.h"
|
|
|
|
/***
|
|
* Note: the while code to decode instruction is not meant to be optimised, but to be easy to maintain.
|
|
* It probably could be more concise, but this is code for the debugger, not runtime, so optimisation does
|
|
* not really matter here.
|
|
*/
|
|
|
|
typedef enum operandParameterTypes
|
|
{
|
|
PR_RM_R8, /**< reg8/mem8, reg8 */
|
|
PR_RM_R16, /**< reg16/mem16, reg16 */
|
|
PR_AL_IM8, /**< AL, immed8 */
|
|
PR_AX_IM16, /**< AX, immed16 */
|
|
PR_ES, /**< ES */
|
|
PR_R_RM8, /**< reg8, reg8/mem8 */
|
|
PR_R_RM16, /**< reg16, ret16/mem16 */
|
|
PR_CS, /**< CS */
|
|
PR_SS, /**< SS */
|
|
PR_DS, /**< DS */
|
|
PR_NONE, /**< No parameter or Prefix */
|
|
PR_AX, /**< AX */
|
|
PR_CX, /**< CX */
|
|
PR_DX, /**< DX */
|
|
PR_BX, /**< BX */
|
|
PR_SP, /**< SP */
|
|
PR_BP, /**< BP */
|
|
PR_SI, /**< SI */
|
|
PR_DI, /**< DI */
|
|
PR_IM16, /**< immediate 16 */
|
|
PR_REL8, /**< short label */
|
|
PR_RM_IM8, /**< reg8/mem8, immediate8 */
|
|
PR_RM_IM16, /**< reg16/mem16, immed16 */
|
|
PR_RM16_SEG, /**< reg16/mem16, SegReg */
|
|
PR_SEG_RM16, /**< SegReg, reg16/mem16 */
|
|
PR_AX_CX, /**< AX, CX */
|
|
PR_AX_DX, /**< AX, DX */
|
|
PR_AX_BX, /**< AX, BX */
|
|
PR_AX_SP, /**< AX, SP */
|
|
PR_AX_BP, /**< AX, BP */
|
|
PR_AX_SI, /**< AX, SI */
|
|
PR_AX_DI, /**< AX, DI */
|
|
PR_ABS32, /**< far proc */
|
|
PR_AL_M8, /**< AL, mem8 */
|
|
PR_AX_M16, /**< AX, mem16 */
|
|
PR_M8_AL, /**< mem8, AL */
|
|
PR_M16_AX, /**< mem16, AX */
|
|
PR_CL_IM8, /**< CL, immed8 */
|
|
PR_DL_IM8, /**< DL, immed8 */
|
|
PR_BL_IM8, /**< BL, immed8 */
|
|
PR_AH_IM8, /**< AH, immed8 */
|
|
PR_CH_IM8, /**< CH, immed8 */
|
|
PR_DH_IM8, /**< DH, immed8 */
|
|
PR_BH_IM8, /**< BH, immed8 */
|
|
PR_CX_IM16, /**< CX, immed16 */
|
|
PR_DX_IM16, /**< DX, immed16 */
|
|
PR_BX_IM16, /**< BX, immed16 */
|
|
PR_SP_IM16, /**< SP, immed16 */
|
|
PR_BP_IM16, /**< BP, immed16 */
|
|
PR_SI_IM16, /**< SI, immed16 */
|
|
PR_DI_IM16, /**< DI, immed16 */
|
|
PR_RM16_IM8, /**< reg16/mem16, immed8 */
|
|
PR_IM16_IM8, /**< immed16, immed8 */
|
|
PR_IM8, /**< immed8 */
|
|
PR_RM8_1, /**< reg8/mem8, 1 */
|
|
PR_RM16_1, /**< reg16/mem16, 1 */
|
|
PR_RM8_CL, /**< reg8/mem8, CL */
|
|
PR_RM16_CL, /**< reg16/mem16, CL */
|
|
PR_AX_IM8, /**< AX, immed8 */
|
|
PR_AL_DX, /**< AL, DX */
|
|
PR_NONE8, /**< No param, work in 8 bit */
|
|
PR_NONE16, /**< No param, work in 16 bits */
|
|
PR_PREFIX, /**< No param, but is a prefix */
|
|
PR_REL16, /**< near label */
|
|
PR_IM8_AL, /**< immed8, AL */
|
|
PR_IM8_AX, /**< immed8, AX */
|
|
PR_DX_AL, /**< DX, AL */
|
|
PR_DX_AX, /**< DX, AX */
|
|
PR_RM8, /**< reg8/mem8 */
|
|
PR_RM16, /**< reg16/mem16 */
|
|
PR_NONEFAR, /**< no opcode but far related */
|
|
} operandParameterTypes;
|
|
|
|
typedef enum operandTypes
|
|
{
|
|
OP_ILEG = 0,
|
|
OP_ADD, OP_PUSH, OP_POP, OP_OR, OP_ADC, OP_SBB, OP_AND, OP_DAA, OP_SUB, OP_DAS, OP_XOR, OP_AAA, OP_CMP,
|
|
OP_AAS, OP_INC, OP_DEC, OP_PUSHA, OP_POPA, OP_IMUL, OP_INS, OP_OUTS, OP_JO, OP_JNO, OP_JB, OP_JNB,
|
|
OP_JE, OP_JNE, OP_JBE, OP_JNBE, OP_JS, OP_JNS, OP_JP, OP_JNP, OP_JL, OP_JNL, OP_JLE, OP_JNLE, OP_TEST,
|
|
OP_XCHG, OP_MOV, OP_LEA, OP_NOP, OP_WAIT, OP_PUSHF, OP_POPF, OP_SAHF, OP_LAHF, OP_MOVS, OP_CMPS,
|
|
OP_STOS, OP_LODS, OP_SCAS, OP_LDS, OP_LES, OP_ENTER, OP_LEAVE, OP_RET, OP_INT3, OP_INT, OP_INTO,
|
|
OP_IRET, OP_XLAT, OP_LOOPNZ, OP_LOOPE, OP_LOOP, OP_JCXZ, OP_IN, OP_OUT, OP_CALL, OP_JMP, OP_HLT,
|
|
OP_CLC, OP_STC, OP_CLI, OP_STI, OP_CLS, OP_STD, OP_IMMED, OP_SHIFT, OP_GRP1, OP_GRP2, OP_BOUND,
|
|
OP_CBW, OP_CWD, OP_AAM, OP_AAD, OP_LOCK, OP_REP, OP_REPNZ, OP_CMC, OP_CS, OP_DS, OP_ES, OP_SS, OP_MOVG
|
|
} operandTypes;
|
|
|
|
const char *operandTypeNameTable[] =
|
|
{
|
|
[OP_ILEG] = "Illegal",
|
|
[OP_ADD] = "add",
|
|
[OP_PUSH] = "push",
|
|
[OP_POP] = "pop",
|
|
[OP_OR] = "or",
|
|
[OP_ADC] = "adc",
|
|
[OP_SBB] = "sbb",
|
|
[OP_AND] = "and",
|
|
[OP_DAA] = "daa",
|
|
[OP_SUB] = "sub",
|
|
[OP_DAS] = "das",
|
|
[OP_XOR] = "xor",
|
|
[OP_AAA] = "aaa",
|
|
[OP_CMP] = "cmp",
|
|
[OP_AAS] = "aas",
|
|
[OP_INC] = "inc",
|
|
[OP_DEC] = "dec",
|
|
[OP_PUSHA] = "pusha",
|
|
[OP_POPA] = "popa",
|
|
[OP_IMUL] = "imul",
|
|
[OP_INS] = "ins",
|
|
[OP_OUTS] = "outs",
|
|
[OP_JO] = "jo",
|
|
[OP_JNO] = "jno",
|
|
[OP_JB] = "jb",
|
|
[OP_JNB] = "inb",
|
|
[OP_JE] = "je",
|
|
[OP_JNE] = "jne",
|
|
[OP_JBE] = "jbe",
|
|
[OP_JNBE] = "jnbe",
|
|
[OP_JS] = "js",
|
|
[OP_JNS] = "jns",
|
|
[OP_JP] = "jo",
|
|
[OP_JNP] = "jno",
|
|
[OP_JL] = "jl",
|
|
[OP_JNL] = "jnl",
|
|
[OP_JLE] = "jle",
|
|
[OP_JNLE] = "jnle",
|
|
[OP_TEST] = "test",
|
|
[OP_XCHG] = "xchg",
|
|
[OP_MOV] = "mov",
|
|
[OP_LEA] = "lea",
|
|
[OP_NOP] = "nop",
|
|
[OP_WAIT] = "wait",
|
|
[OP_PUSHF] = "pushf",
|
|
[OP_POPF] = "popf",
|
|
[OP_SAHF] = "sahf",
|
|
[OP_LAHF] = "lahf",
|
|
[OP_MOVS] = "movs",
|
|
[OP_CMPS] = "cmps",
|
|
[OP_STOS] = "stos",
|
|
[OP_LODS] = "lods",
|
|
[OP_SCAS] = "scas",
|
|
[OP_LDS] = "lds",
|
|
[OP_LES] = "led",
|
|
[OP_ENTER] = "enter",
|
|
[OP_LEAVE] = "leave",
|
|
[OP_RET] = "ret",
|
|
[OP_INT3] = "int3",
|
|
[OP_INT] = "int",
|
|
[OP_INTO] = "into",
|
|
[OP_IRET] = "iret",
|
|
[OP_XLAT] = "xlat",
|
|
[OP_LOOPNZ] = "loopnz",
|
|
[OP_LOOPE] = "loope",
|
|
[OP_LOOP] = "loop",
|
|
[OP_JCXZ] = "jcxz",
|
|
[OP_IN] = "in",
|
|
[OP_OUT] = "out",
|
|
[OP_CALL] = "call",
|
|
[OP_JMP] = "jmp",
|
|
[OP_HLT] = "hlt",
|
|
[OP_CLC] = "clc",
|
|
[OP_STC] = "stc",
|
|
[OP_CLI] = "cli",
|
|
[OP_STI] = "sti",
|
|
[OP_CLS] = "cls",
|
|
[OP_STD] = "std",
|
|
[OP_IMMED] = "",
|
|
[OP_SHIFT] = "",
|
|
[OP_GRP1] = "",
|
|
[OP_GRP2] = "",
|
|
[OP_CS] = "cs:",
|
|
[OP_ES] = "es:",
|
|
[OP_DS] = "ds:",
|
|
[OP_SS] = "ss:",
|
|
[OP_BOUND] = "bound",
|
|
[OP_CBW] = "cbw",
|
|
[OP_CWD] = "cwd",
|
|
[OP_AAM] = "aam",
|
|
[OP_AAD] = "aad",
|
|
[OP_LOCK] = "lock",
|
|
[OP_REP] = "rep",
|
|
[OP_REPNZ] = "repnz",
|
|
[OP_CMC] = "cmc",
|
|
[OP_MOVG] = "",
|
|
};
|
|
|
|
operandTypes opcodeTypeTable[256] =
|
|
{
|
|
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
|
OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_PUSH, OP_POP, OP_OR, OP_OR, OP_OR, OP_OR, OP_OR, OP_OR, OP_PUSH, OP_ILEG, /* 0 */
|
|
OP_ADC, OP_ADC, OP_ADC, OP_ADC, OP_ADC, OP_ADC, OP_PUSH, OP_POP, OP_SBB, OP_SBB, OP_SBB, OP_SBB, OP_SBB, OP_SBB, OP_PUSH, OP_POP, /* 1 */
|
|
OP_AND, OP_AND, OP_AND, OP_AND, OP_AND, OP_AND, OP_ES, OP_DAA, OP_SUB, OP_SUB, OP_SUB, OP_SUB, OP_SUB, OP_SUB, OP_CS, OP_DAS, /* 2 */
|
|
OP_XOR, OP_XOR, OP_XOR, OP_XOR, OP_XOR, OP_XOR, OP_SS, OP_AAA, OP_CMP, OP_CMP, OP_CMP, OP_CMP, OP_CMP, OP_CMP, OP_DS, OP_AAS, /* 3 */
|
|
OP_INC, OP_INC, OP_INC, OP_INC, OP_INC, OP_INC, OP_INC, OP_INC, OP_DEC, OP_DEC, OP_DEC, OP_DEC, OP_DEC, OP_DEC, OP_DEC, OP_DEC, /* 4 */
|
|
OP_PUSH, OP_PUSH, OP_PUSH, OP_PUSH, OP_PUSH, OP_PUSH, OP_PUSH, OP_PUSH, OP_POP, OP_POP, OP_POP, OP_POP, OP_POP, OP_POP, OP_POP, OP_POP, /* 5 */
|
|
OP_PUSHA, OP_POPA, OP_BOUND, OP_ILEG, OP_ILEG, OP_ILEG, OP_ILEG, OP_ILEG, OP_PUSH, OP_IMUL, OP_PUSH, OP_IMUL, OP_INS, OP_INS, OP_OUTS, OP_OUTS, /* 6 */
|
|
OP_JO, OP_JNO, OP_JB, OP_JNB, OP_JE, OP_JNE, OP_JBE, OP_JNBE, OP_JS, OP_JNS, OP_JP, OP_JNP, OP_JL, OP_JNL, OP_JLE, OP_JNLE, /* 7 */
|
|
OP_IMMED, OP_IMMED, OP_IMMED, OP_IMMED, OP_TEST, OP_TEST, OP_XCHG, OP_XCHG, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_LEA, OP_MOV, OP_POP, /* 8 */
|
|
OP_NOP, OP_XCHG, OP_XCHG, OP_XCHG, OP_XCHG, OP_XCHG, OP_XCHG, OP_XCHG, OP_CBW, OP_CWD, OP_CALL, OP_WAIT, OP_PUSHF, OP_POPF, OP_SAHF, OP_LAHF, /* 9 */
|
|
OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOVS, OP_MOVS, OP_CMPS, OP_CMPS, OP_TEST, OP_TEST, OP_STOS, OP_STOS, OP_LODS, OP_LODS, OP_SCAS, OP_SCAS, /* A */
|
|
OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, OP_MOV, /* B */
|
|
OP_SHIFT, OP_SHIFT, OP_RET, OP_RET, OP_LES, OP_LDS, OP_MOVG, OP_MOVG, OP_ENTER, OP_LEAVE, OP_RET, OP_RET, OP_INT3, OP_INT, OP_INTO, OP_IRET, /* C */
|
|
OP_SHIFT, OP_SHIFT, OP_SHIFT, OP_SHIFT, OP_AAM, OP_AAD, OP_ILEG, OP_XLAT, OP_ILEG, OP_ILEG, OP_ILEG, OP_ILEG, OP_ILEG, OP_ILEG, OP_ILEG, OP_ILEG, /* D */
|
|
OP_LOOPNZ, OP_LOOPE, OP_LOOP, OP_JCXZ, OP_IN, OP_IN, OP_OUT, OP_OUT, OP_CALL, OP_JMP, OP_JMP, OP_JMP, OP_IN, OP_IN, OP_OUT, OP_OUT, /* E */
|
|
OP_LOCK, OP_ILEG, OP_REPNZ, OP_REP, OP_HLT, OP_CMC, OP_GRP1, OP_GRP1, OP_CLC, OP_STC, OP_CLI, OP_STI, OP_CLS, OP_STD, OP_GRP2, OP_GRP2, /* F */
|
|
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
|
};
|
|
|
|
operandParameterTypes opcodeParamTypeTable[256] =
|
|
{
|
|
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
|
PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_AL_IM8, PR_AX_IM16, PR_ES, PR_ES, PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_AL_IM8, PR_AX_IM16, PR_CS, PR_NONE, /* 0 */
|
|
PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_AL_IM8, PR_AX_IM16, PR_SS, PR_SS, PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_AL_IM8, PR_AX_IM16, PR_DS, PR_DS, /* 1 */
|
|
PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_AL_IM8, PR_AX_IM16, PR_PREFIX, PR_NONE, PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_AL_IM8, PR_AX_IM16, PR_PREFIX, PR_NONE, /* 2 */
|
|
PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_AL_IM8, PR_AX_IM16, PR_PREFIX, PR_NONE, PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_AL_IM8, PR_AX_IM16, PR_PREFIX, PR_NONE, /* 3 */
|
|
PR_AX, PR_CX, PR_DX, PR_BX, PR_SP, PR_BP, PR_SI, PR_DI, PR_AX, PR_CX, PR_DX, PR_BX, PR_SP, PR_BP, PR_SI, PR_DI, /* 4 */
|
|
PR_AX, PR_CX, PR_DX, PR_BX, PR_SP, PR_BP, PR_SI, PR_DI, PR_AX, PR_CX, PR_DX, PR_BX, PR_SP, PR_BP, PR_SI, PR_DI, /* 5 */
|
|
PR_NONE, PR_NONE, PR_R_RM16, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_IM16, PR_RM_IM16, PR_IM8, PR_RM16_IM8, PR_NONE8, PR_NONE16, PR_NONE8, PR_NONE16, /* 6 */
|
|
PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_REL8, /* 7 */
|
|
PR_RM_IM8, PR_RM_IM16, PR_RM_IM8, PR_RM16_IM8, PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_RM_R8, PR_RM_R16, PR_R_RM8, PR_R_RM16, PR_RM16_SEG, PR_R_RM16, PR_SEG_RM16, PR_NONE, /* 8 */
|
|
PR_NONE, PR_AX_CX, PR_AX_DX, PR_AX_BX, PR_AX_SP, PR_AX_BP, PR_AX_SI, PR_AX_DI, PR_NONE, PR_NONE, PR_ABS32, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, /* 9 */
|
|
PR_AL_M8, PR_AX_M16, PR_M8_AL, PR_M16_AX, PR_NONE8, PR_NONE16, PR_NONE8, PR_NONE16, PR_AL_IM8, PR_AX_IM16, PR_NONE8, PR_NONE16, PR_NONE8, PR_NONE16, PR_NONE8, PR_NONE16, /* A */
|
|
PR_AL_IM8, PR_CL_IM8, PR_DL_IM8, PR_BL_IM8, PR_AH_IM8, PR_CH_IM8, PR_DH_IM8, PR_BH_IM8, PR_AX_IM16, PR_CX_IM16, PR_DX_IM16, PR_BX_IM16, PR_SP_IM16, PR_BP_IM16, PR_SI_IM16, PR_DI_IM16, /* B */
|
|
PR_RM_IM8, PR_RM16_IM8, PR_IM16, PR_NONE, PR_R_RM16, PR_R_RM16, PR_RM_IM8, PR_RM_IM16, PR_IM16_IM8, PR_NONE, PR_IM16, PR_NONEFAR, PR_NONE, PR_IM8, PR_NONE, PR_NONE, /* C */
|
|
PR_RM8_1, PR_RM16_1, PR_RM8_CL, PR_RM16_CL, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, /* D */
|
|
PR_REL8, PR_REL8, PR_REL8, PR_REL8, PR_AL_IM8, PR_AX_IM8, PR_IM8_AL, PR_IM8_AX, PR_REL16, PR_REL16, PR_ABS32, PR_REL8, PR_AL_DX, PR_AX_DX, PR_DX_AL, PR_DX_AX, /* E */
|
|
PR_PREFIX, PR_NONE, PR_PREFIX, PR_PREFIX, PR_NONE, PR_NONE, PR_RM8, PR_RM16, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_NONE, PR_RM8, PR_RM16, /* F */
|
|
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
|
};
|
|
|
|
enum extendedOpcodes
|
|
{
|
|
OP_IMD_ADD = 0,
|
|
OP_IMD_OR = 1,
|
|
OP_IMD_ADC = 2,
|
|
OP_IMD_SBB = 3,
|
|
OP_IMD_AND = 4,
|
|
OP_IMD_SUB = 5,
|
|
OP_IMD_XOR = 6,
|
|
OP_IMD_CMP = 7,
|
|
|
|
OP_SFT_ROL = 0,
|
|
OP_SFT_ROR = 1,
|
|
OP_SFT_RCL = 2,
|
|
OP_SFT_RCR = 3,
|
|
OP_SFT_SHL = 4,
|
|
OP_SFT_SHR = 5,
|
|
OP_SFT_SAR = 7,
|
|
|
|
OP_GP1_TEST = 0,
|
|
OP_GP1_NOT = 2,
|
|
OP_GP1_NEG = 3,
|
|
OP_GP1_MUL = 4,
|
|
OP_GP1_IMUL = 5,
|
|
OP_GP1_DIV = 6,
|
|
OP_GP1_IDIV = 7,
|
|
|
|
OP_GP2_INC = 0,
|
|
OP_GP2_DEC = 1,
|
|
OP_GP2_CALL = 2,
|
|
OP_GP2_CALLF = 3,
|
|
OP_GP2_JMP = 4,
|
|
OP_GP2_JMPF = 5,
|
|
OP_GP2_PUSH = 6,
|
|
};
|
|
|
|
typedef enum modrmValues
|
|
{
|
|
MR_BX_SI = 0, /**< [BX + SI] */
|
|
MR_BX_DI, /**< [BX + DI] */
|
|
MR_BP_SI, /**< [BP + SI] */
|
|
MR_BP_DI, /**< [BP + DI] */
|
|
MR_SI, /**< [SI] */
|
|
MR_DI, /**< [DI] */
|
|
MR_DISP16, /**< disp16 */
|
|
MR_BX, /**< [BX] */
|
|
MR_BX_SI_D8, /**< [BX + SI] + disp8 */
|
|
MR_BX_DI_D8, /**< [BX + DI] + disp8 */
|
|
MR_BP_SI_D8, /**< [BP + SI] + disp8 */
|
|
MR_BP_DI_D8, /**< [BP + DI] + disp8 */
|
|
MR_SI_D8, /**< [SI] + disp8 */
|
|
MR_DI_D8, /**< [DI] + disp8 */
|
|
MR_BP_D8, /**< [BX] + disp8 */
|
|
MR_BX_D8, /**< [BP] + disp8 */
|
|
MR_BX_SI_D16, /**< [BX + SI] + disp16 */
|
|
MR_BX_DI_D16, /**< [BX + DI] + disp16 */
|
|
MR_BP_SI_D16, /**< [BP + SI] + disp16 */
|
|
MR_BP_DI_D16, /**< [BP + DI] + disp16 */
|
|
MR_SI_D16, /**< [SI] + disp16 */
|
|
MR_DI_D16, /**< [DI] + disp16 */
|
|
MR_BP_D16, /**< [BX] + disp16 */
|
|
MR_BX_D16, /**< [Bp] + disp16 */
|
|
MR_AX_AL, /**< AX or AL */
|
|
MR_CX_CL, /**< CX or CL */
|
|
MR_DX_DL, /**< DX or DL */
|
|
MR_BX_BL, /**< BC or BL */
|
|
MR_SP_AH, /**< SP or AH */
|
|
MR_BP_CH, /**< BP or CH */
|
|
MR_SI_DH, /**< SI or DH */
|
|
MR_DI_BH, /**< DI or BH */
|
|
} modrmValues;
|
|
|
|
const char *modrmReg8List[8] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" };
|
|
const char *modrmReg16List[8] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" };
|
|
const char *segmentRegList[8] = { "es", "cs", "ss", "ds", "ILLEGAL", "ILLEGAL", "ILLEGAL", "ILLEGAL" };
|
|
static inline void get_mod_reg_rm(uint8_t value, uint8_t *mod, uint8_t *reg, uint8_t *rm, uint8_t *modrm)
|
|
{
|
|
if (mod)
|
|
{
|
|
*mod = (value >> 6) & 0x3;
|
|
}
|
|
if (reg)
|
|
{
|
|
*reg = (value >> 3) & 0x7;
|
|
}
|
|
if (rm)
|
|
{
|
|
*rm = (value) & 0x7;
|
|
}
|
|
if (modrm)
|
|
{
|
|
*modrm = (value) & 0x7;
|
|
*modrm = ((value & 0xC0) >> 3) | (*modrm);
|
|
}
|
|
}
|
|
|
|
#define MAKE_LINEAR(_seg, _off) ( ((_seg) << 4) + (_off) )
|
|
|
|
static int decode_modrm(uint16_t segment, uint16_t offset, modrmValues modrm, bool is8bit, char *buffer, uint32_t bufferLength)
|
|
{
|
|
uint8_t disp8 = cpu_readmem20(MAKE_LINEAR(segment, offset));
|
|
uint16_t disp16 = (cpu_readmem20(MAKE_LINEAR(segment, offset + 1)) << 8) | disp8;
|
|
char buf[63];
|
|
int offsetReturn = 0;
|
|
|
|
switch (modrm)
|
|
{
|
|
case MR_BX_SI:
|
|
snprintf(buf, 63, " %s [bx + si]", is8bit?"byte":"word");
|
|
strncat(buffer, buf, bufferLength);
|
|
break;
|
|
|
|
case MR_BX_DI:
|
|
snprintf(buf, 63, " %s [bx + di]", is8bit?"byte":"word");
|
|
strncat(buffer, buf, bufferLength);
|
|
break;
|
|
|
|
case MR_BP_SI:
|
|
snprintf(buf, 63, " %s [bp + si]", is8bit?"byte":"word");
|
|
strncat(buffer, buf, bufferLength);
|
|
break;
|
|
|
|
case MR_BP_DI:
|
|
snprintf(buf, 63, " %s [bx + di]", is8bit?"byte":"word");
|
|
strncat(buffer, buf, bufferLength);
|
|
break;
|
|
|
|
case MR_SI:
|
|
snprintf(buf, 63, " %s [si]", is8bit?"byte":"word");
|
|
strncat(buffer, buf, bufferLength);
|
|
break;
|
|
|
|
case MR_DI:
|
|
snprintf(buf, 63, " %s [di]", is8bit?"byte":"word");
|
|
strncat(buffer, buf, bufferLength);
|
|
break;
|
|
|
|
case MR_DISP16:
|
|
snprintf(buf, 63, " %s [0%Xh]", is8bit?"byte":"word", disp16);
|
|
strncat(buffer, buf, bufferLength);
|
|
offsetReturn = 2;
|
|
break;
|
|
|
|
case MR_BX:
|
|
snprintf(buf, 63, " %s [bx]", is8bit?"byte":"word");
|
|
strncat(buffer, buf, bufferLength);
|
|
break;
|
|
|
|
case MR_BX_SI_D8:
|
|
snprintf(buf, 63, " %s [bx + si] + 0%Xh", is8bit?"byte":"word", disp8);
|
|
strncat(buffer, buf, bufferLength);
|
|
offsetReturn = 1;
|
|
break;
|
|
|
|
case MR_BX_DI_D8:
|
|
snprintf(buf, 63, " %s [bx + di] + 0%Xh", is8bit?"byte":"word", disp8);
|
|
strncat(buffer, buf, bufferLength);
|
|
offsetReturn = 1;
|
|
break;
|
|
|
|
case MR_BP_SI_D8:
|
|
snprintf(buf, 63, " %s [bp + si] + 0%Xh", is8bit?"byte":"word", disp8);
|
|
strncat(buffer, buf, bufferLength);
|
|
offsetReturn = 1;
|
|
break;
|
|
|
|
case MR_BP_DI_D8:
|
|
snprintf(buf, 63, " %s [bp + di] + 0%Xh", is8bit?"byte":"word", disp8);
|
|
strncat(buffer, buf, bufferLength);
|
|
offsetReturn = 1;
|
|
break;
|
|
|
|
case MR_SI_D8:
|
|
snprintf(buf, 63, " %s [si] + 0%Xh", is8bit?"byte":"word", disp8);
|
|
strncat(buffer, buf, bufferLength);
|
|
offsetReturn = 1;
|
|
break;
|
|
|
|
case MR_DI_D8:
|
|
snprintf(buf, 63, " %s [di] + 0%Xh", is8bit?"byte":"word", disp8);
|
|
strncat(buffer, buf, bufferLength);
|
|
offsetReturn = 1;
|
|
break;
|
|
|
|
case MR_BP_D8:
|
|
snprintf(buf, 63, " %s [bp] + 0%Xh", is8bit?"byte":"word", disp8);
|
|
strncat(buffer, buf, bufferLength);
|
|
offsetReturn = 1;
|
|
break;
|
|
|
|
case MR_BX_D8:
|
|
snprintf(buf, 63, " %s [bx] + 0%Xh", is8bit?"byte":"word", disp8);
|
|
strncat(buffer, buf, bufferLength);
|
|
offsetReturn = 1;
|
|
break;
|
|
|
|
case MR_BX_SI_D16:
|
|
snprintf(buf, 63, " %s [bx + si] + 0%Xh", is8bit?"byte":"word", disp16);
|
|
strncat(buffer, buf, bufferLength);
|
|
offsetReturn = 2;
|
|
break;
|
|
|
|
case MR_BX_DI_D16:
|
|
snprintf(buf, 63, " %s [bx + di] + 0%Xh", is8bit?"byte":"word", disp16);
|
|
strncat(buffer, buf, bufferLength);
|
|
offsetReturn = 2;
|
|
break;
|
|
|
|
case MR_BP_SI_D16:
|
|
snprintf(buf, 63, " %s [bp + si] + 0%Xh", is8bit?"byte":"word", disp16);
|
|
strncat(buffer, buf, bufferLength);
|
|
offsetReturn = 2;
|
|
break;
|
|
|
|
case MR_BP_DI_D16:
|
|
snprintf(buf, 63, " %s [bp + di] + 0%Xh", is8bit?"byte":"word", disp16);
|
|
strncat(buffer, buf, bufferLength);
|
|
offsetReturn = 2;
|
|
break;
|
|
|
|
case MR_SI_D16:
|
|
snprintf(buf, 63, " %s [si] + 0%Xh", is8bit?"byte":"word", disp16);
|
|
strncat(buffer, buf, bufferLength);
|
|
offsetReturn = 2;
|
|
break;
|
|
|
|
case MR_DI_D16:
|
|
snprintf(buf, 63, " %s [di] + 0%Xh", is8bit?"byte":"word", disp16);
|
|
strncat(buffer, buf, bufferLength);
|
|
offsetReturn = 2;
|
|
break;
|
|
|
|
case MR_BP_D16:
|
|
snprintf(buf, 63, " %s [bp] + 0%Xh", is8bit?"byte":"word", disp16);
|
|
strncat(buffer, buf, bufferLength);
|
|
offsetReturn = 2;
|
|
break;
|
|
|
|
case MR_BX_D16:
|
|
snprintf(buf, 63, " %s [bx] + 0%Xh", is8bit?"byte":"word", disp16);
|
|
strncat(buffer, buf, bufferLength);
|
|
offsetReturn = 2;
|
|
break;
|
|
|
|
case MR_AX_AL:
|
|
snprintf(buf, 63, " %s", is8bit?"al":"ax");
|
|
strncat(buffer, buf, bufferLength);
|
|
break;
|
|
|
|
case MR_CX_CL:
|
|
snprintf(buf, 63, " %s", is8bit?"cl":"cx");
|
|
strncat(buffer, buf, bufferLength);
|
|
break;
|
|
|
|
case MR_DX_DL:
|
|
snprintf(buf, 63, " %s", is8bit?"dl":"dx");
|
|
strncat(buffer, buf, bufferLength);
|
|
break;
|
|
|
|
case MR_BX_BL:
|
|
snprintf(buf, 63, " %s", is8bit?"bl":"bx");
|
|
strncat(buffer, buf, bufferLength);
|
|
break;
|
|
|
|
case MR_SP_AH:
|
|
snprintf(buf, 63, " %s", is8bit?"ah":"sp");
|
|
strncat(buffer, buf, bufferLength);
|
|
break;
|
|
|
|
case MR_BP_CH:
|
|
snprintf(buf, 63, " %s", is8bit?"ch":"bp");
|
|
strncat(buffer, buf, bufferLength);
|
|
break;
|
|
|
|
case MR_SI_DH:
|
|
snprintf(buf, 63, " %s", is8bit?"dh":"si");
|
|
strncat(buffer, buf, bufferLength);
|
|
break;
|
|
|
|
case MR_DI_BH:
|
|
snprintf(buf, 63, " %s", is8bit?"bh":"di");
|
|
strncat(buffer, buf, bufferLength);
|
|
break;
|
|
}
|
|
|
|
return offsetReturn;
|
|
}
|
|
|
|
|
|
int nec_decode_instruction(uint16_t segment, uint16_t offset, char *buffer, unsigned int bufferSize)
|
|
{
|
|
uint8_t opcode = cpu_readmem20(MAKE_LINEAR(segment, offset));
|
|
uint16_t currentOffset = offset;
|
|
int16_t param1, param2;
|
|
uint8_t modrm, reg;
|
|
|
|
char buf[64];
|
|
|
|
bool isPrefix = false;
|
|
operandTypes opcodeType = opcodeTypeTable[opcode];
|
|
const char *opcodeName = operandTypeNameTable[opcodeType];
|
|
operandParameterTypes opcodeParams = opcodeParamTypeTable[opcode];
|
|
|
|
currentOffset++;
|
|
|
|
switch(opcodeType)
|
|
{
|
|
/* Need to handle opcode group */
|
|
case OP_IMMED:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, offset + 1));
|
|
get_mod_reg_rm(param1, NULL, ®, NULL, NULL);
|
|
switch (reg)
|
|
{
|
|
case OP_IMD_ADD:
|
|
strncat(buffer, "add", bufferSize);
|
|
break;
|
|
|
|
case OP_IMD_OR:
|
|
/* This is not available in B2 and B3 */
|
|
if (opcode > 0xB1)
|
|
{
|
|
strncat(buffer, "illegal", bufferSize);
|
|
opcodeParams = PR_NONE;
|
|
currentOffset++;
|
|
}
|
|
else
|
|
{
|
|
strncat(buffer, "or", bufferSize);
|
|
}
|
|
break;
|
|
|
|
case OP_IMD_ADC:
|
|
strncat(buffer, "adc", bufferSize);
|
|
break;
|
|
|
|
case OP_IMD_SBB:
|
|
strncat(buffer, "sbb", bufferSize);
|
|
break;
|
|
|
|
case OP_IMD_AND:
|
|
/* This is not available in B2 and B3 */
|
|
if (opcode > 0xB1)
|
|
{
|
|
strncat(buffer, "illegal", bufferSize);
|
|
opcodeParams = PR_NONE;
|
|
currentOffset++;
|
|
}
|
|
else
|
|
{
|
|
strncat(buffer, "and", bufferSize);
|
|
}
|
|
break;
|
|
|
|
case OP_IMD_SUB:
|
|
strncat(buffer, "sub", bufferSize);
|
|
break;
|
|
|
|
case OP_IMD_XOR:
|
|
/* This is not available in B2 and B3 */
|
|
if (opcode > 0xB1)
|
|
{
|
|
strncat(buffer, "illegal", bufferSize);
|
|
opcodeParams = PR_NONE;
|
|
currentOffset++;
|
|
}
|
|
else
|
|
{
|
|
strncat(buffer, "xor", bufferSize);
|
|
}
|
|
break;
|
|
|
|
case OP_IMD_CMP:
|
|
strncat(buffer, "cmp", bufferSize);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case OP_SHIFT:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, offset + 1));
|
|
get_mod_reg_rm(param1, NULL, ®, NULL, NULL);
|
|
switch (reg)
|
|
{
|
|
case OP_SFT_ROL:
|
|
strncat(buffer, "rol", bufferSize);
|
|
break;
|
|
case OP_SFT_ROR:
|
|
strncat(buffer, "ror", bufferSize);
|
|
break;
|
|
case OP_SFT_RCL:
|
|
strncat(buffer, "rcl", bufferSize);
|
|
break;
|
|
case OP_SFT_RCR:
|
|
strncat(buffer, "rcr", bufferSize);
|
|
break;
|
|
case OP_SFT_SHL:
|
|
strncat(buffer, "shl", bufferSize);
|
|
break;
|
|
case OP_SFT_SHR:
|
|
strncat(buffer, "shr", bufferSize);
|
|
break;
|
|
case OP_SFT_SAR:
|
|
strncat(buffer, "sar", bufferSize);
|
|
break;
|
|
|
|
default:
|
|
strncat(buffer, "illegal", bufferSize);
|
|
opcodeParams = PR_NONE;
|
|
currentOffset++;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case OP_GRP1:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, offset + 1));
|
|
get_mod_reg_rm(param1, NULL, ®, NULL, NULL);
|
|
switch (reg)
|
|
{
|
|
case OP_GP1_TEST:
|
|
strncat(buffer, "test", bufferSize);
|
|
/* Special case, test is IM_I not just IM */
|
|
if (opcodeParams == PR_RM8)
|
|
{
|
|
opcodeParams = PR_RM_IM8;
|
|
}
|
|
else
|
|
{
|
|
opcodeParams = PR_RM_IM16;
|
|
}
|
|
break;
|
|
|
|
case OP_GP1_NOT:
|
|
strncat(buffer, "not", bufferSize);
|
|
break;
|
|
case OP_GP1_NEG:
|
|
strncat(buffer, "neg", bufferSize);
|
|
break;
|
|
case OP_GP1_MUL:
|
|
strncat(buffer, "mul", bufferSize);
|
|
break;
|
|
case OP_GP1_IMUL:
|
|
strncat(buffer, "imul", bufferSize);
|
|
break;
|
|
case OP_GP1_DIV:
|
|
strncat(buffer, "div", bufferSize);
|
|
break;
|
|
case OP_GP1_IDIV:
|
|
strncat(buffer, "idiv", bufferSize);
|
|
break;
|
|
|
|
default:
|
|
strncat(buffer, "illegal", bufferSize);
|
|
opcodeParams = PR_NONE;
|
|
currentOffset++;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case OP_GRP2:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, offset + 1));
|
|
get_mod_reg_rm(param1, NULL, ®, NULL, NULL);
|
|
switch (reg)
|
|
{
|
|
case OP_GP2_INC:
|
|
strncat(buffer, "inc", bufferSize);
|
|
break;
|
|
case OP_GP2_DEC:
|
|
strncat(buffer, "dec", bufferSize);
|
|
break;
|
|
case OP_GP2_CALL:
|
|
if (opcode == 0xFF)
|
|
{
|
|
strncat(buffer, "call", bufferSize);
|
|
}
|
|
else
|
|
{
|
|
strncat(buffer, "illegal", bufferSize);
|
|
opcodeParams = PR_NONE;
|
|
}
|
|
break;
|
|
case OP_GP2_CALLF:
|
|
if (opcode == 0xFF)
|
|
{
|
|
strncat(buffer, "call far", bufferSize);
|
|
}
|
|
else
|
|
{
|
|
strncat(buffer, "illegal", bufferSize);
|
|
opcodeParams = PR_NONE;
|
|
}
|
|
break;
|
|
case OP_GP2_JMP:
|
|
if (opcode == 0xFF)
|
|
{
|
|
strncat(buffer, "jmp", bufferSize);
|
|
}
|
|
else
|
|
{
|
|
strncat(buffer, "illegal", bufferSize);
|
|
opcodeParams = PR_NONE;
|
|
}
|
|
break;
|
|
case OP_GP2_JMPF:
|
|
if (opcode == 0xFF)
|
|
{
|
|
strncat(buffer, "jmp far", bufferSize);
|
|
}
|
|
else
|
|
{
|
|
strncat(buffer, "illegal", bufferSize);
|
|
opcodeParams = PR_NONE;
|
|
}
|
|
break;
|
|
case OP_GP2_PUSH:
|
|
if (opcode == 0xFF)
|
|
{
|
|
strncat(buffer, "push", bufferSize);
|
|
}
|
|
else
|
|
{
|
|
strncat(buffer, "illegal", bufferSize);
|
|
opcodeParams = PR_NONE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
strncat(buffer, "illegal", bufferSize);
|
|
opcodeParams = PR_NONE;
|
|
currentOffset++;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case OP_MOVG:
|
|
/* Special case for C6 and C7, they are valid ONLY if reg == 0 */
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, offset + 1));
|
|
get_mod_reg_rm(param1, NULL, ®, NULL, NULL);
|
|
if (reg > 0)
|
|
{
|
|
strncat(buffer, "illegal", bufferSize);
|
|
opcodeParams = PR_NONE;
|
|
currentOffset++;
|
|
}
|
|
else
|
|
{
|
|
strncat(buffer, "mov", bufferSize);
|
|
}
|
|
|
|
default:
|
|
strncat(buffer, opcodeName, bufferSize);
|
|
break;
|
|
}
|
|
|
|
switch(opcodeParams)
|
|
{
|
|
/*******************************************************************************************************************
|
|
*********************************************** Trivials parameters ***********************************************
|
|
******************************************************************************************************************/
|
|
|
|
/*----------------------------- Prefix have nothing to display, but need to be known -----------------------------*/
|
|
case PR_PREFIX: isPrefix = true; break;
|
|
|
|
/*---------------------------------------------- Nothing to display ----------------------------------------------*/
|
|
case PR_NONE: break;
|
|
|
|
/*------------------------------------------------ Only registers ------------------------------------------------*/
|
|
case PR_AX: strncat(buffer, " ax", bufferSize); break;
|
|
case PR_BX: strncat(buffer, " bx", bufferSize); break;
|
|
case PR_CX: strncat(buffer, " cx", bufferSize); break;
|
|
case PR_DX: strncat(buffer, " dx", bufferSize); break;
|
|
case PR_SI: strncat(buffer, " si", bufferSize); break;
|
|
case PR_DI: strncat(buffer, " di", bufferSize); break;
|
|
case PR_BP: strncat(buffer, " bp", bufferSize); break;
|
|
case PR_SP: strncat(buffer, " sp", bufferSize); break;
|
|
case PR_SS: strncat(buffer, " ss", bufferSize); break;
|
|
case PR_DS: strncat(buffer, " ds", bufferSize); break;
|
|
case PR_ES: strncat(buffer, " es", bufferSize); break;
|
|
case PR_CS: strncat(buffer, " cs", bufferSize); break;
|
|
case PR_AX_CX: strncat(buffer, " ax, cx", bufferSize); break;
|
|
case PR_AX_DX: strncat(buffer, " ax, dx", bufferSize); break;
|
|
case PR_AX_BX: strncat(buffer, " ax, bx", bufferSize); break;
|
|
case PR_AX_BP: strncat(buffer, " ax, bp", bufferSize); break;
|
|
case PR_AX_SI: strncat(buffer, " ax, si", bufferSize); break;
|
|
case PR_AX_DI: strncat(buffer, " ax, di", bufferSize); break;
|
|
case PR_AX_SP: strncat(buffer, " ax, sp", bufferSize); break;
|
|
case PR_AL_DX: strncat(buffer, " al, dx", bufferSize); break;
|
|
case PR_DX_AL: strncat(buffer, " dx, al", bufferSize); break;
|
|
case PR_DX_AX: strncat(buffer, " dx, ax", bufferSize); break;
|
|
|
|
/*------------------------------- opcode name alteration to match their specifics --------------------------------*/
|
|
case PR_NONE8: strncat(buffer, "b", bufferSize); break; /* working on byte */
|
|
case PR_NONE16: strncat(buffer, "w", bufferSize); break; /* working on word */
|
|
case PR_NONEFAR: strncat(buffer, "f", bufferSize); break; /* far pointer related */
|
|
|
|
/*******************************************************************************************************************
|
|
********************************************** Somewhat simple cases **********************************************
|
|
******************************************************************************************************************/
|
|
|
|
/******* Immediate values *******/
|
|
case PR_IM8:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset++;
|
|
break;
|
|
|
|
case PR_IM16:
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset += 2;
|
|
break;
|
|
|
|
/******* Register / Immediate *******/
|
|
case PR_AL_IM8:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " al, 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset++;
|
|
break;
|
|
|
|
case PR_AH_IM8:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " ah, 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset++;
|
|
break;
|
|
|
|
case PR_AX_IM8:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " ax, 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset++;
|
|
break;
|
|
|
|
case PR_AX_IM16:
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " ax, 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset += 2;
|
|
break;
|
|
|
|
case PR_IM8_AL:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " 0%Xh, al", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset++;
|
|
break;
|
|
|
|
case PR_IM8_AX:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " 0%Xh, ax", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset++;
|
|
break;
|
|
|
|
case PR_BL_IM8:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " bl, 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset++;
|
|
break;
|
|
|
|
case PR_BH_IM8:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " bh, 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset++;
|
|
break;
|
|
|
|
case PR_BX_IM16:
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " bx, 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset += 2;
|
|
break;
|
|
|
|
case PR_CL_IM8:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " cl, 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset++;
|
|
break;
|
|
|
|
case PR_CH_IM8:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " ch, 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset++;
|
|
break;
|
|
|
|
case PR_CX_IM16:
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " cx, 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset += 2;
|
|
break;
|
|
|
|
case PR_DL_IM8:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " dl, 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset++;
|
|
break;
|
|
|
|
case PR_DH_IM8:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " dh, 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset++;
|
|
break;
|
|
|
|
case PR_DX_IM16:
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " dx, 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset += 2;
|
|
break;
|
|
|
|
case PR_SP_IM16:
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " sp, 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset += 2;
|
|
break;
|
|
|
|
case PR_BP_IM16:
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " bp, 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset += 2;
|
|
break;
|
|
|
|
case PR_DI_IM16:
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " di, 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset += 2;
|
|
break;
|
|
|
|
case PR_SI_IM16:
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
snprintf(buf, 63, " si, 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset += 2;
|
|
break;
|
|
|
|
/******* Register / Memory *******/
|
|
case PR_M8_AL:
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
/* TODO: If having a list of known label, try to match and display label instead of value */
|
|
snprintf(buf, 63, " byte [0%Xh], al", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset += 2;
|
|
break;
|
|
|
|
case PR_M16_AX:
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
/* TODO: If having a list of known label, try to match and display label instead of value */
|
|
snprintf(buf, 63, " word [0%Xh], ax", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset += 2;
|
|
break;
|
|
|
|
case PR_AL_M8:
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
/* TODO: If having a list of known label, try to match and display label instead of value */
|
|
snprintf(buf, 63, " al, byte [0%Xh]", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset += 2;
|
|
break;
|
|
|
|
case PR_AX_M16:
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
/* TODO: If having a list of known label, try to match and display label instead of value */
|
|
snprintf(buf, 63, " ax, word [0%Xh]", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset += 2;
|
|
break;
|
|
|
|
/******* Address calculation *******/
|
|
case PR_REL8:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset++;
|
|
param1 = currentOffset + (int8_t)param1;
|
|
/* TODO: If having a list of known label, try to match and display label instead of value */
|
|
snprintf(buf, 63, " 0%Xh", param1);
|
|
strncat(buffer, buf, bufferSize);
|
|
|
|
break;
|
|
|
|
case PR_REL16:
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset += 2;
|
|
param1 = currentOffset + (int16_t) param1;
|
|
|
|
/* TODO: If having a list of known label, try to match and display label instead of value */
|
|
snprintf(buf, 63, " 0%Xh", param1);
|
|
strncat(buffer, buf, bufferSize);
|
|
|
|
break;
|
|
|
|
case PR_ABS32:
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
param2 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 3)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 2));
|
|
/* TODO: If having a list of known label, try to match and display label instead of value */
|
|
snprintf(buf, 63, " 0%Xh:0%Xh", param2, param1);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset += 4;
|
|
break;
|
|
|
|
/******* Other cases *******/
|
|
case PR_IM16_IM8:
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
param2 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 2));
|
|
snprintf(buf, 63, " 0%Xh:0%Xh", param1, param2);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset += 3;
|
|
break;
|
|
|
|
/*******************************************************************************************************************
|
|
************************************************ Complicated cases ************************************************
|
|
******************************************************************************************************************/
|
|
case PR_RM8:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset++;
|
|
get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm);
|
|
currentOffset += decode_modrm(segment, currentOffset, modrm, true, buffer, bufferSize);
|
|
break;
|
|
|
|
case PR_RM16:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset++;
|
|
get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm);
|
|
currentOffset += decode_modrm(segment, currentOffset, modrm, false, buffer, bufferSize);
|
|
break;
|
|
|
|
case PR_RM_IM8:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset++;
|
|
get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm);
|
|
currentOffset += decode_modrm(segment, currentOffset, modrm, true, buffer, bufferSize);
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset++;
|
|
snprintf(buf, 63, ", 0%Xh", param1);
|
|
strncat(buffer, buf, bufferSize);
|
|
break;
|
|
|
|
case PR_RM16_IM8:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset++;
|
|
get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm);
|
|
currentOffset += decode_modrm(segment, currentOffset, modrm, false, buffer, bufferSize);
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset ++;
|
|
snprintf(buf, 63, ", 0%Xh", param1 & 0xFF);
|
|
strncat(buffer, buf, bufferSize);
|
|
break;
|
|
|
|
case PR_RM_IM16:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset++;
|
|
get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm);
|
|
currentOffset += decode_modrm(segment, currentOffset, modrm, false, buffer, bufferSize);
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset += 2;
|
|
snprintf(buf, 63, ", 0%Xh", param1);
|
|
strncat(buffer, buf, bufferSize);
|
|
break;
|
|
|
|
case PR_RM8_1:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset++;
|
|
get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm);
|
|
currentOffset += decode_modrm(segment, currentOffset, modrm, true, buffer, bufferSize);
|
|
strncat(buffer, ", 1", bufferSize);
|
|
break;
|
|
|
|
case PR_RM16_1:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset++;
|
|
get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm);
|
|
currentOffset += decode_modrm(segment, currentOffset, modrm, false, buffer, bufferSize);
|
|
strncat(buffer, ", 1", bufferSize);
|
|
break;
|
|
|
|
case PR_RM8_CL:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset++;
|
|
get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm);
|
|
currentOffset += decode_modrm(segment, currentOffset, modrm, true, buffer, bufferSize);
|
|
strncat(buffer, ", cl", bufferSize);
|
|
break;
|
|
|
|
case PR_RM16_CL:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset++;
|
|
get_mod_reg_rm(param1, NULL, NULL, NULL, &modrm);
|
|
currentOffset += decode_modrm(segment, currentOffset, modrm, false, buffer, bufferSize);
|
|
strncat(buffer, ", cl", bufferSize);
|
|
break;
|
|
|
|
case PR_RM_R8:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset++;
|
|
get_mod_reg_rm(param1, NULL, ®, NULL, &modrm);
|
|
currentOffset += decode_modrm(segment, currentOffset, modrm, true, buffer, bufferSize);
|
|
snprintf(buf, 63, ", %s", modrmReg8List[reg]);
|
|
strncat(buffer, buf, bufferSize);
|
|
break;
|
|
|
|
case PR_RM_R16:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset++;
|
|
get_mod_reg_rm(param1, NULL, ®, NULL, &modrm);
|
|
currentOffset += decode_modrm(segment, currentOffset, modrm, false, buffer, bufferSize);
|
|
snprintf(buf, 63, ", %s", modrmReg16List[reg]);
|
|
strncat(buffer, buf, bufferSize);
|
|
break;
|
|
|
|
case PR_R_RM8:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset++;
|
|
get_mod_reg_rm(param1, NULL, ®, NULL, &modrm);
|
|
snprintf(buf, 63, " %s,", modrmReg8List[reg]);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset += decode_modrm(segment, currentOffset, modrm, true, buffer, bufferSize);
|
|
break;
|
|
|
|
case PR_R_RM16:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset++;
|
|
get_mod_reg_rm(param1, NULL, ®, NULL, &modrm);
|
|
snprintf(buf, 63, " %s,", modrmReg16List[reg]);
|
|
strncat(buffer, buf, bufferSize);
|
|
currentOffset += decode_modrm(segment, currentOffset, modrm, false, buffer, bufferSize);
|
|
break;
|
|
|
|
case PR_RM16_SEG:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset++;
|
|
get_mod_reg_rm(param1, NULL, ®, NULL, &modrm);
|
|
currentOffset += decode_modrm(segment, currentOffset, modrm, false, buffer, bufferSize);
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset += 2;
|
|
snprintf(buf, 63, ", %s", segmentRegList[reg]);
|
|
strncat(buffer, buf, bufferSize);
|
|
break;
|
|
|
|
case PR_SEG_RM16:
|
|
param1 = cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset++;
|
|
get_mod_reg_rm(param1, NULL, ®, NULL, &modrm);
|
|
snprintf(buf, 63, ", %s", segmentRegList[reg]);
|
|
currentOffset += decode_modrm(segment, currentOffset, modrm, false, buffer, bufferSize);
|
|
param1 = (cpu_readmem20(MAKE_LINEAR(segment, currentOffset + 1)) << 8) |
|
|
cpu_readmem20(MAKE_LINEAR(segment, currentOffset));
|
|
currentOffset += 2;
|
|
strncat(buffer, buf, bufferSize);
|
|
break;
|
|
|
|
default:
|
|
Log(TLOG_ERROR, "debugger", "Unsupported opcode param type: %d for opcode %02X (%s)", opcodeParams, opcode, opcodeName);
|
|
break;
|
|
}
|
|
|
|
if (isPrefix)
|
|
{
|
|
/* call this function from the next byte */
|
|
strncat(buffer, " ", bufferSize);
|
|
nec_decode_instruction(segment, currentOffset, buffer, bufferSize);
|
|
}
|
|
|
|
return currentOffset - offset;
|
|
}
|