#define _CRT_SECURE_NO_WARNINGS #include #include #include #include #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_GOT64 = 27, R_X86_64_GOTPCREL64 = 28, R_X86_64_GOTPC64 = 29, R_X86_64_GOTPLT64 = 30, R_X86_64_PLTOFF64 = 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_GOT64", "R_X86_64_GOTPCREL64", "R_X86_64_GOTPC64", "R_X86_64_GOTPLT64", "R_X86_64_PLTOFF64", "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, m_disassembly_options.mpx); // 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 if (xedd_iClass != XED_ICLASS_XABORT) 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& result, const bool lowerCase) { // Size result.emplace_back(BeginMemoryOperandToken, ""); switch (bytes) { case 1: if (lowerCase) result.emplace_back(KeywordToken, "byte "); else result.emplace_back(KeywordToken, "BYTE "); break; case 2: if (lowerCase) result.emplace_back(KeywordToken, "word "); else result.emplace_back(KeywordToken, "WORD "); break; case 4: if (lowerCase) result.emplace_back(KeywordToken, "dword "); else result.emplace_back(KeywordToken, "DWORD "); break; case 8: if (lowerCase) result.emplace_back(KeywordToken, "qword "); else result.emplace_back(KeywordToken, "QWORD "); break; case 10: if (lowerCase) result.emplace_back(KeywordToken, "tword "); else result.emplace_back(KeywordToken, "TWORD "); break; case 16: if (lowerCase) result.emplace_back(KeywordToken, "xmmword "); else result.emplace_back(KeywordToken, "XMMWORD "); break; case 32: if (lowerCase) result.emplace_back(KeywordToken, "ymmword "); else result.emplace_back(KeywordToken, "YMMWORD "); break; case 64: if (lowerCase) result.emplace_back(KeywordToken, "zmmword "); else result.emplace_back(KeywordToken, "ZMMWORD "); break; default: break; } } unsigned short X86CommonArchitecture::GetInstructionOpcode(const xed_decoded_inst_t* const xedd, const xed_operand_values_t* const ov, vector& 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& 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& 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(KeywordToken, "ptr "); else result.emplace_back(KeywordToken, "PTR "); result.emplace_back(BraceToken, "["); // 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(OperationToken, ":"); } 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, ""); result.emplace_back(BraceToken, "]"); 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(OperationToken, "+"); 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(OperationToken, "*"); 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(OperationToken, "-"); disp = -disp; } else result.emplace_back(OperationToken, "+"); 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, ""); result.emplace_back(BraceToken, "]"); 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(KeywordToken, "ptr "); else result.emplace_back(KeywordToken, "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(OperationToken, ":"); } result.emplace_back(BraceToken, "["); 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, ""); result.emplace_back(BraceToken, "]"); 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(KeywordToken, "unimplemented"); } // 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& 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(OperationToken, " {z}"); else result.emplace_back(OperationToken, " {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(BraceToken, "["); // 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(OperationToken, ":"); } 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(KeywordToken, "rel "); else result.emplace_back(KeywordToken, "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, ""); result.emplace_back(BraceToken, "]"); 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(OperationToken, "+"); 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(OperationToken, "*"); 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(OperationToken, "-"); disp = -disp; } else result.emplace_back(OperationToken, "+"); 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, ""); result.emplace_back(BraceToken, "]"); 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(OperationToken, ":"); } result.emplace_back(BraceToken, "["); 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, ""); result.emplace_back(BraceToken, "]"); 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: case XED_OPERAND_ABSBR: { 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(OperationToken, 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(KeywordToken, "unimplemented "); else result.emplace_back(KeywordToken, "UNIMPLEMENTED "); } // 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& 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= 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(KeywordToken, "ptr "); else result.emplace_back(KeywordToken, "PTR "); result.emplace_back(BraceToken, "["); // 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(OperationToken, ":"); } 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, ""); result.emplace_back(BraceToken, "]"); 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(OperationToken, "+"); 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(OperationToken, "*"); 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(OperationToken, "-"); disp = -disp; } else result.emplace_back(OperationToken, "+"); 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, ""); result.emplace_back(BraceToken, "]"); 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(KeywordToken, "ptr "); else result.emplace_back(KeywordToken, "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(OperationToken, ":"); } result.emplace_back(BraceToken, "["); 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, ""); result.emplace_back(BraceToken, "]"); 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(KeywordToken, "unimplemented"); } // 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& 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& 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::Instance(); const bool lowercase = settings->Get("arch.x86.disassembly.lowercase"); const string flavor = settings->Get("arch.x86.disassembly.syntax"); const string separator = settings->Get("arch.x86.disassembly.separator"); const bool mpx = settings->Get("arch.x86.disassembly.mpx"); 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, mpx); } BNEndianness X86CommonArchitecture::GetEndianness() const { return LittleEndian; } vector 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 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& 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.Unimplemented(); } 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; } } // POPCNT sets ZF from the result and clears every other flag. ZF falls through to the default // (result == 0) handling below. if (flagWriteType == IL_FLAGWRITE_POPCNT && flag != IL_FLAG_Z) return il.Const(0, 0); // LZCNT/TZCNT set CF when the source is zero and ZF from the result. The remaining flags are // undefined and are not written. ZF falls through to the default (result == 0) handling below. if (flagWriteType == IL_FLAGWRITE_LZTZCNT && flag == IL_FLAG_C && operandCount >= 1) return il.AddExpr(LLIL_CMP_E, size, 0, il.GetExprForRegisterOrConstant(operands[0], size), il.AddExpr(LLIL_CONST, size, 0, 0)); if (flagWriteType == IL_FLAGWRITE_X87RND && flag == IL_FLAG_C1) return il.Unimplemented(); 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 X86CommonArchitecture::GetAllFlags() { return vector {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 X86CommonArchitecture::GetAllSemanticFlagClasses() { return vector {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 X86CommonArchitecture::GetAllSemanticFlagGroups() { return vector {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"; case IL_FLAGWRITE_POPCNT: return "popcnt"; case IL_FLAGWRITE_LZTZCNT: return "lztzcnt"; 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 X86CommonArchitecture::GetAllFlagWriteTypes() { return vector {IL_FLAGWRITE_ALL, IL_FLAGWRITE_NOCARRY, IL_FLAGWRITE_CO, IL_FLAGWRITE_X87COM, IL_FLAGWRITE_X87COMI, IL_FLAGWRITE_X87C1Z, IL_FLAGWRITE_X87RND, IL_FLAGWRITE_VCOMI, IL_FLAGWRITE_POPCNT, IL_FLAGWRITE_LZTZCNT}; } 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 X86CommonArchitecture::GetFlagsRequiredForFlagCondition(BNLowLevelILFlagCondition cond, uint32_t semClass) { if (semClass == IL_FLAG_CLASS_X87COM) { switch (cond) { case LLFC_FE: case LLFC_FNE: return vector{ IL_FLAG_C3 }; case LLFC_FLT: case LLFC_FGE: return vector{ IL_FLAG_C0 }; case LLFC_FLE: case LLFC_FGT: return vector{ IL_FLAG_C0, IL_FLAG_C3 }; case LLFC_FO: case LLFC_FUO: return vector{ IL_FLAG_C2 }; default: return vector(); } } switch (cond) { case LLFC_E: case LLFC_NE: case LLFC_FE: case LLFC_FNE: return vector{ IL_FLAG_Z }; case LLFC_SLT: case LLFC_SGE: return vector{ IL_FLAG_S, IL_FLAG_O }; case LLFC_ULT: case LLFC_UGE: case LLFC_FLT: case LLFC_FGE: return vector{ IL_FLAG_C }; case LLFC_SLE: case LLFC_SGT: return vector{ IL_FLAG_Z, IL_FLAG_S, IL_FLAG_O }; case LLFC_ULE: case LLFC_UGT: case LLFC_FLE: case LLFC_FGT: return vector{ IL_FLAG_C, IL_FLAG_Z }; case LLFC_NEG: case LLFC_POS: return vector{ IL_FLAG_S }; case LLFC_O: case LLFC_NO: return vector{ IL_FLAG_O }; case LLFC_FO: case LLFC_FUO: return vector{ IL_FLAG_P }; default: return vector(); } } vector X86CommonArchitecture::GetFlagsRequiredForSemanticFlagGroup(uint32_t semGroup) { switch (semGroup) { case IL_FLAG_GROUP_E: case IL_FLAG_GROUP_NE: return vector{ IL_FLAG_Z }; case IL_FLAG_GROUP_LT: case IL_FLAG_GROUP_GE: return vector{ IL_FLAG_C }; case IL_FLAG_GROUP_LE: case IL_FLAG_GROUP_GT: return vector{ IL_FLAG_C, IL_FLAG_Z }; case IL_FLAG_GROUP_PE: case IL_FLAG_GROUP_PO: return vector{ IL_FLAG_P }; default: return vector(); } } map X86CommonArchitecture::GetFlagConditionsForSemanticFlagGroup(uint32_t semGroup) { switch (semGroup) { case IL_FLAG_GROUP_E: return map { {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 { {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 { {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 { {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 { {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 { {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 { {IL_FLAG_CLASS_X87COMI, LLFC_FUO}, {IL_FLAG_CLASS_VCOMI, LLFC_FUO}, }; case IL_FLAG_GROUP_PO: return map { {IL_FLAG_CLASS_X87COMI, LLFC_FO}, {IL_FLAG_CLASS_VCOMI, LLFC_FO}, }; default: return map(); } } vector X86CommonArchitecture::GetFlagsWrittenByFlagWriteType(uint32_t writeType) { switch (writeType) { case IL_FLAGWRITE_ALL: return vector{ IL_FLAG_C, IL_FLAG_P, IL_FLAG_A, IL_FLAG_Z, IL_FLAG_S, IL_FLAG_O }; case IL_FLAGWRITE_NOCARRY: return vector{ IL_FLAG_P, IL_FLAG_A, IL_FLAG_Z, IL_FLAG_S, IL_FLAG_O }; case IL_FLAGWRITE_CO: return vector{ IL_FLAG_C, IL_FLAG_O }; case IL_FLAGWRITE_X87COM: return vector{ IL_FLAG_C0, IL_FLAG_C1, IL_FLAG_C2, IL_FLAG_C3 }; case IL_FLAGWRITE_X87COMI: return vector{ IL_FLAG_C, IL_FLAG_Z, IL_FLAG_P }; case IL_FLAGWRITE_X87C1Z: case IL_FLAGWRITE_X87RND: return vector{ IL_FLAG_C1 }; case IL_FLAGWRITE_VCOMI: return vector{ IL_FLAG_C, IL_FLAG_P, IL_FLAG_A, IL_FLAG_Z, IL_FLAG_S, IL_FLAG_O }; case IL_FLAGWRITE_POPCNT: return vector{ IL_FLAG_C, IL_FLAG_P, IL_FLAG_A, IL_FLAG_Z, IL_FLAG_S, IL_FLAG_O }; case IL_FLAGWRITE_LZTZCNT: return vector{ IL_FLAG_C, IL_FLAG_Z }; default: return vector(); } } string X86CommonArchitecture::GetRegisterStackName(uint32_t regStack) { if (regStack == REG_STACK_X87) return "x87"; return ""; } vector X86CommonArchitecture::GetAllRegisterStacks() { return vector{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 inputFile = new TemporaryFile(finalCode); Ref 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 args = vector { 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 GetFullWidthRegisters() override { return vector{ // 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 GetAllRegisters() override { return vector{ // 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 GetFullWidthRegisters() override { return vector { // 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 GetAllRegisters() override { return vector{ // 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 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_R16, XED_REG_R17, XED_REG_R18, XED_REG_R19, XED_REG_R20, XED_REG_R21, XED_REG_R22, XED_REG_R23, // APX XED_REG_R24, XED_REG_R25, XED_REG_R26, XED_REG_R27, XED_REG_R28, XED_REG_R29, XED_REG_R30, XED_REG_R31, // APX 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 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+ XED_REG_R16B, XED_REG_R17B, XED_REG_R18B, XED_REG_R19B, XED_REG_R20B, XED_REG_R21B, XED_REG_R22B, XED_REG_R23B, // APX XED_REG_R24B, XED_REG_R25B, XED_REG_R26B, XED_REG_R27B, XED_REG_R28B, XED_REG_R29B, XED_REG_R30B, XED_REG_R31B, // APX // 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+ XED_REG_R16W, XED_REG_R17W, XED_REG_R18W, XED_REG_R19W, XED_REG_R20W, XED_REG_R21W, XED_REG_R22W, XED_REG_R23W, // APX XED_REG_R24W, XED_REG_R25W, XED_REG_R26W, XED_REG_R27W, XED_REG_R28W, XED_REG_R29W, XED_REG_R30W, XED_REG_R31W, // APX // 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+ XED_REG_R16D, XED_REG_R17D, XED_REG_R18D, XED_REG_R19D, XED_REG_R20D, XED_REG_R21D, XED_REG_R22D, XED_REG_R23D, // APX XED_REG_R24D, XED_REG_R25D, XED_REG_R26D, XED_REG_R27D, XED_REG_R28D, XED_REG_R29D, XED_REG_R30D, XED_REG_R31D, // APX // 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_R16, XED_REG_R17, XED_REG_R18, XED_REG_R19, XED_REG_R20, XED_REG_R21, XED_REG_R22, XED_REG_R23, // APX XED_REG_R24, XED_REG_R25, XED_REG_R26, XED_REG_R27, XED_REG_R28, XED_REG_R29, XED_REG_R30, XED_REG_R31, // APX 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); case XED_REG_R16B: return RegisterInfo(XED_REG_R16, 0, 1); case XED_REG_R17B: return RegisterInfo(XED_REG_R17, 0, 1); case XED_REG_R18B: return RegisterInfo(XED_REG_R18, 0, 1); case XED_REG_R19B: return RegisterInfo(XED_REG_R19, 0, 1); case XED_REG_R20B: return RegisterInfo(XED_REG_R20, 0, 1); case XED_REG_R21B: return RegisterInfo(XED_REG_R21, 0, 1); case XED_REG_R22B: return RegisterInfo(XED_REG_R22, 0, 1); case XED_REG_R23B: return RegisterInfo(XED_REG_R23, 0, 1); case XED_REG_R24B: return RegisterInfo(XED_REG_R24, 0, 1); case XED_REG_R25B: return RegisterInfo(XED_REG_R25, 0, 1); case XED_REG_R26B: return RegisterInfo(XED_REG_R26, 0, 1); case XED_REG_R27B: return RegisterInfo(XED_REG_R27, 0, 1); case XED_REG_R28B: return RegisterInfo(XED_REG_R28, 0, 1); case XED_REG_R29B: return RegisterInfo(XED_REG_R29, 0, 1); case XED_REG_R30B: return RegisterInfo(XED_REG_R30, 0, 1); case XED_REG_R31B: return RegisterInfo(XED_REG_R31, 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); case XED_REG_R16W: return RegisterInfo(XED_REG_R16, 0, 2); case XED_REG_R17W: return RegisterInfo(XED_REG_R17, 0, 2); case XED_REG_R18W: return RegisterInfo(XED_REG_R18, 0, 2); case XED_REG_R19W: return RegisterInfo(XED_REG_R19, 0, 2); case XED_REG_R20W: return RegisterInfo(XED_REG_R20, 0, 2); case XED_REG_R21W: return RegisterInfo(XED_REG_R21, 0, 2); case XED_REG_R22W: return RegisterInfo(XED_REG_R22, 0, 2); case XED_REG_R23W: return RegisterInfo(XED_REG_R23, 0, 2); case XED_REG_R24W: return RegisterInfo(XED_REG_R24, 0, 2); case XED_REG_R25W: return RegisterInfo(XED_REG_R25, 0, 2); case XED_REG_R26W: return RegisterInfo(XED_REG_R26, 0, 2); case XED_REG_R27W: return RegisterInfo(XED_REG_R27, 0, 2); case XED_REG_R28W: return RegisterInfo(XED_REG_R28, 0, 2); case XED_REG_R29W: return RegisterInfo(XED_REG_R29, 0, 2); case XED_REG_R30W: return RegisterInfo(XED_REG_R30, 0, 2); case XED_REG_R31W: return RegisterInfo(XED_REG_R31, 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); case XED_REG_R16D: return RegisterInfo(XED_REG_R16, 0, 4, true); case XED_REG_R17D: return RegisterInfo(XED_REG_R17, 0, 4, true); case XED_REG_R18D: return RegisterInfo(XED_REG_R18, 0, 4, true); case XED_REG_R19D: return RegisterInfo(XED_REG_R19, 0, 4, true); case XED_REG_R20D: return RegisterInfo(XED_REG_R20, 0, 4, true); case XED_REG_R21D: return RegisterInfo(XED_REG_R21, 0, 4, true); case XED_REG_R22D: return RegisterInfo(XED_REG_R22, 0, 4, true); case XED_REG_R23D: return RegisterInfo(XED_REG_R23, 0, 4, true); case XED_REG_R24D: return RegisterInfo(XED_REG_R24, 0, 4, true); case XED_REG_R25D: return RegisterInfo(XED_REG_R25, 0, 4, true); case XED_REG_R26D: return RegisterInfo(XED_REG_R26, 0, 4, true); case XED_REG_R27D: return RegisterInfo(XED_REG_R27, 0, 4, true); case XED_REG_R28D: return RegisterInfo(XED_REG_R28, 0, 4, true); case XED_REG_R29D: return RegisterInfo(XED_REG_R29, 0, 4, true); case XED_REG_R30D: return RegisterInfo(XED_REG_R30, 0, 4, true); case XED_REG_R31D: return RegisterInfo(XED_REG_R31, 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_R16: return RegisterInfo(XED_REG_R16, 0, 8); case XED_REG_R17: return RegisterInfo(XED_REG_R17, 0, 8); case XED_REG_R18: return RegisterInfo(XED_REG_R18, 0, 8); case XED_REG_R19: return RegisterInfo(XED_REG_R19, 0, 8); case XED_REG_R20: return RegisterInfo(XED_REG_R20, 0, 8); case XED_REG_R21: return RegisterInfo(XED_REG_R21, 0, 8); case XED_REG_R22: return RegisterInfo(XED_REG_R22, 0, 8); case XED_REG_R23: return RegisterInfo(XED_REG_R23, 0, 8); case XED_REG_R24: return RegisterInfo(XED_REG_R24, 0, 8); case XED_REG_R25: return RegisterInfo(XED_REG_R25, 0, 8); case XED_REG_R26: return RegisterInfo(XED_REG_R26, 0, 8); case XED_REG_R27: return RegisterInfo(XED_REG_R27, 0, 8); case XED_REG_R28: return RegisterInfo(XED_REG_R28, 0, 8); case XED_REG_R29: return RegisterInfo(XED_REG_R29, 0, 8); case XED_REG_R30: return RegisterInfo(XED_REG_R30, 0, 8); case XED_REG_R31: return RegisterInfo(XED_REG_R31, 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 GetCallerSavedRegisters() override { return vector{ XED_REG_EAX, XED_REG_ECX, XED_REG_EDX }; } virtual vector GetCalleeSavedRegisters() override { return vector{ 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; } bool IsReturnTypeRegisterCompatible(BinaryView*, Type* type) override { if (!type) return false; if (type->IsFloat()) return true; if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4 || type->GetWidth() == 8) return true; return false; } std::optional GetReturnedIndirectReturnValuePointer() override { return Variable::Register(XED_REG_EAX); } }; class X86SystemVCallingConvention: public X86BaseCallingConvention { public: X86SystemVCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "sysv") { } bool IsReturnTypeRegisterCompatible(BinaryView*, Type* type) override { if (!type) return false; if (type->IsFloat()) return true; if (type->IsStructure() || type->IsArray()) return false; // If we have an unresolved NTR, we don't actually know what the type is. But it is more likely to // be a structure than anything else, so use the same logic as an identified structure. if (type->IsNamedTypeRefer()) return false; if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4 || type->GetWidth() == 8) return true; return false; } bool IsStackAdjustedOnReturn() override { // Only for indirect returns, see GetStackAdjustmentForLocations below return true; } int64_t GetStackAdjustmentForLocations(BinaryView*, const std::optional& returnValue, const vector&, const vector>&) override { if (!returnValue.has_value()) return 0; // Indirect return values have the pointer popped off the stack by the called function if (returnValue->indirect) return 4; return 0; } }; 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 X86SystemVStdcallCallingConvention: public X86BaseCallingConvention { public: X86SystemVStdcallCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "sysv-stdcall") { } bool IsStackAdjustedOnReturn() override { return true; } bool IsReturnTypeRegisterCompatible(BinaryView*, Type* type) override { if (!type) return false; if (type->IsFloat()) return true; if (type->IsStructure() || type->IsArray()) return false; if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4 || type->GetWidth() == 8) return true; return false; } }; class X86RegParmCallingConvention: public X86BaseCallingConvention { public: X86RegParmCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "regparm") { } vector GetIntegerArgumentRegisters() override { return vector{ XED_REG_EAX, XED_REG_EDX, XED_REG_ECX }; } bool IsReturnTypeRegisterCompatible(BinaryView*, Type* type) override { if (!type) return false; if (type->IsFloat()) return true; if (type->IsStructure() || type->IsArray()) return false; if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4 || type->GetWidth() == 8) return true; return false; } bool IsArgumentTypeRegisterCompatible(BinaryView*, Type* type) override { if (!type) return false; if (type->IsFloat()) return true; return type->GetWidth() <= 12; } }; class X86FastcallCallingConvention: public X86BaseCallingConvention { public: X86FastcallCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "fastcall") { } virtual vector GetIntegerArgumentRegisters() override { return vector{ XED_REG_ECX, XED_REG_EDX }; } virtual bool IsStackAdjustedOnReturn() override { return true; } }; class X86GCCFastcallCallingConvention: public X86BaseCallingConvention { public: X86GCCFastcallCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "gcc-fastcall") { } vector GetIntegerArgumentRegisters() override { return vector{ XED_REG_ECX, XED_REG_EDX }; } bool IsStackAdjustedOnReturn() override { return true; } bool IsReturnTypeRegisterCompatible(BinaryView*, Type* type) override { if (!type) return false; if (type->IsFloat()) return true; if (type->IsStructure() || type->IsArray()) return false; if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4 || type->GetWidth() == 8) return true; return false; } Variable GetIndirectReturnValueLocation() override { return Variable::Register(XED_REG_ECX); } }; class X86ClangFastcallCallingConvention: public X86BaseCallingConvention { public: X86ClangFastcallCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "clang-fastcall") { } vector GetIntegerArgumentRegisters() override { return vector{ XED_REG_ECX, XED_REG_EDX }; } bool IsStackAdjustedOnReturn() override { return true; } bool IsReturnTypeRegisterCompatible(BinaryView*, Type* type) override { if (!type) return false; if (type->IsFloat()) return true; if (type->IsStructure() || type->IsArray()) return false; if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4 || type->GetWidth() == 8) return true; return false; } Variable GetIndirectReturnValueLocation() override { return Variable::StackOffset(4); } }; class X86ThiscallCallingConvention: public X86BaseCallingConvention { public: X86ThiscallCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "thiscall") { } virtual vector GetIntegerArgumentRegisters() override { return vector{ XED_REG_ECX }; } virtual vector GetRequiredArgumentRegisters() override { return vector{ XED_REG_ECX }; } virtual bool IsStackAdjustedOnReturn() override { return true; } }; class X86GCCThiscallCallingConvention: public X86BaseCallingConvention { public: X86GCCThiscallCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "gcc-thiscall") { } vector GetIntegerArgumentRegisters() override { return vector{ XED_REG_ECX }; } vector GetRequiredArgumentRegisters() override { return vector{ XED_REG_ECX }; } bool IsStackAdjustedOnReturn() override { return true; } bool IsReturnTypeRegisterCompatible(BinaryView*, Type* type) override { if (!type) return false; if (type->IsFloat()) return true; if (type->IsStructure() || type->IsArray()) return false; if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4 || type->GetWidth() == 8) return true; return false; } Variable GetIndirectReturnValueLocation() override { return Variable::Register(XED_REG_ECX); } }; class X86ClangThiscallCallingConvention: public X86BaseCallingConvention { public: X86ClangThiscallCallingConvention(Architecture* arch): X86BaseCallingConvention(arch, "clang-thiscall") { } vector GetIntegerArgumentRegisters() override { return vector{ XED_REG_ECX }; } vector GetRequiredArgumentRegisters() override { return vector{ XED_REG_ECX }; } bool IsStackAdjustedOnReturn() override { return true; } bool IsReturnTypeRegisterCompatible(BinaryView*, Type* type) override { if (!type) return false; if (type->IsFloat()) return true; if (type->IsStructure() || type->IsArray()) return false; if (type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4 || type->GetWidth() == 8) return true; return false; } Variable GetIndirectReturnValueLocation() override { return Variable::StackOffset(4); } }; class X86LinuxSystemCallConvention: public CallingConvention { public: X86LinuxSystemCallConvention(Architecture* arch): CallingConvention(arch, "linux-syscall") { } virtual vector GetIntegerArgumentRegisters() override { return vector { XED_REG_EAX, XED_REG_EBX, XED_REG_ECX, XED_REG_EDX, XED_REG_ESI, XED_REG_EDI, XED_REG_EBP }; } virtual vector GetCallerSavedRegisters() override { return vector { XED_REG_EAX, XED_REG_EDX }; } virtual vector GetCalleeSavedRegisters() override { return vector { 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 X86PascalCallingConvention : public X86BaseCallingConvention { public: X86PascalCallingConvention(Architecture* arch) : X86BaseCallingConvention(arch, "pascal") {} bool IsNonRegisterArgumentIndirect(BinaryView*, Type* type) override { return type && !type->IsFloat() && type->GetWidth() > 4; } bool IsStackAdjustedOnReturn() override { return true; } bool AreStackArgumentsPushedLeftToRight() override { return true; } Variable GetIndirectReturnValueLocation() override { // Return value pointer is always at the top of the stack (effectively the last parameter // in a left-to-right convention) return Variable::StackOffset(4); } std::optional GetReturnedIndirectReturnValuePointer() override { return std::nullopt; } }; class X86PascalRegisterCallingConvention : public X86BaseCallingConvention { public: X86PascalRegisterCallingConvention(Architecture* arch) : X86BaseCallingConvention(arch, "register") {} vector GetIntegerArgumentRegisters() override { return { XED_REG_EAX, XED_REG_EDX, XED_REG_ECX }; } bool IsNonRegisterArgumentIndirect(BinaryView*, Type* type) override { return type && !type->IsFloat() && type->GetWidth() > 4; } bool AreStackArgumentsPushedLeftToRight() override { return true; } std::optional GetReturnedIndirectReturnValuePointer() override { return std::nullopt; } }; class X86GoStackCallingConvention: public CallingConvention { public: X86GoStackCallingConvention(Architecture* arch): CallingConvention(arch, "go-stack") { } bool IsEligibleForHeuristics() override { // This convention cannot be detected by heuristics at this time and will cause issues // with non-Go code. return false; } uint32_t GetIntegerReturnValueRegister() override { return BN_INVALID_REGISTER; } vector GetCallerSavedRegisters() override { return vector { XED_REG_EAX, XED_REG_ECX, XED_REG_EDX, XED_REG_EBX, XED_REG_EBP }; } RegisterValue GetIncomingFlagValue(uint32_t flag, Function*) override { RegisterValue result; if (flag == IL_FLAG_D) { result.state = ConstantValue; result.value = 0; } return result; } ValueLocation GetReturnValueLocation(BinaryView*, const ReturnValue&) override { // It is not possible for this API to determine the return value location on the stack at // this point, return an invalid location and fall back to GetCallLayout. return ValueLocation(); } CallLayout GetCallLayout(BinaryView* view, const ReturnValue& returnValue, const vector& params, const std::optional>& permittedRegs) override { CallLayout result; result.parameters = GetParameterLocations(view, result.returnValue, params, permittedRegs); if (returnValue.type.GetValue() && returnValue.type->GetClass() != VoidTypeClass) { if (returnValue.defaultLocation) { int64_t stackOffset = 4; size_t i = 0; for (auto it = result.parameters.begin(); it != result.parameters.end(); ++i, ++it) { std::optional varStorage; std::optional varSize; for (auto& component: it->components) { if (component.variable.type != StackVariableSourceType) continue; if (!varStorage.has_value() || component.variable.storage > varStorage.value()) { varStorage = component.variable.storage; if (!it->indirect) varSize = component.size; } } if (!varStorage.has_value() || varStorage.value() < stackOffset) continue; if (it->indirect) varSize = 4; size_t width = 4; if (varSize.has_value()) width = varSize.value(); else if (i < params.size() && params[i].type.GetValue()) width = params[i].type->GetWidth(); if (width < 4) width = 4; else if ((width % 4) != 0) width += 4 - (width % 4); stackOffset = varStorage.value() + width; } result.returnValue = Variable::StackOffset(stackOffset); } else { result.returnValue = returnValue.location.GetValue(); } } result.registerStackAdjustments = GetRegisterStackAdjustments(view, result.returnValue, result.parameters); return result; } }; 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 { enum ValueClass { NoClass, Integer, SSE, SSEUpper, X87, X87Upper, X87Complex }; struct Component { ValueClass valueClass; uint64_t offset; uint64_t size; }; std::optional> GetTypeFields(BinaryView* view, Type* type, std::set& visitedTypes) { vector result; if (!type || type->GetWidth() > 64) return std::nullopt; if (type->GetWidth() == 0) return result; switch (type->GetClass()) { case VoidTypeClass: break; case BoolTypeClass: case IntegerTypeClass: case EnumerationTypeClass: case PointerTypeClass: case WideCharTypeClass: for (uint64_t offset = 0; offset < type->GetWidth(); offset += 8) { if (offset + 8 > type->GetWidth()) result.emplace_back(Integer, offset, type->GetWidth() - offset); else result.emplace_back(Integer, offset, 8); } break; case FloatTypeClass: if (type->GetWidth() == 10) { result.emplace_back(X87, 0, 8); result.emplace_back(X87Upper, 8, 2); } else { for (uint64_t offset = 0; offset < type->GetWidth(); offset += 8) { ValueClass valueClass; if (offset == 0) valueClass = SSE; else valueClass = SSEUpper; if (offset + 8 > type->GetWidth()) result.emplace_back(valueClass, offset, type->GetWidth() - offset); else result.emplace_back(valueClass, offset, 8); } } break; case StructureTypeClass: { Ref structure = type->GetStructure(); if (!structure || !view) return std::nullopt; for (auto& member : structure->GetMembersIncludingInherited(view->GetTypeContainer())) { // Ensure that everything is aligned on natural boundaries. If it is not, it is stored in memory. uint64_t alignment = 1; if (member.member.type.GetValue() && member.member.type->GetAlignment() != 0) alignment = member.member.type->GetAlignment(); if (member.member.offset % alignment != 0) return std::nullopt; std::set fieldVisitedTypes = visitedTypes; std::optional> fieldComponents = GetTypeFields(view, member.member.type.GetValue(), fieldVisitedTypes); if (!fieldComponents.has_value()) return std::nullopt; for (auto& component : fieldComponents.value()) result.emplace_back(component.valueClass, member.member.offset + component.offset, component.size); } break; } case ArrayTypeClass: { Ref elementType = type->GetChildType().GetValue(); std::optional> elementComponents = GetTypeFields(view, elementType, visitedTypes); if (!elementComponents.has_value() || elementComponents->empty()) return std::nullopt; if (type->GetElementCount() > 64) return std::nullopt; for (uint64_t i = 0; i < type->GetElementCount(); i++) { uint64_t offset = i * elementType->GetWidth(); for (auto& component : elementComponents.value()) result.emplace_back(component.valueClass, offset + component.offset, component.size); } break; } case NamedTypeReferenceClass: { auto ntr = type->GetNamedTypeReference(); if (!view || visitedTypes.contains(ntr->GetTypeId())) return std::nullopt; visitedTypes.insert(ntr->GetTypeId()); return GetTypeFields(view, view->GetTypeByRef(ntr), visitedTypes); } default: return std::nullopt; } return result; } std::optional> GetValueClassificationForType(BinaryView* view, Type* type) { if (!type) return std::nullopt; if (type->GetWidth() > 64) return std::nullopt; // Split the component up into fields, with each field split into 8 byte components std::optional> fields; std::set visitedTypes; fields = GetTypeFields(view, type, visitedTypes); if (!fields.has_value() || fields->empty()) return fields; // Initialize components for each 8 bytes of the type. The last component may be smaller than 8 bytes, // but will be padded to fit in an 8-byte component. vector result; for (uint64_t offset = 0; offset < type->GetWidth(); offset += 8) { if (offset + 8 > type->GetWidth()) result.emplace_back(NoClass, offset, type->GetWidth() - offset); else result.emplace_back(NoClass, offset, 8); } // Resolve the classes of each component based on the fields for (auto& field : fields.value()) { size_t componentIndex = (size_t)(field.offset / 8); if (componentIndex >= result.size()) return std::nullopt; auto& component = result[componentIndex]; if (component.valueClass == field.valueClass) { continue; } if (component.valueClass == NoClass) { component.valueClass = field.valueClass; continue; } switch (field.valueClass) { case NoClass: break; case Integer: component.valueClass = Integer; break; case X87: case X87Upper: case X87Complex: return std::nullopt; default: if (component.valueClass != Integer) component.valueClass = SSE; break; } } // Any components that are still assigned to NoClass are converted to Integer as a default. This // usually happens when there are chunks of a structure that have no fields defined yet. This is // the most likely class by far, and there isn't any information available to know for sure. for (auto& component : result) { if (component.valueClass == NoClass) component.valueClass = Integer; } // The X87Upper class is only valid if preceded by X87 and is only valid for a 16-byte result if (result.size() == 2 && result[0].valueClass == X87 && result[1].valueClass == X87Upper) return result; if (std::ranges::any_of(result, [](const Component& component) { return component.valueClass == X87Upper; })) return std::nullopt; // If the result is larger than 16 bytes, it is passed in memory unless it is all SSE, with SSEUpper // as the class for all but the first component. if (result.size() > 2) { if (result[0].valueClass != SSE) return std::nullopt; if (std::any_of(result.begin() + 1, result.end(), [](const Component& component) { return component.valueClass != SSEUpper; })) return std::nullopt; return result; } // Clean up SSEUpper components that aren't preceded by an SSE component for (size_t i = 0; i < result.size(); i++) { if (result[i].valueClass != SSEUpper) continue; if (i == 0 || (result[i - 1].valueClass != SSE && result[i - 1].valueClass != SSEUpper)) result[i].valueClass = SSE; } return result; } bool IsTypeRegisterCompatible(BinaryView* view, Type* type, size_t maxIntegerRegs, size_t maxSSERegs, size_t maxX87Regs, size_t maxX87ComplexRegs) { auto components = GetValueClassificationForType(view, type); if (!components.has_value()) return false; size_t integerCount = 0; size_t sseCount = 0; size_t x87Count = 0; size_t x87ComplexCount = 0; for (auto& component : components.value()) { switch (component.valueClass) { case NoClass: return false; case Integer: integerCount++; break; case SSE: sseCount++; break; case X87: x87Count++; break; case X87Complex: x87ComplexCount++; break; case SSEUpper: case X87Upper: break; } } if (integerCount > maxIntegerRegs) return false; if (sseCount > maxSSERegs) return false; if (x87Count > maxX87Regs) return false; if (x87ComplexCount % 4 != 0) return false; x87Count += x87ComplexCount / 2; if (x87Count > maxX87ComplexRegs) return false; return true; } public: X64SystemVCallingConvention(Architecture* arch): X64BaseCallingConvention(arch, "sysv") { } virtual vector GetIntegerArgumentRegisters() override { return vector { XED_REG_RDI, XED_REG_RSI, XED_REG_RDX, XED_REG_RCX, XED_REG_R8, XED_REG_R9 }; } virtual vector GetFloatArgumentRegisters() override { return vector { 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 GetCallerSavedRegisters() override { return vector { 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 GetCalleeSavedRegisters() override { return vector { XED_REG_RBX, XED_REG_RBP, XED_REG_R12, XED_REG_R13, XED_REG_R14, XED_REG_R15 }; } bool IsReturnTypeRegisterCompatible(BinaryView* view, Type* type) override { // If we have an unresolved NTR, use the default handling. We can't really know what // this type is, so just preserve the old behavior. if (type && type->GetClass() == NamedTypeReferenceClass && type->GetWidth() == 0) return DefaultIsReturnTypeRegisterCompatible(type); return IsTypeRegisterCompatible(view, type, 2, 2, 1, 2); } bool IsArgumentTypeRegisterCompatible(BinaryView* view, Type* type) override { // If we have an unresolved NTR, use the default handling. We can't really know what // this type is, so just preserve the old behavior. if (type && type->GetClass() == NamedTypeReferenceClass && type->GetWidth() == 0) return DefaultIsArgumentTypeRegisterCompatible(type); return IsTypeRegisterCompatible(view, type, 6, 8, 0, 0); } ValueLocation GetReturnValueLocation(BinaryView* view, const ReturnValue& returnValue) override { Ref type = returnValue.type.GetValue(); if (!type || type->IsVoid()) return ValueLocation(); // If we have an unresolved NTR, use the default handling. We can't really know what // this type is, so just preserve the old behavior. if (type->GetClass() == NamedTypeReferenceClass && type->GetWidth() == 0) return GetDefaultReturnValueLocation(view, returnValue); auto components = GetValueClassificationForType(view, type); if (!components.has_value()) { // Value doesn't work in a register, return through an indirect pointer return ValueLocation({GetIndirectReturnValueLocation()}, true, GetReturnedIndirectReturnValuePointer()); } ValueLocation result; size_t integerCount = 0; static constexpr uint32_t integerRegs[2] = {XED_REG_RAX, XED_REG_RDX}; size_t sseCount = 0; static constexpr uint32_t sseRegs[2] = {XED_REG_ZMM0, XED_REG_ZMM1}; size_t x87Count = 0; static constexpr uint32_t x87Regs[2] = {XED_REG_ST0, XED_REG_ST1}; bool valid = true; for (auto& component : components.value()) { switch (component.valueClass) { case NoClass: valid = false; break; case Integer: if (integerCount >= 2) { valid = false; break; } result.components.emplace_back( Variable::Register(integerRegs[integerCount++]), component.offset, component.size); break; case SSE: if (sseCount >= 2) { valid = false; break; } result.components.emplace_back( Variable::Register(sseRegs[sseCount++]), component.offset, component.size); break; case X87: if (x87Count >= 1) { valid = false; break; } result.components.emplace_back( Variable::Register(x87Regs[x87Count++]), component.offset, component.size); break; case SSEUpper: case X87Upper: if (result.components.empty()) { valid = false; break; } result.components.back().size = result.components.back().size.value_or(0) + component.size; break; case X87Complex: if (result.components.empty() || result.components.back().size.value_or(0) > 8) { if (x87Count >= 2) { valid = false; break; } result.components.emplace_back( Variable::Register(x87Regs[x87Count++]), component.offset, component.size); } else { result.components.back().size = result.components.back().size.value_or(0) + component.size; } break; } } // Single component values shouldn't have the size set, otherwise heuristically determined locations // will not match. if (result.components.size() == 1) result.components[0].size.reset(); if (valid) return result; // Value doesn't work in a register, return through an indirect pointer return ValueLocation({GetIndirectReturnValueLocation()}, true, GetReturnedIndirectReturnValuePointer()); } Variable GetIndirectReturnValueLocation() override { return Variable::Register(XED_REG_RDI); } std::optional GetReturnedIndirectReturnValuePointer() override { return Variable::Register(XED_REG_RAX); } std::vector GetParameterLocations(BinaryView* view, const std::optional& returnValue, const std::vector& params, const std::optional>& permittedRegs = std::nullopt) override { vector result; result.reserve(params.size()); vector intArgs = GetIntegerArgumentRegisters(); vector sseArgs = GetFloatArgumentRegisters(); auto intArgIter = intArgs.begin(); auto sseArgIter = sseArgs.begin(); size_t addrSize = GetArchitecture()->GetAddressSize(); int64_t stackOffset = addrSize; if (returnValue.has_value() && returnValue->indirect) { // If the return value is stored as an indirect location parameter, ensure that the normal parameters // don't overlap with it. for (auto& component : returnValue->components) { if (component.variable.type == RegisterVariableSourceType) { if (intArgIter != intArgs.end() && *intArgIter == component.variable.storage) intArgIter++; if (sseArgIter != sseArgs.end() && *sseArgIter == component.variable.storage) sseArgIter++; } else if (component.variable.type == StackVariableSourceType && component.variable.storage >= stackOffset) { // Adjust the next automatic stack location to after this one stackOffset = component.variable.storage; stackOffset += 8; } } } for (auto& param : params) { if (param.locationSource == CustomLocationSource) { // Parameter is not stored in a normal location, use custom variable result.push_back(param.location); for (auto& component : param.location.components) { if (component.variable.type == RegisterVariableSourceType) { // If the non-default location matches the next register in the register parameter // lists, advance the iterators. It may just be a type mismatch, and we still // want to maintain the state for future parameters. if (intArgIter != intArgs.end() && *intArgIter == component.variable.storage) intArgIter++; if (sseArgIter != sseArgs.end() && *sseArgIter == component.variable.storage) sseArgIter++; } else if (component.variable.type == StackVariableSourceType && component.variable.storage >= stackOffset) { // Adjust the next automatic stack location to after this one stackOffset = component.variable.storage; stackOffset += 8; } } continue; } Ref type = param.type.GetValue(); size_t width = type->GetWidth(); bool indirect = false; if ((type->GetClass() == ArrayTypeClass || param.locationSource == PassByReferenceLocationSource) && param.locationSource != PassByValueLocationSource) { type = Type::PointerType(GetArchitecture(), type); indirect = true; width = type->GetWidth(); } if (IsArgumentTypeRegisterCompatible(view, type)) { auto components = GetValueClassificationForType(view, type); if (components.has_value() && !components->empty()) { // Save off the current register iterators. If we fail to find enough registers, we // need to revert the register allocations. auto savedIntArgIter = intArgIter; auto savedSseArgIter = sseArgIter; ValueLocation location; bool valid = true; for (auto& component : components.value()) { switch (component.valueClass) { case Integer: if (intArgIter == intArgs.end() || (permittedRegs.has_value() && !permittedRegs->contains(*intArgIter))) { valid = false; break; } location.components.emplace_back( Variable::Register(*intArgIter), component.offset, component.size); ++intArgIter; break; case SSE: if (sseArgIter == sseArgs.end() || (permittedRegs.has_value() && !permittedRegs->contains(*sseArgIter))) { valid = false; break; } location.components.emplace_back( Variable::Register(*sseArgIter), component.offset, component.size); ++sseArgIter; break; case SSEUpper: if (location.components.empty()) { valid = false; break; } location.components.back().size = location.components.back().size.value_or(0) + component.size; break; default: valid = false; break; } } if (indirect) { location.indirect = true; std::ranges::for_each(location.components, [&](auto& component) { component.size = param.type->GetWidth(); }); } // Single component values shouldn't have the size set, otherwise heuristically determined locations // will not match. if (location.components.size() == 1) location.components[0].size.reset(); if (valid) { // Value fit in registers result.emplace_back(location); continue; } // Value does not fit in available registers, revert to prior available registers intArgIter = savedIntArgIter; sseArgIter = savedSseArgIter; } } // Value must be placed on the stack if (width % addrSize != 0) width += addrSize - width % addrSize; // Stack offset must be naturally aligned. Alignment is performed on the offset before the // return address is pushed (using caller's stack alignment). int64_t alignment = type->GetAlignment(); int64_t afterRetOffset = stackOffset - addrSize; if (alignment != 0 && afterRetOffset % alignment != 0) stackOffset += alignment - afterRetOffset % alignment; result.emplace_back(ValueLocation({{Variable::StackOffset(stackOffset), 0}}, indirect)); stackOffset += width; } return result; } }; class X64WindowsCallingConvention: public X64BaseCallingConvention { public: X64WindowsCallingConvention(Architecture* arch): X64BaseCallingConvention(arch, "win64") { } virtual vector GetIntegerArgumentRegisters() override { return vector { XED_REG_RCX, XED_REG_RDX, XED_REG_R8, XED_REG_R9 }; } virtual vector GetFloatArgumentRegisters() override { return vector { XED_REG_ZMM0, XED_REG_ZMM1, XED_REG_ZMM2, XED_REG_ZMM3 }; } virtual vector GetCallerSavedRegisters() override { return vector { 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 GetCalleeSavedRegisters() override { return vector { 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; } bool IsReturnTypeRegisterCompatible(BinaryView*, Type* type) override { if (!type) return false; if (type->IsFloat()) return true; return type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4 || type->GetWidth() == 8; } std::optional GetReturnedIndirectReturnValuePointer() override { return Variable::Register(XED_REG_RAX); } bool IsArgumentTypeRegisterCompatible(BinaryView*, Type* type) override { if (!type) return false; if (type->IsFloat()) return true; return type->GetWidth() == 0 || type->GetWidth() == 1 || type->GetWidth() == 2 || type->GetWidth() == 4 || type->GetWidth() == 8; } bool IsNonRegisterArgumentIndirect(BinaryView*, Type*) override { return true; } }; class X64LinuxSystemCallConvention: public CallingConvention { public: X64LinuxSystemCallConvention(Architecture* arch): CallingConvention(arch, "linux-syscall") { } virtual vector GetIntegerArgumentRegisters() override { return vector { XED_REG_RAX, XED_REG_RDI, XED_REG_RSI, XED_REG_RDX, XED_REG_R10, XED_REG_R8, XED_REG_R9 }; } virtual vector GetCallerSavedRegisters() override { return vector { XED_REG_RAX, XED_REG_RCX, XED_REG_R11 }; } virtual vector GetCalleeSavedRegisters() override { return vector { 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 X64GoStackCallingConvention: public CallingConvention { public: X64GoStackCallingConvention(Architecture* arch): CallingConvention(arch, "go-stack") { } bool IsEligibleForHeuristics() override { // This convention cannot be detected by heuristics at this time and will cause issues // with non-Go code. return false; } uint32_t GetIntegerReturnValueRegister() override { return BN_INVALID_REGISTER; } vector GetCallerSavedRegisters() override { return vector { XED_REG_RAX, XED_REG_RCX, XED_REG_RDX, XED_REG_RBX, XED_REG_RBP, XED_REG_R8, XED_REG_R9, XED_REG_R10, XED_REG_R11, XED_REG_R12, XED_REG_R13, XED_REG_R14, XED_REG_R15 }; } RegisterValue GetIncomingFlagValue(uint32_t flag, Function*) override { RegisterValue result; if (flag == IL_FLAG_D) { result.state = ConstantValue; result.value = 0; } return result; } ValueLocation GetReturnValueLocation(BinaryView*, const ReturnValue&) override { // It is not possible for this API to determine the return value location on the stack at // this point, return an invalid location and fall back to GetCallLayout. return ValueLocation(); } CallLayout GetCallLayout(BinaryView* view, const ReturnValue& returnValue, const vector& params, const std::optional>& permittedRegs) override { CallLayout result; result.parameters = GetParameterLocations(view, result.returnValue, params, permittedRegs); if (returnValue.type.GetValue() && returnValue.type->GetClass() != VoidTypeClass) { if (returnValue.defaultLocation) { int64_t stackOffset = 8; size_t i = 0; for (auto it = result.parameters.begin(); it != result.parameters.end(); ++i, ++it) { std::optional varStorage; std::optional varSize; for (auto& component: it->components) { if (component.variable.type != StackVariableSourceType) continue; if (!varStorage.has_value() || component.variable.storage > varStorage.value()) { varStorage = component.variable.storage; if (!it->indirect) varSize = component.size; } } if (!varStorage.has_value() || varStorage.value() < stackOffset) continue; if (it->indirect) varSize = 8; size_t width = 8; if (varSize.has_value()) width = varSize.value(); else if (i < params.size() && params[i].type.GetValue()) width = params[i].type->GetWidth(); if (width < 8) width = 8; else if ((width % 8) != 0) width += 8 - (width % 8); stackOffset = varStorage.value() + width; } result.returnValue = Variable::StackOffset(stackOffset); } else { result.returnValue = returnValue.location.GetValue(); } } result.registerStackAdjustments = GetRegisterStackAdjustments(view, result.returnValue, result.parameters); return result; } }; class x86MachoRelocationHandler: public RelocationHandler { public: virtual bool ApplyRelocation(Ref view, Ref arch, Ref 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)info.addend - (uint32_t)reloc->GetAddress() - 5; break; case (uint64_t)-2: // Magic number defined in MachOView.cpp dest32[0] = target + (uint32_t)info.addend; 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 view, Ref arch, vector& result) override { (void)arch; Ref logger = view->CreateLogger("X86MachoReloc"); set 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) logger->LogWarn("Unsupported Mach-O relocation type: %s", GetRelocationString((Machox86RelocationType)reloc)); return true; } }; class x86ElfRelocationHandler: public RelocationHandler { public: virtual bool GetRelocationInfo(Ref view, Ref arch, vector& result) override { (void)arch; Ref logger = view->CreateLogger("X86ElfReloc"); set 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; case R_386_IRELATIVE: reloc.pcRelative = false; reloc.baseRelative = false; reloc.hasSign = false; reloc.size = 4; reloc.truncateSize = 4; reloc.implicitAddend = true; break; default: reloc.type = UnhandledRelocation; relocTypes.insert(reloc.nativeType); } } for (auto& reloc : relocTypes) logger->LogWarn("Unsupported ELF relocation type: %s", GetRelocationString((Elfx86RelocationType)reloc)); return true; } }; class x64MachoRelocationHandler: public RelocationHandler { public: virtual bool ApplyRelocation(Ref view, Ref arch, Ref 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: 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] = info.target + info.addend; break; } return true; } virtual bool GetRelocationInfo(Ref view, Ref arch, vector& result) override { (void)arch; Ref logger = view->CreateLogger("X86MachoReloc"); set 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 + 1].type = IgnoredRelocation; result[i].next = new BNRelocationInfo(result[i + 1]); i++; } break; default: result[i].type = UnhandledRelocation; relocTypes.insert(result[i].nativeType); break; } } for (auto& reloc : relocTypes) logger->LogWarn("Unsupported Mach-O relocation: %s", GetRelocationString((Machox64RelocationType)reloc)); return true; } }; class x64ElfRelocationHandler: public RelocationHandler { public: virtual bool ApplyRelocation(Ref view, Ref arch, Ref 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; } case R_X86_64_DTPMOD64: { uint64_t write = 0; memcpy(dest, (uint8_t*)&write, sizeof(uint64_t)); return true; } case R_X86_64_DTPOFF64: { uint64_t write = reloc->GetTarget() + 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 view, Ref arch, vector& 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)arch; Ref logger = view->CreateLogger("X86ElfReloc"); set 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_DTPMOD64: reloc.pcRelative = false; reloc.baseRelative = false; reloc.hasSign = false; reloc.size = 8; reloc.truncateSize = 8; reloc.symbolIndex = 0; break; case R_X86_64_DTPOFF64: reloc.pcRelative = false; reloc.baseRelative = false; reloc.hasSign = false; reloc.size = 8; reloc.truncateSize = 8; break; case R_X86_64_GOTOFF64: case R_X86_64_GOT64: case R_X86_64_GOTPLT64: case R_X86_64_PLTOFF64: 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_GOTPCREL64: case R_X86_64_GOTPC64: 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) logger->LogWarn("Unsupported ELF relocation: %s", GetRelocationString((Elfx64RelocationType)reloc)); return true; } }; class CoffRelocationHandler: public RelocationHandler { public: virtual bool ApplyRelocation(Ref view, Ref arch, Ref 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; uint64_t* data64 = (uint64_t*)dest; uint32_t* data32 = (uint32_t*)dest; uint16_t* data16 = (uint16_t*)dest; auto info = reloc->GetInfo(); if (len < info.size) return false; 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 view, Ref arch, vector& result) override { (void)arch; Ref logger = view->CreateLogger("X86CoffReloc"); set 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) logger->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) logger->LogWarn("Unsupported COFF relocation: %s", GetRelocationString((COFFx86RelocationType)reloc)); } } return true; } }; class PeRelocationHandler: public RelocationHandler { public: virtual bool ApplyRelocation(Ref view, Ref arch, Ref 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 view, Ref arch, vector& result) override { (void)arch; Ref logger = view->CreateLogger("X86PeReloc"); set 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) logger->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 il, Ref relocation) override { (void)data; (void)addr; (void)length; (void)il; (void)relocation; return BN_AUTOCOERCE_EXTERN_PTR; } }; static void InitX86Settings() { Ref 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.", "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"] })~"); settings->RegisterSetting("arch.x86.disassembly.mpx", R"~({ "title" : "x86 Disassembly Support for MPX", "type" : "boolean", "default" : false, "description" : "Enable support for MPX extensions in the disassembler.", "ignore" : ["SettingsProjectScope", "SettingsResourceScope"] })~"); } extern "C" { BN_DECLARE_CORE_ABI_VERSION #ifndef DEMO_EDITION BINARYNINJAPLUGIN void CorePluginDependencies() { AddOptionalPluginDependency("view_elf"); AddOptionalPluginDependency("view_macho"); AddOptionalPluginDependency("view_pe"); } #endif #ifdef DEMO_EDITION 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 conv; conv = new X86CdeclCallingConvention(x86); x86->RegisterCallingConvention(conv); x86->SetDefaultCallingConvention(conv); x86->SetCdeclCallingConvention(conv); conv = new X86SystemVCallingConvention(x86); x86->RegisterCallingConvention(conv); conv = new X86StdcallCallingConvention(x86); x86->RegisterCallingConvention(conv); x86->SetStdcallCallingConvention(conv); conv = new X86SystemVStdcallCallingConvention(x86); x86->RegisterCallingConvention(conv); conv = new X86RegParmCallingConvention(x86); x86->RegisterCallingConvention(conv); conv = new X86FastcallCallingConvention(x86); x86->RegisterCallingConvention(conv); conv = new X86GCCFastcallCallingConvention(x86); x86->RegisterCallingConvention(conv); conv = new X86ClangFastcallCallingConvention(x86); x86->RegisterCallingConvention(conv); conv = new X86ThiscallCallingConvention(x86); x86->RegisterCallingConvention(conv); conv = new X86GCCThiscallCallingConvention(x86); x86->RegisterCallingConvention(conv); conv = new X86ClangThiscallCallingConvention(x86); x86->RegisterCallingConvention(conv); conv = new X86LinuxSystemCallConvention(x86); x86->RegisterCallingConvention(conv); conv = new X86PascalCallingConvention(x86); x86->RegisterCallingConvention(conv); conv = new X86PascalRegisterCallingConvention(x86); x86->RegisterCallingConvention(conv); conv = new X86GoStackCallingConvention(x86); x86->RegisterCallingConvention(conv); x86->RegisterRelocationHandler("Mach-O", new x86MachoRelocationHandler()); x86->RegisterRelocationHandler("KCView", 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); conv = new X64GoStackCallingConvention(x64); x64->RegisterCallingConvention(conv); x64->RegisterRelocationHandler("Mach-O", new x64MachoRelocationHandler()); x64->RegisterRelocationHandler("KCView", 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; } }