From 3c091fe6eacd542a506a3f8adf1a8bd91e2e34b0 Mon Sep 17 00:00:00 2001 From: ladevieq Date: Thu, 21 May 2026 23:21:43 +0200 Subject: Initial work on disassembler --- build.bat | 7 +- compile_flags.txt | 14 +- src/disasm.c | 789 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/parser.c | 33 ++- src/utils.c | 32 ++- 5 files changed, 851 insertions(+), 24 deletions(-) create mode 100644 src/disasm.c diff --git a/build.bat b/build.bat index 14d0588..88a175b 100644 --- a/build.bat +++ b/build.bat @@ -25,9 +25,10 @@ if EXIST %VS2022_PRO% ( :compilation -set C_FLAGS=/DHASHMAP /nologo /W4 /WX /Zi /GS- /GR- /Gs1000000000 /Fo:%BUILD_DIR%\ /Iinclude /Isrc /std:c17 /c /Tc -REM set C_FLAGS=/nologo /W4 /WX /Zi /GS- /GR- /Gs1000000000 /Fo:%BUILD_DIR%\ /Iinclude /Isrc /std:c17 /c /Tc -set L_FLAGS=/WX /SUBSYSTEM:CONSOLE /NODEFAULTLIB /stack:0x100000,100000 +REM set C_FLAGS=/DHASHMAP /nologo /W4 /WX /Zi /GS- /GR- /Gs1000000000 /Fo:%BUILD_DIR%\ /Iinclude /Isrc /std:c17 /c /Tc +set C_FLAGS=/nologo /W4 /WX /Zi /GS- /GR- /Gs1000000000 /Fo:%BUILD_DIR%\ /Iinclude /Isrc /std:clatest /c /Tc +REM set L_FLAGS=/WX /SUBSYSTEM:CONSOLE /NODEFAULTLIB /stack:0x100000,100000 +set L_FLAGS=/WX /SUBSYSTEM:CONSOLE /NODEFAULTLIB if "%release%"=="0" ( set C_FLAGS=/Od %C_FLAGS% diff --git a/compile_flags.txt b/compile_flags.txt index 854c6c0..e1ac440 100644 --- a/compile_flags.txt +++ b/compile_flags.txt @@ -1,10 +1,4 @@ -/W4 -/WX -/GS- -/GR- -/Gs1000000000 -/Fo:%BUILD_DIR%\ -/Iinclude -/Isrc -/std:c17 -/TC +-W4 +-WX +-Iinclude +-Isrc diff --git a/src/disasm.c b/src/disasm.c new file mode 100644 index 0000000..62f3fab --- /dev/null +++ b/src/disasm.c @@ -0,0 +1,789 @@ +const u8 MAX_LEGACY_PREFIXES = 4U; +const u8 legacy_prefixes[] = { + // Operand-size override + 0x66, + 0x67, + // Address-size override + 0x2E, + 0x3E, + 0x26, + 0x64, + 0x65, + 0x36, + // Lock + 0xF0, + // Repeat + 0xF2, + 0xF3, +}; + +const u8 REX_prefixes[] = { + 0x40, + 0x41, + 0x42, + 0x43, + 0x44, + 0x45, + 0x46, + 0x47, + 0x48, + 0x49, + 0x4A, + 0x4B, + 0x4C, + 0x4D, + 0x4E, + 0x4F, +}; + +const char* ModRM_registers[8U][5U] = { + { "YMM0", "XMM0", "MMX0", "RAX" }, + { "YMM1", "XMM1", "MMX1", "RCX" }, + { "YMM2", "XMM2", "MMX2", "RDX" }, + { "YMM3", "XMM3", "MMX3", "RBX" }, + { "YMM4", "XMM4", "MMX4", "RSP", "AH" }, + { "YMM5", "XMM5", "MMX5", "RBP", "CH" }, + { "YMM6", "XMM6", "MMX6", "RSI", "DH" }, + { "YMM7", "XMM7", "MMX7", "RDI", "BH" } +}; + +const char* SIB_index_registers[8U] = { + "RAX", + "RCX", + "RDX", + "RBX", + "", + "RBP", + "RSI", + "RDI" +}; + +const char* SIB_base_registers[8U] = { + "RAX", + "RCX", + "RDX", + "RBX", + "RSP", + "RBP", + "RSI", + "RDI" +}; + +struct operand { + // Default operand size in 64bit mode is 32bit. + // If 66h legacy prefix is present 16bit override the default operand size + // If REX.W prefix is present 64bit override the default operand size + // In some cases instruction forces 64bit operand size + enum OPERAND_TYPE { + None, + Inst_FAR, // A + TYPE_E, // E + ModRM_Reg, // G + Imm, // I + ModRM_MEM, // M, mod != 0b11 + Vector_REG, // L + DS_rSI, // X + ES_rSI, // Y + } src; // Handle eventual SIB byte following ModRM byte + + enum DATA_TYPE { + TYPE_BYTE = 0x1, // b + TYPE_WORD = 0x2, + TYPE_DWORD = 0x4, + TYPE_QWORD = 0x8, + TYPE_FP = 0x10, + TYPE_v = 0x1f, // v + TYPE_p = 0x20, // 32 or 48 bit depending on 16 or 32 bit operand size + TYPE_z = 0x1000, // z + TYPE_1 = 0x2000, // Hardcoded 1 + } type; + // SSE stuff +}; + +struct opcode { + const char* name; + struct operand src_operand; + struct operand dst_operand; +}; + +const struct opcode rep_f3_opcode_map[] = { + { "PAUSE", { .src = None }, { .src = None }}, // 0x90 +} + +const struct opcode primary_opcode_map[256U] = { + { "ADD", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, + { "ADD", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, + { "ADD", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, + { "ADD", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, + { "ADD", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // AL, need to understand and handle + { "ADD", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, + { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "POP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "OR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, + { "OR", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, + { "OR", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, + { "OR", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, + { "OR", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // AL, need to understand and handle + { "OR", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, + { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + {}, // Escape to secondary op code map + { "ADC", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, + { "ADC", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, + { "ADC", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, + { "ADC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, + { "ADC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // AL, need to understand and handle + { "ADC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, + { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "POP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "SBB", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, + { "SBB", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, + { "SBB", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, + { "SBB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, + { "SBB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // AL, need to understand and handle + { "ADC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, + { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "POP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "AND", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, + { "AND", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, + { "AND", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, + { "AND", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, + { "AND", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // AL, need to understand and handle + { "AND", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, + { "seg", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "DAA", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "SUB", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, + { "SUB", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, + { "SUB", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, + { "SUB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, + { "SUB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // AL, need to understand and handle + { "SUB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, + { "seg", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "DAS", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "XOR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, + { "XOR", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, + { "XOR", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, + { "XOR", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, + { "XOR", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // AL, need to understand and handle + { "XOR", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, + { "seg", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "AAA", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "CMP", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, + { "CMP", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, + { "CMP", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, + { "CMP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, + { "CMP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // AL, need to understand and handle + { "CMP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, + { "seg", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "AAS", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "INC", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO + { "INC", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + { "INC", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO + { "INC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "INC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // AL, need to understand and handle + { "INC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "INC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "INC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "DEC", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO + { "DEC", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + { "DEC", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO + { "DEC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "DEC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // AL, need to understand and handle + { "DEC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "DEC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "DEC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "PUSH", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO + { "PUSH", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + { "PUSH", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO + { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "PUSH", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "POP", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO + { "POP", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + { "POP", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO + { "POP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "POP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "POP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "POP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "POP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "PUSHA", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO + { "POPA", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + { "BOUND", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO + { "ARPL", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "seg", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "seg", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + {}, // Operand size overide prefix + {}, // Address size override prefix + { "PUSH", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO + { "IMUL", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + { "PUSH", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO + { "IMUL", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "INSB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "INSW/D", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "OUTS/B", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "OUTS/W/D", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "JO", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO + { "JNO", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + { "JB", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO + { "JNB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "JZ", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "JNZ", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "JBE", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "JNBE", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "JS", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO + { "JNS", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + { "JP", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO + { "JNP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "JL", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "JNL", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "JLE", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "JNLE", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + {}, // Group 1 Opcode + {}, // Group 1 Opcode + {}, // Group 1 Opcode + {}, // Group 1 Opcode + { "TEST", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "TEST", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "XCHG", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "XCHG", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO + { "MOV", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "LEA", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + {}, // Group 1 Opcode + { "NOP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "XCHG", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "XCHG", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "XCHG", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "XCHG", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "XCHG", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "XCHG", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "XCHG", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "CBW/WDE/DQE", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "CWD/DQ/QO", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "CALL", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "F/WAIT", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "PUSHF/D/Q", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "POPF/D/Q", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "SAHF", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "LAHF", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOVSB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOBSW/D/Q", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "CMPSB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "CMPSW/D/Q", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "TEST", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "TEST", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "STOSB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "STOW/D/Q", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "LODSB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "LODSW/D/Q", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "SCASB", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "SCASW/D/Q", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "MOV", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + {}, // Group 2 opcode + {}, // Group 2 opcode + { "RET", { .src = ModRM_Reg, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO + { "RET", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "LES", { .src = ModRM_Reg, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, // TODO + { "LDS", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + {}, // Group 11 opcode + {}, // Group 11 opcode + { "ENTER", { .src = ModRM_Reg, .type = TYPE_WORD }, { .src = Imm, .type = TYPE_BYTE }}, + { "LEAVE", { .src = None }, { .src = None }}, + { "RET far", { .src = Imm, .type = TYPE_WORD }, { .src = None }}, + { "RET far", { .src = None }, { .src = None }}, + { "INT 3", { .src = None }, { .src = None }}, + { "INT", { .src = Imm, .type = TYPE_BYTE }, { .src = None }}, + { "INTO", { .src = None }, { .src = None }}, // Invalid in 64bit mode + { "IRET/D/Q", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + {}, // Group 2 Opcode + {}, // Group 2 Opcode + {}, // Group 2 Opcode + {}, // Group 2 Opcode + { "AAM", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO + { "AAD", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + {}, // invalid + { "XLAT", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + {}, // TODO x87 instructions + {}, // TODO x87 instructions + {}, // TODO x87 instructions + {}, // TODO x87 instructions + {}, // TODO x87 instructions + {}, // TODO x87 instructions + {}, // TODO x87 instructions + {}, // TODO x87 instructions + { "LOOPNE/NZ", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "LOOPE/Z", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "LOOP", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "JrCXZ", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "IN", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "IN", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "OUT", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "OUT", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "CALL", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "JMP", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + { "JMP", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO + { "JMP", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + { "IN", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "IN", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "OUT", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "OUT", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "LOCK", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "INT1", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + { "REPNE", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO + { "REP/E", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + { "HLT", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "CMC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + {}, // Group 3 opcode + {}, // Group 3 opcode + { "CLC", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "STC", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + { "CLI", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = ModRM_Reg, .type = TYPE_BYTE }}, // TODO + { "STI", { .src = TYPE_E, .type = TYPE_v}, { .src = ModRM_Reg, .type = TYPE_v }}, // TODO + { "CLD", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "STD", { .src = ModRM_Reg, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + {}, // Group 4 opcode + {}, // Group 5 opcode +}; + +// TODO: Think about a smart way to retrieve groups opcodes +const struct opcode group_1[32U] = { + // Opcode 0x80 + { "ADD", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "OR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "ADC", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "SBB", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "AND", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "SUB", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "XOR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "CMP", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + // Opcode 0x81 + { "ADD", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_z }}, + { "OR", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_z }}, + { "ADC", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_z }}, + { "SBB", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_z }}, + { "AND", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_z }}, + { "SUB", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_z }}, + { "XOR", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_z }}, + { "CMD", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_z }}, + // Opcode = 0x82 + { "ADD", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "OR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "ADC", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "SBB", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "AND", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "SUB", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "XOR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "CMP", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + // Opcode 0x83 + { "ADD", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, + { "OR", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, + { "ADC", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, + { "SBB", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, + { "AND", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, + { "SUB", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, + { "XOR", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, + { "CMP", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, +}; + +const struct opcode group_1a[8U] = { + { "POP", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "XOP", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "XOP", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "XOP", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "XOP", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "XOP", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "XOP", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO + { "XOP", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_v }}, // TODO +}; + +const struct opcode group_2[48U] = { + // Opcode 0xC0 + { "ROL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "ROR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "RCL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "RCR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "SHL/SAL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "SHR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "SHL/SAL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "SAR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + // Opcode 0xC1 + { "ROL", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, + { "ROR", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, + { "RCL", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, + { "RCR", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, + { "SHL/SAL", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, + { "SHR", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, + { "SHL/SAL", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, + { "SAR", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_BYTE }}, + // Opcode 0xD0 + { "ROL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_1 }}, + { "ROR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_1 }}, + { "RCL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_1 }}, + { "RCR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_1 }}, + { "SHL/SAL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_1 }}, + { "SHR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_1 }}, + { "SHL/SAL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_1 }}, + { "SAR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_1 }}, + // Opcode 0xD1 + { "ROL", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_1 }}, + { "ROR", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_1 }}, + { "RCL", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_1 }}, + { "RCR", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_1 }}, + { "SHL/SAL", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_1 }}, + { "SHR", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_1 }}, + { "SHL/SAL", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_1 }}, + { "SAR", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_1 }}, + // Opcode 0xD2 + { "ROL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL + { "ROR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL + { "RCL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL + { "RCR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL + { "SHL/SAL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL + { "SHR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL + { "SHL/SAL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL + { "SAR", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL + // Opcode 0xD3 + { "ROL", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL + { "ROR", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL + { "RCL", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL + { "RCR", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL + { "SHL/SAL", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL + { "SHR", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL + { "SHL/SAL", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL + { "SAR", { .src = TYPE_E, .type = TYPE_v }, { .src = TYPE_E, .type = TYPE_BYTE }}, // TODO handle CL +}; + +const struct opcode group_3[16U] = { + { "TEST", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "TEST", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = None }}, + { "NOT", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = None }}, + { "NEG", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = None }}, + { "MUL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = None }}, + { "IMUL", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = None }}, + { "DIV", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = None }}, + { "IDIV", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = None }}, + { "TEST", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_z }}, + { "TEST", { .src = TYPE_E, .type = TYPE_v }, { .src = None }}, + { "NOT", { .src = TYPE_E, .type = TYPE_v }, { .src = None }}, + { "NEG", { .src = TYPE_E, .type = TYPE_v }, { .src = None }}, + { "MUL", { .src = TYPE_E, .type = TYPE_v }, { .src = None }}, + { "IMUL", { .src = TYPE_E, .type = TYPE_v }, { .src = None }}, + { "DIV", { .src = TYPE_E, .type = TYPE_v }, { .src = None }}, + { "IDIV", { .src = TYPE_E, .type = TYPE_v }, { .src = None }}, +}; + +const struct opcode group_4[2U] = { + { "INC", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = None }}, + { "DEC", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = None }}, +}; + +const struct opcode group_5[7U] = { + { "INC", { .src = TYPE_E, .type = TYPE_v }, { .src = None }}, + { "DEC", { .src = TYPE_E, .type = TYPE_v }, { .src = None }}, + { "CALL", { .src = TYPE_E, .type = TYPE_v }, { .src = None }}, + { "CALL", { .src = ModRM_MEM, .type = TYPE_p }, { .src = None }}, + { "JMP", { .src = TYPE_E, .type = TYPE_v }, { .src = None }}, + { "JMP", { .src = ModRM_MEM, .type = TYPE_p }, { .src = None }}, + { "PUSH", { .src = TYPE_E, .type = TYPE_v }, { .src = None }}, +}; + +const struct opcode group_11[2U] = { + { "MOV", { .src = TYPE_E, .type = TYPE_BYTE }, { .src = Imm, .type = TYPE_BYTE }}, + { "MOV", { .src = TYPE_E, .type = TYPE_v }, { .src = Imm, .type = TYPE_z }}, +}; + +u8 is_legacy_prefix(u8 byte) { + for (u8 index = 0U; index < sizeof(legacy_prefixes); index++) { + if (byte == legacy_prefixes[index]) { + return TRUE; + } + } + return FALSE; +} + +u8 is_REX_prefix(u8 byte) { + for (u8 index = 0U; index < sizeof(REX_prefixes); index++) { + if (byte == REX_prefixes[index]) { + return TRUE; + } + } + return FALSE; +} + +const struct opcode* primary_map_group(u8 opcode, u8 ModRM) { + const u8 reg_size = 0x8; + const u8 reg_byte_mask = 0b111; + u8 reg = (ModRM >> 3U) & reg_byte_mask; + if (0x80 <= opcode && opcode <= 0x83) { + return &group_1[(opcode - 0x80) * reg_size + reg]; + } else if (opcode == 0x8F) { + return &group_1a[reg]; + } else if (opcode == 0xC0 || opcode == 0xC1) { + return &group_2[(opcode == 0xC1) * reg_size + reg]; + } else if (0xD0 <= opcode && opcode <= 0xD3) { + return &group_2[((opcode - 0xD0) + 2U) * reg_size + reg]; + } else if (opcode == 0xF6 || opcode == 0xF7) { + return &group_3[(opcode - 0xF6) * reg_size + reg]; + } else if (opcode == 0xFE) { + return &group_4[reg]; + } else if (opcode == 0xFF) { + return &group_5[reg]; + } else if (opcode == 0xC6 || opcode == 0xC7) { + return &group_11[opcode == 0xC7]; + } else { + return NULL; + } +} + +u64 get_immediate(u8** bytes, enum DATA_TYPE type, u8 operand_effective_size) { + u64 imm = 0U; + if (type == TYPE_BYTE) { + imm = (u8)**bytes; + *bytes += 1U; + } else if (type == TYPE_WORD) { + imm = (u16)**bytes; + *bytes += 2U; + } else if (type == TYPE_DWORD) { + imm = (u32)**bytes; + *bytes += 4U; + } else if (type == TYPE_QWORD) { + imm = (u64)**bytes; + *bytes += 8U; + } else if (type == TYPE_v) { + if (operand_effective_size == 16U) { + imm = (u16)**bytes; + } else if (operand_effective_size == 32U) { + imm = (u32)**bytes; + } else if (operand_effective_size == 64U) { + imm = (u64)**bytes; + } else { + print("ERROR: Unhandled operand type\n"); + } + + *bytes += operand_effective_size / 8U; + } else if (type == TYPE_z) { + if (operand_effective_size == 16U) { + imm = (u16)**bytes; + *bytes += 2U; + } else { + imm = (u32)**bytes; + *bytes += 2U; + } + } else { + print("ERROR: Unhandled operand type\n"); + } + return imm; +} + +u8 get_immediate_size(enum OPERAND_TYPE type, u8 operand_effective_size) { + if (type == TYPE_BYTE) { + return 1U; + } else if (type == TYPE_WORD) { + return 2U; + } else if (type == TYPE_DWORD) { + return 4U; + } else if (type == TYPE_QWORD) { + return 8U; + } else if (type == TYPE_v) { + return operand_effective_size / 8U; + } else { + print("ERROR: Unhandled operand type\n"); + return 0U; + } +} + +#define MODRM_MOD(ModRM) (ModRM >> 6U) +#define MODRM_REG(ModRM) (ModRM & 0b00111000) >> 0x3 +#define MODRM_RM(ModRM) (ModRM & 0b00000111) + +#define SIB_SCALE(SIB) (SIB >> 6U) +#define SIB_INDEX(SIB) (SIB & 0b00111000) >> 0x3 +#define SIB_BASE(SIB) (SIB & 0b00000111) + +#define REXW(REX) (REX & 0b00001000) >> 3U +#define REXR(REX) (REX & 0b00000100) >> 2U +#define REXX(REX) (REX & 0b00000010) >> 1U +#define REXB(REX) (REX & 0b00000001) + +// void unassemble(CONTEXT* ctx, u32 count) { +void unassemble(u8* start, u64 size) { + // u8* current_byte = (u8*)ctx->Rip; + u8* inst_buffer = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if(!read_memory((const void*)start, (void*)inst_buffer, size)) { + print("Failed to read instructions\n"); + } + + u8* current_byte = inst_buffer; + while ((u64)(current_byte - inst_buffer) < size) { + u8* inst_start = current_byte; + u8 legacy_prefixes_count = 0U; + u8 effective_operand_size = 32U; // 32 by default in 64bit mode + i32 effective_address = -1; + u8 operand_size_override_66 = FALSE; + u8 operand_size_override_REX = FALSE; + u8 REX = 0U; + while (is_legacy_prefix(*current_byte) && legacy_prefixes_count < MAX_LEGACY_PREFIXES) { + if (*current_byte == 0x66) { // Override effective operand size + effective_operand_size = 16U; + operand_size_override_66 = TRUE; + } + legacy_prefixes_count++; + current_byte++; + } + + if (is_REX_prefix(*current_byte)) { + REX = *current_byte; + + if (REXW(REX) && operand_size_override_66 == FALSE) { + effective_operand_size = 64U; + operand_size_override_REX = TRUE; + } + + current_byte++; + } + + // TODO: VEX, XOP prefixes + + u8 op_byte = *current_byte; + current_byte++; + u8 ModRM = *current_byte; + const struct opcode* op = NULL; + if (op_byte == 0x0F) { // Secondary op code map needed + current_byte++; + } else if ((op = primary_map_group(op_byte, ModRM)) != NULL) { + } else { + op = &primary_opcode_map[op_byte]; + } + + u8 has_displacement = FALSE; + u8 has_src_SIB = FALSE; + u8 has_dst_SIB = FALSE; + if (op->src_operand.src & (TYPE_E | ModRM_Reg) || op->dst_operand.src & (TYPE_E | ModRM_Reg)) { + u8 Mod = MODRM_MOD(ModRM); + u8 RM = MODRM_RM(ModRM); + + if (Mod == 0b10 || Mod == 0b01) { + has_displacement = TRUE; + } + + if (Mod != 0b11 && RM == 0b100) { // This may not be the only way to has an SIB byte + if (op->src_operand.src & (TYPE_E | ModRM_Reg)) { + has_src_SIB = TRUE; + } + if (op->dst_operand.src & (TYPE_E | ModRM_Reg)) { + has_dst_SIB = TRUE; + } + } + + current_byte++; + } + + // SIB + u8 SIB = *current_byte; + if (has_SIB) { + current_byte++; + } + + // Displacement bits + if (has_displacement) { + // Read displacement bits + current_byte++; + } + + u64 src_imm = 0U; + u64 dst_imm = 0U; + if (op->src_operand.src == Imm) { + // Read immediate + src_imm = get_immediate(¤t_byte, op->src_operand.type, effective_operand_size); + } + + if (op->dst_operand.src == Imm) { + // Read immediate + dst_imm = get_immediate(¤t_byte, op->dst_operand.type, effective_operand_size); + } + + u8 inst_size = (u8)(current_byte - inst_start); + + for (u8 index = 0U; index < inst_size; index++) { + print("%2xb ", inst_start[index]); + } + print("\t\t%s", op->name); + + if (op->src_operand.src == Imm) { + print(" %u", src_imm); + } else if (op->src_operand.src == ModRM_Reg) { + u8 Reg = MODRM_REG(ModRM); + print(" %s", ModRM_registers[Reg][3U]); + } else if (op->src_operand.src == TYPE_E) { + u8 Mod = MODRM_MOD(ModRM); + u8 RM = MODRM_RM(ModRM); + if (Mod == 0b11) { + print(" %s", ModRM_registers[RM][3U]); + } + } + + if (has_src_SIB) { + // Read SIB + i32 scale_factors[4U] = { + 1, 2, 4, 8, + } + effective_address = scale_factors[SIB_SCALE(SIB)] * SIB_INDEX(SIB) + SIB_BASE(SIB) + off; + } + + if (op->dst_operand.src == Imm) { + print(" %xu", dst_imm); + } + + if (has_dst_SIB) { + // Read SIB + i32 scale_factors[4U] = { + 1, 2, 4, 8, + } + + u8 index = SIB_INDEX(SIB); + if (index != 0b100) { + print(" [%d * %s", scale_factors[SIB_SCALE(SIB)], SIB_index_registers[index]); + } + + u8 base = SIB_BASE(SIB); + if (base != 0b101 && MODRM_MOD(ModRM) != 0U) { + print(" + %s", SIB_base_registers[base]); + } + + if (has_displacement) { + print("+ %d]", ); + } else { + print("]"); + } + } + + print("\n"); + + // u8 low_nibble = current_byte & 0xf; + // u8 high_nibble = (current_byte >> 4U) & 0xf; + } +} diff --git a/src/parser.c b/src/parser.c index 1731c70..985543b 100644 --- a/src/parser.c +++ b/src/parser.c @@ -18,6 +18,7 @@ enum TOKEN_TYPE { TOKEN_PRINT_REG, TOKEN_STEP_INTO, TOKEN_DUMP_MEMORY, + TOKEN_UNASSEMBLE, TOKEN_QUIT, // Primaries @@ -47,14 +48,15 @@ struct ast_node { #define DECLARE_COMMAND(x) { .start = x, .size = sizeof(x) } static struct command commands[] = { - { .start = "g", .size = 1 }, - { .start = "k", .size = 1 }, - { .start = "lm", .size = 2 }, + DECLARE_COMMAND("g"), + DECLARE_COMMAND("k"), + DECLARE_COMMAND("lm"), DECLARE_COMMAND("x"), - { .start = "r", .size = 1 }, - { .start = "t", .size = 1 }, - { .start = "db", .size = 2 }, - { .start = "q", .size = 1 }, + DECLARE_COMMAND("r"), + DECLARE_COMMAND("t"), + DECLARE_COMMAND("db"), + DECLARE_COMMAND("u"), + DECLARE_COMMAND("q"), }; _Static_assert((sizeof(commands) / sizeof(commands[0])) == TOKEN_QUIT + 1, "Missing commands"); @@ -183,6 +185,13 @@ struct ast_node* parse_command(struct token* tokens, struct ast_node* nodes) { cur_node->left = parse_primary(tokens++, ++nodes); cur_node->right = parse_primary(tokens++, ++nodes); return cur_node; + case TOKEN_UNASSEMBLE: + tokens++; + print("TOKEN_UNASSEMBLE\n"); + cur_node->token = cur_token; + cur_node->left = NULL; + cur_node->right = NULL; + return cur_node; case TOKEN_QUIT: tokens++; print("TOKEN_QUIT\n"); @@ -292,6 +301,16 @@ void run(struct ast_node* root) { #endif } } + } else if (cur_node.token->type == TOKEN_UNASSEMBLE) { + struct module* module = get_addr_module(ctx.Rip); + u32 sym_index = find_function(module, ctx.Rip - (u64)module->base_addr); + if (sym_index != (u32)-1) { + u32 start = module->functions_start[sym_index]; + u32 end = module->functions_end[sym_index]; + unassemble((u8*)module->base_addr + start, end - start); + } else { + print("No symbol found at address %xu\n", ctx.Rip); + } } else { print("Command unknown\n"); process_commands = TRUE; diff --git a/src/utils.c b/src/utils.c index 440b9fb..27dab87 100644 --- a/src/utils.c +++ b/src/utils.c @@ -84,6 +84,13 @@ u64 atou64(const char* str, u32 len) { return number; } +void fill_chars(u8* ptr, u8 c, u32 len) { + for (u32 index = 0U; index < len; index++) { + *ptr = c; + ptr++; + } +} + void print(const char* format, ...) { va_list args; va_start(args, format); @@ -94,24 +101,41 @@ void print(const char* format, ...) { while(*cur_fmt != '\0') { if(*cur_fmt == '%') { cur_fmt++; + const char* num_start = cur_fmt; + u8 num_len = 0U; + u64 fill_count = 0U; + while (is_decimal_digit(*cur_fmt)) { + cur_fmt++; + num_len++; + } + + if (num_len > 0U) { + fill_count = atou64(num_start, num_len); + } + if (*cur_fmt == 's') { const char* str = va_arg(args, const char*); if(str != NULL) { size_t length = 0U; StringCchLengthA(str, sizeof(formatted_str), &length); + i64 relative_fill_count = fill_count - length; + if (relative_fill_count > 0) { + fill_chars((u8*)cur_char, ' ', (u32)relative_fill_count); + cur_char += relative_fill_count; + } StringCchCatA(cur_char, length + 1U, str); cur_char += length; } } else if(*cur_fmt == 'c') { char c = va_arg(args, char); + if (fill_count > 1U) { + fill_chars((u8*)cur_char, ' ', (u32)fill_count - 1U); + cur_char += fill_count - 1U; + } StringCchCatA(cur_char, 1U, &c); cur_char += 1U; } else if (*cur_fmt == 'x' && is_alpha(cur_fmt[1])) { u32 base = 16U; - *cur_char = '0'; - cur_char++; - *cur_char = 'x'; - cur_char++; cur_fmt++; if(*cur_fmt == 'b') { -- cgit v1.3