diff options
| author | Rusty Wagner <rusty.wagner@gmail.com> | 2024-03-05 19:50:13 -0500 |
|---|---|---|
| committer | Rusty Wagner <rusty.wagner@gmail.com> | 2024-03-05 20:34:34 -0500 |
| commit | e093c21ed880ac3eb72119be15093ee04f8ce299 (patch) | |
| tree | 9f720ebdc0ae415734b1199ed341668c69710a94 /arch/x86/arch_x86.cpp | |
| parent | 0609276712622908254065546102381466033141 (diff) | |
Move architecture modules into the API repo
Diffstat (limited to 'arch/x86/arch_x86.cpp')
| -rw-r--r-- | arch/x86/arch_x86.cpp | 4880 |
1 files changed, 4880 insertions, 0 deletions
diff --git a/arch/x86/arch_x86.cpp b/arch/x86/arch_x86.cpp new file mode 100644 index 00000000..e19fbef0 --- /dev/null +++ b/arch/x86/arch_x86.cpp @@ -0,0 +1,4880 @@ +#define _CRT_SECURE_NO_WARNINGS +#include <inttypes.h> +#include <stdio.h> +#include <string.h> +#include <sstream> +#include "binaryninjaapi.h" +#include "il.h" +extern "C" { + #include "xed-interface.h" +} +#include "arch_x86_common_architecture.h" + +using namespace BinaryNinja; +using namespace std; + +enum Elfx86RelocationType : uint32_t +{ + R_386_NONE = 0, // No relocation. + R_386_32 = 1, // Add symbol value. + R_386_PC32 = 2, // Add PC-relative symbol value. + R_386_GOT32 = 3, // Add PC-relative GOT offset. + R_386_PLT32 = 4, // Add PC-relative PLT offset. + R_386_COPY = 5, // Copy data from shared object. + R_386_GLOB_DAT = 6, // Set GOT entry to data address. + R_386_JUMP_SLOT = 7, // Set GOT entry to code address. + R_386_RELATIVE = 8, // Add load address of shared object. + R_386_GOTOFF = 9, // Add GOT-relative symbol address. + R_386_GOTPC = 10, // Add PC-relative GOT table address. + R_386_TLS_TPOFF = 14, // Negative offset in static TLS block + R_386_TLS_IE = 15, // Absolute address of GOT for -ve static TLS + R_386_TLS_GOTIE = 16, // GOT entry for negative static TLS block + R_386_TLS_LE = 17, // Negative offset relative to static TLS + R_386_TLS_GD = 18, // 32 bit offset to GOT (index,off) pair + R_386_TLS_LDM = 19, // 32 bit offset to GOT (index,zero) pair + R_386_16 = 20, // + R_386_PC16 = 21, // + R_386_8 = 22, // + R_386_PC8 = 23, // + R_386_TLS_GD_32 = 24, // 32 bit offset to GOT (index,off) pair + R_386_TLS_GD_PUSH = 25, // pushl instruction for Sun ABI GD sequence + R_386_TLS_GD_CALL = 26, // call instruction for Sun ABI GD sequence + R_386_TLS_GD_POP = 27, // popl instruction for Sun ABI GD sequence + R_386_TLS_LDM_32 = 28, // 32 bit offset to GOT (index,zero) pair + R_386_TLS_LDM_PUSH = 29, // pushl instruction for Sun ABI LD sequence + R_386_TLS_LDM_CALL = 30, // call instruction for Sun ABI LD sequence + R_386_TLS_LDM_POP = 31, // popl instruction for Sun ABI LD sequence + R_386_TLS_LDO_32 = 32, // 32 bit offset from start of TLS block + R_386_TLS_IE_32 = 33, // 32 bit offset to GOT static TLS offset entry + R_386_TLS_LE_32 = 34, // 32 bit offset within static TLS block + R_386_TLS_DTPMOD32 = 35, // GOT entry containing TLS index + R_386_TLS_DTPOFF32 = 36, // GOT entry containing TLS offset + R_386_TLS_TPOFF32 = 37, // GOT entry of -ve static TLS offset + R_386_SIZE32 = 38, // + R_386_TLS_GOTDESC = 39, // + R_386_TLS_DESC_CALL = 40, // + R_386_TLS_DESC = 41, // + R_386_IRELATIVE = 42, // PLT entry resolved indirectly at runtime + MAX_ELF_X86_RELOCATION +}; + +enum Elfx64RelocationType : uint32_t +{ + R_X86_64_NONE = 0, // No reloc + R_X86_64_64 = 1, // Direct 64 bit + R_X86_64_PC32 = 2, // PC relative 32 bit signed + R_X86_64_GOT32 = 3, // 32 bit GOT entry + R_X86_64_PLT32 = 4, // 32 bit PLT address + R_X86_64_COPY = 5, // Copy symbol at runtime + R_X86_64_GLOB_DAT = 6, // Create GOT entry + R_X86_64_JUMP_SLOT = 7, // Create PLT entry + R_X86_64_RELATIVE = 8, // Adjust by program base + R_X86_64_GOTPCREL = 9, // 32 bit signed pc relative offset to GOT + R_X86_64_32 = 10, // Direct 32 bit zero extended + R_X86_64_32S = 11, // Direct 32 bit sign extended + R_X86_64_16 = 12, // Direct 16 bit zero extended + R_X86_64_PC16 = 13, // 16 bit sign extended pc relative + R_X86_64_8 = 14, // Direct 8 bit sign extended + R_X86_64_PC8 = 15, // 8 bit sign extended pc relative + R_X86_64_DTPMOD64 = 16, + R_X86_64_DTPOFF64 = 17, + R_X86_64_TPOFF64 = 18, + R_X86_64_TLSGD = 19, + R_X86_64_TLSLD = 20, + R_X86_64_DTPOFF32 = 21, + R_X86_64_GOTTPOFF = 22, + R_X86_64_TPOFF32 = 23, + R_X86_64_PC64 = 24, + R_X86_64_GOTOFF64 = 25, + R_X86_64_GOTPC32 = 26, + R_X86_64_UNKNOWN27 = 27, + R_X86_64_UNKNOWN28 = 28, + R_X86_64_UNKNOWN29 = 29, + R_X86_64_UNKNOWN30 = 30, + R_X86_64_UNKNOWN31 = 31, + R_X86_64_SIZE32 = 32, + R_X86_64_SIZE64 = 33, + R_X86_64_GOTPC32_TLSDESC = 34, + R_X86_64_TLSDESC_CALL = 35, + R_X86_64_TLSDESC = 36, + R_X86_64_IRELATIVE = 37, + R_X86_64_RELATIVE64 = 38, + R_X86_64_PC32_BND = 39, + R_X86_64_PLT32_BND = 40, + R_X86_64_GOTPCRELX = 41, + R_X86_64_REX_GOTPCRELX = 42, + MAX_ELF_X64_RELOCATION +}; + +enum Machox86RelocationType : uint32_t +{ + GENERIC_RELOC_VANILLA = 0, + GENERIC_RELOC_PAIR = 1, + GENERIC_RELOC_SECTDIFF = 2, + GENERIC_RELOC_PB_LA_PTR = 3, + GENERIC_RELOC_LOCAL_SECTDIFF = 4, + GENERIC_RELOC_TLV = 5, + MACHO_MAX_X86_RELOCATION +}; + +enum Machox64RelocationType : uint32_t +{ + X86_64_RELOC_UNSIGNED = 0, + X86_64_RELOC_SIGNED = 1, + X86_64_RELOC_BRANCH = 2, + X86_64_RELOC_GOT_LOAD = 3, + X86_64_RELOC_GOT = 4, + X86_64_RELOC_SUBTRACTOR = 5, + X86_64_RELOC_SIGNED_1 = 6, + X86_64_RELOC_SIGNED_2 = 7, + X86_64_RELOC_SIGNED_4 = 8, + X86_64_RELOC_TLV = 9, + MACHO_MAX_X86_64_RELOCATION +}; + +enum COFFx86RelocationType : uint32_t +{ + PE_IMAGE_REL_I386_ABSOLUTE = 0x0000, // The relocation is ignored. + PE_IMAGE_REL_I386_DIR16 = 0x0001, // Not supported. + PE_IMAGE_REL_I386_REL16 = 0x0002, // Not supported. + PE_IMAGE_REL_I386_DIR32 = 0x0006, // The target's 32-bit VA. + PE_IMAGE_REL_I386_DIR32NB = 0x0007, // The target's 32-bit RVA. + PE_IMAGE_REL_I386_SEG12 = 0x0009, // Not supported. + PE_IMAGE_REL_I386_SECTION = 0x000A, // The 16-bit section index of the section that contains the target. This is used to support debugging information. + PE_IMAGE_REL_I386_SECREL = 0x000B, // The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage. + PE_IMAGE_REL_I386_TOKEN = 0x000C, // The CLR token. + PE_IMAGE_REL_I386_SECREL7 = 0x000D, // A 7-bit offset from the base of the section that contains the target. + PE_IMAGE_REL_I386_REL32 = 0x0014, // The 32-bit relative displacement to the target. This supports the x86 relative branch and call instructions. + MAX_PE_X86_RELOCATION +}; + +enum COFFx64RelocationType : uint32_t +{ + PE_IMAGE_REL_AMD64_ABSOLUTE = 0x0000, // The relocation is ignored. + PE_IMAGE_REL_AMD64_ADDR64 = 0x0001, // The 64-bit VA of the relocation target. + PE_IMAGE_REL_AMD64_ADDR32 = 0x0002, // The 32-bit VA of the relocation target. + PE_IMAGE_REL_AMD64_ADDR32NB = 0x0003, // The 32-bit address without an image base (RVA). + PE_IMAGE_REL_AMD64_REL32 = 0x0004, // The 32-bit relative address from the byte following the relocation. + PE_IMAGE_REL_AMD64_REL32_1 = 0x0005, // The 32-bit address relative to byte distance 1 from the relocation. + PE_IMAGE_REL_AMD64_REL32_2 = 0x0006, // The 32-bit address relative to byte distance 2 from the relocation. + PE_IMAGE_REL_AMD64_REL32_3 = 0x0007, // The 32-bit address relative to byte distance 3 from the relocation. + PE_IMAGE_REL_AMD64_REL32_4 = 0x0008, // The 32-bit address relative to byte distance 4 from the relocation. + PE_IMAGE_REL_AMD64_REL32_5 = 0x0009, // The 32-bit address relative to byte distance 5 from the relocation. + PE_IMAGE_REL_AMD64_SECTION = 0x000A, // The 16-bit section index of the section that contains the target. This is used to support debugging information. + PE_IMAGE_REL_AMD64_SECREL = 0x000B, // The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage. + PE_IMAGE_REL_AMD64_SECREL7 = 0x000C, // A 7-bit unsigned offset from the base of the section that contains the target. + PE_IMAGE_REL_AMD64_TOKEN = 0x000D, // CLR tokens. + PE_IMAGE_REL_AMD64_SREL32 = 0x000E, // A 32-bit signed span-dependent value emitted into the object. + PE_IMAGE_REL_AMD64_PAIR = 0x000F, // A pair that must immediately follow every span-dependent value. + PE_IMAGE_REL_AMD64_SSPAN32 = 0x0010, // A 32-bit signed span-dependent value that is applied at link time. + MAX_PE_X64_RELOCATION +}; + +enum PeRelocationType : uint32_t +{ + PE_IMAGE_USER_DEFINED = 0xffffffff, // User defined relocation type for synthesized relocations at IAT sites. + PE_IMAGE_REL_BASED_ABSOLUTE = 0, // The base relocation is skipped. This type can be used to pad a block. + PE_IMAGE_REL_BASED_HIGH = 1, // The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the high value of a 32-bit word. + PE_IMAGE_REL_BASED_LOW = 2, // The base relocation adds the low 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the low half of a 32-bit word. + PE_IMAGE_REL_BASED_HIGHLOW = 3, // The base relocation applies all 32 bits of the difference to the 32-bit field at offset. + PE_IMAGE_REL_BASED_HIGHADJ = 4, // The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the high value of a 32-bit word. The low 16 bits of the 32-bit value are stored in the 16-bit word that follows this base relocation. This means that this base relocation occupies two slots. + PE_IMAGE_REL_BASED_MIPS_JMPADDR = 5, // The relocation interpretation is dependent on the machine type. When the machine type is MIPS, the base relocation applies to a MIPS jump instruction. + PE_IMAGE_REL_BASED_ARM_MOV32 = 5, // This relocation is meaningful only when the machine type is ARM or Thumb. The base relocation applies the 32-bit address of a symbol across a consecutive MOVW/MOVT instruction pair. + PE_IMAGE_REL_BASED_RISCV_HIGH20 = 5, // This relocation is only meaningful when the machine type is RISC-V. The base relocation applies to the high 20 bits of a 32-bit absolute address. + PE_IMAGE_REL_BASE_RESERVED = 6, // Reserved, must be zero. + PE_IMAGE_REL_BASED_THUMB_MOV32 = 7, // This relocation is meaningful only when the machine type is Thumb. The base relocation applies the 32-bit address of a symbol to a consecutive MOVW/MOVT instruction pair. + PE_IMAGE_REL_BASED_RISCV_LOW12I = 7, // This relocation is only meaningful when the machine type is RISC-V. The base relocation applies to the low 12 bits of a 32-bit absolute address formed in RISC-V I-type instruction format. + PE_IMAGE_REL_BASED_RISCV_LOW12S = 8, // This relocation is only meaningful when the machine type is RISC-V. The base relocation applies to the low 12 bits of a 32-bit absolute address formed in RISC-V S-type instruction format. + PE_IMAGE_REL_BASED_MIPS_JMPADDR16 = 9, // The relocation is only meaningful when the machine type is MIPS. The base relocation applies to a MIPS16 jump instruction. + PE_IMAGE_REL_BASED_DIR64 = 10, // The base relocation applies the difference to the 64-bit field at offset. + MAX_PE_RELOCATION +}; + + +static const char* GetRelocationString(PeRelocationType relocType) +{ + static const char* relocTable[] = + { + "PE_IMAGE_REL_BASED_ABSOLUTE", + "PE_IMAGE_REL_BASED_HIGH", + "PE_IMAGE_REL_BASED_LOW", + "PE_IMAGE_REL_BASED_HIGHLOW", + "PE_IMAGE_REL_BASED_HIGHADJ", + "PE_IMAGE_REL_BASED_MIPS_JMPADDR", + "PE_IMAGE_REL_BASED_ARM_MOV32", + "PE_IMAGE_REL_BASED_RISCV_HIGH20", + "PE_IMAGE_REL_BASE_RESERVED", + "PE_IMAGE_REL_BASED_THUMB_MOV32", + "PE_IMAGE_REL_BASED_RISCV_LOW12I", + "PE_IMAGE_REL_BASED_RISCV_LOW12S", + "PE_IMAGE_REL_BASED_MIPS_JMPADDR16", + "PE_IMAGE_REL_BASED_DIR64" + }; + + if (relocType < MAX_PE_RELOCATION) + return relocTable[relocType]; + return "Unknown relocation"; +} + + +static const char* GetRelocationString(COFFx86RelocationType relocType) +{ + static const char* relocTable[] = + { + "PE_IMAGE_REL_I386_ABSOLUTE", + "PE_IMAGE_REL_I386_DIR16", + "PE_IMAGE_REL_I386_REL16", + "", "", "", + "PE_IMAGE_REL_I386_DIR32", + "PE_IMAGE_REL_I386_DIR32NB", + "", + "PE_IMAGE_REL_I386_SEG12", + "PE_IMAGE_REL_I386_SECTION", + "PE_IMAGE_REL_I386_SECREL", + "PE_IMAGE_REL_I386_TOKEN", + "PE_IMAGE_REL_I386_SECREL7", + "", "", "", "", "", "", + "PE_IMAGE_REL_I386_REL32", + }; + + if (relocType < MAX_PE_X86_RELOCATION) + return relocTable[relocType]; + return "Unknown x86 relocation"; +} + + +static const char* GetRelocationString(COFFx64RelocationType relocType) +{ + static const char* relocTable[] = + { + "PE_IMAGE_REL_AMD64_ABSOLUTE", + "PE_IMAGE_REL_AMD64_ADDR64", + "PE_IMAGE_REL_AMD64_ADDR32", + "PE_IMAGE_REL_AMD64_ADDR32NB", + "PE_IMAGE_REL_AMD64_REL32", + "PE_IMAGE_REL_AMD64_REL32_1", + "PE_IMAGE_REL_AMD64_REL32_2", + "PE_IMAGE_REL_AMD64_REL32_3", + "PE_IMAGE_REL_AMD64_REL32_4", + "PE_IMAGE_REL_AMD64_REL32_5", + "PE_IMAGE_REL_AMD64_SECTION", + "PE_IMAGE_REL_AMD64_SECREL", + "PE_IMAGE_REL_AMD64_SECREL7", + "PE_IMAGE_REL_AMD64_TOKEN", + "PE_IMAGE_REL_AMD64_SREL32", + "PE_IMAGE_REL_AMD64_PAIR", + "PE_IMAGE_REL_AMD64_SSPAN32", + }; + + if (relocType < MAX_PE_X64_RELOCATION) + return relocTable[relocType]; + return "Unknown x86_64 relocation"; +} + + +static const char* GetRelocationString(Elfx86RelocationType relocType) +{ + static const char* relocTable[] = + { + "R_386_NONE", + "R_386_32", + "R_386_PC32", + "R_386_GOT32", + "R_386_PLT32", + "R_386_COPY", + "R_386_GLOB_DAT", + "R_386_JUMP_SLOT", + "R_386_RELATIVE", + "R_386_GOTOFF", + "R_386_GOTPC", + "", + "", + "", + "R_386_TLS_TPOFF", + "R_386_TLS_IE", + "R_386_TLS_GOTIE", + "R_386_TLS_LE", + "R_386_TLS_GD", + "R_386_TLS_LDM", + "R_386_16", + "R_386_PC16", + "R_386_8", + "R_386_PC8", + "R_386_TLS_GD_32", + "R_386_TLS_GD_PUSH", + "R_386_TLS_GD_CALL", + "R_386_TLS_GD_POP", + "R_386_TLS_LDM_32", + "R_386_TLS_LDM_PUSH", + "R_386_TLS_LDM_CALL", + "R_386_TLS_LDM_POP", + "R_386_TLS_LDO_32", + "R_386_TLS_IE_32", + "R_386_TLS_LE_32", + "R_386_TLS_DTPMOD32", + "R_386_TLS_DTPOFF32", + "R_386_TLS_TPOFF32", + "R_386_SIZE32", + "R_386_TLS_GOTDESC", + "R_386_TLS_DESC_CALL", + "R_386_TLS_DESC", + "R_386_IRELATIVE", + }; + if (relocType < MAX_ELF_X86_RELOCATION) + return relocTable[relocType]; + return "Unknown x86 relocation"; +} + +static const char* GetRelocationString(Elfx64RelocationType relocType) +{ + static const char* relocTable[] = { + "R_X86_64_NONE", + "R_X86_64_64", + "R_X86_64_PC32", + "R_X86_64_GOT32", + "R_X86_64_PLT32", + "R_X86_64_COPY", + "R_X86_64_GLOB_DAT", + "R_X86_64_JUMP_SLOT", + "R_X86_64_RELATIVE", + "R_X86_64_GOTPCREL", + "R_X86_64_32", + "R_X86_64_32S", + "R_X86_64_16", + "R_X86_64_PC16", + "R_X86_64_8", + "R_X86_64_PC8", + "R_X86_64_DTPMOD64", + "R_X86_64_DTPOFF64", + "R_X86_64_TPOFF64", + "R_X86_64_TLSGD", + "R_X86_64_TLSLD", + "R_X86_64_DTPOFF32", + "R_X86_64_GOTTPOFF", + "R_X86_64_TPOFF32", + "R_X86_64_PC64", + "R_X86_64_GOTOFF64", + "R_X86_64_GOTPC32", + "R_X86_64_UNKNOWN27", + "R_X86_64_UNKNOWN28", + "R_X86_64_UNKNOWN29", + "R_X86_64_UNKNOWN30", + "R_X86_64_UNKNOWN31", + "R_X86_64_SIZE32", + "R_X86_64_SIZE64", + "R_X86_64_GOTPC32_TLSDESC", + "R_X86_64_TLSDESC_CALL", + "R_X86_64_TLSDESC", + "R_X86_64_IRELATIVE", + "R_X86_64_RELATIVE64", + "R_X86_64_PC32_BND", + "R_X86_64_PLT32_BND", + "R_X86_64_GOTPCRELX", + "R_X86_64_REX_GOTPCRELX"}; + if (relocType < MAX_ELF_X64_RELOCATION) + return relocTable[relocType]; + return "Unknown x86_64 relocation"; +} + +static const char* GetRelocationString(Machox86RelocationType relocType) +{ + static const char* relocTable[] = { + "GENERIC_RELOC_VANILLA", + "GENERIC_RELOC_PAIR", + "GENERIC_RELOC_SECTDIFF", + "GENERIC_RELOC_PB_LA_PTR", + "GENERIC_RELOC_LOCAL_SECTDIFF", + "GENERIC_RELOC_TLV", + }; + if (relocType < MACHO_MAX_X86_RELOCATION) + return relocTable[relocType]; + return "Unknown x86 relocation"; +} + +static const char* GetRelocationString(Machox64RelocationType relocType) +{ + static const char* relocTable[] = { + "X86_64_RELOC_UNSIGNED", + "X86_64_RELOC_SIGNED", + "X86_64_RELOC_BRANCH", + "X86_64_RELOC_GOT_LOAD", + "X86_64_RELOC_GOT", + "X86_64_RELOC_SUBTRACTOR", + "X86_64_RELOC_SIGNED_1", + "X86_64_RELOC_SIGNED_2", + "X86_64_RELOC_SIGNED_4", + "X86_64_RELOC_TLV" + }; + if (relocType < MACHO_MAX_X86_64_RELOCATION) + return relocTable[relocType]; + return "Unknown x64 relocation"; +} + + +bool X86CommonArchitecture::Decode(const uint8_t* data, size_t len, xed_decoded_inst_t* xedd) +{ + // Zero out structure data, and keep the current destructuring mode (32/64/etc) + xed_decoded_inst_zero_keep_mode(xedd); + + xed3_operand_set_cet(xedd, 1); + xed3_operand_set_mpxmode(xedd, 1); + + // Decode the data and check for errors + xed_error_enum_t xed_error = xed_decode(xedd, data, (unsigned)len); + switch(xed_error) + { + case XED_ERROR_NONE: + return true; + default: + return false; + } +} + +size_t X86CommonArchitecture::GetAddressSizeBits() const +{ + return GetAddressSize() * 8; +} + +uint64_t X86CommonArchitecture::GetAddressMask() const +{ + if (GetAddressSizeBits() == 64) + return (uint64_t)-1; + return (((uint64_t)1) << GetAddressSizeBits()) - 1; +} + +void X86CommonArchitecture::SetInstructionInfoForInstruction(uint64_t addr, InstructionInfo& result, xed_decoded_inst_t* xedd) +{ + result.length = xed_decoded_inst_get_length(xedd); + + const uint64_t abs_br = xed_decoded_inst_get_branch_displacement(xedd) + addr + xed_decoded_inst_get_length(xedd); + const xed_iform_enum_t xedd_iForm = xed_decoded_inst_get_iform_enum(xedd); + const xed_iclass_enum_t xedd_iClass = xed_decoded_inst_get_iclass(xedd); + const uint64_t immediateOne = xed_decoded_inst_get_unsigned_immediate(xedd); + // 1. First parse 'generally', by instruction category, then + // 2. break down to special cases and impliment iclass and possibly iform-specific cases + + switch (xed_decoded_inst_get_category(xedd)) + { + case XED_CATEGORY_CALL: + // CALL instruction with an immediate as the first operand and it's not the next instruction + if ((abs_br != addr+result.length) && ((xedd_iForm == XED_IFORM_CALL_NEAR_RELBRz) || (xedd_iForm == XED_IFORM_CALL_NEAR_RELBRd))) + result.AddBranch(CallDestination, abs_br); + break; + + case XED_CATEGORY_UNCOND_BR: + if (xed_operand_name(xed_inst_operand(xed_decoded_inst_inst(xedd), 0)) == XED_OPERAND_RELBR) + result.AddBranch(UnconditionalBranch, abs_br); + else + result.AddBranch(UnresolvedBranch); + break; + + case XED_CATEGORY_COND_BR: + result.AddBranch(TrueBranch, abs_br); + result.AddBranch(FalseBranch, addr + result.length); + break; + + case XED_CATEGORY_INTERRUPT: + if (xed_decoded_inst_get_unsigned_immediate(xedd) == 0x80) + result.AddBranch(SystemCall); + else if (xedd_iClass == XED_ICLASS_INT3 || (xedd_iClass == XED_ICLASS_INT && immediateOne == 0x29)) + result.AddBranch(ExceptionBranch); + break; + + case XED_CATEGORY_SYSCALL: + result.AddBranch(SystemCall); + break; + + case XED_CATEGORY_SYSRET: + result.AddBranch(FunctionReturn); + break; + + case XED_CATEGORY_RET: + result.AddBranch(FunctionReturn); + break; + + default: + switch (xedd_iClass) + { + // case XED_ICLASS_UD0: + // case XED_ICLASS_UD1: + case XED_ICLASS_UD2: + case XED_ICLASS_HLT: + result.AddBranch(ExceptionBranch); + break; + + default: + break; + } + break; + } +} + +bool X86CommonArchitecture::IsConditionalJump(xed_decoded_inst_t* xedd) +{ + return (xed_decoded_inst_get_category(xedd) == XED_CATEGORY_COND_BR); +} + +string X86CommonArchitecture::GetSizeString(const size_t size) const +{ + switch (size) + { + case 1: + return "byte "; + case 2: + return "word "; + case 4: + return "dword "; + case 8: + return "qword "; + case 10: + return "tword "; + case 16: + return "oword "; + default: + return ""; + } +} + +BNRegisterInfo X86CommonArchitecture::RegisterInfo(xed_reg_enum_t fullWidthReg, size_t offset, size_t size, bool zeroExtend) +{ + BNRegisterInfo result; + result.fullWidthRegister = fullWidthReg; + result.offset = offset; + result.size = size; + result.extend = zeroExtend ? ZeroExtendToFullWidth : NoExtend; + return result; +} + +void X86CommonArchitecture::GetAddressSizeToken(const short bytes, vector<InstructionTextToken>& result, const bool lowerCase) +{ + // Size + switch (bytes) + { + case 1: + if (lowerCase) + result.emplace_back(BeginMemoryOperandToken,"byte "); + else + result.emplace_back(BeginMemoryOperandToken,"BYTE "); + break; + case 2: + if (lowerCase) + result.emplace_back(BeginMemoryOperandToken,"word "); + else + result.emplace_back(BeginMemoryOperandToken,"WORD "); + break; + case 4: + if (lowerCase) + result.emplace_back(BeginMemoryOperandToken,"dword "); + else + result.emplace_back(BeginMemoryOperandToken,"DWORD "); + break; + case 8: + if (lowerCase) + result.emplace_back(BeginMemoryOperandToken,"qword "); + else + result.emplace_back(BeginMemoryOperandToken,"QWORD "); + break; + case 10: + if (lowerCase) + result.emplace_back(BeginMemoryOperandToken,"tword "); + else + result.emplace_back(BeginMemoryOperandToken,"TWORD "); + break; + case 16: + if (lowerCase) + result.emplace_back(BeginMemoryOperandToken,"xmmword "); + else + result.emplace_back(BeginMemoryOperandToken,"XMMWORD "); + break; + case 32: + if (lowerCase) + result.emplace_back(BeginMemoryOperandToken,"ymmword "); + else + result.emplace_back(BeginMemoryOperandToken,"YMMWORD "); + break; + case 64: + if (lowerCase) + result.emplace_back(BeginMemoryOperandToken,"zmmword "); + else + result.emplace_back(BeginMemoryOperandToken,"ZMMWORD "); + break; + default: + break; + } +} + +unsigned short X86CommonArchitecture::GetInstructionOpcode(const xed_decoded_inst_t* const xedd, const xed_operand_values_t* const ov, vector<InstructionTextToken>& result) const +{ + string opcode = ""; + if (xed_decoded_inst_has_mpx_prefix(xedd)) + opcode += "BND "; + if (xed_decoded_inst_is_xacquire(xedd)) + opcode += "XACQUIRE "; + if (xed_decoded_inst_is_xrelease(xedd)) + opcode += "XRELEASE "; + if (xed_operand_values_has_lock_prefix(ov)) + opcode += "LOCK "; + if (xed_operand_values_has_real_rep(ov)) + { + if (xed_operand_values_has_rep_prefix(ov)) + opcode += "REP "; + if (xed_operand_values_has_repne_prefix(ov)) + opcode += "REPNE "; + } + else if (xed_operand_values_branch_not_taken_hint(ov)) + opcode += "HINT-NOT-TAKEN "; + else if (xed_operand_values_branch_taken_hint(ov)) + opcode += "HINT-TAKEN "; + + switch (m_disassembly_options.df) + { + case DF_INTEL: + opcode += string(xed_iform_to_iclass_string_intel(xed_decoded_inst_get_iform_enum(xedd))); + break; + case DF_BN_INTEL: + // To match asmx86 disassembly + switch (xed_decoded_inst_get_iclass(xedd)) + { + case XED_ICLASS_RET_NEAR: + opcode += "RETN"; + break; + case XED_ICLASS_JZ: + opcode += "JE"; + break; + case XED_ICLASS_JNZ: + opcode += "JNE"; + break; + case XED_ICLASS_JNB: + opcode += "JAE"; + break; + case XED_ICLASS_JNBE: + opcode += "JA"; + break; + case XED_ICLASS_JP: + opcode += "JPE"; + break; + case XED_ICLASS_JNP: + opcode += "JPO"; + break; + case XED_ICLASS_JNL: + opcode += "JGE"; + break; + case XED_ICLASS_JNLE: + opcode += "JG"; + break; + + case XED_ICLASS_SETNB: + opcode += "SETAE"; + break; + case XED_ICLASS_SETZ: + opcode += "SETE"; + break; + case XED_ICLASS_SETNZ: + opcode += "SETNE"; + break; + case XED_ICLASS_SETNBE: + opcode += "SETA"; + break; + case XED_ICLASS_SETP: + opcode += "SETPE"; + break; + case XED_ICLASS_SETNP: + opcode += "SETPO"; + break; + case XED_ICLASS_SETNL: + opcode += "SETGE"; + break; + case XED_ICLASS_SETNLE: + opcode += "SETG"; + break; + + case XED_ICLASS_CMOVNB: + opcode += "CMOVAE"; + break; + case XED_ICLASS_CMOVZ: + opcode += "CMOVE"; + break; + case XED_ICLASS_CMOVNZ: + opcode += "CMOVNE"; + break; + case XED_ICLASS_CMOVNBE: + opcode += "CMOVA"; + break; + case XED_ICLASS_CMOVP: + opcode += "CMOVPE"; + break; + case XED_ICLASS_CMOVNP: + opcode += "CMOVPO"; + break; + case XED_ICLASS_CMOVNL: + opcode += "CMOVGE"; + break; + case XED_ICLASS_CMOVNLE: + opcode += "CMOVG"; + break; + + default: + opcode += string(xed_iform_to_iclass_string_intel(xed_decoded_inst_get_iform_enum(xedd))); + } + break; + case DF_ATT: + opcode += string(xed_iform_to_iclass_string_att(xed_decoded_inst_get_iform_enum(xedd))); + break; + case DF_XED: + opcode += string(xed_iclass_enum_t2str(xed_decoded_inst_get_iclass(xedd))); + break; + default: + LogError("Invalid Disassembly Flavor"); + } + + if (m_disassembly_options.lowerCase) + for (char& c : opcode) + c = tolower(c); + else + for (char& c : opcode) + c = toupper(c); + + result.emplace_back(InstructionToken, opcode); + + return (unsigned short)opcode.length(); +} + +void X86CommonArchitecture::GetInstructionPadding(const unsigned int instruction_name_length, vector<InstructionTextToken>& result) const +{ + string padding = ""; + const short min = 7 < instruction_name_length ? 7 : instruction_name_length; + for (unsigned short delim = 0; delim < (8 - min); ++delim) + padding += ' '; + result.emplace_back(TextToken, padding); +} + +// (in theory) Exactly how XED wants the world to see x86 +void X86CommonArchitecture::GetOperandTextIntel(const xed_decoded_inst_t* const xedd, const uint64_t addr, const size_t len, const xed_operand_values_t* const ov, const xed_inst_t* const xi, vector<InstructionTextToken>& result) const +{ + xed_reg_enum_t extra_index_operand = XED_REG_INVALID; + + // Get operands + for (unsigned int opIndex = 0; opIndex < xed_inst_noperands(xi); ++opIndex) + { + const xed_operand_t* op = xed_inst_operand(xi, opIndex); + const xed_operand_enum_t op_name = xed_operand_name(op); + + // XED's suppressed operands shouln't be represented in Intel syntax + if (xed_operand_operand_visibility(op) == XED_OPVIS_SUPPRESSED) + { + if ((xed_decoded_inst_get_category(xedd) == XED_CATEGORY_STRINGOP) && + (op_name == XED_OPERAND_MEM0 || op_name == XED_OPERAND_MEM1)) + { + if (op_name == XED_OPERAND_MEM1) + result.emplace_back(OperandSeparatorToken, m_disassembly_options.separator); + } + else + continue; + } + + switch(op_name) + { + case XED_OPERAND_REG0: + case XED_OPERAND_REG1: + case XED_OPERAND_REG2: + case XED_OPERAND_REG3: + case XED_OPERAND_REG4: + case XED_OPERAND_REG5: + case XED_OPERAND_REG6: + case XED_OPERAND_REG7: + case XED_OPERAND_REG8: + { + string reg = ""; + + const xed_reg_enum_t xedReg = xed_decoded_inst_get_reg(xedd, op_name); + if ((xedReg >= XED_REG_X87_FIRST) && (xedReg <= XED_REG_X87_LAST)) + { + reg += "ST"; + reg += ('0' + (xedReg-XED_REG_X87_FIRST)); + } + else + { + reg += xed_reg_enum_t2str(xedReg); + } + if (m_disassembly_options.lowerCase) + for (char& c : reg) + c = tolower(c); + result.emplace_back(RegisterToken, reg); + break; + } + case XED_OPERAND_AGEN: + case XED_OPERAND_MEM0: + { + GetAddressSizeToken(xed_decoded_inst_operand_length_bits(xedd, opIndex) / 8, result, m_disassembly_options.lowerCase); + + if (m_disassembly_options.lowerCase) + result.emplace_back(TextToken, "ptr "); + else + result.emplace_back(TextToken, "PTR "); + result.emplace_back(TextToken, "["); + + // Segment + const xed_reg_enum_t seg = xed_decoded_inst_get_seg_reg(xedd, 0); + const bool validSegment = (seg != XED_REG_INVALID && !xed_operand_values_using_default_segment(ov, 0)); + if (validSegment) + { + string seg_str(xed_reg_enum_t2str(seg)); + if (m_disassembly_options.lowerCase) + for (char& c : seg_str) + c = tolower(c); + result.emplace_back(RegisterToken, seg_str); + result.emplace_back(TextToken, ":"); + } + + bool started = false; + const xed_reg_enum_t base = xed_decoded_inst_get_base_reg(xedd, 0); + + int64_t disp = xed_decoded_inst_get_memory_displacement(xedd, 0); + + if ((base != XED_REG_INVALID) && !((base == XED_REG_RIP) || (base == XED_REG_EIP) || (base == XED_REG_IP))) + { + string base_str(xed_reg_enum_t2str(base)); + if (m_disassembly_options.lowerCase) + for (char& c : base_str) + c = tolower(c); + result.emplace_back(RegisterToken, base_str); + started = true; + } + else if ((base == XED_REG_RIP) || (base == XED_REG_EIP) || (base == XED_REG_IP)) + { + if (xed_operand_values_has_memory_displacement(ov)) + disp += addr + len; + else + disp = addr + len; + + stringstream sstream; + if (m_disassembly_options.lowerCase) + sstream << "0x" << hex << nouppercase << disp; + else + sstream << "0x" << hex << uppercase << disp; + + result.emplace_back(CodeRelativeAddressToken, sstream.str(), disp, GetAddressSize()); + + result.emplace_back(EndMemoryOperandToken, "]"); + break; + } + + const xed_reg_enum_t index = xed_decoded_inst_get_index_reg(xedd, 0); + if (index != XED_REG_INVALID) + { + if (xed_decoded_inst_get_attribute(xedd, XED_ATTRIBUTE_INDEX_REG_IS_POINTER)) + { + // MPX BNDLDX/BNDSTX instr are unusual in that they use + // the index reg as distinct operand. + extra_index_operand = index; + } + else // normal path + { + if (started) + result.emplace_back(TextToken, "+"); + started = true; + + string index_str(xed_reg_enum_t2str(index)); + if (m_disassembly_options.lowerCase) + for (char& c : index_str) + c = tolower(c); + + result.emplace_back(RegisterToken, index_str); + + const unsigned int scale = xed_decoded_inst_get_scale(xedd, 0); + if (scale != 1) + { + result.emplace_back(TextToken, "*"); + stringstream sstream; + sstream << scale; + result.emplace_back(IntegerToken, sstream.str(), scale, 1); + } + } + } + + const unsigned short disp_bytes = xed_decoded_inst_get_memory_displacement_width_bits(xedd, 0) / 8; + + if (xed_operand_values_has_memory_displacement(ov) && + ((disp != 0) || (!started && validSegment))) + { + stringstream sstream; + sstream << "0x" << hex; + if (m_disassembly_options.lowerCase) + sstream << nouppercase; + else + sstream << uppercase; + + if (started) + { + if (disp < 0) + { + result.emplace_back(TextToken, "-"); + disp = -disp; + } + else + result.emplace_back(TextToken, "+"); + + if (disp_bytes == 2) + sstream << (uint16_t)disp; + else if (disp_bytes == 4) + sstream << (uint32_t)disp; + else if (disp_bytes == 8) + sstream << (uint64_t)disp; + else + sstream << disp; + result.emplace_back(IntegerToken, sstream.str(), disp, disp_bytes); + } + else + { + sstream << disp; + + if (validSegment) + result.emplace_back(IntegerToken, sstream.str(), disp, GetAddressSize()); + else + result.emplace_back(PossibleAddressToken, sstream.str(), disp, GetAddressSize()); + } + } + else if (xed_operand_values_has_memory_displacement(ov) && + ((disp == 0) && (!started))) + { + result.emplace_back(IntegerToken, "0x0", disp, GetAddressSize()); + } + result.emplace_back(EndMemoryOperandToken, "]"); + + break; + } + case XED_OPERAND_MEM1: + { + GetAddressSizeToken(xed_decoded_inst_operand_length_bits(xedd, opIndex) / 8, result, m_disassembly_options.lowerCase); + + if (m_disassembly_options.lowerCase) + result.emplace_back(TextToken, "ptr "); + else + result.emplace_back(TextToken, "PTR "); + + // Segment + const xed_reg_enum_t seg = xed_decoded_inst_get_seg_reg(xedd, 1); + if (seg != XED_REG_INVALID && !xed_operand_values_using_default_segment(ov, 1)) + { + string seg_str(xed_reg_enum_t2str(seg)); + if (m_disassembly_options.lowerCase) + for (char& c : seg_str) + c = tolower(c); + result.emplace_back(RegisterToken, seg_str); + + result.emplace_back(TextToken, ":"); + } + + result.emplace_back(TextToken, "["); + const xed_reg_enum_t base = xed_decoded_inst_get_base_reg(xedd, 1); + if (base != XED_REG_INVALID) + { + string base_str(xed_reg_enum_t2str(base)); + if (m_disassembly_options.lowerCase) + for (char& c : base_str) + c = tolower(c); + result.emplace_back(RegisterToken, base_str); + } + result.emplace_back(EndMemoryOperandToken, "]"); + + break; + } + case XED_OPERAND_IMM0: + { + const size_t addrSize = xed_decoded_inst_get_machine_mode_bits(xedd) / 8; + const unsigned int immediateSize = xed_decoded_inst_get_operand_width(xedd) / 8; + + stringstream sstream; + sstream << "0x" << hex; + if (m_disassembly_options.lowerCase) + sstream << nouppercase; + else + sstream << uppercase; + + if (xed_decoded_inst_get_immediate_is_signed(xedd) && (immediateSize != 1)) + { + const int64_t immediateValue = xed_decoded_inst_get_signed_immediate(xedd); + + if (immediateValue >= 0) + sstream << immediateValue; // Don't zero extend + else + { + // I'm not proud of this switch statement... It was the product of a lot of pain. + switch (immediateSize) // For sign extentions + { + case 1: + sstream << (int8_t)immediateValue; + break; + case 2: + sstream << (int16_t)immediateValue; + break; + case 4: + sstream << (int32_t)immediateValue; + break; + default: + sstream << (int64_t)immediateValue; + } + } + + if (immediateSize == addrSize) + result.emplace_back(PossibleAddressToken, sstream.str(), immediateValue, immediateSize); + else + result.emplace_back(IntegerToken, sstream.str(), immediateValue, immediateSize); + } + else + { + const uint64_t immediateValue = xed_decoded_inst_get_unsigned_immediate(xedd); + sstream << immediateValue; + if (immediateSize == addrSize) + result.emplace_back(PossibleAddressToken, sstream.str(), immediateValue, immediateSize); + else + result.emplace_back(IntegerToken, sstream.str(), immediateValue, immediateSize); + } + break; + } + case XED_OPERAND_IMM1: // The ENTER instruction + { + stringstream sstream; + sstream << "0x" << hex; + if (m_disassembly_options.lowerCase) + sstream << nouppercase; + else + sstream << uppercase; + + sstream << (uint16_t)xed_decoded_inst_get_second_immediate(xedd); + result.emplace_back(IntegerToken, sstream.str(), xed_decoded_inst_get_second_immediate(xedd), 1); + break; + } + case XED_OPERAND_PTR: // TODO...remove? + { + stringstream sstream; + sstream << "0x" << hex; + if (m_disassembly_options.lowerCase) + sstream << nouppercase; + else + sstream << uppercase; + + sstream << xed_decoded_inst_get_branch_displacement(xedd); + result.emplace_back(PossibleAddressToken, sstream.str(), xed_decoded_inst_get_branch_displacement(xedd), 8); + break; + } + case XED_OPERAND_RELBR: + { + const int64_t relbr = xed_decoded_inst_get_branch_displacement(xedd) + addr + xed_decoded_inst_get_length(xedd); + + stringstream sstream; + sstream << "0x" << hex; + if (m_disassembly_options.lowerCase) + sstream << nouppercase; + else + sstream << uppercase; + + sstream << relbr; + result.emplace_back(CodeRelativeAddressToken, sstream.str(), relbr, 8); + break; + } + default: + { + result.emplace_back(TextToken, "unimplimented"); + } // default case of outer switch + } // outer switch + + // If there is another operand and it is visable, print delimiter + if ((opIndex != xed_inst_noperands(xi)-1) && + ((xed_operand_operand_visibility(xed_inst_operand(xi, opIndex+1)) == XED_OPVIS_EXPLICIT) || + (xed_operand_operand_visibility(xed_inst_operand(xi, opIndex+1)) == XED_OPVIS_IMPLICIT))) + result.emplace_back(OperandSeparatorToken, m_disassembly_options.separator); + } + + if (extra_index_operand != XED_REG_INVALID) + { + result.emplace_back(OperandSeparatorToken, m_disassembly_options.separator); + string reg = xed_reg_enum_t2str(extra_index_operand); + if (m_disassembly_options.lowerCase) + for (char& c : reg) + c = tolower(c); + result.emplace_back(RegisterToken, reg); + } +} + +// The syntax used by asmx86, that users are used to (also the only one that should be garenteed to roundtrip with asm) +void X86CommonArchitecture::GetOperandTextBNIntel(const xed_decoded_inst_t* const xedd, const uint64_t addr, const size_t len, const xed_operand_values_t* const ov, const xed_inst_t* const xi, vector<InstructionTextToken>& result) const +{ + xed_reg_enum_t extra_index_operand = XED_REG_INVALID; + + // Get operands + for (unsigned int opIndex = 0; opIndex < xed_inst_noperands(xi); ++opIndex) + { + const xed_operand_t* op = xed_inst_operand(xi, opIndex); + const xed_operand_enum_t op_name = xed_operand_name(op); + + // XED's suppressed operands shouln't be represented in Intel syntax + if (xed_operand_operand_visibility(op) == XED_OPVIS_SUPPRESSED) + { + if ((xed_decoded_inst_get_category(xedd) == XED_CATEGORY_STRINGOP) && + (op_name == XED_OPERAND_MEM0 || op_name == XED_OPERAND_MEM1)) + { + if (op_name == XED_OPERAND_MEM1) + result.emplace_back(OperandSeparatorToken, m_disassembly_options.separator); + } + else + continue; + } + + switch(op_name) + { + case XED_OPERAND_REG0: + case XED_OPERAND_REG1: + case XED_OPERAND_REG2: + case XED_OPERAND_REG3: + case XED_OPERAND_REG4: + case XED_OPERAND_REG5: + case XED_OPERAND_REG6: + case XED_OPERAND_REG7: + case XED_OPERAND_REG8: + { + string reg = ""; + + const xed_reg_enum_t xedReg = xed_decoded_inst_get_reg(xedd, op_name); + if ((xedReg >= XED_REG_X87_FIRST) && (xedReg <= XED_REG_X87_LAST)) + { + reg += "ST"; + reg += ('0' + (xedReg - XED_REG_X87_FIRST)); + } + // As of July 2020, the XED now outputs these registers as mm0, etc. + // However, to maintain backward-compatibility, we need to make them mmx0, etc, + // as they previously are + else if ((xedReg >= XED_REG_MMX0) && (xedReg <= XED_REG_MMX1)) + { + reg += "MMX"; + reg += ('0' + (xedReg - XED_REG_MMX0)); + } + else + { + reg += xed_reg_enum_t2str(xedReg); + } + + if (m_disassembly_options.lowerCase) + for (char& c : reg) + c = tolower(c); + + result.emplace_back(RegisterToken, reg); + + // handle the {z} modifier + if (XED_REG_K1 <= xedReg && xedReg <= XED_REG_K7) + { + if(xed_decoded_inst_zeroing(xedd)) + { + if (m_disassembly_options.lowerCase) + result.emplace_back(TextToken, " {z}"); + else + result.emplace_back(TextToken, " {Z}"); + } + } + + break; + } + case XED_OPERAND_AGEN: + case XED_OPERAND_MEM0: + { + // Size + if (xed_inst_iclass(xi) != XED_ICLASS_LEA) + GetAddressSizeToken(xed_decoded_inst_operand_length_bits(xedd, opIndex) / 8, result, m_disassembly_options.lowerCase); + + result.emplace_back(TextToken, "["); + // Segment + const xed_reg_enum_t seg = xed_decoded_inst_get_seg_reg(xedd, 0); + const bool validSegment = (seg != XED_REG_INVALID && !xed_operand_values_using_default_segment(ov, 0)); + if (validSegment) + { + string seg_str(xed_reg_enum_t2str(seg)); + if (m_disassembly_options.lowerCase) + for (char& c : seg_str) + c = tolower(c); + result.emplace_back(RegisterToken, seg_str); + result.emplace_back(TextToken, ":"); + } + + bool started = false; + xed_reg_enum_t base = xed_decoded_inst_get_base_reg(xedd, 0); + + int64_t disp = xed_decoded_inst_get_memory_displacement(xedd, 0); + + if ((base != XED_REG_INVALID) && !((base == XED_REG_RIP) || (base == XED_REG_EIP) || (base == XED_REG_IP))) + { + string base_str(xed_reg_enum_t2str(base)); + if (m_disassembly_options.lowerCase) + for (char& c : base_str) + c = tolower(c); + result.emplace_back(RegisterToken, base_str); + started = true; + } + else if ((base == XED_REG_RIP) || (base == XED_REG_EIP) || (base == XED_REG_IP)) + { + if (m_disassembly_options.lowerCase) + result.emplace_back(TextToken, "rel "); + else + result.emplace_back(TextToken, "REL "); + + if (xed_operand_values_has_memory_displacement(ov)) + disp += addr + len; + else + disp = addr + len; + + stringstream sstream; + if (m_disassembly_options.lowerCase) + sstream << "0x" << hex << nouppercase << disp; + else + sstream << "0x" << hex << uppercase << disp; + + result.emplace_back(CodeRelativeAddressToken, sstream.str(), disp, GetAddressSize()); + + result.emplace_back(EndMemoryOperandToken, "]"); + break; + } + + const xed_reg_enum_t index = xed_decoded_inst_get_index_reg(xedd, 0); + if (index != XED_REG_INVALID) + { + if (xed_decoded_inst_get_attribute(xedd, XED_ATTRIBUTE_INDEX_REG_IS_POINTER)) + { + // MPX BNDLDX/BNDSTX instr are unusual in that they use + // the index reg as distinct operand. + extra_index_operand = index; + } + else // normal path + { + if (started) + result.emplace_back(TextToken, "+"); + started = true; + + string index_str(xed_reg_enum_t2str(index)); + if (m_disassembly_options.lowerCase) + for (char& c : index_str) + c = tolower(c); + + result.emplace_back(RegisterToken, index_str); + + const unsigned int scale = xed_decoded_inst_get_scale(xedd, 0); + if (scale != 1) + { + result.emplace_back(TextToken, "*"); + stringstream sstream; + sstream << scale; + result.emplace_back(IntegerToken, sstream.str(), scale, 1); + } + } + } + + const unsigned short disp_bytes = xed_decoded_inst_get_memory_displacement_width_bits(xedd, 0) / 8; + + if (xed_operand_values_has_memory_displacement(ov) && + ((disp != 0) || (!started && validSegment))) + { + stringstream sstream; + sstream << "0x" << hex; + if (m_disassembly_options.lowerCase) + sstream << nouppercase; + else + sstream << uppercase; + + if (started) + { + if (disp < 0) + { + result.emplace_back(TextToken, "-"); + disp = -disp; + } + else + result.emplace_back(TextToken, "+"); + + if (disp_bytes == 2) + sstream << (uint16_t)disp; + else if (disp_bytes == 4) + sstream << (uint32_t)disp; + else if (disp_bytes == 8) + sstream << (uint64_t)disp; + else + sstream << disp; + result.emplace_back(IntegerToken, sstream.str(), disp, disp_bytes); + } + else + { + sstream << disp; + + if (validSegment) + result.emplace_back(IntegerToken, sstream.str(), disp, GetAddressSize()); + else + result.emplace_back(PossibleAddressToken, sstream.str(), disp, GetAddressSize()); + } + } + else if (xed_operand_values_has_memory_displacement(ov) && + ((disp == 0) && (!started))) + { + result.emplace_back(IntegerToken, "0x0", disp, GetAddressSize()); + } + + result.emplace_back(EndMemoryOperandToken, "]"); + + break; + } + case XED_OPERAND_MEM1: + { + + + // Segment + const xed_reg_enum_t seg = xed_decoded_inst_get_seg_reg(xedd, 1); + if (seg != XED_REG_INVALID && !xed_operand_values_using_default_segment(ov, 1)) + { + string seg_str(xed_reg_enum_t2str(seg)); + if (m_disassembly_options.lowerCase) + for (char& c : seg_str) + c = tolower(c); + result.emplace_back(RegisterToken, seg_str); + + result.emplace_back(TextToken, ":"); + } + + result.emplace_back(TextToken, "["); + const xed_reg_enum_t base = xed_decoded_inst_get_base_reg(xedd, 1); + if (base != XED_REG_INVALID) + { + string base_str(xed_reg_enum_t2str(base)); + if (m_disassembly_options.lowerCase) + for (char& c : base_str) + c = tolower(c); + result.emplace_back(RegisterToken, base_str); + } + result.emplace_back(EndMemoryOperandToken, "]"); + + break; + } + case XED_OPERAND_IMM0: + { + const size_t addrSize = xed_decoded_inst_get_machine_mode_bits(xedd) / 8; + const unsigned int immediateSize = xed_decoded_inst_get_operand_width(xedd) / 8; + + stringstream sstream; + sstream << "0x" << hex; + if (m_disassembly_options.lowerCase) + sstream << nouppercase; + else + sstream << uppercase; + + if (xed_decoded_inst_get_immediate_is_signed(xedd) && (immediateSize != 1)) + { + const int64_t immediateValue = xed_decoded_inst_get_signed_immediate(xedd); + + if (immediateValue >= 0) + sstream << immediateValue; // Don't zero extend + else + { + // I'm not proud of this switch statement... It was the product of a lot of pain. + switch (immediateSize) // For sign extentions + { + case 1: + sstream << (int8_t)immediateValue; + break; + case 2: + sstream << (int16_t)immediateValue; + break; + case 4: + sstream << (int32_t)immediateValue; + break; + default: + sstream << (int64_t)immediateValue; + } + } + + if (immediateSize == addrSize) + result.emplace_back(PossibleAddressToken, sstream.str(), immediateValue, immediateSize); + else + result.emplace_back(IntegerToken, sstream.str(), immediateValue, immediateSize); + } + else + { + const uint64_t immediateValue = xed_decoded_inst_get_unsigned_immediate(xedd); + sstream << immediateValue; + if (immediateSize == addrSize) + result.emplace_back(PossibleAddressToken, sstream.str(), immediateValue, immediateSize); + else + result.emplace_back(IntegerToken, sstream.str(), immediateValue, immediateSize); + } + break; + } + case XED_OPERAND_IMM1: // The ENTER instruction + { + stringstream sstream; + sstream << "0x" << hex; + if (m_disassembly_options.lowerCase) + sstream << nouppercase; + else + sstream << uppercase; + + sstream << (uint16_t)xed_decoded_inst_get_second_immediate(xedd); + result.emplace_back(IntegerToken, sstream.str(), xed_decoded_inst_get_second_immediate(xedd), 1); + break; + } + case XED_OPERAND_PTR: + { + stringstream sstream; + sstream << "0x" << hex; + if (m_disassembly_options.lowerCase) + sstream << nouppercase; + else + sstream << uppercase; + + sstream << xed_decoded_inst_get_branch_displacement(xedd); + result.emplace_back(PossibleAddressToken, sstream.str(), xed_decoded_inst_get_branch_displacement(xedd), 8); + break; + } + case XED_OPERAND_RELBR: + { + const int64_t relbr = xed_decoded_inst_get_branch_displacement(xedd) + addr + xed_decoded_inst_get_length(xedd); + + stringstream sstream; + if ((xed_decoded_inst_get_iclass(xedd) == XED_ICLASS_CALL_NEAR) && (relbr == (int64_t)(addr + xed_decoded_inst_get_length(xedd)))) + { + sstream << "$+" << xed_decoded_inst_get_length(xedd); + result.emplace_back(TextToken, sstream.str()); + break; + } + + sstream << "0x" << hex; + if (m_disassembly_options.lowerCase) + sstream << nouppercase; + else + sstream << uppercase; + + sstream << relbr; + result.emplace_back(CodeRelativeAddressToken, sstream.str(), relbr, 8); + break; + } + default: + { + if (m_disassembly_options.lowerCase) + result.emplace_back(TextToken, "unimplimented "); + else + result.emplace_back(TextToken, "UNIMPLIMENTED "); + } // default case of outer switch + } // outer switch + + // If there is another operand and it is visable, print delimiter + if ((opIndex != xed_inst_noperands(xi)-1) && + ((xed_operand_operand_visibility(xed_inst_operand(xi, opIndex+1)) == XED_OPVIS_EXPLICIT) || + (xed_operand_operand_visibility(xed_inst_operand(xi, opIndex+1)) == XED_OPVIS_IMPLICIT))) + result.emplace_back(OperandSeparatorToken, m_disassembly_options.separator); + } + + if (extra_index_operand != XED_REG_INVALID) + { + result.emplace_back(OperandSeparatorToken, m_disassembly_options.separator); + string reg = xed_reg_enum_t2str(extra_index_operand); + if (m_disassembly_options.lowerCase) + for (char& c : reg) + c = tolower(c); + result.emplace_back(RegisterToken, reg); + } +} + +void X86CommonArchitecture::GetOperandTextATT(const xed_decoded_inst_t* const xedd, const uint64_t addr, const size_t len, const xed_operand_values_t* const ov, const xed_inst_t* const xi, vector<InstructionTextToken>& result) const +{ + unsigned i,j; + unsigned noperands = xed_inst_noperands(xi); + + bool intel_way = false; + + if (xed_inst_get_attribute(xi, XED_ATTRIBUTE_ATT_OPERAND_ORDER_EXCEPTION)) + intel_way = true; + + // if (xed_decoded_inst_get_attribute(xedd, XED_ATTRIBUTE_INDEX_REG_IS_POINTER)) + // { + // for(j=0; j<noperands; ++j) + // { + // i = noperands - j - 1; // never intel_way + + // if(xed_operand_name(xed_inst_operand(xi,i)) == XED_OPERAND_MEM0) + // cout << "%" + xed_reg_enum_t2str(xed3_operand_get_index(xedd)); + // } + // } + + for(j=0; j<noperands; ++j) + { + if (intel_way) + i = j; + else + i = noperands - j - 1; + + const xed_operand_t* op = xed_inst_operand(xi, i); + const xed_operand_enum_t op_name = xed_operand_name(op); + + // XED's suppressed operands shouln't be represented in Intel syntax + if (xed_operand_operand_visibility(op) == XED_OPVIS_SUPPRESSED) + { + if ((xed_decoded_inst_get_category(xedd) == XED_CATEGORY_STRINGOP) && + (op_name == XED_OPERAND_MEM0 || op_name == XED_OPERAND_MEM1)) + { + if (op_name == XED_OPERAND_MEM1) + result.emplace_back(OperandSeparatorToken, m_disassembly_options.separator); + } + else + { + continue; + } + } + + switch(xed_operand_name(op)) + { + case XED_OPERAND_REG0: + case XED_OPERAND_REG1: + case XED_OPERAND_REG2: + case XED_OPERAND_REG3: + case XED_OPERAND_REG4: + case XED_OPERAND_REG5: + case XED_OPERAND_REG6: + case XED_OPERAND_REG7: + case XED_OPERAND_REG8: + { + string reg = "%"; + + const xed_reg_enum_t xedReg = xed_decoded_inst_get_reg(xedd, op_name); + if ((xedReg >= XED_REG_X87_FIRST) && (xedReg <= XED_REG_X87_LAST)) + { + reg += "ST"; + reg += ('0' + (xedReg-XED_REG_X87_FIRST)); + } + else + { + reg += xed_reg_enum_t2str(xedReg); + } + if (m_disassembly_options.lowerCase) + for (char& c : reg) + c = tolower(c); + result.emplace_back(RegisterToken, reg); + break; + } + case XED_OPERAND_AGEN: + case XED_OPERAND_MEM0: + { + GetAddressSizeToken(xed_decoded_inst_operand_length_bits(xedd, i) / 8, result, m_disassembly_options.lowerCase); + + if (m_disassembly_options.lowerCase) + result.emplace_back(TextToken, "ptr "); + else + result.emplace_back(TextToken, "PTR "); + result.emplace_back(TextToken, "["); + + // Segment + const xed_reg_enum_t seg = xed_decoded_inst_get_seg_reg(xedd, 0); + const bool validSegment = (seg != XED_REG_INVALID && !xed_operand_values_using_default_segment(ov, 0)); + if (validSegment) + { + string seg_str(xed_reg_enum_t2str(seg)); + seg_str = "%" + seg_str; + if (m_disassembly_options.lowerCase) + for (char& c : seg_str) + c = tolower(c); + result.emplace_back(RegisterToken, seg_str); + result.emplace_back(TextToken, ":"); + } + + bool started = false; + xed_reg_enum_t base = xed_decoded_inst_get_base_reg(xedd, 0); + + int64_t disp = xed_decoded_inst_get_memory_displacement(xedd, 0); + + if ((base != XED_REG_INVALID) && !((base == XED_REG_RIP) || (base == XED_REG_EIP) || (base == XED_REG_IP))) + { + string base_str(xed_reg_enum_t2str(base)); + base_str = "%" + base_str; + if (m_disassembly_options.lowerCase) + for (char& c : base_str) + c = tolower(c); + result.emplace_back(RegisterToken, base_str); + started = true; + } + else if ((base == XED_REG_RIP) || (base == XED_REG_EIP) || (base == XED_REG_IP)) + { + if (xed_operand_values_has_memory_displacement(ov)) + disp += addr + len; + else + disp = addr + len; + + stringstream sstream; + if (m_disassembly_options.lowerCase) + sstream << "0x" << hex << nouppercase << disp; + else + sstream << "0x" << hex << uppercase << disp; + + result.emplace_back(CodeRelativeAddressToken, sstream.str(), disp, GetAddressSize()); + + result.emplace_back(EndMemoryOperandToken, "]"); + break; + } + + const xed_reg_enum_t index = xed_decoded_inst_get_index_reg(xedd, 0); + if (index != XED_REG_INVALID) + { + if (started) + result.emplace_back(TextToken, "+"); + started = true; + + string index_str(xed_reg_enum_t2str(index)); + index_str = "%" + index_str; + if (m_disassembly_options.lowerCase) + for (char& c : index_str) + c = tolower(c); + + result.emplace_back(RegisterToken, index_str); + + const unsigned int scale = xed_decoded_inst_get_scale(xedd, 0); + if (scale != 1) + { + result.emplace_back(TextToken, "*"); + stringstream sstream; + sstream << scale; + result.emplace_back(IntegerToken, sstream.str(), scale, 1); + } + } + + const unsigned short disp_bytes = xed_decoded_inst_get_memory_displacement_width_bits(xedd, 0) / 8; + + if (xed_operand_values_has_memory_displacement(ov) && + ((disp != 0) || (!started && validSegment))) + { + stringstream sstream; + sstream << "0x" << hex; + if (m_disassembly_options.lowerCase) + sstream << nouppercase; + else + sstream << uppercase; + + if (started) + { + if (disp < 0) + { + result.emplace_back(TextToken, "-"); + disp = -disp; + } + else + result.emplace_back(TextToken, "+"); + + if (disp_bytes == 2) + sstream << (uint16_t)disp; + else if (disp_bytes == 4) + sstream << (uint32_t)disp; + else if (disp_bytes == 8) + sstream << (uint64_t)disp; + else + sstream << disp; + result.emplace_back(IntegerToken, sstream.str(), disp, disp_bytes); + } + else + { + sstream << disp; + + if (validSegment) + result.emplace_back(IntegerToken, sstream.str(), disp, GetAddressSize()); + else + result.emplace_back(PossibleAddressToken, sstream.str(), disp, GetAddressSize()); + } + } + else if (xed_operand_values_has_memory_displacement(ov) && + ((disp == 0) && (!started))) + { + result.emplace_back(IntegerToken, "0x0", disp, GetAddressSize()); + } + result.emplace_back(EndMemoryOperandToken, "]"); + + break; + } + + case XED_OPERAND_MEM1: + { + GetAddressSizeToken(xed_decoded_inst_operand_length_bits(xedd, i) / 8, result, m_disassembly_options.lowerCase); + + if (m_disassembly_options.lowerCase) + result.emplace_back(TextToken, "ptr "); + else + result.emplace_back(TextToken, "PTR "); + + // Segment + const xed_reg_enum_t seg = xed_decoded_inst_get_seg_reg(xedd, 1); + if (seg != XED_REG_INVALID && !xed_operand_values_using_default_segment(ov, 1)) + { + string seg_str(xed_reg_enum_t2str(seg)); + seg_str = "%" + seg_str; + if (m_disassembly_options.lowerCase) + for (char& c : seg_str) + c = tolower(c); + result.emplace_back(RegisterToken, seg_str); + + result.emplace_back(TextToken, ":"); + } + + result.emplace_back(TextToken, "["); + const xed_reg_enum_t base = xed_decoded_inst_get_base_reg(xedd, 1); + if (base != XED_REG_INVALID) + { + string base_str(xed_reg_enum_t2str(base)); + base_str = "%" + base_str; + if (m_disassembly_options.lowerCase) + for (char& c : base_str) + c = tolower(c); + result.emplace_back(RegisterToken, base_str); + } + result.emplace_back(EndMemoryOperandToken, "]"); + + break; + } + + case XED_OPERAND_IMM0: + { + const size_t addrSize = xed_decoded_inst_get_machine_mode_bits(xedd) / 8; + const unsigned int immediateSize = xed_decoded_inst_get_operand_width(xedd) / 8; + + stringstream sstream; + sstream << "$0x" << hex; + if (m_disassembly_options.lowerCase) + sstream << nouppercase; + else + sstream << uppercase; + + if (xed_decoded_inst_get_immediate_is_signed(xedd) && (immediateSize != 1)) + { + const int64_t immediateValue = xed_decoded_inst_get_signed_immediate(xedd); + + if (immediateValue >= 0) + sstream << immediateValue; // Don't zero extend + else + { + // I'm not proud of this switch statement... It was the product of a lot of pain. + switch (immediateSize) // For sign extentions + { + case 1: + sstream << (int8_t)immediateValue; + break; + case 2: + sstream << (int16_t)immediateValue; + break; + case 4: + sstream << (int32_t)immediateValue; + break; + default: + sstream << (int64_t)immediateValue; + } + } + + if (immediateSize == addrSize) + result.emplace_back(PossibleAddressToken, sstream.str(), immediateValue, immediateSize); + else + result.emplace_back(IntegerToken, sstream.str(), immediateValue, immediateSize); + } + else + { + const uint64_t immediateValue = xed_decoded_inst_get_unsigned_immediate(xedd); + sstream << immediateValue; + if (immediateSize == addrSize) + result.emplace_back(PossibleAddressToken, sstream.str(), immediateValue, immediateSize); + else + result.emplace_back(IntegerToken, sstream.str(), immediateValue, immediateSize); + } + break; + } + + case XED_OPERAND_IMM1: + { + stringstream sstream; + sstream << "$0x" << hex; + if (m_disassembly_options.lowerCase) + sstream << nouppercase; + else + sstream << uppercase; + + sstream << (uint16_t)xed_decoded_inst_get_second_immediate(xedd); + result.emplace_back(IntegerToken, sstream.str(), xed_decoded_inst_get_second_immediate(xedd), 1); + break; + } + + case XED_OPERAND_PTR: + { + stringstream sstream; + sstream << "$0x" << hex; + if (m_disassembly_options.lowerCase) + sstream << nouppercase; + else + sstream << uppercase; + + sstream << xed_decoded_inst_get_branch_displacement(xedd); + result.emplace_back(PossibleAddressToken, sstream.str(), xed_decoded_inst_get_branch_displacement(xedd), 8); + break; + + } + + case XED_OPERAND_RELBR: + { + const int64_t relbr = xed_decoded_inst_get_branch_displacement(xedd) + addr + xed_decoded_inst_get_length(xedd); + + stringstream sstream; + sstream << "$0x" << hex; + if (m_disassembly_options.lowerCase) + sstream << nouppercase; + else + sstream << uppercase; + + sstream << relbr; + result.emplace_back(CodeRelativeAddressToken, sstream.str(), relbr, 8); + break; + } + + default: + { + result.emplace_back(TextToken, "unimplimented"); + } // default case of outer switch + } // outer switch + + // If there is another operand and it is visable, print delimiter + if (intel_way) + { + if ((i != (size_t)xed_inst_noperands(xi)-1) && + ((xed_operand_operand_visibility(xed_inst_operand(xi, i+1)) == XED_OPVIS_EXPLICIT) || + (xed_operand_operand_visibility(xed_inst_operand(xi, i+1)) == XED_OPVIS_IMPLICIT))) + { + result.emplace_back(OperandSeparatorToken, m_disassembly_options.separator); + } + } + else + { + if ((i != 0) && + ((xed_operand_operand_visibility(xed_inst_operand(xi, noperands - j - 2)) == XED_OPVIS_EXPLICIT) || + (xed_operand_operand_visibility(xed_inst_operand(xi, noperands - j - 2)) == XED_OPVIS_IMPLICIT))) + { + result.emplace_back(OperandSeparatorToken, m_disassembly_options.separator); + } + } + + } +} + +void X86CommonArchitecture::GetOperandTextXED(const xed_decoded_inst_t* const xedd, const uint64_t addr, const size_t, const xed_operand_values_t* const, const xed_inst_t* const, vector<InstructionTextToken>& result) const +{ + char out_buffer[100]; + if (!xed_format_context(XED_SYNTAX_XED, xedd, out_buffer, 100, addr, 0, 0)) + { + LogError("Can't disassemble"); + return; + } + + // Find space + int i = 0; + for (; ; ++i) + if ((out_buffer[i] == ' ') && (out_buffer[i+1] != ' ')) + break; + + // Convert To String + string outstring(out_buffer+i); + + result.emplace_back(TextToken, outstring); +} + +void X86CommonArchitecture::GetOperandText(const xed_decoded_inst_t* const xedd, const uint64_t addr, const size_t len, const xed_operand_values_t* const ov, const xed_inst_t* const xi, vector<InstructionTextToken>& result) const +{ + switch (m_disassembly_options.df) + { + case DF_INTEL: + GetOperandTextIntel(xedd, addr, len, ov, xi, result); + break; + + case DF_BN_INTEL: + GetOperandTextBNIntel(xedd, addr, len, ov, xi, result); + break; + + case DF_ATT: + GetOperandTextATT(xedd, addr, len, ov, xi, result); + break; + + case DF_XED: + GetOperandTextXED(xedd, addr, len, ov, xi, result); + break; + + default: + LogError("Invalid Disassembly Flavor"); + } +} + +X86CommonArchitecture::X86CommonArchitecture(const string& name, size_t bits): Architecture(name), m_bits(bits) +{ + Ref<Settings> settings = Settings::Instance(); + const bool lowercase = settings->Get<bool>("arch.x86.disassembly.lowercase"); + const string flavor = settings->Get<string>("arch.x86.disassembly.syntax"); + const string separator = settings->Get<string>("arch.x86.disassembly.separator"); + + DISASSEMBLY_FLAVOR_ENUM flavorEnum; + + if (flavor == "BN_INTEL") + flavorEnum = DF_BN_INTEL; + else if (flavor == "INTEL") + flavorEnum = DF_INTEL; + else if (flavor == "AT&T") + flavorEnum = DF_ATT; + // else if (flavor == "XED") + // flavorEnum = DF_XED; + else + flavorEnum = DF_BN_INTEL; + + m_disassembly_options = DISASSEMBLY_OPTIONS(flavorEnum, lowercase, separator); +} + +BNEndianness X86CommonArchitecture::GetEndianness() const +{ + return LittleEndian; +} + +vector<uint32_t> X86CommonArchitecture::GetGlobalRegisters() +{ + return vector< uint32_t> { + XED_REG_CS, + XED_REG_DS, + XED_REG_ES, + XED_REG_SS, + XED_REG_FS, + XED_REG_GS, + XED_REG_FSBASE, + XED_REG_GSBASE, + XED_REG_FLAGS, + XED_REG_EFLAGS, + XED_REG_RFLAGS + }; +} + +vector<uint32_t> X86CommonArchitecture::GetSystemRegisters() +{ + return vector< uint32_t> { + XED_REG_BND0, + XED_REG_BND1, + XED_REG_BND2, + XED_REG_BND3, + + XED_REG_CR0, + XED_REG_CR1, + XED_REG_CR2, + XED_REG_CR3, + XED_REG_CR4, + XED_REG_CR5, + XED_REG_CR6, + XED_REG_CR7, + XED_REG_CR8, + XED_REG_CR9, + XED_REG_CR10, + XED_REG_CR11, + XED_REG_CR12, + XED_REG_CR13, + XED_REG_CR14, + XED_REG_CR15, + + XED_REG_DR0, + XED_REG_DR1, + XED_REG_DR2, + XED_REG_DR3, + XED_REG_DR4, + XED_REG_DR5, + XED_REG_DR6, + XED_REG_DR7, + + XED_REG_GDTR, + XED_REG_LDTR, + XED_REG_IDTR, + XED_REG_TR, + + XED_REG_TSC, + XED_REG_TSCAUX, + XED_REG_MSRS + }; +} + +bool X86CommonArchitecture::GetInstructionInfo(const uint8_t* data, uint64_t addr, size_t maxLen, InstructionInfo& result) +{ + xed_decoded_inst_t xedd; + switch (m_bits) + { + case 64: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LONG_64, XED_ADDRESS_WIDTH_64b); + break; + case 32: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_32, XED_ADDRESS_WIDTH_32b); + break; + case 16: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_16, XED_ADDRESS_WIDTH_16b); + break; + default: + LogError("Invalid Processor Mode"); + return false; + } + if (!Decode(data, maxLen, &xedd)) + return false; + + SetInstructionInfoForInstruction(addr, result, &xedd); + return true; +} + + +bool X86CommonArchitecture::GetInstructionText(const uint8_t* data, uint64_t addr, size_t& len, vector<InstructionTextToken>& result) +{ + xed_decoded_inst_t xedd; + switch (m_bits) + { + case 64: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LONG_64, XED_ADDRESS_WIDTH_64b); + break; + case 32: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_32, XED_ADDRESS_WIDTH_32b); + break; + case 16: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_16, XED_ADDRESS_WIDTH_16b); + break; + default: + LogError("Invalid Processor Mode"); + return false; + } + + if (Decode(data, len, &xedd)) + { + len = xed_decoded_inst_get_length(&xedd); + + // If there's no instruction + const xed_inst_t* xi = xed_decoded_inst_inst(&xedd); + if (!xi) + return false; + + // Opcodes + const xed_operand_values_t* const ov = xed_decoded_inst_operands_const(&xedd); + unsigned short instruction_name_length = GetInstructionOpcode(&xedd, ov, result); + + // Padding + GetInstructionPadding(instruction_name_length, result); + + // Operands + GetOperandText(&xedd, addr, len, ov, xi, result); + + return true; + } + + return false; +} + +bool X86CommonArchitecture::GetInstructionLowLevelIL(const uint8_t* data, uint64_t addr, size_t& len, LowLevelILFunction& il) +{ + xed_decoded_inst_t xedd; + switch (m_bits) + { + case 64: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LONG_64, XED_ADDRESS_WIDTH_64b); + break; + case 32: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_32, XED_ADDRESS_WIDTH_32b); + break; + case 16: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_16, XED_ADDRESS_WIDTH_16b); + break; + default: + LogError("Invalid Processor Mode"); + return false; + } + if (!Decode(data, len, &xedd)) + { + il.AddInstruction(il.Undefined()); + return false; + } + + len = xed_decoded_inst_get_length(&xedd); + return GetLowLevelILForInstruction(this, addr, il, &xedd); +} + +size_t X86CommonArchitecture::GetFlagWriteLowLevelIL(BNLowLevelILOperation op, size_t size, uint32_t flagWriteType, + uint32_t flag, BNRegisterOrConstant* operands, size_t operandCount, LowLevelILFunction& il) +{ + switch (op) + { + case LLIL_NEG: + switch (flag) + { + case IL_FLAG_O: + return il.AddExpr(LLIL_CMP_E, size, 0, il.GetExprForRegisterOrConstantOperation(op, size, operands, operandCount), + il.AddExpr(LLIL_CONST, size, 0, (1LL << ((size * 8) - 1)))); + } + break; + case LLIL_XOR: + case LLIL_AND: + case LLIL_OR: + switch (flag) + { + case IL_FLAG_C: + case IL_FLAG_O: + return il.Const(0, 0); + case IL_FLAG_A: + return il.Undefined(); + } + break; + case LLIL_MULU_DP: + switch (flag) + { + case IL_FLAG_C: + case IL_FLAG_O: + return il.AddExpr(LLIL_CMP_NE, size * 2, 0, il.AddExpr(LLIL_LSR, size * 2, 0, + il.GetExprForRegisterOrConstantOperation(op, size, operands, operandCount), + il.AddExpr(LLIL_CONST, 1, 0, size * 8)), il.AddExpr(LLIL_CONST, size * 2, 0, 0)); + } + default: + break; + } + + if (flagWriteType == IL_FLAGWRITE_VCOMI) + { + switch (flag) + { + case IL_FLAG_S: + case IL_FLAG_O: + case IL_FLAG_A: + return il.Const(0, 0); + default: + break; + } + } + if (((flagWriteType == IL_FLAGWRITE_X87COM) || (flagWriteType == IL_FLAGWRITE_X87C1Z)) && (flag == IL_FLAG_C1)) + return il.Const(0, 0); + return Architecture::GetFlagWriteLowLevelIL(op, size, flagWriteType, flag, operands, operandCount, il); +} + +size_t X86CommonArchitecture::GetSemanticFlagGroupLowLevelIL(uint32_t semGroup, LowLevelILFunction& il) +{ + switch (semGroup) + { + case IL_FLAG_GROUP_E: + return GetFlagConditionLowLevelIL(LLFC_E, IL_FLAG_CLASS_INT, il); + case IL_FLAG_GROUP_NE: + return GetFlagConditionLowLevelIL(LLFC_NE, IL_FLAG_CLASS_INT, il); + case IL_FLAG_GROUP_LT: + return GetFlagConditionLowLevelIL(LLFC_ULT, IL_FLAG_CLASS_INT, il); + case IL_FLAG_GROUP_LE: + return GetFlagConditionLowLevelIL(LLFC_ULE, IL_FLAG_CLASS_INT, il); + case IL_FLAG_GROUP_GE: + return GetFlagConditionLowLevelIL(LLFC_UGE, IL_FLAG_CLASS_INT, il); + case IL_FLAG_GROUP_GT: + return GetFlagConditionLowLevelIL(LLFC_UGT, IL_FLAG_CLASS_INT, il); + case IL_FLAG_GROUP_PE: + return il.Flag(IL_FLAG_P); + case IL_FLAG_GROUP_PO: + return il.Not(0, il.Flag(IL_FLAG_P)); + default: + return il.Unimplemented(); + } +} + +string X86CommonArchitecture::GetRegisterName(uint32_t reg) +{ + string reg_str = ""; + if (m_disassembly_options.df == DF_ATT) + reg_str += "%"; + + if ((reg >= REG_X87_r(0)) && (reg <= REG_X87_r(7))) + reg_str += "X87_R" + to_string(reg - REG_X87_r(0)); + else if (reg == REG_X87_TOP) + reg_str += "TOP"; + else if ((reg >= XED_REG_X87_FIRST) && (reg <= XED_REG_X87_LAST)) + reg_str += "ST" + to_string(reg - XED_REG_X87_FIRST); + else + reg_str += xed_reg_enum_t2str((xed_reg_enum_t)reg); + + if (m_disassembly_options.lowerCase) + for (char& c : reg_str) + c = tolower(c); + + return reg_str; +} + +string X86CommonArchitecture::GetFlagName(uint32_t flag) +{ + char result[32]; + switch (flag) + { + case IL_FLAG_C: + return "c"; + case IL_FLAG_P: + return "p"; + case IL_FLAG_A: + return "a"; + case IL_FLAG_Z: + return "z"; + case IL_FLAG_S: + return "s"; + case IL_FLAG_D: + return "d"; + case IL_FLAG_O: + return "o"; + case IL_FLAG_C0: + return "c0"; + case IL_FLAG_C1: + return "c1"; + case IL_FLAG_C2: + return "c2"; + case IL_FLAG_C3: + return "c3"; + default: + snprintf(result, sizeof(result), "flag%" PRIu32, flag); + return result; + } +} + +vector<uint32_t> X86CommonArchitecture::GetAllFlags() +{ + return vector<uint32_t> {IL_FLAG_C, IL_FLAG_P, IL_FLAG_A, IL_FLAG_Z, IL_FLAG_S, IL_FLAG_D, IL_FLAG_O, + IL_FLAG_C0, IL_FLAG_C1, IL_FLAG_C2, IL_FLAG_C3}; +} + +string X86CommonArchitecture::GetSemanticFlagClassName(uint32_t semClass) +{ + switch (semClass) + { + case IL_FLAG_CLASS_X87COM: + return "x87com"; + case IL_FLAG_CLASS_X87COMI: + return "x87comi"; + case IL_FLAG_CLASS_VCOMI: + return "vcomi"; + default: + return ""; + } +} + +vector<uint32_t> X86CommonArchitecture::GetAllSemanticFlagClasses() +{ + return vector<uint32_t> {IL_FLAG_CLASS_X87COM, IL_FLAG_CLASS_X87COMI, IL_FLAG_CLASS_VCOMI}; +} + +string X86CommonArchitecture::GetSemanticFlagGroupName(uint32_t semGroup) +{ + switch (semGroup) + { + case IL_FLAG_GROUP_E: + return "e"; + case IL_FLAG_GROUP_NE: + return "ne"; + case IL_FLAG_GROUP_LT: + return "lt"; + case IL_FLAG_GROUP_LE: + return "le"; + case IL_FLAG_GROUP_GE: + return "ge"; + case IL_FLAG_GROUP_GT: + return "gt"; + case IL_FLAG_GROUP_PE: + return "pe"; + case IL_FLAG_GROUP_PO: + return "po"; + default: + return ""; + } +} + +vector<uint32_t> X86CommonArchitecture::GetAllSemanticFlagGroups() +{ + return vector<uint32_t> {IL_FLAG_GROUP_E, IL_FLAG_GROUP_NE, IL_FLAG_GROUP_LT, IL_FLAG_GROUP_LE, + IL_FLAG_GROUP_GE, IL_FLAG_GROUP_GT, IL_FLAG_GROUP_PE, IL_FLAG_GROUP_PO}; +} + +string X86CommonArchitecture::GetFlagWriteTypeName(uint32_t flags) +{ + switch (flags) + { + case IL_FLAGWRITE_ALL: + return "*"; + case IL_FLAGWRITE_NOCARRY: + return "!c"; + case IL_FLAGWRITE_CO: + return "co"; + case IL_FLAGWRITE_X87COM: + return "x87com"; + case IL_FLAGWRITE_X87COMI: + return "x87comi"; + case IL_FLAGWRITE_X87C1Z: + return "x87c1z"; + case IL_FLAGWRITE_X87RND: + return "x87rnd"; + case IL_FLAGWRITE_VCOMI: + return "vcomi"; + default: + return ""; + } +} + +uint32_t X86CommonArchitecture::GetSemanticClassForFlagWriteType(uint32_t writeType) +{ + switch (writeType) + { + case IL_FLAGWRITE_X87COM: + case IL_FLAGWRITE_X87C1Z: + case IL_FLAGWRITE_X87RND: + return IL_FLAG_CLASS_X87COM; + case IL_FLAGWRITE_X87COMI: + return IL_FLAG_CLASS_X87COMI; + case IL_FLAGWRITE_VCOMI: + return IL_FLAG_CLASS_VCOMI; + default: + return IL_FLAG_CLASS_INT; + } +} + +vector<uint32_t> X86CommonArchitecture::GetAllFlagWriteTypes() +{ + return vector<uint32_t> {IL_FLAGWRITE_ALL, IL_FLAGWRITE_NOCARRY, IL_FLAGWRITE_CO, + IL_FLAGWRITE_X87COM, IL_FLAGWRITE_X87COMI, IL_FLAGWRITE_X87C1Z, IL_FLAGWRITE_X87RND, + IL_FLAGWRITE_VCOMI}; +} + +BNFlagRole X86CommonArchitecture::GetFlagRole(uint32_t flag, uint32_t semClass) +{ + switch (semClass) + { + case IL_FLAG_CLASS_X87COM: + switch (flag) + { + case IL_FLAG_C0: + return CarryFlagRole; + case IL_FLAG_C2: + return UnorderedFlagRole; + case IL_FLAG_C3: + return ZeroFlagRole; + default: + return SpecialFlagRole; + } + + case IL_FLAG_CLASS_VCOMI: + switch (flag) + { + case IL_FLAG_C: + return CarryFlagRole; + case IL_FLAG_Z: + return ZeroFlagRole; + case IL_FLAG_P: + return UnorderedFlagRole; + default: + // O, A, S cleared + return SpecialFlagRole; + } + + default: + break; + } + + switch (flag) + { + case IL_FLAG_C: + return CarryFlagRole; + case IL_FLAG_P: + if (semClass == IL_FLAG_CLASS_X87COMI) + return UnorderedFlagRole; + return EvenParityFlagRole; + case IL_FLAG_A: + return HalfCarryFlagRole; + case IL_FLAG_Z: + return ZeroFlagRole; + case IL_FLAG_S: + return NegativeSignFlagRole; + case IL_FLAG_O: + return OverflowFlagRole; + default: + return SpecialFlagRole; + } +} + +vector<uint32_t> X86CommonArchitecture::GetFlagsRequiredForFlagCondition(BNLowLevelILFlagCondition cond, uint32_t semClass) +{ + if (semClass == IL_FLAG_CLASS_X87COM) + { + switch (cond) + { + case LLFC_FE: + case LLFC_FNE: + return vector<uint32_t>{ IL_FLAG_C3 }; + case LLFC_FLT: + case LLFC_FGE: + return vector<uint32_t>{ IL_FLAG_C0 }; + case LLFC_FLE: + case LLFC_FGT: + return vector<uint32_t>{ IL_FLAG_C0, IL_FLAG_C3 }; + case LLFC_FO: + case LLFC_FUO: + return vector<uint32_t>{ IL_FLAG_C2 }; + default: + return vector<uint32_t>(); + } + } + + switch (cond) + { + case LLFC_E: + case LLFC_NE: + case LLFC_FE: + case LLFC_FNE: + return vector<uint32_t>{ IL_FLAG_Z }; + case LLFC_SLT: + case LLFC_SGE: + return vector<uint32_t>{ IL_FLAG_S, IL_FLAG_O }; + case LLFC_ULT: + case LLFC_UGE: + case LLFC_FLT: + case LLFC_FGE: + return vector<uint32_t>{ IL_FLAG_C }; + case LLFC_SLE: + case LLFC_SGT: + return vector<uint32_t>{ IL_FLAG_Z, IL_FLAG_S, IL_FLAG_O }; + case LLFC_ULE: + case LLFC_UGT: + case LLFC_FLE: + case LLFC_FGT: + return vector<uint32_t>{ IL_FLAG_C, IL_FLAG_Z }; + case LLFC_NEG: + case LLFC_POS: + return vector<uint32_t>{ IL_FLAG_S }; + case LLFC_O: + case LLFC_NO: + return vector<uint32_t>{ IL_FLAG_O }; + case LLFC_FO: + case LLFC_FUO: + return vector<uint32_t>{ IL_FLAG_P }; + default: + return vector<uint32_t>(); + } +} + +vector<uint32_t> X86CommonArchitecture::GetFlagsRequiredForSemanticFlagGroup(uint32_t semGroup) +{ + switch (semGroup) + { + case IL_FLAG_GROUP_E: + case IL_FLAG_GROUP_NE: + return vector<uint32_t>{ IL_FLAG_Z }; + case IL_FLAG_GROUP_LT: + case IL_FLAG_GROUP_GE: + return vector<uint32_t>{ IL_FLAG_C }; + case IL_FLAG_GROUP_LE: + case IL_FLAG_GROUP_GT: + return vector<uint32_t>{ IL_FLAG_C, IL_FLAG_Z }; + case IL_FLAG_GROUP_PE: + case IL_FLAG_GROUP_PO: + return vector<uint32_t>{ IL_FLAG_P }; + default: + return vector<uint32_t>(); + } +} + +map<uint32_t, BNLowLevelILFlagCondition> X86CommonArchitecture::GetFlagConditionsForSemanticFlagGroup(uint32_t semGroup) +{ + switch (semGroup) + { + case IL_FLAG_GROUP_E: + return map<uint32_t, BNLowLevelILFlagCondition> { + {IL_FLAG_CLASS_INT, LLFC_E}, + {IL_FLAG_CLASS_X87COMI, LLFC_FE}, + {IL_FLAG_CLASS_VCOMI, LLFC_FE}, + }; + case IL_FLAG_GROUP_NE: + return map<uint32_t, BNLowLevelILFlagCondition> { + {IL_FLAG_CLASS_INT, LLFC_NE}, + {IL_FLAG_CLASS_X87COMI, LLFC_FNE}, + {IL_FLAG_CLASS_VCOMI, LLFC_FNE}, + }; + case IL_FLAG_GROUP_LT: + return map<uint32_t, BNLowLevelILFlagCondition> { + {IL_FLAG_CLASS_INT, LLFC_ULT}, + {IL_FLAG_CLASS_X87COMI, LLFC_FLT}, + {IL_FLAG_CLASS_VCOMI, LLFC_FLT}, + }; + case IL_FLAG_GROUP_LE: + return map<uint32_t, BNLowLevelILFlagCondition> { + {IL_FLAG_CLASS_INT, LLFC_ULE}, + {IL_FLAG_CLASS_X87COMI, LLFC_FLE}, + {IL_FLAG_CLASS_VCOMI, LLFC_FLE}, + }; + case IL_FLAG_GROUP_GE: + return map<uint32_t, BNLowLevelILFlagCondition> { + {IL_FLAG_CLASS_INT, LLFC_UGE}, + {IL_FLAG_CLASS_X87COMI, LLFC_FGE}, + {IL_FLAG_CLASS_VCOMI, LLFC_FGE}, + }; + case IL_FLAG_GROUP_GT: + return map<uint32_t, BNLowLevelILFlagCondition> { + {IL_FLAG_CLASS_INT, LLFC_UGT}, + {IL_FLAG_CLASS_X87COMI, LLFC_FGT}, + {IL_FLAG_CLASS_VCOMI, LLFC_FGT}, + }; + case IL_FLAG_GROUP_PE: + return map<uint32_t, BNLowLevelILFlagCondition> { + {IL_FLAG_CLASS_X87COMI, LLFC_FUO}, + {IL_FLAG_CLASS_VCOMI, LLFC_FUO}, + }; + case IL_FLAG_GROUP_PO: + return map<uint32_t, BNLowLevelILFlagCondition> { + {IL_FLAG_CLASS_X87COMI, LLFC_FO}, + {IL_FLAG_CLASS_VCOMI, LLFC_FO}, + }; + default: + return map<uint32_t, BNLowLevelILFlagCondition>(); + } +} + +vector<uint32_t> X86CommonArchitecture::GetFlagsWrittenByFlagWriteType(uint32_t writeType) +{ + switch (writeType) + { + case IL_FLAGWRITE_ALL: + return vector<uint32_t>{ IL_FLAG_C, IL_FLAG_P, IL_FLAG_A, IL_FLAG_Z, IL_FLAG_S, IL_FLAG_O }; + case IL_FLAGWRITE_NOCARRY: + return vector<uint32_t>{ IL_FLAG_P, IL_FLAG_A, IL_FLAG_Z, IL_FLAG_S, IL_FLAG_O }; + case IL_FLAGWRITE_CO: + return vector<uint32_t>{ IL_FLAG_C, IL_FLAG_O }; + case IL_FLAGWRITE_X87COM: + return vector<uint32_t>{ IL_FLAG_C0, IL_FLAG_C1, IL_FLAG_C2, IL_FLAG_C3 }; + case IL_FLAGWRITE_X87COMI: + return vector<uint32_t>{ IL_FLAG_C, IL_FLAG_Z, IL_FLAG_P }; + case IL_FLAGWRITE_X87C1Z: + case IL_FLAGWRITE_X87RND: + return vector<uint32_t>{ IL_FLAG_C1 }; + case IL_FLAGWRITE_VCOMI: + return vector<uint32_t>{ IL_FLAG_C, IL_FLAG_P, IL_FLAG_A, IL_FLAG_Z, IL_FLAG_S, IL_FLAG_O }; + default: + return vector<uint32_t>(); + } +} + +string X86CommonArchitecture::GetRegisterStackName(uint32_t regStack) +{ + if (regStack == REG_STACK_X87) + return "x87"; + return ""; +} + +vector<uint32_t> X86CommonArchitecture::GetAllRegisterStacks() +{ + return vector<uint32_t>{REG_STACK_X87}; +} + +BNRegisterStackInfo X86CommonArchitecture::GetRegisterStackInfo(uint32_t regStack) +{ + if (regStack == REG_STACK_X87) + { + BNRegisterStackInfo result; + result.firstStorageReg = REG_X87_r(0); + result.storageCount = 8; + result.firstTopRelativeReg = XED_REG_ST0; + result.topRelativeCount = 8; + result.stackTopReg = REG_X87_TOP; + return result; + } + return Architecture::GetRegisterStackInfo(regStack); +} + +bool X86CommonArchitecture::CanAssemble() +{ + return true; +} + +bool X86CommonArchitecture::Assemble(const string& code, uint64_t addr, DataBuffer& result, string& errors) +{ + string finalCode; + + if (GetAddressSizeBits() == 32) + finalCode = "\tsection .text align=1\n\tbits 32\n"; + else + finalCode = "\tsection .text align=1\n\tbits 64\n"; + + char orgStr[32]; + snprintf(orgStr, sizeof(orgStr), "\torg 0x%" PRIx64 "\n", addr); + finalCode += orgStr; + + finalCode += "%line 0 input\n"; + finalCode += code; + + Ref<TemporaryFile> inputFile = new TemporaryFile(finalCode); + Ref<TemporaryFile> outputFile = new TemporaryFile(); + if (!inputFile->IsValid()) + { + errors = "Unable to create temporary file for input\n"; + return false; + } + if (!outputFile->IsValid()) + { + errors = "Unable to create temporary file for output\n"; + return false; + } + + #ifdef WIN32 + string yasmPath = GetPathRelativeToBundledPluginDirectory("yasm.exe"); + #else + string yasmPath = GetPathRelativeToBundledPluginDirectory("yasm"); + #endif + + string inputPath = inputFile->GetPath(); + string outputPath = outputFile->GetPath(); + + vector<string> args = vector<string> { yasmPath, "-fbin", "-w", "-Worphan-labels", "-Werror", "-o", outputPath, inputPath }; + + string output; + bool ok = ExecuteWorkerProcess(yasmPath, args, DataBuffer(), + output, // _binary_ stdout is ignored + errors, // _text_ stderr becomes the error message + false, // yasm stdout is ignored (stay with default: no newline translate) + true // yasm stderr is known to be text (translate newlines) + ); + + if(!ok) + { + /* when there was a problem creating the yasm process + OR the yasm process return code was nonzero */ + if(errors.size() == 0) + { + errors = yasmPath + " returned nonzero\n"; + } + } + else + { + result = outputFile->GetContents(); /* assembled bytes */ + if(result.GetLength() == 0) + { + errors = "Empty output from assembler\n"; + ok = false; + } + } + + return ok; +} + +bool X86CommonArchitecture::IsNeverBranchPatchAvailable(const uint8_t* data, uint64_t, size_t len) +{ + xed_decoded_inst_t xedd; + switch (m_bits) + { + case 64: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LONG_64, XED_ADDRESS_WIDTH_64b); + break; + case 32: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_32, XED_ADDRESS_WIDTH_32b); + break; + case 16: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_16, XED_ADDRESS_WIDTH_16b); + break; + default: + LogError("Invalid Processor Mode"); + return false; + } + + if (!Decode(data, len, &xedd)) + return false; + return IsConditionalJump(&xedd); +} + +bool X86CommonArchitecture::IsAlwaysBranchPatchAvailable(const uint8_t* data, uint64_t, size_t len) +{ + xed_decoded_inst_t xedd; + switch (m_bits) + { + case 64: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LONG_64, XED_ADDRESS_WIDTH_64b); + break; + case 32: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_32, XED_ADDRESS_WIDTH_32b); + break; + case 16: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_16, XED_ADDRESS_WIDTH_16b); + break; + default: + LogError("Invalid Processor Mode"); + return false; + } + if (!Decode(data, len, &xedd)) + return false; + return IsConditionalJump(&xedd); +} + +bool X86CommonArchitecture::IsInvertBranchPatchAvailable(const uint8_t* data, uint64_t, size_t len) +{ + xed_decoded_inst_t xedd; + switch (m_bits) + { + case 64: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LONG_64, XED_ADDRESS_WIDTH_64b); + break; + case 32: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_32, XED_ADDRESS_WIDTH_32b); + break; + case 16: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_16, XED_ADDRESS_WIDTH_16b); + break; + default: + LogError("Invalid Processor Mode"); + return false; + } + if (!Decode(data, len, &xedd)) + return false; + return IsConditionalJump(&xedd); +} + +bool X86CommonArchitecture::IsSkipAndReturnZeroPatchAvailable(const uint8_t* data, uint64_t, size_t len) +{ + xed_decoded_inst_t xedd; + switch (m_bits) + { + case 64: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LONG_64, XED_ADDRESS_WIDTH_64b); + break; + case 32: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_32, XED_ADDRESS_WIDTH_32b); + break; + case 16: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_16, XED_ADDRESS_WIDTH_16b); + break; + default: + LogError("Invalid Processor Mode"); + return false; + } + if (!Decode(data, len, &xedd)) + return false; + return xed_decoded_inst_get_category(&xedd) == XED_CATEGORY_CALL; +} + +bool X86CommonArchitecture::IsSkipAndReturnValuePatchAvailable(const uint8_t* data, uint64_t, size_t len) +{ + xed_decoded_inst_t xedd; + switch (m_bits) + { + case 64: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LONG_64, XED_ADDRESS_WIDTH_64b); + break; + case 32: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_32, XED_ADDRESS_WIDTH_32b); + break; + case 16: + xed_decoded_inst_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_16, XED_ADDRESS_WIDTH_16b); + break; + default: + LogError("Invalid Processor Mode"); + return false; + } + if (!Decode(data, len, &xedd)) + return false; + return (xed_decoded_inst_get_category(&xedd) == XED_CATEGORY_CALL) && (xed_decoded_inst_get_length(&xedd) >= 5); +} + +bool X86CommonArchitecture::ConvertToNop(uint8_t* data, uint64_t, size_t len) +{ + memset(data, 0x90, len); + return true; +} + +size_t X86CommonArchitecture::FindOpcodeOffset(const uint8_t* data, size_t len) +{ + size_t i; + for (i = 0; i < len; i++) + { + if ((data[0] >= 0x26) && (data[0] <= 0x3e) && ((data[0] & 7) == 6)) // Segment prefix + continue; + if ((data[0] >= 0x64) && (data[0] <= 0x67)) // FS/GS prefix and size overrides + continue; + if (data[0] == 0xf0) // Lock prefix + continue; + if ((data[0] == 0xf2) || (data[0] == 0xf3)) // Rep prefixes + continue; + if ((GetAddressSizeBits() == 64) && (data[0] >= 0x40) && (data[0] <= 0x4f)) // REX prefix + continue; + break; + } + return i; +} + +bool X86CommonArchitecture::AlwaysBranch(uint8_t* data, uint64_t, size_t len) +{ + size_t i = FindOpcodeOffset(data, len); + if (i >= len) + return false; + + if ((len - i) == 2) + { + data[i] = 0xeb; + return true; + } + + if ((len - i) == 5) + { + data[i] = 0xe9; + return true; + } + + if ((len - i) > 5) + { + memmove(&data[(len - i) - 5], data, i); + memset(data, 0x90, (len - i) - 5); + data[len - 5] = 0xe9; + return true; + } + + return false; +} + +bool X86CommonArchitecture::InvertBranch(uint8_t* data, uint64_t, size_t len) +{ + size_t i = FindOpcodeOffset(data, len); + if (i >= len) + return false; + + if (data[i] == 0x0f) + { + if ((i + 1) >= len) + return false; + data[i + 1] ^= 1; + return true; + } + + data[i] ^= 1; + return true; +} + +bool X86CommonArchitecture::SkipAndReturnValue(uint8_t* data, uint64_t, size_t len, uint64_t value) +{ + if (len >= 5) + { + data[0] = 0xb8; + *(uint32_t*)&data[1] = (uint32_t)value; + memset(&data[5], 0x90, len - 5); + return true; + } + + if ((value == 0) && (len >= 2)) + { + // xor eax, eax + data[0] = 0x31; + data[1] = 0xc0; + memset(&data[2], 0x90, len - 2); + return true; + } + + return false; +} + + +class X86Architecture: public X86CommonArchitecture +{ +protected: + virtual size_t GetAddressSize() const override + { + return 4; + } + +public: + X86Architecture(): X86CommonArchitecture("x86", 32) + {} + + virtual vector<uint32_t> GetFullWidthRegisters() override + { + return vector<uint32_t>{ + // 16-Bit + XED_REG_CS, XED_REG_DS, XED_REG_ES, XED_REG_SS, XED_REG_FS, XED_REG_GS, XED_REG_FSBASE, XED_REG_GSBASE, // 16+ + + // 32-Bit + XED_REG_EIP, // 32+ + XED_REG_ESP, XED_REG_EBP, XED_REG_ESI, XED_REG_EDI, // 32+ + XED_REG_EFLAGS, // 32+ + + XED_REG_EAX, XED_REG_ECX, XED_REG_EDX, XED_REG_EBX, // 32+ + + XED_REG_TSC, XED_REG_TSCAUX, // 32+ (32 on 32, 64 on 64) Timestamp Counters + XED_REG_TR, // 16+ (16 on 16, 32 on 32, 64 on 64) Task Register + + XED_REG_CR0, XED_REG_CR1, XED_REG_CR2, XED_REG_CR3, XED_REG_CR4, XED_REG_CR5, XED_REG_CR6, XED_REG_CR7, XED_REG_CR8, XED_REG_CR9, XED_REG_CR10, XED_REG_CR11, XED_REG_CR12, XED_REG_CR13, XED_REG_CR14, XED_REG_CR15, // 32+ (32 on 32, 64 on 64) Control Registers + XED_REG_DR0, XED_REG_DR1, XED_REG_DR2, XED_REG_DR3, XED_REG_DR4, XED_REG_DR5, XED_REG_DR6, XED_REG_DR7, // 32+ (starting in later revisions of 32) (32 on 32, 64 on 64) Debug registers + + XED_REG_MXCSR, // 32+ SSE (MMX) Control Reg (32 on 32, 64 on 64) + + // x87 FPU related + REG_X87_TOP, XED_REG_X87CONTROL, XED_REG_X87STATUS, XED_REG_X87TAG, XED_REG_X87OPCODE, XED_REG_X87LASTCS, + XED_REG_X87LASTDS, XED_REG_X87LASTIP, XED_REG_X87LASTDP, XED_REG_X87PUSH, XED_REG_X87POP, XED_REG_X87POP2, + + // 48-Bit (All 32+) + XED_REG_GDTR, // Global Descriptor Table Register + XED_REG_LDTR, // Local Descriptor Table Register + XED_REG_IDTR, // Interrupt Descriptor Table Register + + // 64-Bit + XED_REG_XCR0, // 32+ (64 on 32, 64 on 64) + + XED_REG_MSRS, + + // 80-Bit + XED_REG_ST0, XED_REG_ST1, XED_REG_ST2, XED_REG_ST3, XED_REG_ST4, XED_REG_ST5, XED_REG_ST6, XED_REG_ST7, // 32+ Floating point + REG_X87_r(0), REG_X87_r(1), REG_X87_r(2), REG_X87_r(3), REG_X87_r(4), REG_X87_r(5), REG_X87_r(6), REG_X87_r(7), + + // 128-Bit + XED_REG_XMM0, XED_REG_XMM1, XED_REG_XMM2, XED_REG_XMM3, XED_REG_XMM4, XED_REG_XMM5, XED_REG_XMM6, XED_REG_XMM7, // 32+ SSE + }; + } + + virtual vector<uint32_t> GetAllRegisters() override + { + return vector<uint32_t>{ + // 8-Bit + XED_REG_AH, XED_REG_CH, XED_REG_DH, XED_REG_BH, XED_REG_AL, XED_REG_CL, XED_REG_DL, XED_REG_BL, // 16+ + + // 16-Bit + XED_REG_IP, // 16+ + XED_REG_CS, XED_REG_DS, XED_REG_ES, XED_REG_SS, XED_REG_FS, XED_REG_GS, XED_REG_FSBASE, XED_REG_GSBASE, // 16+ + XED_REG_SP, XED_REG_BP, XED_REG_SI, XED_REG_DI, // 16+ + XED_REG_FLAGS, // 16+ + + XED_REG_AX, XED_REG_CX, XED_REG_DX, XED_REG_BX, // 16+ + + REG_X87_TOP, // 32+ + XED_REG_X87CONTROL, XED_REG_X87STATUS, XED_REG_X87TAG, XED_REG_X87PUSH, XED_REG_X87POP, + XED_REG_X87POP2, XED_REG_X87OPCODE, XED_REG_X87LASTCS, XED_REG_X87LASTIP, XED_REG_X87LASTDS, XED_REG_X87LASTDP, + + // 32-Bit + XED_REG_EIP, // 32+ + XED_REG_ESP, XED_REG_EBP, XED_REG_ESI, XED_REG_EDI, // 32+ + XED_REG_EFLAGS, // 32+ + + XED_REG_EAX, XED_REG_ECX, XED_REG_EDX, XED_REG_EBX, // 32+ + + XED_REG_TSC, XED_REG_TSCAUX, // 32+ (32 on 32, 64 on 64) Timestamp Counters + XED_REG_TR, // 16+ (16 on 16, 32 on 32, 64 on 64) Task Register + + XED_REG_CR0, XED_REG_CR1, XED_REG_CR2, XED_REG_CR3, XED_REG_CR4, XED_REG_CR5, XED_REG_CR6, XED_REG_CR7, XED_REG_CR8, XED_REG_CR9, XED_REG_CR10, XED_REG_CR11, XED_REG_CR12, XED_REG_CR13, XED_REG_CR14, XED_REG_CR15, // 32+ (32 on 32, 64 on 64) Control Registers + XED_REG_DR0, XED_REG_DR1, XED_REG_DR2, XED_REG_DR3, XED_REG_DR4, XED_REG_DR5, XED_REG_DR6, XED_REG_DR7, // 32+ (starting in later revisions of 32) (32 on 32, 64 on 64) Debug registers + + XED_REG_MXCSR, // 32+ SSE (MMX) Control Reg (32 on 32, 64 on 64) + + // 48-Bit (All 32+) + XED_REG_GDTR, // Global Descriptor Table Register + XED_REG_LDTR, // Local Descriptor Table Register + XED_REG_IDTR, // Interrupt Descriptor Table Register + + // 64-Bit + XED_REG_MMX0, XED_REG_MMX1, XED_REG_MMX2, XED_REG_MMX3, XED_REG_MMX4, XED_REG_MMX5, XED_REG_MMX6, XED_REG_MMX7, // 32+ Floating point, bottom of st regs + XED_REG_XCR0, // 32+ (64 on 32, 64 on 64) + + XED_REG_RFLAGS, + + XED_REG_MSRS, + + // 80-Bit + XED_REG_ST0, XED_REG_ST1, XED_REG_ST2, XED_REG_ST3, XED_REG_ST4, XED_REG_ST5, XED_REG_ST6, XED_REG_ST7, // 32+ Floating point + REG_X87_r(0), REG_X87_r(1), REG_X87_r(2), REG_X87_r(3), REG_X87_r(4), REG_X87_r(5), REG_X87_r(6), REG_X87_r(7), + + // 128-Bit + XED_REG_XMM0, XED_REG_XMM1, XED_REG_XMM2, XED_REG_XMM3, XED_REG_XMM4, XED_REG_XMM5, XED_REG_XMM6, XED_REG_XMM7, // 32+ SSE + + XED_REG_BND0, XED_REG_BND1, XED_REG_BND2, XED_REG_BND3, + }; + } + + virtual BNRegisterInfo GetRegisterInfo(const uint32_t reg) override + { + switch (reg) + { + // 8-Bit + case XED_REG_AH: return RegisterInfo(XED_REG_EAX, 1, 1); + case XED_REG_CH: return RegisterInfo(XED_REG_ECX, 1, 1); + case XED_REG_DH: return RegisterInfo(XED_REG_EDX, 1, 1); + case XED_REG_BH: return RegisterInfo(XED_REG_EBX, 1, 1); + case XED_REG_AL: return RegisterInfo(XED_REG_EAX, 0, 1); + case XED_REG_CL: return RegisterInfo(XED_REG_ECX, 0, 1); + case XED_REG_DL: return RegisterInfo(XED_REG_EDX, 0, 1); + case XED_REG_BL: return RegisterInfo(XED_REG_EBX, 0, 1); + + // 16-Bit + case XED_REG_IP: return RegisterInfo(XED_REG_EIP, 0, 2); + + case XED_REG_CS: return RegisterInfo(XED_REG_CS, 0, 2); + case XED_REG_DS: return RegisterInfo(XED_REG_DS, 0, 2); + case XED_REG_ES: return RegisterInfo(XED_REG_ES, 0, 2); + case XED_REG_SS: return RegisterInfo(XED_REG_SS, 0, 2); + case XED_REG_FS: return RegisterInfo(XED_REG_FS, 0, 2); + case XED_REG_GS: return RegisterInfo(XED_REG_GS, 0, 2); + + case XED_REG_SP: return RegisterInfo(XED_REG_ESP, 0, 2); + case XED_REG_BP: return RegisterInfo(XED_REG_EBP, 0, 2); + case XED_REG_SI: return RegisterInfo(XED_REG_ESI, 0, 2); + case XED_REG_DI: return RegisterInfo(XED_REG_EDI, 0, 2); + + case XED_REG_FLAGS: return RegisterInfo(XED_REG_EFLAGS, 0, 2); + + case XED_REG_AX: return RegisterInfo(XED_REG_EAX, 0, 2); + case XED_REG_CX: return RegisterInfo(XED_REG_ECX, 0, 2); + case XED_REG_DX: return RegisterInfo(XED_REG_EDX, 0, 2); + case XED_REG_BX: return RegisterInfo(XED_REG_EBX, 0, 2); + + // 32-Bit + case XED_REG_EIP: return RegisterInfo(XED_REG_EIP, 0, 4); + case XED_REG_FSBASE: return RegisterInfo(XED_REG_FSBASE, 0, 4); + case XED_REG_GSBASE: return RegisterInfo(XED_REG_GSBASE, 0, 4); + + case XED_REG_ESP: return RegisterInfo(XED_REG_ESP, 0, 4); + case XED_REG_EBP: return RegisterInfo(XED_REG_EBP, 0, 4); + case XED_REG_ESI: return RegisterInfo(XED_REG_ESI, 0, 4); + case XED_REG_EDI: return RegisterInfo(XED_REG_EDI, 0, 4); + + case XED_REG_EFLAGS: return RegisterInfo(XED_REG_EFLAGS, 0, 4); + + case XED_REG_EAX: return RegisterInfo(XED_REG_EAX, 0, 4); + case XED_REG_ECX: return RegisterInfo(XED_REG_ECX, 0, 4); + case XED_REG_EDX: return RegisterInfo(XED_REG_EDX, 0, 4); + case XED_REG_EBX: return RegisterInfo(XED_REG_EBX, 0, 4); + + case XED_REG_TSC: return RegisterInfo(XED_REG_TSC, 0, 4); + case XED_REG_TSCAUX: return RegisterInfo(XED_REG_TSCAUX, 0, 4); + + case XED_REG_TR: return RegisterInfo(XED_REG_TR, 0, 4); + + case REG_X87_TOP: return RegisterInfo((xed_reg_enum_t)REG_X87_TOP, 0, 2); + case XED_REG_X87CONTROL: return RegisterInfo(XED_REG_X87CONTROL, 0, 2); + case XED_REG_X87STATUS: return RegisterInfo(XED_REG_X87STATUS, 0, 2); + case XED_REG_X87TAG: return RegisterInfo(XED_REG_X87TAG, 0, 2); + case XED_REG_X87OPCODE: return RegisterInfo(XED_REG_X87OPCODE, 0, 2); + case XED_REG_X87LASTCS: return RegisterInfo(XED_REG_X87LASTCS, 0, 2); + case XED_REG_X87LASTDS: return RegisterInfo(XED_REG_X87LASTDS, 0, 2); + case XED_REG_X87LASTIP: return RegisterInfo(XED_REG_X87LASTIP, 0, 4); + case XED_REG_X87LASTDP: return RegisterInfo(XED_REG_X87LASTDP, 0, 4); + case XED_REG_X87PUSH: return RegisterInfo(XED_REG_X87PUSH, 0, 4); + case XED_REG_X87POP: return RegisterInfo(XED_REG_X87POP, 0, 4); + case XED_REG_X87POP2: return RegisterInfo(XED_REG_X87POP2, 0, 4); + + case XED_REG_CR0: return RegisterInfo(XED_REG_CR0, 0, 4); + case XED_REG_CR1: return RegisterInfo(XED_REG_CR1, 0, 4); + case XED_REG_CR2: return RegisterInfo(XED_REG_CR2, 0, 4); + case XED_REG_CR3: return RegisterInfo(XED_REG_CR3, 0, 4); + case XED_REG_CR4: return RegisterInfo(XED_REG_CR4, 0, 4); + case XED_REG_CR5: return RegisterInfo(XED_REG_CR5, 0, 4); + case XED_REG_CR6: return RegisterInfo(XED_REG_CR6, 0, 4); + case XED_REG_CR7: return RegisterInfo(XED_REG_CR7, 0, 4); + case XED_REG_CR8: return RegisterInfo(XED_REG_CR8, 0, 4); + case XED_REG_CR9: return RegisterInfo(XED_REG_CR9, 0, 4); + case XED_REG_CR10: return RegisterInfo(XED_REG_CR10, 0, 4); + case XED_REG_CR11: return RegisterInfo(XED_REG_CR11, 0, 4); + case XED_REG_CR12: return RegisterInfo(XED_REG_CR12, 0, 4); + case XED_REG_CR13: return RegisterInfo(XED_REG_CR13, 0, 4); + case XED_REG_CR14: return RegisterInfo(XED_REG_CR14, 0, 4); + case XED_REG_CR15: return RegisterInfo(XED_REG_CR15, 0, 4); + + case XED_REG_DR0: return RegisterInfo(XED_REG_DR0, 0, 4); + case XED_REG_DR1: return RegisterInfo(XED_REG_DR1, 0, 4); + case XED_REG_DR2: return RegisterInfo(XED_REG_DR2, 0, 4); + case XED_REG_DR3: return RegisterInfo(XED_REG_DR3, 0, 4); + case XED_REG_DR4: return RegisterInfo(XED_REG_DR4, 0, 4); + case XED_REG_DR5: return RegisterInfo(XED_REG_DR5, 0, 4); + case XED_REG_DR6: return RegisterInfo(XED_REG_DR6, 0, 4); + case XED_REG_DR7: return RegisterInfo(XED_REG_DR7, 0, 4); + + case XED_REG_MXCSR: return RegisterInfo(XED_REG_MXCSR, 0, 4); + + // 48-Bit + case XED_REG_GDTR: return RegisterInfo(XED_REG_GDTR, 0, 6); + case XED_REG_LDTR: return RegisterInfo(XED_REG_LDTR, 0, 6); + case XED_REG_IDTR: return RegisterInfo(XED_REG_IDTR, 0, 6); + + // 64-Bit + case XED_REG_MMX0: return RegisterInfo(XED_REG_ST0, 0, 8); + case XED_REG_MMX1: return RegisterInfo(XED_REG_ST1, 0, 8); + case XED_REG_MMX2: return RegisterInfo(XED_REG_ST2, 0, 8); + case XED_REG_MMX3: return RegisterInfo(XED_REG_ST3, 0, 8); + case XED_REG_MMX4: return RegisterInfo(XED_REG_ST4, 0, 8); + case XED_REG_MMX5: return RegisterInfo(XED_REG_ST5, 0, 8); + case XED_REG_MMX6: return RegisterInfo(XED_REG_ST6, 0, 8); + case XED_REG_MMX7: return RegisterInfo(XED_REG_ST7, 0, 8); + + case XED_REG_XCR0: return RegisterInfo(XED_REG_XCR0, 0, 8); + + case XED_REG_RFLAGS: return RegisterInfo(XED_REG_RFLAGS, 0, 8); + + case XED_REG_MSRS: return RegisterInfo(XED_REG_MSRS, 0, 8); + + // 80-Bit + case XED_REG_ST0: return RegisterInfo(XED_REG_ST0, 0, 10); + case XED_REG_ST1: return RegisterInfo(XED_REG_ST1, 0, 10); + case XED_REG_ST2: return RegisterInfo(XED_REG_ST2, 0, 10); + case XED_REG_ST3: return RegisterInfo(XED_REG_ST3, 0, 10); + case XED_REG_ST4: return RegisterInfo(XED_REG_ST4, 0, 10); + case XED_REG_ST5: return RegisterInfo(XED_REG_ST5, 0, 10); + case XED_REG_ST6: return RegisterInfo(XED_REG_ST6, 0, 10); + case XED_REG_ST7: return RegisterInfo(XED_REG_ST7, 0, 10); + + case REG_X87_r(0): return RegisterInfo((xed_reg_enum_t)REG_X87_r(0), 0, 10); + case REG_X87_r(1): return RegisterInfo((xed_reg_enum_t)REG_X87_r(1), 0, 10); + case REG_X87_r(2): return RegisterInfo((xed_reg_enum_t)REG_X87_r(2), 0, 10); + case REG_X87_r(3): return RegisterInfo((xed_reg_enum_t)REG_X87_r(3), 0, 10); + case REG_X87_r(4): return RegisterInfo((xed_reg_enum_t)REG_X87_r(4), 0, 10); + case REG_X87_r(5): return RegisterInfo((xed_reg_enum_t)REG_X87_r(5), 0, 10); + case REG_X87_r(6): return RegisterInfo((xed_reg_enum_t)REG_X87_r(6), 0, 10); + case REG_X87_r(7): return RegisterInfo((xed_reg_enum_t)REG_X87_r(7), 0, 10); + + // 128-Bit + case XED_REG_XMM0: return RegisterInfo(XED_REG_XMM0, 0, 16); + case XED_REG_XMM1: return RegisterInfo(XED_REG_XMM1, 0, 16); + case XED_REG_XMM2: return RegisterInfo(XED_REG_XMM2, 0, 16); + case XED_REG_XMM3: return RegisterInfo(XED_REG_XMM3, 0, 16); + case XED_REG_XMM4: return RegisterInfo(XED_REG_XMM4, 0, 16); + case XED_REG_XMM5: return RegisterInfo(XED_REG_XMM5, 0, 16); + case XED_REG_XMM6: return RegisterInfo(XED_REG_XMM6, 0, 16); + case XED_REG_XMM7: return RegisterInfo(XED_REG_XMM7, 0, 16); + + case XED_REG_BND0: return RegisterInfo(XED_REG_BND0, 0, 16); + case XED_REG_BND1: return RegisterInfo(XED_REG_BND1, 0, 16); + case XED_REG_BND2: return RegisterInfo(XED_REG_BND2, 0, 16); + case XED_REG_BND3: return RegisterInfo(XED_REG_BND3, 0, 16); + + default: + return RegisterInfo(XED_REG_INVALID, 0, 0); + } + } + + virtual uint32_t GetStackPointerRegister() override + { + return XED_REG_ESP; + } +}; + + +class X16Architecture: public X86CommonArchitecture +{ +protected: + virtual size_t GetAddressSize() const override + { + return 2; + } + +public: + X16Architecture(): X86CommonArchitecture("x86_16", 16) + {} + + virtual vector<uint32_t> GetFullWidthRegisters() override + { + return vector<uint32_t> { + // 16-Bit + XED_REG_IP, // 16+ + XED_REG_CS, XED_REG_DS, XED_REG_ES, XED_REG_SS, XED_REG_FS, XED_REG_GS, XED_REG_FSBASE, XED_REG_GSBASE, // 16+ + XED_REG_SP, XED_REG_BP, XED_REG_SI, XED_REG_DI, // 16+ + XED_REG_FLAGS, // 16+ + + XED_REG_AX, XED_REG_CX, XED_REG_DX, XED_REG_BX, // 16+ + + XED_REG_TR, // 16+ (16 on 16, 32 on 32, 64 on 64) Task Register + }; + } + + virtual vector<uint32_t> GetAllRegisters() override + { + return vector<uint32_t>{ + // 8-Bit + XED_REG_AH, XED_REG_CH, XED_REG_DH, XED_REG_BH, XED_REG_AL, XED_REG_CL, XED_REG_DL, XED_REG_BL, // 16+ + + // 16-Bit + XED_REG_IP, // 16+ + XED_REG_CS, XED_REG_DS, XED_REG_ES, XED_REG_SS, XED_REG_FS, XED_REG_GS, XED_REG_FSBASE, XED_REG_GSBASE, // 16+ + XED_REG_SP, XED_REG_BP, XED_REG_SI, XED_REG_DI, // 16+ + XED_REG_FLAGS, // 16+ + + XED_REG_AX, XED_REG_CX, XED_REG_DX, XED_REG_BX, // 16+ + + XED_REG_TR, // 16+ (16 on 16, 32 on 32, 64 on 64) Task Register + }; + } + + virtual BNRegisterInfo GetRegisterInfo(const uint32_t reg) override + { + switch (reg) + { + // 8-Bit + case XED_REG_AH: return RegisterInfo(XED_REG_AX, 1, 1); + case XED_REG_CH: return RegisterInfo(XED_REG_CX, 1, 1); + case XED_REG_DH: return RegisterInfo(XED_REG_DX, 1, 1); + case XED_REG_BH: return RegisterInfo(XED_REG_BX, 1, 1); + case XED_REG_AL: return RegisterInfo(XED_REG_AX, 0, 1); + case XED_REG_CL: return RegisterInfo(XED_REG_CX, 0, 1); + case XED_REG_DL: return RegisterInfo(XED_REG_DX, 0, 1); + case XED_REG_BL: return RegisterInfo(XED_REG_BX, 0, 1); + + // 16-Bit + case XED_REG_IP: return RegisterInfo(XED_REG_IP, 0, 2); + case XED_REG_CS: return RegisterInfo(XED_REG_CS, 0, 2); + case XED_REG_DS: return RegisterInfo(XED_REG_DS, 0, 2); + case XED_REG_ES: return RegisterInfo(XED_REG_ES, 0, 2); + case XED_REG_SS: return RegisterInfo(XED_REG_SS, 0, 2); + case XED_REG_FS: return RegisterInfo(XED_REG_FS, 0, 2); + case XED_REG_GS: return RegisterInfo(XED_REG_GS, 0, 2); + case XED_REG_FSBASE: return RegisterInfo(XED_REG_FSBASE, 0, 2); + case XED_REG_GSBASE: return RegisterInfo(XED_REG_GSBASE, 0, 2); + case XED_REG_SP: return RegisterInfo(XED_REG_SP, 0, 2); + case XED_REG_BP: return RegisterInfo(XED_REG_BP, 0, 2); + case XED_REG_SI: return RegisterInfo(XED_REG_SI, 0, 2); + case XED_REG_DI: return RegisterInfo(XED_REG_DI, 0, 2); + case XED_REG_FLAGS: return RegisterInfo(XED_REG_FLAGS, 0, 2); + case XED_REG_AX: return RegisterInfo(XED_REG_AX, 0, 2); + case XED_REG_CX: return RegisterInfo(XED_REG_CX, 0, 2); + case XED_REG_DX: return RegisterInfo(XED_REG_DX, 0, 2); + case XED_REG_BX: return RegisterInfo(XED_REG_BX, 0, 2); + case XED_REG_TR: return RegisterInfo(XED_REG_TR, 0, 2); + + default: return RegisterInfo(XED_REG_INVALID, 0, 0); + } + } + + virtual uint32_t GetStackPointerRegister() override + { + return XED_REG_SP; + } +}; + + +class X64Architecture: public X86CommonArchitecture +{ +protected: + virtual size_t GetAddressSize() const override + { + return 8; + } + +public: + X64Architecture(): X86CommonArchitecture("x86_64", 64) + {} + + virtual vector<uint32_t> GetFullWidthRegisters() override + { + return vector< uint32_t> { + // 16-Bit + XED_REG_CS, XED_REG_DS, XED_REG_ES, XED_REG_SS, XED_REG_FS, XED_REG_GS, XED_REG_FSBASE, XED_REG_GSBASE, // 16+ + XED_REG_SP, XED_REG_BP, XED_REG_SI, XED_REG_DI, // 16+ + + // x87 FPU related + REG_X87_TOP, XED_REG_X87CONTROL, XED_REG_X87STATUS, XED_REG_X87TAG, XED_REG_X87OPCODE, XED_REG_X87LASTCS, + XED_REG_X87LASTDS, XED_REG_X87LASTIP, XED_REG_X87LASTDP, XED_REG_X87PUSH, XED_REG_X87POP, XED_REG_X87POP2, + + // 48-Bit (All 32+) + XED_REG_GDTR, // Global Descriptor Table Register + XED_REG_LDTR, // Local Descriptor Table Register + XED_REG_IDTR, // Interrupt Descriptor Table Register + + // 64-Bit + XED_REG_TR, // 16+ (16 on 16, 32 on 32, 64 on 64) Task Register + XED_REG_TSC, XED_REG_TSCAUX, // 32+ (32 on 32, 64 on 64) Timestamp Counters + XED_REG_RIP, // 64+ + XED_REG_RSP, XED_REG_RBP, XED_REG_RSI, XED_REG_RDI, // 64+ + XED_REG_RFLAGS, // 64+ + XED_REG_MXCSR, // 32+ SSE (MMX) Control Reg (32 on 32, 64 on 64) + XED_REG_XCR0, // 32+ (64 on 32, 64 on 64) + XED_REG_SSP, // 64+ Shadow Stack Reg + + XED_REG_RAX, XED_REG_RCX, XED_REG_RDX, XED_REG_RBX, // 64+ + XED_REG_R8, XED_REG_R9, XED_REG_R10, XED_REG_R11, XED_REG_R12, XED_REG_R13, XED_REG_R14, XED_REG_R15, // 64+ + + XED_REG_BNDCFGU, XED_REG_BNDSTATUS, // 64 briefly. MPX control registers + XED_REG_K0, XED_REG_K1, XED_REG_K2, XED_REG_K3, XED_REG_K4, XED_REG_K5, XED_REG_K6, XED_REG_K7, // 64+ AVX bit-masking registers (also not confident in size) + + XED_REG_MSRS, + + XED_REG_CR0, XED_REG_CR1, XED_REG_CR2, XED_REG_CR3, XED_REG_CR4, XED_REG_CR5, XED_REG_CR6, XED_REG_CR7, XED_REG_CR8, XED_REG_CR9, XED_REG_CR10, XED_REG_CR11, XED_REG_CR12, XED_REG_CR13, XED_REG_CR14, XED_REG_CR15, // 32+ (32 on 32, 64 on 64) Control Registers + XED_REG_DR0, XED_REG_DR1, XED_REG_DR2, XED_REG_DR3, XED_REG_DR4, XED_REG_DR5, XED_REG_DR6, XED_REG_DR7, // 32+ (starting in later revisions of 32) (32 on 32, 64 on 64) Debug registers + + // 80-Bit + XED_REG_ST0, XED_REG_ST1, XED_REG_ST2, XED_REG_ST3, XED_REG_ST4, XED_REG_ST5, XED_REG_ST6, XED_REG_ST7, // 32+ Floating point + REG_X87_r(0), REG_X87_r(1), REG_X87_r(2), REG_X87_r(3), REG_X87_r(4), REG_X87_r(5), REG_X87_r(6), REG_X87_r(7), + + // 128-Bit + XED_REG_BND0, XED_REG_BND1, XED_REG_BND2, XED_REG_BND3, // 64 briefly. MPX registers + + // 512-Bit + XED_REG_ZMM0, XED_REG_ZMM1, XED_REG_ZMM2, XED_REG_ZMM3, XED_REG_ZMM4, XED_REG_ZMM5, XED_REG_ZMM6, XED_REG_ZMM7, XED_REG_ZMM8, XED_REG_ZMM9, XED_REG_ZMM10, XED_REG_ZMM11, XED_REG_ZMM12, XED_REG_ZMM13, XED_REG_ZMM14, XED_REG_ZMM15, XED_REG_ZMM16, XED_REG_ZMM17, XED_REG_ZMM18, XED_REG_ZMM19, XED_REG_ZMM20, XED_REG_ZMM21, XED_REG_ZMM22, XED_REG_ZMM23, XED_REG_ZMM24, XED_REG_ZMM25, XED_REG_ZMM26, XED_REG_ZMM27, XED_REG_ZMM28, XED_REG_ZMM29, XED_REG_ZMM30, XED_REG_ZMM31 // 64+ AVX + }; + } + + virtual vector<uint32_t> GetAllRegisters() override + { + return vector< uint32_t> { + // 8-Bit + XED_REG_AH, XED_REG_CH, XED_REG_DH, XED_REG_BH, XED_REG_AL, XED_REG_CL, XED_REG_DL, XED_REG_BL, // 16+ + XED_REG_SPL, XED_REG_BPL, XED_REG_SIL, XED_REG_DIL, // 64+ + XED_REG_R8B, XED_REG_R9B, XED_REG_R10B, XED_REG_R11B, XED_REG_R12B, XED_REG_R13B, XED_REG_R14B, XED_REG_R15B, // 64+ + + // 16-Bit + XED_REG_IP, // 16+ + XED_REG_CS, XED_REG_DS, XED_REG_ES, XED_REG_SS, XED_REG_FS, XED_REG_GS, XED_REG_FSBASE, XED_REG_GSBASE, // 16+ + XED_REG_SP, XED_REG_BP, XED_REG_SI, XED_REG_DI, // 16+ + XED_REG_FLAGS, // 16+ + + REG_X87_TOP, // 32+ + XED_REG_X87CONTROL, XED_REG_X87STATUS, XED_REG_X87TAG, XED_REG_X87PUSH, XED_REG_X87POP, + XED_REG_X87POP2, XED_REG_X87OPCODE, XED_REG_X87LASTCS, XED_REG_X87LASTIP, XED_REG_X87LASTDS, XED_REG_X87LASTDP, + + XED_REG_AX, XED_REG_CX, XED_REG_DX, XED_REG_BX, // 16+ + XED_REG_R8W, XED_REG_R9W, XED_REG_R10W, XED_REG_R11W, XED_REG_R12W, XED_REG_R13W, XED_REG_R14W, XED_REG_R15W, // 64+ + + // 32-Bit + XED_REG_EIP, // 32+ + XED_REG_ESP, XED_REG_EBP, XED_REG_ESI, XED_REG_EDI, // 32+ + XED_REG_EFLAGS, // 32+ + + XED_REG_EAX, XED_REG_ECX, XED_REG_EDX, XED_REG_EBX, // 32+ + XED_REG_R8D, XED_REG_R9D, XED_REG_R10D, XED_REG_R11D, XED_REG_R12D, XED_REG_R13D, XED_REG_R14D, XED_REG_R15D, // 64+ + + // 48-Bit (All 32+) + XED_REG_GDTR, // Global Descriptor Table Register + XED_REG_LDTR, // Local Descriptor Table Register + XED_REG_IDTR, // Interrupt Descriptor Table Register + + // 64-Bit + XED_REG_TR, // 16+ (16 on 16, 32 on 32, 64 on 64) Task Register + XED_REG_TSC, XED_REG_TSCAUX, // 32+ (32 on 32, 64 on 64) Timestamp Counters + XED_REG_MMX0, XED_REG_MMX1, XED_REG_MMX2, XED_REG_MMX3, XED_REG_MMX4, XED_REG_MMX5, XED_REG_MMX6, XED_REG_MMX7, // 32+ Floating point, bottom of st regs + XED_REG_RIP, // 64+ + XED_REG_RSP, XED_REG_RBP, XED_REG_RSI, XED_REG_RDI, // 64+ + XED_REG_RFLAGS, // 64+ + XED_REG_MXCSR, // 32+ SSE (MMX) Control Reg (32 on 32, 64 on 64) + XED_REG_XCR0, // 32+ (64 on 32, 64 on 64) + XED_REG_SSP, // 64+ Shadow Stack Reg + + XED_REG_RAX, XED_REG_RCX, XED_REG_RDX, XED_REG_RBX, // 64+ + XED_REG_R8, XED_REG_R9, XED_REG_R10, XED_REG_R11, XED_REG_R12, XED_REG_R13, XED_REG_R14, XED_REG_R15, // 64+ + + XED_REG_BNDCFGU, XED_REG_BNDSTATUS, // 64 briefly. MPX control registers + XED_REG_K0, XED_REG_K1, XED_REG_K2, XED_REG_K3, XED_REG_K4, XED_REG_K5, XED_REG_K6, XED_REG_K7, // 64+ AVX bit-masking registers (also not confident in size) + + XED_REG_MSRS, + + XED_REG_CR0, XED_REG_CR1, XED_REG_CR2, XED_REG_CR3, XED_REG_CR4, XED_REG_CR5, XED_REG_CR6, XED_REG_CR7, XED_REG_CR8, XED_REG_CR9, XED_REG_CR10, XED_REG_CR11, XED_REG_CR12, XED_REG_CR13, XED_REG_CR14, XED_REG_CR15, // 32+ (32 on 32, 64 on 64) Control Registers + XED_REG_DR0, XED_REG_DR1, XED_REG_DR2, XED_REG_DR3, XED_REG_DR4, XED_REG_DR5, XED_REG_DR6, XED_REG_DR7, // 32+ (starting in later revisions of 32) (32 on 32, 64 on 64) Debug registers + + // 80-Bit + XED_REG_ST0, XED_REG_ST1, XED_REG_ST2, XED_REG_ST3, XED_REG_ST4, XED_REG_ST5, XED_REG_ST6, XED_REG_ST7, // 32+ Floating point + REG_X87_r(0), REG_X87_r(1), REG_X87_r(2), REG_X87_r(3), REG_X87_r(4), REG_X87_r(5), REG_X87_r(6), REG_X87_r(7), + + // 128-Bit + XED_REG_XMM0, XED_REG_XMM1, XED_REG_XMM2, XED_REG_XMM3, XED_REG_XMM4, XED_REG_XMM5, XED_REG_XMM6, XED_REG_XMM7, // 32+ SSE + XED_REG_XMM8, XED_REG_XMM9, XED_REG_XMM10, XED_REG_XMM11, XED_REG_XMM12, XED_REG_XMM13, XED_REG_XMM14, XED_REG_XMM15, // 64+ SSE + XED_REG_XMM16, XED_REG_XMM17, XED_REG_XMM18, XED_REG_XMM19, XED_REG_XMM20, XED_REG_XMM21, XED_REG_XMM22, XED_REG_XMM23, XED_REG_XMM24, XED_REG_XMM25, XED_REG_XMM26, XED_REG_XMM27, XED_REG_XMM28, XED_REG_XMM29, XED_REG_XMM30, XED_REG_XMM31, // 64+ AVX + XED_REG_BND0, XED_REG_BND1, XED_REG_BND2, XED_REG_BND3, // 64 briefly. MPX registers + + // 256-Bit + XED_REG_YMM0, XED_REG_YMM1, XED_REG_YMM2, XED_REG_YMM3, XED_REG_YMM4, XED_REG_YMM5, XED_REG_YMM6, XED_REG_YMM7, XED_REG_YMM8, XED_REG_YMM9, XED_REG_YMM10, XED_REG_YMM11, XED_REG_YMM12, XED_REG_YMM13, XED_REG_YMM14, XED_REG_YMM15, XED_REG_YMM16, XED_REG_YMM17, XED_REG_YMM18, XED_REG_YMM19, XED_REG_YMM20, XED_REG_YMM21, XED_REG_YMM22, XED_REG_YMM23, XED_REG_YMM24, XED_REG_YMM25, XED_REG_YMM26, XED_REG_YMM27, XED_REG_YMM28, XED_REG_YMM29, XED_REG_YMM30, XED_REG_YMM31, // 64+ AVX + + // 512-Bit + XED_REG_ZMM0, XED_REG_ZMM1, XED_REG_ZMM2, XED_REG_ZMM3, XED_REG_ZMM4, XED_REG_ZMM5, XED_REG_ZMM6, XED_REG_ZMM7, XED_REG_ZMM8, XED_REG_ZMM9, XED_REG_ZMM10, XED_REG_ZMM11, XED_REG_ZMM12, XED_REG_ZMM13, XED_REG_ZMM14, XED_REG_ZMM15, XED_REG_ZMM16, XED_REG_ZMM17, XED_REG_ZMM18, XED_REG_ZMM19, XED_REG_ZMM20, XED_REG_ZMM21, XED_REG_ZMM22, XED_REG_ZMM23, XED_REG_ZMM24, XED_REG_ZMM25, XED_REG_ZMM26, XED_REG_ZMM27, XED_REG_ZMM28, XED_REG_ZMM29, XED_REG_ZMM30, XED_REG_ZMM31 // 64+ AVX + }; + } + + virtual BNRegisterInfo GetRegisterInfo(const uint32_t reg) override + { + switch (reg) + { + // 8-Bit + case XED_REG_AH: return RegisterInfo(XED_REG_RAX, 1, 1); + case XED_REG_CH: return RegisterInfo(XED_REG_RCX, 1, 1); + case XED_REG_DH: return RegisterInfo(XED_REG_RDX, 1, 1); + case XED_REG_BH: return RegisterInfo(XED_REG_RBX, 1, 1); + case XED_REG_AL: return RegisterInfo(XED_REG_RAX, 0, 1); + case XED_REG_CL: return RegisterInfo(XED_REG_RCX, 0, 1); + case XED_REG_DL: return RegisterInfo(XED_REG_RDX, 0, 1); + case XED_REG_BL: return RegisterInfo(XED_REG_RBX, 0, 1); + + case XED_REG_SPL: return RegisterInfo(XED_REG_RSP, 0, 1); + case XED_REG_BPL: return RegisterInfo(XED_REG_RBP, 0, 1); + case XED_REG_SIL: return RegisterInfo(XED_REG_RSI, 0, 1); + case XED_REG_DIL: return RegisterInfo(XED_REG_RDI, 0, 1); + + case XED_REG_R8B: return RegisterInfo(XED_REG_R8, 0, 1); + case XED_REG_R9B: return RegisterInfo(XED_REG_R9, 0, 1); + case XED_REG_R10B: return RegisterInfo(XED_REG_R10, 0, 1); + case XED_REG_R11B: return RegisterInfo(XED_REG_R11, 0, 1); + case XED_REG_R12B: return RegisterInfo(XED_REG_R12, 0, 1); + case XED_REG_R13B: return RegisterInfo(XED_REG_R13, 0, 1); + case XED_REG_R14B: return RegisterInfo(XED_REG_R14, 0, 1); + case XED_REG_R15B: return RegisterInfo(XED_REG_R15, 0, 1); + + // 16-Bit + case XED_REG_IP: return RegisterInfo(XED_REG_RIP, 0, 2); + + case XED_REG_CS: return RegisterInfo(XED_REG_CS, 0, 2); + case XED_REG_DS: return RegisterInfo(XED_REG_DS, 0, 2); + case XED_REG_ES: return RegisterInfo(XED_REG_ES, 0, 2); + case XED_REG_SS: return RegisterInfo(XED_REG_SS, 0, 2); + case XED_REG_FS: return RegisterInfo(XED_REG_FS, 0, 2); + case XED_REG_GS: return RegisterInfo(XED_REG_GS, 0, 2); + + case XED_REG_SP: return RegisterInfo(XED_REG_RSP, 0, 2); + case XED_REG_BP: return RegisterInfo(XED_REG_RBP, 0, 2); + case XED_REG_SI: return RegisterInfo(XED_REG_RSI, 0, 2); + case XED_REG_DI: return RegisterInfo(XED_REG_RDI, 0, 2); + + case XED_REG_FLAGS: return RegisterInfo(XED_REG_RFLAGS, 0, 2); + + case XED_REG_AX: return RegisterInfo(XED_REG_RAX, 0, 2); + case XED_REG_CX: return RegisterInfo(XED_REG_RCX, 0, 2); + case XED_REG_DX: return RegisterInfo(XED_REG_RDX, 0, 2); + case XED_REG_BX: return RegisterInfo(XED_REG_RBX, 0, 2); + case XED_REG_R8W: return RegisterInfo(XED_REG_R8, 0, 2); + case XED_REG_R9W: return RegisterInfo(XED_REG_R9, 0, 2); + case XED_REG_R10W: return RegisterInfo(XED_REG_R10, 0, 2); + case XED_REG_R11W: return RegisterInfo(XED_REG_R11, 0, 2); + case XED_REG_R12W: return RegisterInfo(XED_REG_R12, 0, 2); + case XED_REG_R13W: return RegisterInfo(XED_REG_R13, 0, 2); + case XED_REG_R14W: return RegisterInfo(XED_REG_R14, 0, 2); + case XED_REG_R15W: return RegisterInfo(XED_REG_R15, 0, 2); + + // 32-Bit + case XED_REG_EIP: return RegisterInfo(XED_REG_RIP, 0, 4); + + case XED_REG_ESP: return RegisterInfo(XED_REG_RSP, 0, 4, true); + case XED_REG_EBP: return RegisterInfo(XED_REG_RBP, 0, 4, true); + case XED_REG_ESI: return RegisterInfo(XED_REG_RSI, 0, 4, true); + case XED_REG_EDI: return RegisterInfo(XED_REG_RDI, 0, 4, true); + + case REG_X87_TOP: return RegisterInfo((xed_reg_enum_t)REG_X87_TOP, 0, 2); + case XED_REG_X87CONTROL: return RegisterInfo(XED_REG_X87CONTROL, 0, 2); + case XED_REG_X87STATUS: return RegisterInfo(XED_REG_X87STATUS, 0, 2); + case XED_REG_X87TAG: return RegisterInfo(XED_REG_X87TAG, 0, 2); + case XED_REG_X87OPCODE: return RegisterInfo(XED_REG_X87OPCODE, 0, 2); + case XED_REG_X87LASTCS: return RegisterInfo(XED_REG_X87LASTCS, 0, 2); + case XED_REG_X87LASTDS: return RegisterInfo(XED_REG_X87LASTDS, 0, 2); + case XED_REG_X87LASTIP: return RegisterInfo(XED_REG_X87LASTIP, 0, 8); + case XED_REG_X87LASTDP: return RegisterInfo(XED_REG_X87LASTDP, 0, 8); + case XED_REG_X87PUSH: return RegisterInfo(XED_REG_X87PUSH, 0, 8); + case XED_REG_X87POP: return RegisterInfo(XED_REG_X87POP, 0, 8); + case XED_REG_X87POP2: return RegisterInfo(XED_REG_X87POP2, 0, 8); + + case XED_REG_EFLAGS: return RegisterInfo(XED_REG_RFLAGS, 0, 4, true); + + case XED_REG_EAX: return RegisterInfo(XED_REG_RAX, 0, 4, true); + case XED_REG_ECX: return RegisterInfo(XED_REG_RCX, 0, 4, true); + case XED_REG_EDX: return RegisterInfo(XED_REG_RDX, 0, 4, true); + case XED_REG_EBX: return RegisterInfo(XED_REG_RBX, 0, 4, true); + + case XED_REG_R8D: return RegisterInfo(XED_REG_R8, 0, 4, true); + case XED_REG_R9D: return RegisterInfo(XED_REG_R9, 0, 4, true); + case XED_REG_R10D: return RegisterInfo(XED_REG_R10, 0, 4, true); + case XED_REG_R11D: return RegisterInfo(XED_REG_R11, 0, 4, true); + case XED_REG_R12D: return RegisterInfo(XED_REG_R12, 0, 4, true); + case XED_REG_R13D: return RegisterInfo(XED_REG_R13, 0, 4, true); + case XED_REG_R14D: return RegisterInfo(XED_REG_R14, 0, 4, true); + case XED_REG_R15D: return RegisterInfo(XED_REG_R15, 0, 4, true); + + // 48-Bit + case XED_REG_GDTR: return RegisterInfo(XED_REG_GDTR, 0, 6); + case XED_REG_LDTR: return RegisterInfo(XED_REG_LDTR, 0, 6); + case XED_REG_IDTR: return RegisterInfo(XED_REG_IDTR, 0, 6); + + // 64-Bit + case XED_REG_FSBASE: return RegisterInfo(XED_REG_FSBASE, 0, 8); + case XED_REG_GSBASE: return RegisterInfo(XED_REG_GSBASE, 0, 8); + case XED_REG_TSC: return RegisterInfo(XED_REG_TSC, 0, 8); + case XED_REG_TSCAUX: return RegisterInfo(XED_REG_TSCAUX, 0, 8); + case XED_REG_TR: return RegisterInfo(XED_REG_TR, 0, 8); + + case XED_REG_MMX0: return RegisterInfo(XED_REG_ST0, 0, 8); + case XED_REG_MMX1: return RegisterInfo(XED_REG_ST1, 0, 8); + case XED_REG_MMX2: return RegisterInfo(XED_REG_ST2, 0, 8); + case XED_REG_MMX3: return RegisterInfo(XED_REG_ST3, 0, 8); + case XED_REG_MMX4: return RegisterInfo(XED_REG_ST4, 0, 8); + case XED_REG_MMX5: return RegisterInfo(XED_REG_ST5, 0, 8); + case XED_REG_MMX6: return RegisterInfo(XED_REG_ST6, 0, 8); + case XED_REG_MMX7: return RegisterInfo(XED_REG_ST7, 0, 8); + + case XED_REG_RIP: return RegisterInfo(XED_REG_RIP, 0, 8); + + case XED_REG_RSP: return RegisterInfo(XED_REG_RSP, 0, 8); + case XED_REG_RBP: return RegisterInfo(XED_REG_RBP, 0, 8); + case XED_REG_RSI: return RegisterInfo(XED_REG_RSI, 0, 8); + case XED_REG_RDI: return RegisterInfo(XED_REG_RDI, 0, 8); + + case XED_REG_RFLAGS: return RegisterInfo(XED_REG_RFLAGS, 0, 8); + + case XED_REG_MXCSR: return RegisterInfo(XED_REG_MXCSR, 0, 8); + case XED_REG_XCR0: return RegisterInfo(XED_REG_XCR0, 0, 8); + case XED_REG_SSP: return RegisterInfo(XED_REG_SSP, 0, 8); + + case XED_REG_RAX: return RegisterInfo(XED_REG_RAX, 0, 8); + case XED_REG_RCX: return RegisterInfo(XED_REG_RCX, 0, 8); + case XED_REG_RDX: return RegisterInfo(XED_REG_RDX, 0, 8); + case XED_REG_RBX: return RegisterInfo(XED_REG_RBX, 0, 8); + case XED_REG_R8: return RegisterInfo(XED_REG_R8, 0, 8); + case XED_REG_R9: return RegisterInfo(XED_REG_R9, 0, 8); + case XED_REG_R10: return RegisterInfo(XED_REG_R10, 0, 8); + case XED_REG_R11: return RegisterInfo(XED_REG_R11, 0, 8); + case XED_REG_R12: return RegisterInfo(XED_REG_R12, 0, 8); + case XED_REG_R13: return RegisterInfo(XED_REG_R13, 0, 8); + case XED_REG_R14: return RegisterInfo(XED_REG_R14, 0, 8); + case XED_REG_R15: return RegisterInfo(XED_REG_R15, 0, 8); + + case XED_REG_BNDCFGU: return RegisterInfo(XED_REG_BNDCFGU, 0, 8); + case XED_REG_BNDSTATUS: return RegisterInfo(XED_REG_BNDSTATUS, 0, 8); + + case XED_REG_K0: return RegisterInfo(XED_REG_K0, 0, 8); + case XED_REG_K1: return RegisterInfo(XED_REG_K1, 0, 8); + case XED_REG_K2: return RegisterInfo(XED_REG_K2, 0, 8); + case XED_REG_K3: return RegisterInfo(XED_REG_K3, 0, 8); + case XED_REG_K4: return RegisterInfo(XED_REG_K4, 0, 8); + case XED_REG_K5: return RegisterInfo(XED_REG_K5, 0, 8); + case XED_REG_K6: return RegisterInfo(XED_REG_K6, 0, 8); + case XED_REG_K7: return RegisterInfo(XED_REG_K7, 0, 8); + + case XED_REG_CR0: return RegisterInfo(XED_REG_CR0, 0, 8); + case XED_REG_CR1: return RegisterInfo(XED_REG_CR1, 0, 8); + case XED_REG_CR2: return RegisterInfo(XED_REG_CR2, 0, 8); + case XED_REG_CR3: return RegisterInfo(XED_REG_CR3, 0, 8); + case XED_REG_CR4: return RegisterInfo(XED_REG_CR4, 0, 8); + case XED_REG_CR5: return RegisterInfo(XED_REG_CR5, 0, 8); + case XED_REG_CR6: return RegisterInfo(XED_REG_CR6, 0, 8); + case XED_REG_CR7: return RegisterInfo(XED_REG_CR7, 0, 8); + case XED_REG_CR8: return RegisterInfo(XED_REG_CR8, 0, 8); + case XED_REG_CR9: return RegisterInfo(XED_REG_CR9, 0, 8); + case XED_REG_CR10: return RegisterInfo(XED_REG_CR10, 0, 8); + case XED_REG_CR11: return RegisterInfo(XED_REG_CR11, 0, 8); + case XED_REG_CR12: return RegisterInfo(XED_REG_CR12, 0, 8); + case XED_REG_CR13: return RegisterInfo(XED_REG_CR13, 0, 8); + case XED_REG_CR14: return RegisterInfo(XED_REG_CR14, 0, 8); + case XED_REG_CR15: return RegisterInfo(XED_REG_CR15, 0, 8); + + case XED_REG_DR0: return RegisterInfo(XED_REG_DR0, 0, 8); + case XED_REG_DR1: return RegisterInfo(XED_REG_DR1, 0, 8); + case XED_REG_DR2: return RegisterInfo(XED_REG_DR2, 0, 8); + case XED_REG_DR3: return RegisterInfo(XED_REG_DR3, 0, 8); + case XED_REG_DR4: return RegisterInfo(XED_REG_DR4, 0, 8); + case XED_REG_DR5: return RegisterInfo(XED_REG_DR5, 0, 8); + case XED_REG_DR6: return RegisterInfo(XED_REG_DR6, 0, 8); + case XED_REG_DR7: return RegisterInfo(XED_REG_DR7, 0, 8); + + case XED_REG_MSRS: return RegisterInfo(XED_REG_MSRS, 0, 8); + + // 80-Bit + case XED_REG_ST0: return RegisterInfo(XED_REG_ST0, 0, 10); + case XED_REG_ST1: return RegisterInfo(XED_REG_ST1, 0, 10); + case XED_REG_ST2: return RegisterInfo(XED_REG_ST2, 0, 10); + case XED_REG_ST3: return RegisterInfo(XED_REG_ST3, 0, 10); + case XED_REG_ST4: return RegisterInfo(XED_REG_ST4, 0, 10); + case XED_REG_ST5: return RegisterInfo(XED_REG_ST5, 0, 10); + case XED_REG_ST6: return RegisterInfo(XED_REG_ST6, 0, 10); + case XED_REG_ST7: return RegisterInfo(XED_REG_ST7, 0, 10); + + case REG_X87_r(0): return RegisterInfo((xed_reg_enum_t)REG_X87_r(0), 0, 10); + case REG_X87_r(1): return RegisterInfo((xed_reg_enum_t)REG_X87_r(1), 0, 10); + case REG_X87_r(2): return RegisterInfo((xed_reg_enum_t)REG_X87_r(2), 0, 10); + case REG_X87_r(3): return RegisterInfo((xed_reg_enum_t)REG_X87_r(3), 0, 10); + case REG_X87_r(4): return RegisterInfo((xed_reg_enum_t)REG_X87_r(4), 0, 10); + case REG_X87_r(5): return RegisterInfo((xed_reg_enum_t)REG_X87_r(5), 0, 10); + case REG_X87_r(6): return RegisterInfo((xed_reg_enum_t)REG_X87_r(6), 0, 10); + case REG_X87_r(7): return RegisterInfo((xed_reg_enum_t)REG_X87_r(7), 0, 10); + + // 128-Bit + case XED_REG_XMM0: return RegisterInfo(XED_REG_ZMM0, 0, 16); + case XED_REG_XMM1: return RegisterInfo(XED_REG_ZMM1, 0, 16); + case XED_REG_XMM2: return RegisterInfo(XED_REG_ZMM2, 0, 16); + case XED_REG_XMM3: return RegisterInfo(XED_REG_ZMM3, 0, 16); + case XED_REG_XMM4: return RegisterInfo(XED_REG_ZMM4, 0, 16); + case XED_REG_XMM5: return RegisterInfo(XED_REG_ZMM5, 0, 16); + case XED_REG_XMM6: return RegisterInfo(XED_REG_ZMM6, 0, 16); + case XED_REG_XMM7: return RegisterInfo(XED_REG_ZMM7, 0, 16); + case XED_REG_XMM8: return RegisterInfo(XED_REG_ZMM8, 0, 16); + case XED_REG_XMM9: return RegisterInfo(XED_REG_ZMM9, 0, 16); + case XED_REG_XMM10: return RegisterInfo(XED_REG_ZMM10, 0, 16); + case XED_REG_XMM11: return RegisterInfo(XED_REG_ZMM11, 0, 16); + case XED_REG_XMM12: return RegisterInfo(XED_REG_ZMM12, 0, 16); + case XED_REG_XMM13: return RegisterInfo(XED_REG_ZMM13, 0, 16); + case XED_REG_XMM14: return RegisterInfo(XED_REG_ZMM14, 0, 16); + case XED_REG_XMM15: return RegisterInfo(XED_REG_ZMM15, 0, 16); + case XED_REG_XMM16: return RegisterInfo(XED_REG_ZMM16, 0, 16); + case XED_REG_XMM17: return RegisterInfo(XED_REG_ZMM17, 0, 16); + case XED_REG_XMM18: return RegisterInfo(XED_REG_ZMM18, 0, 16); + case XED_REG_XMM19: return RegisterInfo(XED_REG_ZMM19, 0, 16); + case XED_REG_XMM20: return RegisterInfo(XED_REG_ZMM20, 0, 16); + case XED_REG_XMM21: return RegisterInfo(XED_REG_ZMM21, 0, 16); + case XED_REG_XMM22: return RegisterInfo(XED_REG_ZMM22, 0, 16); + case XED_REG_XMM23: return RegisterInfo(XED_REG_ZMM23, 0, 16); + case XED_REG_XMM24: return RegisterInfo(XED_REG_ZMM24, 0, 16); + case XED_REG_XMM25: return RegisterInfo(XED_REG_ZMM25, 0, 16); + case XED_REG_XMM26: return RegisterInfo(XED_REG_ZMM26, 0, 16); + case XED_REG_XMM27: return RegisterInfo(XED_REG_ZMM27, 0, 16); + case XED_REG_XMM28: return RegisterInfo(XED_REG_ZMM28, 0, 16); + case XED_REG_XMM29: return RegisterInfo(XED_REG_ZMM29, 0, 16); + case XED_REG_XMM30: return RegisterInfo(XED_REG_ZMM30, 0, 16); + case XED_REG_XMM31: return RegisterInfo(XED_REG_ZMM31, 0, 16); + + case XED_REG_BND0: return RegisterInfo(XED_REG_BND0, 0, 16); + case XED_REG_BND1: return RegisterInfo(XED_REG_BND1, 0, 16); + case XED_REG_BND2: return RegisterInfo(XED_REG_BND2, 0, 16); + case XED_REG_BND3: return RegisterInfo(XED_REG_BND3, 0, 16); + + // 256-Bit + case XED_REG_YMM0: return RegisterInfo(XED_REG_ZMM0, 0, 32); + case XED_REG_YMM1: return RegisterInfo(XED_REG_ZMM1, 0, 32); + case XED_REG_YMM2: return RegisterInfo(XED_REG_ZMM2, 0, 32); + case XED_REG_YMM3: return RegisterInfo(XED_REG_ZMM3, 0, 32); + case XED_REG_YMM4: return RegisterInfo(XED_REG_ZMM4, 0, 32); + case XED_REG_YMM5: return RegisterInfo(XED_REG_ZMM5, 0, 32); + case XED_REG_YMM6: return RegisterInfo(XED_REG_ZMM6, 0, 32); + case XED_REG_YMM7: return RegisterInfo(XED_REG_ZMM7, 0, 32); + case XED_REG_YMM8: return RegisterInfo(XED_REG_ZMM8, 0, 32); + case XED_REG_YMM9: return RegisterInfo(XED_REG_ZMM9, 0, 32); + case XED_REG_YMM10: return RegisterInfo(XED_REG_ZMM10, 0, 32); + case XED_REG_YMM11: return RegisterInfo(XED_REG_ZMM11, 0, 32); + case XED_REG_YMM12: return RegisterInfo(XED_REG_ZMM12, 0, 32); + case XED_REG_YMM13: return RegisterInfo(XED_REG_ZMM13, 0, 32); + case XED_REG_YMM14: return RegisterInfo(XED_REG_ZMM14, 0, 32); + case XED_REG_YMM15: return RegisterInfo(XED_REG_ZMM15, 0, 32); + case XED_REG_YMM16: return RegisterInfo(XED_REG_ZMM16, 0, 32); + case XED_REG_YMM17: return RegisterInfo(XED_REG_ZMM17, 0, 32); + case XED_REG_YMM18: return RegisterInfo(XED_REG_ZMM18, 0, 32); + case XED_REG_YMM19: return RegisterInfo(XED_REG_ZMM19, 0, 32); + case XED_REG_YMM20: return RegisterInfo(XED_REG_ZMM20, 0, 32); + case XED_REG_YMM21: return RegisterInfo(XED_REG_ZMM21, 0, 32); + case XED_REG_YMM22: return RegisterInfo(XED_REG_ZMM22, 0, 32); + case XED_REG_YMM23: return RegisterInfo(XED_REG_ZMM23, 0, 32); + case XED_REG_YMM24: return RegisterInfo(XED_REG_ZMM24, 0, 32); + case XED_REG_YMM25: return RegisterInfo(XED_REG_ZMM25, 0, 32); + case XED_REG_YMM26: return RegisterInfo(XED_REG_ZMM26, 0, 32); + case XED_REG_YMM27: return RegisterInfo(XED_REG_ZMM27, 0, 32); + case XED_REG_YMM28: return RegisterInfo(XED_REG_ZMM28, 0, 32); + case XED_REG_YMM29: return RegisterInfo(XED_REG_ZMM29, 0, 32); + case XED_REG_YMM30: return RegisterInfo(XED_REG_ZMM30, 0, 32); + case XED_REG_YMM31: return RegisterInfo(XED_REG_ZMM31, 0, 32); + + // 512-Bit + case XED_REG_ZMM0: return RegisterInfo(XED_REG_ZMM0, 0, 64); + case XED_REG_ZMM1: return RegisterInfo(XED_REG_ZMM1, 0, 64); + case XED_REG_ZMM2: return RegisterInfo(XED_REG_ZMM2, 0, 64); + case XED_REG_ZMM3: return RegisterInfo(XED_REG_ZMM3, 0, 64); + case XED_REG_ZMM4: return RegisterInfo(XED_REG_ZMM4, 0, 64); + case XED_REG_ZMM5: return RegisterInfo(XED_REG_ZMM5, 0, 64); + case XED_REG_ZMM6: return RegisterInfo(XED_REG_ZMM6, 0, 64); + case XED_REG_ZMM7: return RegisterInfo(XED_REG_ZMM7, 0, 64); + case XED_REG_ZMM8: return RegisterInfo(XED_REG_ZMM8, 0, 64); + case XED_REG_ZMM9: return RegisterInfo(XED_REG_ZMM9, 0, 64); + case XED_REG_ZMM10: return RegisterInfo(XED_REG_ZMM10, 0, 64); + case XED_REG_ZMM11: return RegisterInfo(XED_REG_ZMM11, 0, 64); + case XED_REG_ZMM12: return RegisterInfo(XED_REG_ZMM12, 0, 64); + case XED_REG_ZMM13: return RegisterInfo(XED_REG_ZMM13, 0, 64); + case XED_REG_ZMM14: return RegisterInfo(XED_REG_ZMM14, 0, 64); + case XED_REG_ZMM15: return RegisterInfo(XED_REG_ZMM15, 0, 64); + case XED_REG_ZMM16: return RegisterInfo(XED_REG_ZMM16, 0, 64); + case XED_REG_ZMM17: return RegisterInfo(XED_REG_ZMM17, 0, 64); + case XED_REG_ZMM18: return RegisterInfo(XED_REG_ZMM18, 0, 64); + case XED_REG_ZMM19: return RegisterInfo(XED_REG_ZMM19, 0, 64); + case XED_REG_ZMM20: return RegisterInfo(XED_REG_ZMM20, 0, 64); + case XED_REG_ZMM21: return RegisterInfo(XED_REG_ZMM21, 0, 64); + case XED_REG_ZMM22: return RegisterInfo(XED_REG_ZMM22, 0, 64); + case XED_REG_ZMM23: return RegisterInfo(XED_REG_ZMM23, 0, 64); + case XED_REG_ZMM24: return RegisterInfo(XED_REG_ZMM24, 0, 64); + case XED_REG_ZMM25: return RegisterInfo(XED_REG_ZMM25, 0, 64); + case XED_REG_ZMM26: return RegisterInfo(XED_REG_ZMM26, 0, 64); + case XED_REG_ZMM27: return RegisterInfo(XED_REG_ZMM27, 0, 64); + case XED_REG_ZMM28: return RegisterInfo(XED_REG_ZMM28, 0, 64); + case XED_REG_ZMM29: return RegisterInfo(XED_REG_ZMM29, 0, 64); + case XED_REG_ZMM30: return RegisterInfo(XED_REG_ZMM30, 0, 64); + case XED_REG_ZMM31: return RegisterInfo(XED_REG_ZMM31, 0, 64); + + default: return RegisterInfo(XED_REG_INVALID, 0, 0); + } + } + + virtual uint32_t GetStackPointerRegister() override + { + return XED_REG_RSP; + } +}; + + +class X86BaseCallingConvention: public CallingConvention +{ +public: + X86BaseCallingConvention(Architecture* arch, const string& name): CallingConvention(arch, name) + { + } + + virtual vector<uint32_t> GetCallerSavedRegisters() override + { + return vector<uint32_t>{ XED_REG_EAX, XED_REG_ECX, XED_REG_EDX }; + } + + virtual vector<uint32_t> GetCalleeSavedRegisters() override + { + return vector<uint32_t>{ XED_REG_EBX, XED_REG_EBP, XED_REG_ESI, XED_REG_EDI }; + } + + virtual uint32_t GetGlobalPointerRegister() override + { + return XED_REG_EBX; + } + + virtual uint32_t GetIntegerReturnValueRegister() override + { + return XED_REG_EAX; + } + + virtual uint32_t GetHighIntegerReturnValueRegister() override + { + return XED_REG_EDX; + } + + virtual uint32_t GetFloatReturnValueRegister() override + { + return XED_REG_ST0; + } + + virtual RegisterValue GetIncomingFlagValue(uint32_t flag, Function*) override + { + RegisterValue result; + if (flag == IL_FLAG_D) + { + result.state = ConstantValue; + result.value = 0; + } + return result; + } +}; + + +class X86CdeclCallingConvention: public X86BaseCallingConvention +{ +public: + X86CdeclCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "cdecl") + { + } +}; + + +class X86StdcallCallingConvention: public X86BaseCallingConvention +{ +public: + X86StdcallCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "stdcall") + { + } + + virtual bool IsStackAdjustedOnReturn() override + { + return true; + } +}; + + +class X86RegParmCallingConvention: public X86BaseCallingConvention +{ +public: + X86RegParmCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "regparm") + { + } + + virtual vector<uint32_t> GetIntegerArgumentRegisters() override + { + return vector<uint32_t>{ XED_REG_EAX, XED_REG_EDX, XED_REG_ECX }; + } +}; + + +class X86FastcallCallingConvention: public X86BaseCallingConvention +{ +public: + X86FastcallCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "fastcall") + { + } + + virtual vector<uint32_t> GetIntegerArgumentRegisters() override + { + return vector<uint32_t>{ XED_REG_ECX, XED_REG_EDX }; + } + + virtual bool IsStackAdjustedOnReturn() override + { + return true; + } +}; + + +class X86ThiscallCallingConvention: public X86BaseCallingConvention +{ +public: + X86ThiscallCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "thiscall") + { + } + + virtual vector<uint32_t> GetIntegerArgumentRegisters() override + { + return vector<uint32_t>{ XED_REG_ECX }; + } + + virtual bool IsStackAdjustedOnReturn() override + { + return true; + } +}; + + +class X86LinuxSystemCallConvention: public CallingConvention +{ +public: + X86LinuxSystemCallConvention(Architecture* arch): CallingConvention(arch, "linux-syscall") + { + } + + virtual vector<uint32_t> GetIntegerArgumentRegisters() override + { + return vector<uint32_t> { XED_REG_EAX, XED_REG_EBX, XED_REG_ECX, XED_REG_EDX, XED_REG_ESI, XED_REG_EDI, XED_REG_EBP }; + } + + virtual vector<uint32_t> GetCallerSavedRegisters() override + { + return vector<uint32_t> { XED_REG_EAX, XED_REG_EDX }; + } + + virtual vector<uint32_t> GetCalleeSavedRegisters() override + { + return vector<uint32_t> { XED_REG_EBX, XED_REG_EBP, XED_REG_ESI, XED_REG_EDI }; + } + + virtual uint32_t GetIntegerReturnValueRegister() override + { + return XED_REG_EAX; + } + + virtual uint32_t GetHighIntegerReturnValueRegister() override + { + return XED_REG_EDX; + } + + virtual uint32_t GetFloatReturnValueRegister() override + { + return XED_REG_ST0; + } + + virtual bool IsEligibleForHeuristics() override + { + return false; + } +}; + + +class X64BaseCallingConvention: public CallingConvention +{ +public: + X64BaseCallingConvention(Architecture* arch, const string& name): CallingConvention(arch, name) + { + } + + virtual uint32_t GetIntegerReturnValueRegister() override + { + return XED_REG_RAX; + } + + virtual uint32_t GetFloatReturnValueRegister() override + { + return XED_REG_ZMM0; + } + + virtual RegisterValue GetIncomingFlagValue(uint32_t flag, Function*) override + { + RegisterValue result; + if (flag == IL_FLAG_D) + { + result.state = ConstantValue; + result.value = 0; + } + return result; + } +}; + + +class X64SystemVCallingConvention: public X64BaseCallingConvention +{ +public: + X64SystemVCallingConvention(Architecture* arch): X64BaseCallingConvention(arch, "sysv") + { + } + + virtual vector<uint32_t> GetIntegerArgumentRegisters() override + { + return vector<uint32_t> { XED_REG_RDI, XED_REG_RSI, XED_REG_RDX, XED_REG_RCX, XED_REG_R8, XED_REG_R9 }; + } + + virtual vector<uint32_t> GetFloatArgumentRegisters() override + { + return vector<uint32_t> { XED_REG_ZMM0, XED_REG_ZMM1, XED_REG_ZMM2, XED_REG_ZMM3, XED_REG_ZMM4, XED_REG_ZMM5, XED_REG_ZMM6, XED_REG_ZMM7 }; + } + + virtual vector<uint32_t> GetCallerSavedRegisters() override + { + return vector<uint32_t> { + XED_REG_RAX, XED_REG_RCX, XED_REG_RDX, + XED_REG_RSI, XED_REG_RDI, + XED_REG_R8, XED_REG_R9, XED_REG_R10, XED_REG_R11, + XED_REG_ZMM0, XED_REG_ZMM1, XED_REG_ZMM2, XED_REG_ZMM3, XED_REG_ZMM4, XED_REG_ZMM5, XED_REG_ZMM6, XED_REG_ZMM7, XED_REG_ZMM8, XED_REG_ZMM9, XED_REG_ZMM10, XED_REG_ZMM11, XED_REG_ZMM12, XED_REG_ZMM13, XED_REG_ZMM14, XED_REG_ZMM15 }; + } + + virtual vector<uint32_t> GetCalleeSavedRegisters() override + { + return vector<uint32_t> { + XED_REG_RBX, XED_REG_RBP, + XED_REG_R12, XED_REG_R13, XED_REG_R14, XED_REG_R15 }; + } +}; + + +class X64WindowsCallingConvention: public X64BaseCallingConvention +{ +public: + X64WindowsCallingConvention(Architecture* arch): X64BaseCallingConvention(arch, "win64") + { + } + + virtual vector<uint32_t> GetIntegerArgumentRegisters() override + { + return vector<uint32_t> { XED_REG_RCX, XED_REG_RDX, XED_REG_R8, XED_REG_R9 }; + } + + virtual vector<uint32_t> GetFloatArgumentRegisters() override + { + return vector<uint32_t> { XED_REG_ZMM0, XED_REG_ZMM1, XED_REG_ZMM2, XED_REG_ZMM3 }; + } + + virtual vector<uint32_t> GetCallerSavedRegisters() override + { + return vector<uint32_t> { + XED_REG_RAX, XED_REG_RCX, XED_REG_RDX, + XED_REG_R8, XED_REG_R9, XED_REG_R10, XED_REG_R11, + XED_REG_ZMM4, XED_REG_ZMM5 }; + } + + virtual vector<uint32_t> GetCalleeSavedRegisters() override + { + return vector<uint32_t> { + XED_REG_RBX, XED_REG_RBP, XED_REG_RSI, XED_REG_RDI, + XED_REG_R12, XED_REG_R13, XED_REG_R14, XED_REG_R15 }; + } + + virtual bool AreArgumentRegistersSharedIndex() override + { + return true; + } + + virtual bool IsStackReservedForArgumentRegisters() override + { + return true; + } +}; + + +class X64LinuxSystemCallConvention: public CallingConvention +{ +public: + X64LinuxSystemCallConvention(Architecture* arch): CallingConvention(arch, "linux-syscall") + { + } + + virtual vector<uint32_t> GetIntegerArgumentRegisters() override + { + return vector<uint32_t> { XED_REG_RAX, XED_REG_RDI, XED_REG_RSI, XED_REG_RDX, XED_REG_R10, XED_REG_R8, XED_REG_R9 }; + } + + virtual vector<uint32_t> GetCallerSavedRegisters() override + { + return vector<uint32_t> { XED_REG_RAX, XED_REG_RCX, XED_REG_R11 }; + } + + virtual vector<uint32_t> GetCalleeSavedRegisters() override + { + return vector<uint32_t> { XED_REG_RBX, XED_REG_RBP, XED_REG_RSI, XED_REG_RDI, + XED_REG_R12, XED_REG_R13, XED_REG_R14, XED_REG_R15 }; + } + + virtual uint32_t GetIntegerReturnValueRegister() override + { + return XED_REG_RAX; + } + + virtual bool IsEligibleForHeuristics() override + { + return false; + } +}; + + +class x86MachoRelocationHandler: public RelocationHandler +{ +public: + + virtual bool ApplyRelocation(Ref<BinaryView> view, Ref<Architecture> arch, Ref<Relocation> reloc, uint8_t* dest, + size_t len) override + { + (void)view; + (void)arch; + (void)len; + auto info = reloc->GetInfo(); + uint64_t pcRelAddr = info.pcRelative ? reloc->GetAddress() : 0; + // TODO these need tested + // uint8_t* dest8 = (uint8_t*)dest; + // uint16_t* dest16 = (uint16_t*)dest; + uint32_t* dest32 = (uint32_t*)dest; + uint32_t target = (uint32_t)reloc->GetTarget(); + + switch (info.nativeType) + { + case (uint64_t)-1: // Magic number defined in MachOView.cpp + // We need to write a jump absolute `jmp target` + dest[0] = '\xe9'; + ((uint32_t*)&dest[1])[0] = target - (uint32_t)reloc->GetAddress() - 5; + break; + case (uint64_t)-2: // Magic number defined in MachOView.cpp + dest32[0] = target; + break; + case GENERIC_RELOC_VANILLA: + switch (info.size) + { + // TODO these need tested + // case 1: *dest8 = target - pcRelAddr; break; + // case 2: *dest16 = target - pcRelAddr; break; + case 4: *dest32 = (uint32_t)(target - pcRelAddr); break; + default: break; + } + // TODO rebasing + break; + + default: + break; + } + + return true; + } + + virtual bool GetRelocationInfo(Ref<BinaryView> view, Ref<Architecture> arch, vector<BNRelocationInfo>& result) override + { + (void)view; (void)arch; + set<uint64_t> relocTypes; + for (size_t i = 0; i < result.size(); i++) + { + result[i].type = StandardRelocationType; + switch (result[i].nativeType) + { + case GENERIC_RELOC_VANILLA: + if (result[i].size != 4) + { + result[i].type = IgnoredRelocation; + relocTypes.insert(result[i].nativeType); + } + break; + default: + result[i].type = UnhandledRelocation; + relocTypes.insert(result[i].nativeType); + break; + } + } + + for (auto& reloc : relocTypes) + LogWarn("Unsupported Mach-O relocation type: %s", GetRelocationString((Machox86RelocationType)reloc)); + return true; + } +}; + +class x86ElfRelocationHandler: public RelocationHandler +{ +public: + virtual bool GetRelocationInfo(Ref<BinaryView> view, Ref<Architecture> arch, vector<BNRelocationInfo>& result) override + { + (void)view; (void)arch; + set<uint64_t> relocTypes; + for (auto& reloc : result) + { + reloc.type = StandardRelocationType; + switch (reloc.nativeType) + { + case R_386_NONE: + reloc.type = IgnoredRelocation; + break; + case R_386_32: + reloc.pcRelative = false; + reloc.baseRelative = false; + reloc.hasSign = false; + reloc.size = 4; + reloc.truncateSize = 4; + break; + case R_386_PC32: + case R_386_GOT32: + case R_386_PLT32: + reloc.pcRelative = true; + reloc.baseRelative = false; + reloc.hasSign = false; + reloc.size = 4; + reloc.truncateSize = 4; + break; + case R_386_RELATIVE: + reloc.pcRelative = false; + reloc.baseRelative = true; + reloc.hasSign = false; + reloc.size = 4; + reloc.truncateSize = 4; + reloc.implicitAddend = true; + reloc.addend = 0; + break; + case R_386_COPY: + reloc.type = ELFCopyRelocationType; + reloc.pcRelative = false; + reloc.baseRelative = false; + reloc.size = 4; + reloc.truncateSize = 4; + break; + case R_386_GLOB_DAT: + reloc.type = ELFGlobalRelocationType; + reloc.pcRelative = false; + reloc.baseRelative = false; + reloc.size = 4; + reloc.truncateSize = 4; + reloc.implicitAddend = false; + break; + case R_386_JUMP_SLOT: + reloc.type = ELFJumpSlotRelocationType; + reloc.pcRelative = false; + reloc.baseRelative = false; + reloc.size = 4; + reloc.truncateSize = 4; + reloc.implicitAddend = false; + break; + default: + reloc.type = UnhandledRelocation; + relocTypes.insert(reloc.nativeType); + } + } + for (auto& reloc : relocTypes) + LogWarn("Unsupported ELF relocation type: %s", GetRelocationString((Elfx86RelocationType)reloc)); + return true; + } +}; + +class x64MachoRelocationHandler: public RelocationHandler +{ +public: + virtual bool ApplyRelocation(Ref<BinaryView> view, Ref<Architecture> arch, Ref<Relocation> reloc, uint8_t* dest, size_t len) override + { + (void)view; + (void)arch; + auto info = reloc->GetInfo(); + uint64_t pcRelAddr = info.pcRelative ? reloc->GetAddress() : 0; + if (len < info.size) + return false; + uint32_t target = (uint32_t)info.target; + uint32_t* dest32 = (uint32_t*)dest; + uint64_t* dest64 = (uint64_t*)dest; + switch (info.nativeType) + { + case X86_64_RELOC_BRANCH: + if (info.size == 4) + dest32[0] = dest32[0] - 4 + target - (uint32_t)pcRelAddr; + break; + case X86_64_RELOC_GOT_LOAD: + dest32[0] = dest32[0] - 4 + target - (uint32_t)pcRelAddr; + break; + case X86_64_RELOC_SIGNED: + dest32[0] = dest32[0] + target - (uint32_t)pcRelAddr; + break; + case X86_64_RELOC_SIGNED_1: + dest32[0] = dest32[0] + 1 + target - (uint32_t)pcRelAddr; + break; + case X86_64_RELOC_SIGNED_2: + dest32[0] = dest32[0] + 2 + target - (uint32_t)pcRelAddr; + break; + case X86_64_RELOC_SIGNED_4: + dest32[0] = dest32[0] + 4 + target - (uint32_t)pcRelAddr; + break; + case X86_64_RELOC_GOT: + dest32[0] = dest32[0] + target - (uint32_t)pcRelAddr; + break; + case X86_64_RELOC_UNSIGNED: + if (!info.external) + { + switch (info.size) + { + case 4: *dest32 += target - (uint32_t)pcRelAddr; break; + case 8: *dest64 += info.target - pcRelAddr; break; + default: break; + } + } + // TODO rebasing + break; + case X86_64_RELOC_SUBTRACTOR: + if (!info.next) + break; + dest64[0] = dest64[0] + info.next->target - target; + break; + case (uint64_t) -2: + dest64[0] = reloc->GetTarget(); + break; + } + return true; + } + + + virtual bool GetRelocationInfo(Ref<BinaryView> view, Ref<Architecture> arch, vector<BNRelocationInfo>& result) override + { + (void)view; (void)arch; + set<uint64_t> relocTypes; + for (size_t i = 0; i < result.size(); i++) + { + result[i].type = StandardRelocationType; + switch (result[i].nativeType) + { + case X86_64_RELOC_UNSIGNED: + result[i].hasSign = false; + break; + case X86_64_RELOC_BRANCH: + result[i].pcRelative = true; + result[i].size = 4; + result[i].implicitAddend = true; + break; + case X86_64_RELOC_GOT: + case X86_64_RELOC_GOT_LOAD: + result[i].pcRelative = true; + result[i].size = 4; + result[i].implicitAddend = true; + break; + case X86_64_RELOC_SIGNED: + result[i].implicitAddend = true; + result[i].size = 4; + result[i].hasSign = true; + break; + case X86_64_RELOC_SIGNED_1: + result[i].implicitAddend = true; + result[i].addend = 1; + result[i].size = 4; + result[i].hasSign = true; + break; + case X86_64_RELOC_SIGNED_2: + result[i].implicitAddend = true; + result[i].addend = 2; + result[i].size = 4; + result[i].hasSign = true; + break; + case X86_64_RELOC_SIGNED_4: + result[i].implicitAddend = true; + result[i].addend = 4; + result[i].size = 4; + result[i].hasSign = true; + break; + case X86_64_RELOC_SUBTRACTOR: + // X86_64_RELOC_SUBTRACTOR should always be followed by a X86_64_RELOC_UNSIGNED + if (i == result.size() - 1) + result[i].type = IgnoredRelocation; + else if ((Machox64RelocationType)result[i + 1].type != X86_64_RELOC_UNSIGNED) + result[i].type = IgnoredRelocation; + else + { + result[i].next = &result[i + 1]; + result[i + 1].type = IgnoredRelocation; + i++; + } + break; + default: + result[i].type = UnhandledRelocation; + relocTypes.insert(result[i].nativeType); + break; + } + } + + for (auto& reloc : relocTypes) + LogWarn("Unsupported Mach-O relocation: %s", GetRelocationString((Machox64RelocationType)reloc)); + return true; + } +}; + +class x64ElfRelocationHandler: public RelocationHandler +{ +public: + virtual bool ApplyRelocation(Ref<BinaryView> view, Ref<Architecture> arch, Ref<Relocation> reloc, uint8_t* dest, size_t len) override + { + BNRelocationInfo info = reloc->GetInfo(); + switch (info.nativeType) + { + case R_X86_64_REX_GOTPCRELX: { + // When we're actually applying this we don't need to change the 3 first bytes, + // just apply it to the immediate and it's fine. However, we track all seven + // variable bytes so we don't lie to the user. + dest += 3; + uint64_t pc = reloc->GetAddress() + 3; + uint64_t addend = 0; + if (info.implicitAddend && info.size < sizeof(addend)) + memcpy(&addend, dest, reloc->GetInfo().size); + else + addend = info.addend; + uint32_t write = (uint32_t)(reloc->GetTarget() + addend - pc); + memcpy(dest, (uint8_t*)&write, sizeof(uint32_t)); + return true; + } + case R_X86_64_IRELATIVE: { + // What??????? + uint64_t write = info.addend; + memcpy(dest, (uint8_t*)&write, sizeof(uint64_t)); + return true; + } + default: + return RelocationHandler::ApplyRelocation(view, arch, reloc, dest, len); + } + } + + virtual bool GetRelocationInfo(Ref<BinaryView> view, Ref<Architecture> arch, vector<BNRelocationInfo>& result) override + { + /* + From the Intel AMD64 ELF Linux ABI + A Represents the addend used to compute the value of the relocatable field. + B Represents the base address at which a shared object has been loaded into memory during execution. + Generally, a shared object is built with a 0 base virtual address, but the execution address will be different. + G Represents the offset into the global offset table at which the relocation entry’s symbol + will reside during execution. + GOT Represents the address of the global offset table. + L Represents the place (section offset or address) of the Procedure Linkage Table + entry for a symbol. + P Represents the place (section offset or address) of the storage unit being relocated (computed using r_offset). + S Represents the value of the symbol whose index resides in the relocation entry. + Z Represents the size of the symbol whose index resides in the relocation entry. + The AMD64 LP64 ABI architecture uses only Elf64_Rela relocation entries with explicit addends. Theg + r_addend member serves as the relocation addend. + The AMD64 ILP32 ABI architecture uses only Elf32_Rela relocation entries in relocatable files. Relocations + contained within executable files or shared objects may use either Elf32_Rela relocation or Elf32_Rel relocation. + */ + (void)view; (void)arch; + set<uint64_t> relocTypes; + for (auto& reloc : result) + { + reloc.type = StandardRelocationType; + switch (reloc.nativeType) + { + case R_X86_64_NONE: + reloc.type = IgnoredRelocation; + break; + case R_X86_64_COPY: + reloc.type = ELFCopyRelocationType; + reloc.pcRelative = false; + reloc.baseRelative = false; + reloc.size = 8; + reloc.truncateSize = 8; + break; + case R_X86_64_GLOB_DAT: + reloc.type = ELFGlobalRelocationType; + reloc.pcRelative = false; + reloc.baseRelative = false; + reloc.size = 8; + reloc.truncateSize = 8; + break; + case R_X86_64_JUMP_SLOT: + reloc.type = ELFJumpSlotRelocationType; + reloc.pcRelative = false; + reloc.baseRelative = false; + reloc.size = 8; + reloc.truncateSize = 8; + break; + case R_X86_64_8: + reloc.pcRelative = false; + reloc.baseRelative = false; + reloc.hasSign = false; + reloc.size = 1; + reloc.truncateSize = 1; + break; + case R_X86_64_16: + reloc.pcRelative = false; + reloc.baseRelative = false; + reloc.hasSign = false; + reloc.size = 2; + reloc.truncateSize = 2; + break; + case R_X86_64_32S: + reloc.pcRelative = false; + reloc.baseRelative = false; + reloc.hasSign = true; + reloc.size = 4; + reloc.truncateSize = 4; + break; + case R_X86_64_32: + case R_X86_64_GOT32: + reloc.pcRelative = false; + reloc.baseRelative = false; + reloc.hasSign = false; + reloc.size = 8; + reloc.truncateSize = 4; + break; + case R_X86_64_64: + reloc.pcRelative = false; + reloc.baseRelative = false; + reloc.hasSign = false; + reloc.size = 8; + reloc.truncateSize = 8; + break; + case R_X86_64_PC32: + case R_X86_64_PLT32: + case R_X86_64_GOTPCREL: + case R_X86_64_GOTPCRELX: + // These are pointers into .got and .plt sections which aren't present + // At some point in the future we may need to create these sections + reloc.pcRelative = true; + reloc.baseRelative = false; + reloc.hasSign = false; + reloc.size = 4; + reloc.truncateSize = 4; + break; + case R_X86_64_PC64: + reloc.pcRelative = true; + reloc.baseRelative = false; + reloc.hasSign = false; + reloc.size = 8; + reloc.truncateSize = 8; + break; + case R_X86_64_REX_GOTPCRELX: + // The 3 bytes before the immediate that specify the registers and operand + // encoding are variable!!! Example: 49c7c400000000 vs 4c8b25d5140000 + reloc.address -= 3; + reloc.pcRelative = true; + reloc.baseRelative = false; + reloc.hasSign = false; + reloc.size = 7; + reloc.truncateSize = 7; + break; + case R_X86_64_RELATIVE: + reloc.pcRelative = false; + reloc.baseRelative = true; + reloc.hasSign = false; + reloc.size = 8; + reloc.truncateSize = 8; + reloc.implicitAddend = true; + break; + case R_X86_64_PC16: + reloc.pcRelative = true; + reloc.baseRelative = false; + reloc.hasSign = false; + reloc.size = 8; + reloc.truncateSize = 2; + break; + case R_X86_64_PC8: + reloc.pcRelative = true; + reloc.baseRelative = false; + reloc.hasSign = false; + reloc.size = 8; + reloc.truncateSize = 1; + break; + case R_X86_64_IRELATIVE: + reloc.pcRelative = false; + reloc.baseRelative = false; + reloc.hasSign = false; + reloc.size = 8; + reloc.truncateSize = 8; + break; + default: + reloc.type = UnhandledRelocation; + relocTypes.insert(reloc.nativeType); + break; + } + } + for (auto& reloc : relocTypes) + LogWarn("Unsupported ELF relocation: %s", GetRelocationString((Elfx64RelocationType)reloc)); + return true; + } +}; + +class CoffRelocationHandler: public RelocationHandler +{ +public: + virtual bool ApplyRelocation(Ref<BinaryView> view, Ref<Architecture> arch, Ref<Relocation> reloc, uint8_t* dest, size_t len) override + { + // Note: info.base contains preferred base address and the base where the image is actually loaded + (void)view; + (void)arch; + (void)len; + uint64_t* data64 = (uint64_t*)dest; + uint32_t* data32 = (uint32_t*)dest; + uint16_t* data16 = (uint16_t*)dest; + auto info = reloc->GetInfo(); + uint64_t offset = 0; + + if (info.pcRelative) + { + int64_t relative_offset = info.target - info.address; + offset = (uint64_t) relative_offset; + } + else + offset = info.target; + + if (! info.implicitAddend && info.addend) + offset += info.addend; + + if (! info.baseRelative) + offset -= info.base; + + switch (info.nativeType) + { + // case PE_IMAGE_REL_I386_SECTION: + case PE_IMAGE_REL_AMD64_SECTION: + // TODO: test this implementation, but for now, just don't warn about it + data16[0] = info.sectionIndex + 1; + break; + // case PE_IMAGE_REL_I386_SECREL: + case PE_IMAGE_REL_AMD64_SECREL: + { + // TODO: test this implementation, but for now, just don't warn about it + auto sections = view->GetSectionsAt(info.target); + if (sections.size() > 0) + { + data32[0] = info.target - sections[0]->GetStart(); + } + break; + } + default: + if (info.size == 8) + { + // LogDebug("%s: address: %#" PRIx64 " target: %#" PRIx64 " base: %#" PRIx64 " offset: %#" PRIx64 " current: %#" PRIx64 " result: %#" PRIx64 "", __func__, info.address, info.target, info.base, offset, data64[0], data64[0] + offset); + data64[0] += offset; + } + else if (info.size == 4) + { + // LogDebug("%s: address: %#" PRIx64 " target: %#" PRIx64 " base: %#" PRIx64 " offset: %#" PRIx32 " %+" PRId32 " current: %#" PRIx32 " result: %#" PRIx32 "", __func__, info.address, info.target, info.base, (uint32_t)offset, (uint32_t)offset, data32[0], data32[0] + (uint32_t)offset); + data32[0] += (uint32_t)offset; + } + } + return true; + } + + virtual bool GetRelocationInfo(Ref<BinaryView> view, Ref<Architecture> arch, vector<BNRelocationInfo>& result) override + { + (void)view; (void)arch; + set<uint64_t> relocTypes; + for (auto& reloc : result) + { + if (arch->GetName() == "x86_64") + { + switch (reloc.nativeType) + { + case PE_IMAGE_REL_AMD64_ABSOLUTE: + reloc.type = IgnoredRelocation; + break; + case PE_IMAGE_REL_AMD64_ADDR64: + reloc.baseRelative = true; + reloc.size = 8; + break; + case PE_IMAGE_REL_AMD64_ADDR32NB: + reloc.baseRelative = false; + reloc.size = 4; + break; + case PE_IMAGE_REL_AMD64_ADDR32: + reloc.baseRelative = true; + reloc.size = 4; + break; + case PE_IMAGE_REL_AMD64_REL32_5: + case PE_IMAGE_REL_AMD64_REL32_4: + case PE_IMAGE_REL_AMD64_REL32_3: + case PE_IMAGE_REL_AMD64_REL32_2: + case PE_IMAGE_REL_AMD64_REL32_1: + // LogDebug("%s: %#" PRIx64 "(%#" PRIx64 ")->%#" PRIx64 " %s addend: %ld", __func__, reloc.address, reloc.target, reloc.address - reloc.target, GetRelocationString((COFFx64RelocationType)reloc.nativeType), (long) reloc.addend); + case PE_IMAGE_REL_AMD64_REL32: + // TODO: treat reloc.addend as offset of target from its section (see llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h:67) + reloc.addend = -(4 + (reloc.nativeType - PE_IMAGE_REL_AMD64_REL32)); + reloc.baseRelative = false; + reloc.pcRelative = true; + reloc.size = 4; + break; + case PE_IMAGE_REL_AMD64_SECTION: + // The 16-bit section index of the section that contains the target. This is used to support debugging information. + reloc.baseRelative = false; + reloc.size = 2; + reloc.addend = 0; + case PE_IMAGE_REL_AMD64_SECREL: + // TODO: implement these, but for now, just don't warn about them + // The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage. reloc.baseRelative = false; + reloc.baseRelative = false; + reloc.size = 4; + reloc.addend = 0; + break; + case PE_IMAGE_REL_AMD64_SECREL7: + // 7-bit offset from the base of the section that contains the target + case PE_IMAGE_REL_AMD64_TOKEN: + case PE_IMAGE_REL_AMD64_SREL32: + case PE_IMAGE_REL_AMD64_PAIR: + case PE_IMAGE_REL_AMD64_SSPAN32: + default: + // By default, PE relocations are correct when not rebased. + // Upon rebasing, support would need to be added to correctly process the relocation + reloc.type = UnhandledRelocation; + relocTypes.insert(reloc.nativeType); + } + for (auto& reloc : relocTypes) + LogWarn("Unsupported COFF relocation: %s", GetRelocationString((COFFx64RelocationType)reloc)); + } + else if (arch->GetName() == "x86") + { + switch (reloc.nativeType) + { + case PE_IMAGE_REL_I386_ABSOLUTE: + reloc.type = IgnoredRelocation; + break; + case PE_IMAGE_REL_I386_REL32: + reloc.baseRelative = false; + reloc.pcRelative = true; + reloc.size = 4; + reloc.addend = -4; + break; + case PE_IMAGE_REL_I386_DIR32NB: + reloc.baseRelative = false; + reloc.size = 4; + break; + case PE_IMAGE_REL_I386_DIR32: + reloc.baseRelative = true; + reloc.size = 4; + break; + case PE_IMAGE_REL_I386_SECTION: + // The 16-bit section index of the section that contains the target. This is used to support debugging information. + reloc.baseRelative = false; + reloc.size = 2; + reloc.addend = 0; + case PE_IMAGE_REL_I386_SECREL: + // The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage. reloc.baseRelative = false; + reloc.baseRelative = false; + reloc.size = 4; + reloc.addend = 0; + break; + case PE_IMAGE_REL_I386_SEG12: + case PE_IMAGE_REL_I386_TOKEN: + case PE_IMAGE_REL_I386_SECREL7: + case PE_IMAGE_REL_I386_DIR16: + case PE_IMAGE_REL_I386_REL16: + default: + reloc.type = UnhandledRelocation; + relocTypes.insert(reloc.nativeType); + } + for (auto& reloc : relocTypes) + LogWarn("Unsupported COFF relocation: %s", GetRelocationString((COFFx86RelocationType)reloc)); + } + } + + return true; + } +}; + +class PeRelocationHandler: public RelocationHandler +{ +public: + virtual bool ApplyRelocation(Ref<BinaryView> view, Ref<Architecture> arch, Ref<Relocation> reloc, uint8_t* dest, size_t len) override + { + // Note: info.base contains preferred base address and the base where the image is actually loaded + (void)view; + (void)arch; + (void)len; + uint64_t* data64 = (uint64_t*)dest; + uint32_t* data32 = (uint32_t*)dest; + uint16_t* data16 = (uint16_t*)dest; + auto info = reloc->GetInfo(); + if ((uint32_t)info.nativeType == PE_IMAGE_USER_DEFINED) + { + if (info.size == 8) + { + data64[0] = info.target; + } + else if (info.size == 4) + { + data32[0] = (uint32_t)info.target; + } + } + else if (info.size == 8) + { + data64[0] += info.base; + } + else if (info.size == 4) + { + data32[0] += (uint32_t)info.base; + } + else if (info.size == 2) + { + if (info.nativeType == PE_IMAGE_REL_BASED_HIGH) + { + data16[0] = data16[0] + (uint16_t)(info.base >> 16); + } + else if (info.nativeType == PE_IMAGE_REL_BASED_LOW) + { + data16[0] = data16[0] + (uint16_t)(info.base & 0xffff); + } + } + return true; + } + + virtual bool GetRelocationInfo(Ref<BinaryView> view, Ref<Architecture> arch, vector<BNRelocationInfo>& result) override + { + (void)view; (void)arch; + set<uint64_t> relocTypes; + for (auto& reloc : result) + { + switch (reloc.nativeType) + { + case PE_IMAGE_REL_BASED_ABSOLUTE: + reloc.type = IgnoredRelocation; + break; + case PE_IMAGE_REL_BASED_HIGHLOW: + reloc.size = 4; + break; + case PE_IMAGE_REL_BASED_DIR64: + reloc.size = 8; + break; + case PE_IMAGE_REL_BASED_HIGH: + reloc.size = 2; + break; + case PE_IMAGE_REL_BASED_LOW: + reloc.size = 2; + break; + case PE_IMAGE_USER_DEFINED: + reloc.type = StandardRelocationType; + break; + default: + // By default, PE relocations are correct when not rebased. + // Upon rebasing, support would need to be added to correctly process the relocation + reloc.type = UnhandledRelocation; + relocTypes.insert(reloc.nativeType); + } + } + + for (auto& reloc : relocTypes) + LogWarn("Unsupported PE relocation: %s", GetRelocationString((PeRelocationType)reloc)); + return false; + } + + virtual size_t GetOperandForExternalRelocation(const uint8_t* data, uint64_t addr, size_t length, + Ref<LowLevelILFunction> il, Ref<Relocation> relocation) override + { + (void)data; + (void)addr; + (void)length; + (void)il; + (void)relocation; + return BN_AUTOCOERCE_EXTERN_PTR; + } +}; + + +static void InitX86Settings() +{ + Ref<Settings> settings = Settings::Instance(); + settings->RegisterSetting("arch.x86.disassembly.syntax", + R"({ + "title" : "x86 Disassembly Syntax", + "type" : "string", + "default" : "BN_INTEL", + "aliases" : ["arch.x86.disassemblyFlavor"], + "description" : "Specify disassembly syntax for the x86/x86_64 architectures.", + "enum" : ["BN_INTEL", "INTEL", "AT&T"], + "enumDescriptions" : [ + "Sets the disassembly syntax to a simplified Intel format. (TBD) ", + "Sets the disassembly syntax to Intel format. (Destination on the left) ", + "Sets the disassembly syntax to AT&T format. (Destination on the right) "], + "ignore" : ["SettingsProjectScope", "SettingsResourceScope"] + })"); + + settings->RegisterSetting("arch.x86.disassembly.separator", + R"({ + "title" : "x86 Disassembly Separator", + "type" : "string", + "default" : ", ", + "aliases" : ["arch.x86.disassemblySeperator", "arch.x86.disassemblySeparator"], + "description" : "Specify the token separator between operands.", + "ignore" : ["SettingsProjectScope", "SettingsResourceScope"] + })"); + + settings->RegisterSetting("arch.x86.disassembly.lowercase", + R"({ + "title" : "x86 Disassembly Case", + "type" : "boolean", + "default" : true, + "aliases" : ["arch.x86.disassemblyLowercase"], + "description" : "Specify the case for opcodes, operands, and registers.", + "ignore" : ["SettingsProjectScope", "SettingsResourceScope"] + })"); +} + + +extern "C" +{ + BN_DECLARE_CORE_ABI_VERSION + +#ifndef DEMO_VERSION + BINARYNINJAPLUGIN void CorePluginDependencies() + { + AddOptionalPluginDependency("view_elf"); + AddOptionalPluginDependency("view_macho"); + AddOptionalPluginDependency("view_pe"); + } +#endif + +#ifdef DEMO_VERSION + bool X86PluginInit() +#else + BINARYNINJAPLUGIN bool CorePluginInit() +#endif + { + InitX86Settings(); + + // XED Setup + xed_tables_init(); + X86CommonArchitecture::InitializeCachedTypes(); + + // Register the architectures in the global list of available architectures + Architecture* x16 = new X16Architecture(); + Architecture::Register(x16); + + Architecture* x86 = new X86Architecture(); + Architecture::Register(x86); + + Architecture* x64 = new X64Architecture(); + Architecture::Register(x64); + + // Register calling conventions + Ref<CallingConvention> conv; + conv = new X86CdeclCallingConvention(x86); + x86->RegisterCallingConvention(conv); + x86->SetDefaultCallingConvention(conv); + x86->SetCdeclCallingConvention(conv); + conv = new X86StdcallCallingConvention(x86); + x86->RegisterCallingConvention(conv); + x86->SetStdcallCallingConvention(conv); + conv = new X86RegParmCallingConvention(x86); + x86->RegisterCallingConvention(conv); + conv = new X86FastcallCallingConvention(x86); + x86->RegisterCallingConvention(conv); + conv = new X86ThiscallCallingConvention(x86); + x86->RegisterCallingConvention(conv); + conv = new X86LinuxSystemCallConvention(x86); + x86->RegisterCallingConvention(conv); + + x86->RegisterRelocationHandler("Mach-O", new x86MachoRelocationHandler()); + x86->RegisterRelocationHandler("ELF", new x86ElfRelocationHandler()); + x86->RegisterRelocationHandler("COFF", new CoffRelocationHandler()); + x86->RegisterRelocationHandler("PE", new PeRelocationHandler()); + + conv = new X64SystemVCallingConvention(x64); + x64->RegisterCallingConvention(conv); + x64->SetDefaultCallingConvention(conv); + x64->SetCdeclCallingConvention(conv); + x64->SetFastcallCallingConvention(conv); + x64->SetStdcallCallingConvention(conv); + conv = new X64WindowsCallingConvention(x64); + x64->RegisterCallingConvention(conv); + conv = new X64LinuxSystemCallConvention(x64); + x64->RegisterCallingConvention(conv); + + x64->RegisterRelocationHandler("Mach-O", new x64MachoRelocationHandler()); + x64->RegisterRelocationHandler("ELF", new x64ElfRelocationHandler()); + x64->RegisterRelocationHandler("COFF", new CoffRelocationHandler()); + x64->RegisterRelocationHandler("PE", new PeRelocationHandler()); + + // Register the architectures with the binary format parsers so that they know when to use + // these architectures for disassembling an executable file + BinaryViewType::RegisterArchitecture("ELF", 3, LittleEndian, x86); + BinaryViewType::RegisterArchitecture("COFF", 0x14c, LittleEndian, x86); + BinaryViewType::RegisterArchitecture("PE", 0x14c, LittleEndian, x86); + BinaryViewType::RegisterArchitecture("Mach-O", 0x00000007, LittleEndian, x86); + + BinaryViewType::RegisterArchitecture("ELF", 62, LittleEndian, x64); + BinaryViewType::RegisterArchitecture("COFF", 0x8664, LittleEndian, x64); + BinaryViewType::RegisterArchitecture("PE", 0x8664, LittleEndian, x64); + BinaryViewType::RegisterArchitecture("Mach-O", 0x01000007, LittleEndian, x64); + + return true; + } +} |
