simplify one-off disassembly and formatting
This commit is contained in:
@@ -3,6 +3,7 @@ const mem = std.mem;
|
|||||||
const zydis = @import("zydis").zydis;
|
const zydis = @import("zydis").zydis;
|
||||||
|
|
||||||
const log = std.log.scoped(.disassembler);
|
const log = std.log.scoped(.disassembler);
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
pub const InstructionIterator = struct {
|
pub const InstructionIterator = struct {
|
||||||
decoder: zydis.ZydisDecoder,
|
decoder: zydis.ZydisDecoder,
|
||||||
@@ -86,49 +87,72 @@ pub const BundledInstruction = struct {
|
|||||||
operands: []const zydis.ZydisDecodedOperand,
|
operands: []const zydis.ZydisDecodedOperand,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const InstructionFormatter = struct {
|
|
||||||
formatter: zydis.ZydisFormatter,
|
|
||||||
|
|
||||||
pub fn init() InstructionFormatter {
|
|
||||||
var formatter: zydis.ZydisFormatter = undefined;
|
|
||||||
const status = zydis.ZydisFormatterInit(&formatter, zydis.ZYDIS_FORMATTER_STYLE_ATT);
|
|
||||||
if (!zydis.ZYAN_SUCCESS(status)) @panic("Zydis formatter init failed");
|
|
||||||
|
|
||||||
return .{
|
|
||||||
.formatter = formatter,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn format(
|
|
||||||
formatter: *const InstructionFormatter,
|
|
||||||
instruction: BundledInstruction,
|
|
||||||
buffer: []u8,
|
|
||||||
) []u8 {
|
|
||||||
const status = zydis.ZydisFormatterFormatInstruction(
|
|
||||||
&formatter.formatter,
|
|
||||||
instruction.instruction,
|
|
||||||
instruction.operands.ptr,
|
|
||||||
instruction.instruction.operand_count_visible,
|
|
||||||
buffer.ptr,
|
|
||||||
buffer.len,
|
|
||||||
instruction.address,
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
if (!zydis.ZYAN_SUCCESS(status)) {
|
|
||||||
@panic("wow");
|
|
||||||
}
|
|
||||||
return mem.sliceTo(buffer, 0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Disassemble `bytes` and format them into the given buffer. Useful for error reporting or
|
/// Disassemble `bytes` and format them into the given buffer. Useful for error reporting or
|
||||||
/// debugging purposes.
|
/// debugging purposes.
|
||||||
/// This function should not be called in a tight loop as it's intentionally inefficient due tue
|
/// This function is not threadsafe.
|
||||||
/// having a simple API.
|
pub fn formatBytes(bytes: []const u8) []u8 {
|
||||||
pub fn formatBytes(bytes: []const u8, buffer: []u8) []u8 {
|
return formatInstruction(disassembleInstruction(bytes));
|
||||||
var iter = InstructionIterator.init(bytes);
|
}
|
||||||
|
|
||||||
const instr = iter.next() orelse return buffer[0..0];
|
/// Format the given instruction into the buffer.
|
||||||
const formatter = InstructionFormatter.init();
|
/// This function is not threadsafe.
|
||||||
return formatter.format(instr, buffer);
|
pub fn formatInstruction(instruction: BundledInstruction) []u8 {
|
||||||
|
// Static variable to initialize the formatter only once and have a valid address for the
|
||||||
|
// buffer.
|
||||||
|
const static = struct {
|
||||||
|
var initialized = false;
|
||||||
|
var formatter: zydis.ZydisFormatter = undefined;
|
||||||
|
var buffer: [256]u8 = undefined;
|
||||||
|
};
|
||||||
|
if (!static.initialized) {
|
||||||
|
const status = zydis.ZydisFormatterInit(&static.formatter, zydis.ZYDIS_FORMATTER_STYLE_ATT);
|
||||||
|
if (!zydis.ZYAN_SUCCESS(status)) @panic("Zydis formatter init failed");
|
||||||
|
}
|
||||||
|
const status = zydis.ZydisFormatterFormatInstruction(
|
||||||
|
&static.formatter,
|
||||||
|
instruction.instruction,
|
||||||
|
instruction.operands.ptr,
|
||||||
|
instruction.instruction.operand_count_visible,
|
||||||
|
&static.buffer,
|
||||||
|
static.buffer.len,
|
||||||
|
instruction.address,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
assert(zydis.ZYAN_SUCCESS(status)); // TODO: handle
|
||||||
|
return mem.sliceTo(&static.buffer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disassemble the first instruction at bytes.
|
||||||
|
/// This function is not threadsafe.
|
||||||
|
pub fn disassembleInstruction(bytes: []const u8) BundledInstruction {
|
||||||
|
// Static variable to initialize the decoder only once and have a valid address for the
|
||||||
|
// instruction and operands.
|
||||||
|
const static = struct {
|
||||||
|
var initialized = false;
|
||||||
|
var decoder: zydis.ZydisDecoder = undefined;
|
||||||
|
var instruction: zydis.ZydisDecodedInstruction = undefined;
|
||||||
|
var operands: [zydis.ZYDIS_MAX_OPERAND_COUNT]zydis.ZydisDecodedOperand = undefined;
|
||||||
|
};
|
||||||
|
if (!static.initialized) {
|
||||||
|
const status = zydis.ZydisDecoderInit(
|
||||||
|
&static.decoder,
|
||||||
|
zydis.ZYDIS_MACHINE_MODE_LONG_64,
|
||||||
|
zydis.ZYDIS_STACK_WIDTH_64,
|
||||||
|
);
|
||||||
|
if (!zydis.ZYAN_SUCCESS(status)) @panic("Zydis decoder init failed");
|
||||||
|
static.initialized = true;
|
||||||
|
}
|
||||||
|
const status = zydis.ZydisDecoderDecodeFull(
|
||||||
|
&static.decoder,
|
||||||
|
bytes.ptr,
|
||||||
|
bytes.len,
|
||||||
|
&static.instruction,
|
||||||
|
&static.operands,
|
||||||
|
);
|
||||||
|
assert(zydis.ZYAN_SUCCESS(status)); // TODO: handle
|
||||||
|
return .{
|
||||||
|
.address = @intFromPtr(bytes.ptr),
|
||||||
|
.instruction = &static.instruction,
|
||||||
|
.operands = &static.operands,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user