mirror of https://github.com/x64dbg/zydis
More formatter changes
- Added `ZydisFormatterFormatOperand` and `ZydisFormatterFormatOperandEx` (this won't print AVX-512/KNC decorators) - User defined callbacks should return `ZYDIS_STATUS_SKIP_OPERAND` to omit an operand (returning `ZYDIS_STATUS_SUCCESS` without writing to the buffer is now deprecated)
This commit is contained in:
parent
4e189721b2
commit
bbb864561d
|
@ -144,8 +144,8 @@ static ZydisStatus ZydisFormatterPrintMnemonic(const ZydisFormatter* formatter,
|
|||
// Rewrite the instruction-mnemonic for the given instructions
|
||||
if (instruction->operands[instruction->operandCount - 1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE)
|
||||
{
|
||||
const uint8_t conditionCode =
|
||||
(uint8_t)instruction->operands[instruction->operandCount - 1].imm.value.u;
|
||||
const ZydisU8 conditionCode =
|
||||
(ZydisU8)instruction->operands[instruction->operandCount - 1].imm.value.u;
|
||||
switch (instruction->mnemonic)
|
||||
{
|
||||
case ZYDIS_MNEMONIC_CMPPS:
|
||||
|
@ -201,9 +201,7 @@ static ZydisStatus ZydisFormatterFormatOperandImm(const ZydisFormatter* formatte
|
|||
// operand, because it got replaced by the alias-mnemonic
|
||||
if (userData->ommitImmediate)
|
||||
{
|
||||
// The formatter will automatically omit the operand, if the buffer remains unchanged
|
||||
// after the callback returns
|
||||
return ZYDIS_STATUS_SUCCESS;
|
||||
return ZYDIS_STATUS_SKIP_OPERAND;
|
||||
}
|
||||
|
||||
// Default immediate formatting
|
||||
|
@ -216,7 +214,8 @@ static ZydisStatus ZydisFormatterFormatOperandImm(const ZydisFormatter* formatte
|
|||
/* Helper functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
void disassembleBuffer(ZydisDecoder* decoder, uint8_t* data, size_t length, ZydisBool installHooks)
|
||||
void disassembleBuffer(ZydisDecoder* decoder, ZydisU8* data, ZydisUSize length,
|
||||
ZydisBool installHooks)
|
||||
{
|
||||
ZydisFormatter formatter;
|
||||
ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);
|
||||
|
@ -233,7 +232,7 @@ void disassembleBuffer(ZydisDecoder* decoder, uint8_t* data, size_t length, Zydi
|
|||
(const void**)&defaultFormatOperandImm);
|
||||
}
|
||||
|
||||
uint64_t instructionPointer = 0x007FFFFFFF400000;
|
||||
ZydisU64 instructionPointer = 0x007FFFFFFF400000;
|
||||
|
||||
ZydisDecodedInstruction instruction;
|
||||
ZydisCustomUserData userData;
|
||||
|
@ -263,7 +262,7 @@ int main()
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
uint8_t data[] =
|
||||
ZydisU8 data[] =
|
||||
{
|
||||
// cmpps xmm1, xmm4, 0x03
|
||||
0x0F, 0xC2, 0xCC, 0x03,
|
||||
|
|
|
@ -456,9 +456,6 @@ typedef struct ZydisFormatter_ ZydisFormatter;
|
|||
*
|
||||
* Returning a status code other than `ZYDIS_STATUS_SUCCESS` will immediately cause the formatting
|
||||
* process to fail.
|
||||
*
|
||||
* Returning `ZYDIS_STATUS_SUCCESS` in `ZYDIS_FORMATTER_HOOK_PRINT_PREFIXES` without writing to
|
||||
* the string is valid and signals that the corresponding element should not be printed.
|
||||
*
|
||||
* This function type is used for:
|
||||
* - `ZYDIS_FORMATTER_HOOK_PRE_INSTRUCTION`
|
||||
|
@ -482,15 +479,17 @@ typedef ZydisStatus (*ZydisFormatterFunc)(const ZydisFormatter* formatter,
|
|||
* @return A zydis status code.
|
||||
*
|
||||
* Returning a status code other than `ZYDIS_STATUS_SUCCESS` will immediately cause the formatting
|
||||
* process to fail.
|
||||
* process to fail (see exceptions below).
|
||||
*
|
||||
* Returning `ZYDIS_STATUS_SUCCESS` in one of the `ZYDIS_FORMATTER_HOOK_FORMAT_OPERAND_X` hooks
|
||||
* without writing to the string is valid and will cause the formatter to omit the current
|
||||
* Returning `ZYDIS_STATUS_SKIP_OPERAND` is valid for `ZYDIS_FORMATTER_HOOK_PRE_OPERAND`,
|
||||
* `ZYDIS_FORMATTER_HOOK_POST_OPERAND` and all of the `ZYDIS_FORMATTER_HOOK_FORMAT_OPERAND_XXX`
|
||||
* callbacks. This will cause the formatter to omit the current operand.
|
||||
*
|
||||
* DEPRECATED:
|
||||
* Returning `ZYDIS_STATUS_SUCCESS` without writing to the string is valid for
|
||||
* `ZYDIS_FORMATTER_HOOK_PRE_OPERAND`, `ZYDIS_FORMATTER_HOOK_POST_OPERAND` and all of the
|
||||
* `ZYDIS_FORMATTER_HOOK_FORMAT_OPERAND_XXX`. This will cause the formatter to omit the current
|
||||
* operand.
|
||||
*
|
||||
* Returning `ZYDIS_STATUS_SUCCESS` in `ZYDIS_FORMATTER_HOOK_PRINT_MEMSIZE` or
|
||||
* `ZYDIS_FORMATTER_HOOK_PRINT_DECORATOR` without writing to the string is valid and signals that
|
||||
* the corresponding element should not be printed for the current operand.
|
||||
*
|
||||
* This function type is used for:
|
||||
* - `ZYDIS_FORMATTER_HOOK_PRE_OPERAND`
|
||||
|
@ -559,9 +558,6 @@ typedef ZydisStatus (*ZydisFormatterAddressFunc)(const ZydisFormatter* formatter
|
|||
*
|
||||
* @return Returning a status code other than `ZYDIS_STATUS_SUCCESS` will immediately cause the
|
||||
* formatting process to fail.
|
||||
*
|
||||
* Returning `ZYDIS_STATUS_SUCCESS` without writing to the string is valid and will cause the
|
||||
* formatter to omit the current decorator.
|
||||
*
|
||||
* This function type is used for:
|
||||
* - `ZYDIS_FORMATTER_HOOK_PRINT_DECORATOR`
|
||||
|
@ -685,6 +681,43 @@ ZYDIS_EXPORT ZydisStatus ZydisFormatterFormatInstruction(const ZydisFormatter* f
|
|||
ZYDIS_EXPORT ZydisStatus ZydisFormatterFormatInstructionEx(const ZydisFormatter* formatter,
|
||||
const ZydisDecodedInstruction* instruction, char* buffer, ZydisUSize bufferLen, void* userData);
|
||||
|
||||
/**
|
||||
* @brief Formats the given operand and writes it into the output buffer.
|
||||
*
|
||||
* @param formatter A pointer to the `ZydisFormatter` instance.
|
||||
* @param instruction A pointer to the `ZydisDecodedInstruction` struct.
|
||||
* @param index The index of the operand to format.
|
||||
* @param buffer A pointer to the output buffer.
|
||||
* @param bufferLen The length of the output buffer.
|
||||
*
|
||||
* @return A zydis status code.
|
||||
*
|
||||
* Use `ZydisFormatterFormatInstruction` or `ZydisFormatterFormatInstructionEx` to format a
|
||||
* complete instruction.
|
||||
*/
|
||||
ZYDIS_EXPORT ZydisStatus ZydisFormatterFormatOperand(const ZydisFormatter* formatter,
|
||||
const ZydisDecodedInstruction* instruction, ZydisU8 index, char* buffer, ZydisUSize bufferLen);
|
||||
|
||||
/**
|
||||
* @brief Formats the given operand and writes it into the output buffer.
|
||||
*
|
||||
* @param formatter A pointer to the `ZydisFormatter` instance.
|
||||
* @param instruction A pointer to the `ZydisDecodedInstruction` struct.
|
||||
* @param index The index of the operand to format.
|
||||
* @param buffer A pointer to the output buffer.
|
||||
* @param bufferLen The length of the output buffer.
|
||||
* @param userData A pointer to user-defined data which can be used in custom formatter
|
||||
* callbacks.
|
||||
*
|
||||
* @return A zydis status code.
|
||||
*
|
||||
* Use `ZydisFormatterFormatInstruction` or `ZydisFormatterFormatInstructionEx` to format a
|
||||
* complete instruction.
|
||||
*/
|
||||
ZYDIS_EXPORT ZydisStatus ZydisFormatterFormatOperandEx(const ZydisFormatter* formatter,
|
||||
const ZydisDecodedInstruction* instruction, ZydisU8 index, char* buffer, ZydisUSize bufferLen,
|
||||
void* userData);
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -126,6 +126,16 @@ enum ZydisStatusCodes
|
|||
*/
|
||||
ZYDIS_STATUS_INVALID_MASK,
|
||||
|
||||
/* ------------------------------------------------------------------------------------------ */
|
||||
/* Formatter */
|
||||
/* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* @brief Returning this status code in operand-related custom formatter callbacks will cause
|
||||
* the formatter to omit the operand.
|
||||
*/
|
||||
ZYDIS_STATUS_SKIP_OPERAND,
|
||||
|
||||
/* ------------------------------------------------------------------------------------------ */
|
||||
/* Encoder */
|
||||
/* ------------------------------------------------------------------------------------------ */
|
||||
|
@ -141,8 +151,8 @@ enum ZydisStatusCodes
|
|||
*/
|
||||
ZYDIS_STATUS_USER = 0x10000000
|
||||
|
||||
// Max value entry intentionally omitted since users might
|
||||
// define custom error codes for formatter hooks.
|
||||
// Max value entry intentionally omitted since users might define custom error codes for
|
||||
// formatter hooks.
|
||||
};
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
|
143
src/Formatter.c
143
src/Formatter.c
|
@ -89,53 +89,80 @@ static ZydisStatus ZydisFormatInstrIntel(const ZydisFormatter* formatter, ZydisS
|
|||
}
|
||||
|
||||
const ZydisUSize strLenPreOperand = string->length;
|
||||
|
||||
// Print embedded-mask registers as decorator instead of a regular operand
|
||||
if ((i == 1) && (instruction->operands[i].type == ZYDIS_OPERAND_TYPE_REGISTER) &&
|
||||
(instruction->operands[i].encoding == ZYDIS_OPERAND_ENCODING_MASK))
|
||||
{
|
||||
goto SkipOperand;
|
||||
}
|
||||
|
||||
ZydisStatus status;
|
||||
if (formatter->funcPreOperand)
|
||||
{
|
||||
if (!ZYDIS_SUCCESS(formatter->funcPreOperand(formatter, string, instruction,
|
||||
&instruction->operands[i], userData)))
|
||||
status = formatter->funcPreOperand(formatter, string, instruction,
|
||||
&instruction->operands[i], userData);
|
||||
if (status == ZYDIS_STATUS_SKIP_OPERAND)
|
||||
{
|
||||
goto SkipOperand;
|
||||
}
|
||||
if (status != ZYDIS_STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
switch (instruction->operands[i].type)
|
||||
{
|
||||
case ZYDIS_OPERAND_TYPE_REGISTER:
|
||||
ZYDIS_CHECK(formatter->funcFormatOperandReg(formatter, string, instruction,
|
||||
&instruction->operands[i], userData));
|
||||
status = formatter->funcFormatOperandReg(formatter, string, instruction,
|
||||
&instruction->operands[i], userData);
|
||||
break;
|
||||
case ZYDIS_OPERAND_TYPE_MEMORY:
|
||||
{
|
||||
ZYDIS_CHECK(formatter->funcPrintMemSize(formatter, string, instruction,
|
||||
&instruction->operands[i], userData));
|
||||
const ZydisUSize strLenTemp = string->length;
|
||||
ZYDIS_CHECK(formatter->funcFormatOperandMem(formatter, string, instruction,
|
||||
&instruction->operands[i], userData));
|
||||
if (strLenTemp == string->length)
|
||||
status = formatter->funcFormatOperandMem(formatter, string, instruction,
|
||||
&instruction->operands[i], userData);
|
||||
if ((status == ZYDIS_STATUS_SUCCESS) && (strLenTemp == string->length))
|
||||
{
|
||||
string->length = strLenPreOperand;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ZYDIS_OPERAND_TYPE_POINTER:
|
||||
ZYDIS_CHECK(formatter->funcFormatOperandPtr(formatter, string, instruction,
|
||||
&instruction->operands[i], userData));
|
||||
status = formatter->funcFormatOperandPtr(formatter, string, instruction,
|
||||
&instruction->operands[i], userData);
|
||||
break;
|
||||
case ZYDIS_OPERAND_TYPE_IMMEDIATE:
|
||||
ZYDIS_CHECK(formatter->funcFormatOperandImm(formatter, string, instruction,
|
||||
&instruction->operands[i], userData));
|
||||
status = formatter->funcFormatOperandImm(formatter, string, instruction,
|
||||
&instruction->operands[i], userData);
|
||||
break;
|
||||
default:
|
||||
return ZYDIS_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
if (status == ZYDIS_STATUS_SKIP_OPERAND)
|
||||
{
|
||||
goto SkipOperand;
|
||||
}
|
||||
if (status != ZYDIS_STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
if (formatter->funcPostOperand)
|
||||
{
|
||||
if (!ZYDIS_SUCCESS(formatter->funcPostOperand(formatter, string, instruction,
|
||||
&instruction->operands[i], userData)))
|
||||
status = formatter->funcPostOperand(formatter, string, instruction,
|
||||
&instruction->operands[i], userData);
|
||||
if (status == ZYDIS_STATUS_SKIP_OPERAND)
|
||||
{
|
||||
goto SkipOperand;
|
||||
}
|
||||
if (status != ZYDIS_STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (strLenPreOperand == string->length)
|
||||
|
@ -203,12 +230,6 @@ static ZydisStatus ZydisFormatOperandRegIntel(const ZydisFormatter* formatter, Z
|
|||
return ZYDIS_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// We want to print embedded-mask registers as decorator instead of a regular operand
|
||||
if ((operand->id == 1) && (operand->encoding == ZYDIS_OPERAND_ENCODING_MASK))
|
||||
{
|
||||
return ZYDIS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return formatter->funcPrintRegister(formatter, string, instruction, operand,
|
||||
operand->reg.value, userData);
|
||||
}
|
||||
|
@ -1176,7 +1197,91 @@ ZydisStatus ZydisFormatterFormatInstructionEx(const ZydisFormatter* formatter,
|
|||
const ZydisStatus status = ZydisFormatInstruction(formatter, instruction, &string, userData);
|
||||
|
||||
buffer[string.length] = 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
ZydisStatus ZydisFormatterFormatOperand(const ZydisFormatter* formatter,
|
||||
const ZydisDecodedInstruction* instruction, ZydisU8 index, char* buffer, ZydisUSize bufferLen)
|
||||
{
|
||||
return ZydisFormatterFormatOperandEx(
|
||||
formatter, instruction, index, buffer, bufferLen, ZYDIS_NULL);
|
||||
}
|
||||
|
||||
ZydisStatus ZydisFormatterFormatOperandEx(const ZydisFormatter* formatter,
|
||||
const ZydisDecodedInstruction* instruction, ZydisU8 index, char* buffer, ZydisUSize bufferLen,
|
||||
void* userData)
|
||||
{
|
||||
if (!formatter || !instruction || index >= instruction->operandCount || !buffer ||
|
||||
(bufferLen == 0))
|
||||
{
|
||||
return ZYDIS_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
ZydisString string;
|
||||
string.buffer = buffer;
|
||||
string.length = 0;
|
||||
string.capacity = bufferLen - 1;
|
||||
|
||||
ZydisStatus status;
|
||||
const ZydisDecodedOperand* operand = &instruction->operands[index];
|
||||
|
||||
if (formatter->funcPreOperand)
|
||||
{
|
||||
status = formatter->funcPreOperand(formatter, &string, instruction, operand, userData);
|
||||
// We ignore `ZYDIS_STATUS_SKIP_OPERAND` as it does not make any sense to skip the only
|
||||
// operand printed by this function
|
||||
if ((status != ZYDIS_STATUS_SUCCESS) && (status != ZYDIS_STATUS_SKIP_OPERAND))
|
||||
{
|
||||
goto FinalizeString;
|
||||
}
|
||||
}
|
||||
|
||||
switch (operand->type)
|
||||
{
|
||||
case ZYDIS_OPERAND_TYPE_REGISTER:
|
||||
status = formatter->funcFormatOperandReg(formatter, &string, instruction, operand,
|
||||
userData);
|
||||
break;
|
||||
case ZYDIS_OPERAND_TYPE_MEMORY:
|
||||
status = formatter->funcPrintMemSize(formatter, &string, instruction, operand, userData);
|
||||
if (!ZYDIS_SUCCESS(status))
|
||||
{
|
||||
goto FinalizeString;
|
||||
}
|
||||
status = formatter->funcFormatOperandMem(formatter, &string, instruction, operand,
|
||||
userData);
|
||||
break;
|
||||
case ZYDIS_OPERAND_TYPE_IMMEDIATE:
|
||||
status = formatter->funcFormatOperandImm(formatter, &string, instruction, operand,
|
||||
userData);
|
||||
break;
|
||||
case ZYDIS_OPERAND_TYPE_POINTER:
|
||||
status = formatter->funcFormatOperandPtr(formatter, &string, instruction, operand,
|
||||
userData);
|
||||
break;
|
||||
default:
|
||||
status = ZYDIS_STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
if (!ZYDIS_SUCCESS(status))
|
||||
{
|
||||
goto FinalizeString;
|
||||
}
|
||||
|
||||
// TODO: Print AVX512/KNC decorator
|
||||
|
||||
if (formatter->funcPostOperand)
|
||||
{
|
||||
status = formatter->funcPostOperand(formatter, &string, instruction, operand, userData);
|
||||
// Ignore `ZYDIS_STATUS_SKIP_OPERAND`
|
||||
if (status == ZYDIS_STATUS_SKIP_OPERAND)
|
||||
{
|
||||
status = ZYDIS_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
FinalizeString:
|
||||
buffer[string.length] = 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue