Use a singleton for instruction decoding

This commit is contained in:
offtkp 2024-09-17 16:42:33 +03:00
parent 4a0bd876ff
commit 9242ad4aca
5 changed files with 27 additions and 22 deletions

View File

@ -350,8 +350,8 @@ set(COMMON src/common/logging/backend.cpp
src/common/config.cpp src/common/config.cpp
src/common/config.h src/common/config.h
src/common/debug.h src/common/debug.h
src/common/disassembler.cpp src/common/decoder.cpp
src/common/disassembler.h src/common/decoder.h
src/common/endian.h src/common/endian.h
src/common/enum.h src/common/enum.h
src/common/io_file.cpp src/common/io_file.cpp

View File

@ -2,18 +2,18 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <fmt/format.h> #include <fmt/format.h>
#include "common/disassembler.h" #include "common/decoder.h"
namespace Common { namespace Common {
Disassembler::Disassembler() { Decoder::Decoder() {
ZydisDecoderInit(&m_decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64); ZydisDecoderInit(&m_decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64);
ZydisFormatterInit(&m_formatter, ZYDIS_FORMATTER_STYLE_INTEL); ZydisFormatterInit(&m_formatter, ZYDIS_FORMATTER_STYLE_INTEL);
} }
Disassembler::~Disassembler() = default; Decoder::~Decoder() = default;
void Disassembler::printInstruction(void* code, u64 address) { void Decoder::printInstruction(void* code, u64 address) {
ZydisDecodedInstruction instruction; ZydisDecodedInstruction instruction;
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT_VISIBLE]; ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT_VISIBLE];
ZyanStatus status = ZyanStatus status =
@ -25,8 +25,7 @@ void Disassembler::printInstruction(void* code, u64 address) {
} }
} }
void Disassembler::printInst(ZydisDecodedInstruction& inst, ZydisDecodedOperand* operands, void Decoder::printInst(ZydisDecodedInstruction& inst, ZydisDecodedOperand* operands, u64 address) {
u64 address) {
const int bufLen = 256; const int bufLen = 256;
char szBuffer[bufLen]; char szBuffer[bufLen];
ZydisFormatterFormatInstruction(&m_formatter, &inst, operands, inst.operand_count_visible, ZydisFormatterFormatInstruction(&m_formatter, &inst, operands, inst.operand_count_visible,
@ -34,4 +33,9 @@ void Disassembler::printInst(ZydisDecodedInstruction& inst, ZydisDecodedOperand*
fmt::print("instruction: {}\n", szBuffer); fmt::print("instruction: {}\n", szBuffer);
} }
ZyanStatus Decoder::decodeInstruction(ZydisDecodedInstruction& inst, ZydisDecodedOperand* operands,
void* data, u64 size) {
return ZydisDecoderDecodeFull(&m_decoder, data, size, &inst, operands);
}
} // namespace Common } // namespace Common

View File

@ -8,13 +8,20 @@
namespace Common { namespace Common {
class Disassembler { class Decoder {
public: public:
Disassembler(); Decoder();
~Disassembler(); ~Decoder();
void printInst(ZydisDecodedInstruction& inst, ZydisDecodedOperand* operands, u64 address); void printInst(ZydisDecodedInstruction& inst, ZydisDecodedOperand* operands, u64 address);
void printInstruction(void* code, u64 address); void printInstruction(void* code, u64 address);
ZyanStatus decodeInstruction(ZydisDecodedInstruction& inst, ZydisDecodedOperand* operands,
void* data, u64 size = 15);
static Decoder& Instance() {
static Decoder instance;
return instance;
}
private: private:
ZydisDecoder m_decoder; ZydisDecoder m_decoder;

View File

@ -9,6 +9,7 @@
#include <xbyak/xbyak.h> #include <xbyak/xbyak.h>
#include "common/alignment.h" #include "common/alignment.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/decoder.h"
#include "common/types.h" #include "common/types.h"
#include "core/signals.h" #include "core/signals.h"
#include "core/tls.h" #include "core/tls.h"
@ -622,7 +623,6 @@ static const std::unordered_map<ZydisMnemonic, PatchInfo> Patches = {
}; };
static std::once_flag init_flag; static std::once_flag init_flag;
static ZydisDecoder instr_decoder;
struct PatchModule { struct PatchModule {
/// Mutex controlling access to module code regions. /// Mutex controlling access to module code regions.
@ -663,8 +663,8 @@ static PatchModule* GetModule(const void* ptr) {
static std::pair<bool, u64> TryPatch(u8* code, PatchModule* module) { static std::pair<bool, u64> TryPatch(u8* code, PatchModule* module) {
ZydisDecodedInstruction instruction; ZydisDecodedInstruction instruction;
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT]; ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
const auto status = const auto status = Common::Decoder::Instance().decodeInstruction(instruction, operands, code,
ZydisDecoderDecodeFull(&instr_decoder, code, module->end - code, &instruction, operands); module->end - code);
if (!ZYAN_SUCCESS(status)) { if (!ZYAN_SUCCESS(status)) {
return std::make_pair(false, 1); return std::make_pair(false, 1);
} }
@ -755,8 +755,6 @@ static bool PatchesIllegalInstructionHandler(void* code_address) {
} }
static void PatchesInit() { static void PatchesInit() {
ZydisDecoderInit(&instr_decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64);
if (!Patches.empty()) { if (!Patches.empty()) {
auto* signals = Signals::Instance(); auto* signals = Signals::Instance();
// Should be called last. // Should be called last.

View File

@ -3,6 +3,7 @@
#include "common/arch.h" #include "common/arch.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/decoder.h"
#include "core/signals.h" #include "core/signals.h"
#ifdef _WIN32 #ifdef _WIN32
@ -10,7 +11,6 @@
#else #else
#include <csignal> #include <csignal>
#ifdef ARCH_X86_64 #ifdef ARCH_X86_64
#include <Zydis/Decoder.h>
#include <Zydis/Formatter.h> #include <Zydis/Formatter.h>
#endif #endif
#endif #endif
@ -66,14 +66,10 @@ static std::string DisassembleInstruction(void* code_address) {
char buffer[256] = "<unable to decode>"; char buffer[256] = "<unable to decode>";
#ifdef ARCH_X86_64 #ifdef ARCH_X86_64
ZydisDecoder decoder;
ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64);
ZydisDecodedInstruction instruction; ZydisDecodedInstruction instruction;
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT]; ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
static constexpr u64 max_length = 0x20;
const auto status = const auto status =
ZydisDecoderDecodeFull(&decoder, code_address, max_length, &instruction, operands); Common::Decoder::Instance().decodeInstruction(instruction, operands, code_address);
if (ZYAN_SUCCESS(status)) { if (ZYAN_SUCCESS(status)) {
ZydisFormatter formatter; ZydisFormatter formatter;
ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL); ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);