Output more available information in formatter
The formatter now includes the following information: - Segment overrides - Address-size overrides - REP/REPNZ prefixes - LOCK prefix - High-byte registers (determined using presence of REX prefix)
This commit is contained in:
195
format.c
195
format.c
@@ -1,6 +1,7 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <decode.h>
|
||||
|
||||
@@ -17,152 +18,90 @@ static const uint16_t _mnemonic_offs[] = {
|
||||
};
|
||||
#undef DECODE_TABLE_STRTAB2
|
||||
|
||||
static
|
||||
void
|
||||
instr_format_decimal(char** cur, uint32_t value)
|
||||
{
|
||||
char buffer[32];
|
||||
size_t buf_idx = sizeof(buffer) - 1;
|
||||
if (value == 0)
|
||||
{
|
||||
buffer[buf_idx] = '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
while (value > 0)
|
||||
{
|
||||
uint32_t digit = value % 10;
|
||||
buffer[buf_idx--] = '0' + digit;
|
||||
value /= 10;
|
||||
}
|
||||
buf_idx++;
|
||||
}
|
||||
|
||||
size_t length = sizeof(buffer) - buf_idx;
|
||||
__builtin_memcpy(*cur, buffer + buf_idx, length);
|
||||
*cur += length;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
instr_format_hex(char** cur, size_t value)
|
||||
{
|
||||
char buffer[32];
|
||||
size_t buf_idx = sizeof(buffer) - 1;
|
||||
if (value == 0)
|
||||
{
|
||||
buffer[buf_idx] = '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
while (value > 0)
|
||||
{
|
||||
uint32_t nibble = value & 0xf;
|
||||
buffer[buf_idx--] = "0123456789abcdef"[nibble];
|
||||
value >>= 4;
|
||||
}
|
||||
buf_idx++;
|
||||
}
|
||||
buffer[--buf_idx] = 'x';
|
||||
buffer[--buf_idx] = '0';
|
||||
|
||||
size_t length = sizeof(buffer) - buf_idx;
|
||||
__builtin_memcpy(*cur, buffer + buf_idx, length);
|
||||
*cur += length;
|
||||
}
|
||||
#define FMT_CONCAT(buf, end, ...) do { \
|
||||
buf += snprintf(buf, end - buf, __VA_ARGS__); \
|
||||
if (buf > end) \
|
||||
buf = end; \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
instr_format(const Instr* instr, char buffer[128])
|
||||
{
|
||||
char* cur = buffer;
|
||||
*(cur++) = '[';
|
||||
char* buf = buffer;
|
||||
char* end = buffer + 128;
|
||||
|
||||
const char* mnemonic = &_mnemonic_str[_mnemonic_offs[instr->type]];
|
||||
while (*mnemonic)
|
||||
{
|
||||
*(cur++) = *(mnemonic++);
|
||||
}
|
||||
FMT_CONCAT(buf, end, "[");
|
||||
if (INSTR_HAS_REP(instr))
|
||||
FMT_CONCAT(buf, end, "rep:");
|
||||
if (INSTR_HAS_REPNZ(instr))
|
||||
FMT_CONCAT(buf, end, "repnz:");
|
||||
if (INSTR_SEGMENT(instr) < 6)
|
||||
FMT_CONCAT(buf, end, "%cs:", "ecsdfg"[INSTR_SEGMENT(instr)]);
|
||||
if (INSTR_IS64(instr) && INSTR_ADDRSZ(instr) == 4)
|
||||
FMT_CONCAT(buf, end, "addr32:");
|
||||
if (!INSTR_IS64(instr) && INSTR_ADDRSZ(instr) == 2)
|
||||
FMT_CONCAT(buf, end, "addr16:");
|
||||
if (INSTR_HAS_LOCK(instr))
|
||||
FMT_CONCAT(buf, end, "lock:");
|
||||
|
||||
FMT_CONCAT(buf, end, "%s", &_mnemonic_str[_mnemonic_offs[instr->type]]);
|
||||
if (INSTR_WIDTH(instr))
|
||||
{
|
||||
*(cur++) = '_';
|
||||
instr_format_decimal(&cur, INSTR_WIDTH(instr));
|
||||
}
|
||||
FMT_CONCAT(buf, end, "_%u", INSTR_WIDTH(instr));
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
const struct Operand* operand = &instr->operands[i];
|
||||
if (operand->type == OT_NONE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
__builtin_memcpy(cur, " REG IMM MEM" + operand->type * 4 - 4, 4);
|
||||
cur += 4;
|
||||
instr_format_decimal(&cur, operand->size);
|
||||
*(cur++) = ':';
|
||||
const char* op_type_name = "reg\0imm\0mem" + operand->type * 4 - 4;
|
||||
FMT_CONCAT(buf, end, " %s%u:", op_type_name, operand->size);
|
||||
|
||||
switch (operand->type)
|
||||
{
|
||||
size_t immediate;
|
||||
case OT_REG:
|
||||
instr_format_decimal(&cur, reg_index(operand->reg));
|
||||
break;
|
||||
case OT_IMM:
|
||||
immediate = instr->immediate;
|
||||
if (operand->size == 1)
|
||||
{
|
||||
immediate &= 0xff;
|
||||
}
|
||||
else if (operand->size == 2)
|
||||
{
|
||||
immediate &= 0xffff;
|
||||
}
|
||||
#if defined(ARCH_X86_64)
|
||||
else if (operand->size == 4)
|
||||
{
|
||||
immediate &= 0xffffffff;
|
||||
}
|
||||
#endif
|
||||
instr_format_hex(&cur, immediate);
|
||||
break;
|
||||
case OT_MEM:
|
||||
if (!reg_is_none(operand->reg))
|
||||
{
|
||||
instr_format_decimal(&cur, reg_index(operand->reg));
|
||||
*(cur++) = ':';
|
||||
}
|
||||
if (instr->scale != 0)
|
||||
{
|
||||
uint8_t scale = 1 << (instr->scale - 1);
|
||||
instr_format_decimal(&cur, scale);
|
||||
*(cur++) = '*';
|
||||
instr_format_decimal(&cur, reg_index(instr->sreg));
|
||||
*(cur++) = ':';
|
||||
}
|
||||
if (instr->disp < 0)
|
||||
{
|
||||
*(cur++) = '-';
|
||||
instr_format_hex(&cur, -instr->disp);
|
||||
}
|
||||
else
|
||||
{
|
||||
instr_format_hex(&cur, instr->disp);
|
||||
}
|
||||
break;
|
||||
case OT_NONE:
|
||||
default:
|
||||
break;
|
||||
size_t immediate;
|
||||
case OT_REG:
|
||||
if (operand->size == 1 && !INSTR_HAS_REX(instr) &&
|
||||
operand->reg >= 4 && operand->reg < 8)
|
||||
FMT_CONCAT(buf, end, "r%uh", operand->reg - 4);
|
||||
else
|
||||
FMT_CONCAT(buf, end, "r%u", operand->reg);
|
||||
break;
|
||||
case OT_IMM:
|
||||
immediate = instr->immediate;
|
||||
if (operand->size == 1)
|
||||
immediate &= 0xff;
|
||||
else if (operand->size == 2)
|
||||
immediate &= 0xffff;
|
||||
else if (operand->size == 4)
|
||||
immediate &= 0xffffffff;
|
||||
FMT_CONCAT(buf, end, "0x%lx", immediate);
|
||||
break;
|
||||
case OT_MEM:
|
||||
if (!reg_is_none(operand->reg))
|
||||
{
|
||||
FMT_CONCAT(buf, end, "r%u", operand->reg);
|
||||
if (instr->scale != 0 || instr->disp > 0)
|
||||
FMT_CONCAT(buf, end, "+");
|
||||
}
|
||||
if (instr->scale != 0)
|
||||
{
|
||||
FMT_CONCAT(buf, end, "%u*r%u", 1 << (instr->scale - 1),
|
||||
instr->sreg);
|
||||
if (instr->disp > 0)
|
||||
FMT_CONCAT(buf, end, "+");
|
||||
}
|
||||
if (instr->disp < 0)
|
||||
FMT_CONCAT(buf, end, "-0x%lx", -instr->disp);
|
||||
else if ((reg_is_none(operand->reg) && instr->scale == 0) ||
|
||||
instr->disp > 0)
|
||||
FMT_CONCAT(buf, end, "0x%lx", instr->disp);
|
||||
break;
|
||||
case OT_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*(cur++) = ']';
|
||||
*(cur++) = '\0';
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (cur - buffer > 128)
|
||||
{
|
||||
__builtin_trap();
|
||||
}
|
||||
#endif
|
||||
FMT_CONCAT(buf, end, "]");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user