/*************************************************************************************************** Zyan Disassembler Engine (Zydis) Original Author : Florian Bernd * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. ***************************************************************************************************/ #include #include #include #include #include #include #include #include #include #include /* ============================================================================================== */ /* Internal macros */ /* ============================================================================================== */ /* ---------------------------------------------------------------------------------------------- */ /* Helper macros */ /* ---------------------------------------------------------------------------------------------- */ #define ZYDIS_CHECK(status) \ if (status != ZYDIS_STATUS_SUCCESS) \ { \ return status; \ } /* ============================================================================================== */ /* Instruction formatter */ /* ============================================================================================== */ /* ---------------------------------------------------------------------------------------------- */ /* Internal functions */ /* ---------------------------------------------------------------------------------------------- */ /** * @brief Inserts the @c text into the @c buffer at the given @c offset and increases the * @c offset by the length of the text. * * @param buffer A pointer to the target buffer. * @param bufferLen The length of the buffer. * @param offset A pointer to the buffer-offset. * @param text The text to insert. * @param uppercase Set true, to convert to uppercase characters. * * @return A zydis status code. */ static ZydisStatus ZydisBufferAppend(char* buffer, size_t bufferLen, size_t* offset, bool uppercase, const char* text) { ZYDIS_ASSERT(buffer); ZYDIS_ASSERT(bufferLen != 0); ZYDIS_ASSERT(offset); ZYDIS_ASSERT(text); size_t strLen = strlen(text); if ((*offset + strLen) >= bufferLen) { return ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE; } strncpy(&buffer[*offset], text, strLen + 1); if (uppercase) { for (size_t i = *offset; i < *offset + strLen; ++i) { buffer[i] = (char)toupper(buffer[i]); } } *offset += strLen; return ZYDIS_STATUS_SUCCESS; } /** * @brief Inserts formatted text into the @c buffer at the given @c offset and increases the * @c offset by the length of the text. * * @param buffer A pointer to the target buffer. * @param bufferLen The length of the buffer. * @param offset A pointer to the buffer-offset. * @param format The format string. * * @return A zydis status code. */ static ZydisStatus ZydisBufferAppendFormat(char* buffer, size_t bufferLen, size_t* offset, bool uppercase, const char* format, ...) { ZYDIS_ASSERT(buffer); ZYDIS_ASSERT(bufferLen != 0); ZYDIS_ASSERT(offset); ZYDIS_ASSERT(format); va_list arglist; va_start(arglist, format); size_t n = bufferLen - *offset; int w = vsnprintf(&buffer[*offset], n, format, arglist); if ((w < 0) || ((size_t)w >= n)) { va_end(arglist); return ZYDIS_STATUS_INSUFFICIENT_BUFFER_SIZE; } if (uppercase) { for (size_t i = *offset; i < *offset + (size_t)w; ++i) { buffer[i] = (char)toupper(buffer[i]); } } *offset += (size_t)w; va_end(arglist); return ZYDIS_STATUS_SUCCESS; } /* ---------------------------------------------------------------------------------------------- */ static ZydisStatus ZydisBufferAppendAbsoluteAddress(const ZydisInstructionFormatter* formatter, char* buffer, size_t bufferLen, size_t* offset, const ZydisInstructionInfo* info, const ZydisOperandInfo* operand) { ZYDIS_ASSERT(formatter); ZYDIS_ASSERT(buffer); ZYDIS_ASSERT(bufferLen != 0); ZYDIS_ASSERT(offset); ZYDIS_ASSERT(info); ZYDIS_ASSERT(operand); ZYDIS_ASSERT((operand->type == ZYDIS_OPERAND_TYPE_MEMORY) || (operand->type == ZYDIS_OPERAND_TYPE_IMMEDIATE)); uint64_t address = 0; switch (operand->type) { case ZYDIS_OPERAND_TYPE_MEMORY: ZYDIS_ASSERT(operand->mem.disp.size != 0); if ((operand->mem.base == ZYDIS_REGISTER_EIP) || (operand->mem.base == ZYDIS_REGISTER_RIP)) { ZYDIS_CHECK(ZydisUtilsCalcAbsoluteTargetAddress(info, operand, &address)); } else { ZYDIS_ASSERT(operand->mem.base == ZYDIS_REGISTER_NONE); ZYDIS_ASSERT(operand->mem.index == ZYDIS_REGISTER_NONE); ZYDIS_ASSERT(operand->mem.scale == 0); address = (uint64_t)operand->mem.disp.value.sqword; } break; case ZYDIS_OPERAND_TYPE_IMMEDIATE: ZYDIS_CHECK(ZydisUtilsCalcAbsoluteTargetAddress(info, operand, &address)); break; } const char* symbol = NULL; int64_t symbolOffset = 0; if (formatter->symbolResolver) { symbol = formatter->symbolResolver->resolveSymbol(formatter->symbolResolver, info, operand, address, &symbolOffset); } if (symbol) { if (symbolOffset == 0) { return ZydisBufferAppendFormat(buffer, bufferLen, offset, false, "%s", symbol); } if (symbolOffset > 0) { return ZydisBufferAppendFormat( buffer, bufferLen, offset, false, "%s+0x%02llX", symbol, symbolOffset); } if (symbolOffset < 0) { return ZydisBufferAppendFormat( buffer, bufferLen, offset, false, "%s-0x%02llX", symbol, -symbolOffset); } } if (info->operandMode == 16) { return ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "0x%04X", address); } switch (info->mode) { case ZYDIS_DISASSEMBLER_MODE_16BIT: return ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "0x%04X", address); case ZYDIS_DISASSEMBLER_MODE_32BIT: return ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "0x%08lX", address); case ZYDIS_DISASSEMBLER_MODE_64BIT: return ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "0x%016llX", address); default: return ZYDIS_STATUS_INVALID_PARAMETER; } } static ZydisStatus ZydisBufferAppendImmediate(const ZydisInstructionFormatter* formatter, char* buffer, size_t bufferLen, size_t* offset, const ZydisInstructionInfo* info, const ZydisOperandInfo* operand) { ZYDIS_ASSERT(formatter); ZYDIS_ASSERT(buffer); ZYDIS_ASSERT(bufferLen != 0); ZYDIS_ASSERT(offset); ZYDIS_ASSERT(info); ZYDIS_ASSERT(operand); if ((formatter->addressFormat == ZYDIS_FORMATTER_ADDRESS_ABSOLUTE) && (operand->imm.isRelative)) { return ZydisBufferAppendAbsoluteAddress(formatter, buffer, bufferLen, offset, info, operand); } bool useSignedHex = ((operand->imm.isSigned && (formatter->addressFormat == ZYDIS_FORMATTER_ADDRESS_RELATIVE_SIGNED)) || (!operand->imm.isSigned && (formatter->immediateFormat == ZYDIS_FORMATTER_IMM_HEX_SIGNED))); if (useSignedHex && (operand->imm.value.sqword < 0)) { switch (operand->size) { case 8: return ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "-0x%02X", -operand->imm.value.sbyte); case 16: return ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "-0x%02X", -operand->imm.value.sword); case 32: return ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "-0x%02lX", -operand->imm.value.sdword); case 64: return ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "-0x%02llX", -operand->imm.value.sqword); default: return ZYDIS_STATUS_INVALID_PARAMETER; } } switch (operand->size) { case 8: return ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "0x%02X", operand->imm.value.ubyte); case 16: return ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "0x%02X", operand->imm.value.uword); case 32: return ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "0x%02lX", operand->imm.value.udword); case 64: return ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "0x%02llX", operand->imm.value.uqword); default: return ZYDIS_STATUS_INVALID_PARAMETER; } } /* ---------------------------------------------------------------------------------------------- */ static ZydisStatus ZydisBufferAppendOperandIntelMemory(const ZydisInstructionFormatter* formatter, char* buffer, size_t bufferLen, size_t* offset, const ZydisInstructionInfo* info, const ZydisOperandInfo* operand, uint16_t typecast) { if (typecast) { char* str = ""; switch (typecast) { case 8: str = "byte ptr "; break; case 16: str = "word ptr "; break; case 32: str = "dword ptr "; break; case 48: str = "fword ptr "; break; case 64: str = "qword ptr "; break; case 80: str = "tbyte ptr "; break; case 128: str = "xmmword ptr "; break; case 256: str = "ymmword ptr "; break; case 512: str = "zmmword ptr "; break; } ZYDIS_CHECK(ZydisBufferAppend( buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), str)); } if (operand->mem.segment != ZYDIS_REGISTER_NONE) { if ((formatter->flags & ZYDIS_FORMATTER_FLAG_ALWAYS_DISPLAY_MEMORY_SEGMENT) || (((operand->mem.segment != ZYDIS_REGISTER_DS) || (info->prefixFlags & ZYDIS_PREFIX_SEGMENT_DS)) && ((operand->mem.segment != ZYDIS_REGISTER_SS) || (info->prefixFlags & ZYDIS_PREFIX_SEGMENT_SS)))) { ZYDIS_CHECK(ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "%s:", ZydisRegisterGetString(operand->mem.segment))); } } ZYDIS_CHECK(ZydisBufferAppend( buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "[")); if ((operand->mem.disp.size != 0) && ((operand->mem.base == ZYDIS_REGISTER_NONE) || (operand->mem.base == ZYDIS_REGISTER_EIP) || (operand->mem.base == ZYDIS_REGISTER_RIP)) && (operand->mem.index == ZYDIS_REGISTER_NONE) && (operand->mem.scale == 0)) { ZYDIS_CHECK(ZydisBufferAppendAbsoluteAddress(formatter, buffer, bufferLen, offset, info, operand)); } else { if (operand->mem.base != ZYDIS_REGISTER_NONE) { ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), ZydisRegisterGetString(operand->mem.base))); } if (operand->mem.index != ZYDIS_REGISTER_NONE) { const char* c = (operand->mem.base != ZYDIS_REGISTER_NONE) ? "+" : ""; ZYDIS_CHECK(ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "%s%s", c, ZydisRegisterGetString(operand->mem.index))); if (operand->mem.scale) { ZYDIS_CHECK(ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "*%d", operand->mem.scale)); } } if ((operand->mem.disp.size) && ((operand->mem.disp.value.sqword) || ((operand->mem.base == ZYDIS_REGISTER_NONE) && (operand->mem.index == ZYDIS_REGISTER_NONE)))) { if ((operand->mem.disp.value.sqword < 0) && ( (operand->mem.base != ZYDIS_REGISTER_NONE) || (operand->mem.index != ZYDIS_REGISTER_NONE))) { ZYDIS_CHECK( ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "-0x%02llX", -operand->mem.disp.value.sqword)); } else { const char* sign = ((operand->mem.base == ZYDIS_REGISTER_NONE) && (operand->mem.index == ZYDIS_REGISTER_NONE)) ? "" : "+"; ZYDIS_CHECK( ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "%s0x%02llX", sign, operand->mem.disp.value.sqword)); } } } return ZydisBufferAppend( buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "]"); } /* ---------------------------------------------------------------------------------------------- */ /* Intel style */ /* ---------------------------------------------------------------------------------------------- */ static ZydisStatus ZydisBufferAppendOperandIntel(const ZydisInstructionFormatter* formatter, char* buffer, size_t bufferLen, size_t* offset, const ZydisInstructionInfo* info, const ZydisOperandInfo* operand, uint16_t typecast) { switch (operand->type) { case ZYDIS_OPERAND_TYPE_REGISTER: { const char* reg = ZydisRegisterGetString(operand->reg); if (!reg) { reg = "invalid"; } return ZydisBufferAppend( buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), reg); } case ZYDIS_OPERAND_TYPE_MEMORY: return ZydisBufferAppendOperandIntelMemory(formatter, buffer, bufferLen, offset, info, operand, typecast); case ZYDIS_OPERAND_TYPE_POINTER: return ZydisBufferAppendFormat(buffer, bufferLen, offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "0x%02X:0x%02lX", operand->ptr.segment, operand->ptr.offset); case ZYDIS_OPERAND_TYPE_IMMEDIATE: return ZydisBufferAppendImmediate(formatter, buffer, bufferLen, offset, info, operand); } return ZYDIS_STATUS_INVALID_PARAMETER; } static ZydisStatus ZydisFormatterFormatInstructionIntel(ZydisInstructionFormatter* formatter, const ZydisInstructionInfo* info, char* buffer, size_t bufferLen) { size_t offset = 0; if ((info->prefixFlags & ZYDIS_PREFIX_ACCEPTS_REPNE) && (info->prefixFlags & ZYDIS_PREFIX_REPNE)) { ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "repne ")); } if ((info->prefixFlags & ZYDIS_PREFIX_ACCEPTS_REP) && (info->prefixFlags & ZYDIS_PREFIX_REP)) { ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "rep ")); } if ((info->prefixFlags & ZYDIS_PREFIX_ACCEPTS_LOCK) && (info->prefixFlags & ZYDIS_PREFIX_LOCK)) { ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "lock ")); } if (info->prefixFlags & ZYDIS_PREFIX_XACQUIRE) { ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "xacquire ")); } else if (info->prefixFlags & ZYDIS_PREFIX_XRELEASE) { ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "xrelease ")); } const char* mnemonic = ZydisMnemonicGetString(info->mnemonic); if (!mnemonic) { mnemonic = "invalid"; } ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), mnemonic)); uint16_t typecast = 0; for (int i = 0; i < 5; ++i) { if (info->operand[i].type == ZYDIS_OPERAND_TYPE_UNUSED) { break; } if (i == 0) { if (formatter->flags & ZYDIS_FORMATTER_FLAG_TAB_AFTER_MNEMONIC) { ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), "\t")); } else { ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), " ")); } } else { if (formatter->flags & ZYDIS_FORMATTER_FLAG_NO_SPACE_BETWEEN_OPERANDS) { ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), ",")); } else { ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), ", ")); } } if (formatter->flags & ZYDIS_FORMATTER_FLAG_ALWAYS_DISPLAY_MEMORY_SIZE) { if (info->operand[i].type == ZYDIS_OPERAND_TYPE_MEMORY) { typecast = info->operand[i].size; } } else if (info->operand[i].type == ZYDIS_OPERAND_TYPE_MEMORY) { switch (i) { case 0: typecast = ((info->operand[1].type == ZYDIS_OPERAND_TYPE_UNUSED) || (info->operand[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE) || (info->operand[0].size != info->operand[1].size)) ? info->operand[0].size : 0; if (!typecast && (info->operand[1].type == ZYDIS_OPERAND_TYPE_REGISTER) && (info->operand[1].reg == ZYDIS_REGISTER_CL)) { switch (info->mnemonic) { case ZYDIS_MNEMONIC_RCL: case ZYDIS_MNEMONIC_ROL: case ZYDIS_MNEMONIC_ROR: case ZYDIS_MNEMONIC_RCR: case ZYDIS_MNEMONIC_SHL: case ZYDIS_MNEMONIC_SHR: case ZYDIS_MNEMONIC_SAR: typecast = info->operand[0].size; } } break; case 1: case 2: typecast = (info->operand[i - 1].size != info->operand[i].size) ? info->operand[i - 1].size : 0; break; } } ZYDIS_CHECK(ZydisBufferAppendOperandIntel(formatter, buffer, bufferLen, &offset, info, &info->operand[i], typecast)); if (info->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) { if (i == 0) { if (info->avx.maskRegister) { ZYDIS_CHECK(ZydisBufferAppendFormat(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), " {%s}", ZydisRegisterGetString(info->avx.maskRegister))); } if (info->avx.maskMode == ZYDIS_AVX_MASKMODE_ZERO) { ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), " {z}")); } } else { if (info->operand[i].type == ZYDIS_OPERAND_TYPE_MEMORY) { switch (info->avx.broadcast) { case ZYDIS_AVX_BCSTMODE_2: ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), " {1to2}")); break; case ZYDIS_AVX_BCSTMODE_4: ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), " {1to4}")); break; case ZYDIS_AVX_BCSTMODE_8: ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), " {1to8}")); break; case ZYDIS_AVX_BCSTMODE_16: ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), " {1to16}")); break; } } if ((i == (info->operandCount - 1)) || ((i != (info->operandCount - 1)) && (info->operand[i + 1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE))) { switch (info->avx.roundingMode) { case ZYDIS_AVX_RNDMODE_INVALID: if (info->avx.sae) { ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), " {sae}")); } break; case ZYDIS_AVX_RNDMODE_RN: ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), " {rn-sae}")); break; case ZYDIS_AVX_RNDMODE_RD: ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), " {rd-sae}")); break; case ZYDIS_AVX_RNDMODE_RU: ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), " {ru-sae}")); break; case ZYDIS_AVX_RNDMODE_RZ: ZYDIS_CHECK(ZydisBufferAppend(buffer, bufferLen, &offset, (formatter->flags & ZYDIS_FORMATTER_FLAG_UPPERCASE), " {rz-sae}")); break; default: return ZYDIS_STATUS_INVALID_PARAMETER; } } } } } return ZYDIS_STATUS_SUCCESS; } /* ---------------------------------------------------------------------------------------------- */ /* Exported functions */ /* ---------------------------------------------------------------------------------------------- */ ZydisStatus ZydisFormatterInitInstructionFormatter(ZydisInstructionFormatter* formatter, ZydisFormatterStyle style) { return ZydisFormatterInitInstructionFormatterEx(formatter, style, 0); } ZydisStatus ZydisFormatterInitInstructionFormatterEx( ZydisInstructionFormatter* formatter, ZydisFormatterStyle style, ZydisFormatterFlags flags) { if (!formatter || (style != ZYDIS_FORMATTER_STYLE_INTEL)) { return ZYDIS_STATUS_INVALID_PARAMETER; } formatter->style = style; formatter->flags = flags; formatter->addressFormat = ZYDIS_FORMATTER_ADDRESS_ABSOLUTE; formatter->displacementFormat = ZYDIS_FORMATTER_DISP_HEX_SIGNED; formatter->immediateFormat = ZYDIS_FORMATTER_IMM_HEX_UNSIGNED; formatter->symbolResolver = NULL; return ZYDIS_STATUS_SUCCESS; } ZydisStatus ZydisFormatterGetSymbolResolver(const ZydisInstructionFormatter* formatter, ZydisCustomSymbolResolver** symbolResolver) { if (!formatter || !symbolResolver) { return ZYDIS_STATUS_INVALID_PARAMETER; } *symbolResolver = formatter->symbolResolver; return ZYDIS_STATUS_SUCCESS; } ZydisStatus ZydisFormatterSetSymbolResolver(ZydisInstructionFormatter* formatter, ZydisCustomSymbolResolver* symbolResolver) { if (!formatter) { return ZYDIS_STATUS_INVALID_PARAMETER; } formatter->symbolResolver = symbolResolver; return ZYDIS_STATUS_SUCCESS; } ZydisStatus ZydisFormatterFormatInstruction(ZydisInstructionFormatter* formatter, const ZydisInstructionInfo* info, char* buffer, size_t bufferLen) { if (!formatter || !info || !buffer || (bufferLen == 0)) { return ZYDIS_STATUS_INVALID_PARAMETER; } switch (formatter->style) { case ZYDIS_FORMATTER_STYLE_INTEL: return ZydisFormatterFormatInstructionIntel(formatter, info, buffer, bufferLen); default: return ZYDIS_STATUS_INVALID_PARAMETER; } } /* ---------------------------------------------------------------------------------------------- */ /* ============================================================================================== */