From bf44a1cce6ce27bc4e5c6385e2fe857b149fe10a Mon Sep 17 00:00:00 2001 From: WerWolv Date: Thu, 26 Dec 2024 20:04:39 +0100 Subject: [PATCH] feat: Added initial support for custom disassemblers --- .gitmodules | 5 +- cmake/build_helpers.cmake | 1 + lib/external/disassembler | 1 + .../include/hex/api/content_registry.hpp | 4 +- .../include/hex/helpers/default_paths.hpp | 4 +- main/gui/source/crash_handlers.cpp | 2 +- .../source/content/views/view_about.cpp | 1 + plugins/disassembler/CMakeLists.txt | 2 + .../include/content/helpers/disassembler.hpp | 4 +- .../disassemblers/capstone_architectures.cpp | 114 ++++++++++++------ .../disassemblers/custom_architectures.cpp | 72 +++++++++++ .../source/plugin_disassembler.cpp | 2 + 12 files changed, 170 insertions(+), 42 deletions(-) create mode 160000 lib/external/disassembler create mode 100644 plugins/disassembler/source/content/disassemblers/custom_architectures.cpp diff --git a/.gitmodules b/.gitmodules index ace9956aa..c678d3e9d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -43,4 +43,7 @@ [submodule "lib/third_party/HashLibPlus"] path = lib/third_party/HashLibPlus - url = https://github.com/WerWolv/HashLibPlus \ No newline at end of file + url = https://github.com/WerWolv/HashLibPlus +[submodule "lib/external/disassembler"] + path = lib/external/disassembler + url = https://github.com/WerWolv/Disassembler diff --git a/cmake/build_helpers.cmake b/cmake/build_helpers.cmake index 7fae1e723..fb358ba84 100644 --- a/cmake/build_helpers.cmake +++ b/cmake/build_helpers.cmake @@ -728,6 +728,7 @@ macro(addBundledLibraries) endif() add_subdirectory(${EXTERNAL_LIBS_FOLDER}/pattern_language EXCLUDE_FROM_ALL) + add_subdirectory(${EXTERNAL_LIBS_FOLDER}/disassembler EXCLUDE_FROM_ALL) if (LIBPL_SHARED_LIBRARY) install( diff --git a/lib/external/disassembler b/lib/external/disassembler new file mode 160000 index 000000000..2209885ee --- /dev/null +++ b/lib/external/disassembler @@ -0,0 +1 @@ +Subproject commit 2209885ee77456fd922999e183f7feb33bed8794 diff --git a/lib/libimhex/include/hex/api/content_registry.hpp b/lib/libimhex/include/hex/api/content_registry.hpp index 372d65794..dbee17784 100644 --- a/lib/libimhex/include/hex/api/content_registry.hpp +++ b/lib/libimhex/include/hex/api/content_registry.hpp @@ -1461,8 +1461,8 @@ namespace hex { template T> void add(auto && ...args) { - impl::addArchitectureCreator([args...] { - return std::make_unique(std::forward(args)...); + impl::addArchitectureCreator([...args = std::move(args)] { + return std::make_unique(args...); }); } diff --git a/lib/libimhex/include/hex/helpers/default_paths.hpp b/lib/libimhex/include/hex/helpers/default_paths.hpp index 5a237fdea..cd8b67545 100644 --- a/lib/libimhex/include/hex/helpers/default_paths.hpp +++ b/lib/libimhex/include/hex/helpers/default_paths.hpp @@ -82,8 +82,9 @@ namespace hex::paths { const static inline impl::DataPath Nodes("scripts/nodes"); const static inline impl::DataPath Layouts("layouts"); const static inline impl::DataPath Workspaces("workspaces"); + const static inline impl::DataPath Disassemblers("disassemblers"); - constexpr static inline std::array All = { + constexpr static inline std::array All = { &Config, &Recent, @@ -106,6 +107,7 @@ namespace hex::paths { &Nodes, &Layouts, &Workspaces, + &Disassemblers }; } \ No newline at end of file diff --git a/main/gui/source/crash_handlers.cpp b/main/gui/source/crash_handlers.cpp index 600f07d65..ba1db844b 100644 --- a/main/gui/source/crash_handlers.cpp +++ b/main/gui/source/crash_handlers.cpp @@ -151,7 +151,7 @@ namespace hex::crash { try { std::rethrow_exception(std::current_exception()); } catch (std::exception &ex) { - std::string exceptionStr = hex::format("{}()::what() -> {}", llvm::itaniumDemangle(typeid(ex).name()), ex.what()); + std::string exceptionStr = hex::format("{}()::what() -> {}", llvm::demangle(typeid(ex).name()), ex.what()); handleCrash(exceptionStr); log::fatal("Program terminated with uncaught exception: {}", exceptionStr); diff --git a/plugins/builtin/source/content/views/view_about.cpp b/plugins/builtin/source/content/views/view_about.cpp index ee43711b5..31ea88189 100644 --- a/plugins/builtin/source/content/views/view_about.cpp +++ b/plugins/builtin/source/content/views/view_about.cpp @@ -476,6 +476,7 @@ namespace hex::plugin::builtin { { "Custom data processor nodes", &paths::Nodes }, { "Layouts", &paths::Layouts }, { "Workspaces", &paths::Workspaces }, + { "Disassemblers", &paths::Disassemblers }, } }; static_assert(PathTypes.back().first != nullptr, "All path items need to be populated!"); diff --git a/plugins/disassembler/CMakeLists.txt b/plugins/disassembler/CMakeLists.txt index dcef2c154..13f7c1701 100644 --- a/plugins/disassembler/CMakeLists.txt +++ b/plugins/disassembler/CMakeLists.txt @@ -27,6 +27,7 @@ add_imhex_plugin( source/content/pl_builtin_types.cpp source/content/disassemblers/capstone_architectures.cpp + source/content/disassemblers/custom_architectures.cpp INCLUDES include ${CAPSTONE_INCLUDE_DIR} @@ -34,4 +35,5 @@ add_imhex_plugin( ui fonts ${CAPSTONE_LIBRARY} + libdisassembler ) diff --git a/plugins/disassembler/include/content/helpers/disassembler.hpp b/plugins/disassembler/include/content/helpers/disassembler.hpp index c5b9fa813..c0ee288f1 100644 --- a/plugins/disassembler/include/content/helpers/disassembler.hpp +++ b/plugins/disassembler/include/content/helpers/disassembler.hpp @@ -30,7 +30,7 @@ namespace hex::plugin::disasm { RISCV = CS_ARCH_RISCV, MOS65XX = CS_ARCH_MOS65XX, BPF = CS_ARCH_BPF, - SH = CS_ARCH_SH, + SUPERH = CS_ARCH_SH, TRICORE = CS_ARCH_TRICORE, MAX = TRICORE, # else @@ -163,7 +163,7 @@ namespace hex::plugin::disasm { arch = CS_ARCH_MOS65XX; else if (equalsIgnoreCase(archName, "bpf")) arch = CS_ARCH_BPF; - else if (equalsIgnoreCase(archName, "sh")) + else if (equalsIgnoreCase(archName, "sh") || equalsIgnoreCase(archName, "superh")) arch = CS_ARCH_SH; else if (equalsIgnoreCase(archName, "tricore")) arch = CS_ARCH_TRICORE; diff --git a/plugins/disassembler/source/content/disassemblers/capstone_architectures.cpp b/plugins/disassembler/source/content/disassemblers/capstone_architectures.cpp index 7b8023466..bd0e395e1 100644 --- a/plugins/disassembler/source/content/disassemblers/capstone_architectures.cpp +++ b/plugins/disassembler/source/content/disassemblers/capstone_architectures.cpp @@ -9,11 +9,15 @@ namespace hex::plugin::disasm { class CapstoneArchitecture : public ContentRegistry::Disassembler::Architecture { public: - explicit CapstoneArchitecture(BuiltinArchitecture architecture) + explicit CapstoneArchitecture(BuiltinArchitecture architecture, cs_mode mode = cs_mode(0)) : Architecture(CapstoneDisassembler::ArchitectureNames[u32(architecture)]), - m_architecture(architecture) { } + m_architecture(architecture), + m_mode(mode) { } bool start() override { + if (m_initialized) return false; + + m_instruction = nullptr; auto mode = m_mode; if (m_endian == true) { mode = cs_mode(u32(mode) | CS_MODE_LITTLE_ENDIAN); @@ -27,39 +31,43 @@ namespace hex::plugin::disasm { cs_option(m_handle, CS_OPT_SKIPDATA, CS_OPT_ON); + m_instruction = cs_malloc(m_handle); + + m_initialized = true; return true; } void end() override { + cs_free(m_instruction, 1); cs_close(&m_handle); + + m_initialized = false; } void drawSettings() override { ImGui::RadioButton("hex.ui.common.little_endian"_lang, &m_endian, true); ImGui::SameLine(); ImGui::RadioButton("hex.ui.common.big_endian"_lang, &m_endian, false); + ImGui::NewLine(); } std::optional disassemble(u64 imageBaseAddress, u64 instructionLoadAddress, u64 instructionDataAddress, std::span code) override { - auto *instruction = cs_malloc(m_handle); - ON_SCOPE_EXIT { cs_free(instruction, 1); }; - auto ptr = code.data(); auto size = code.size_bytes(); - if (!cs_disasm_iter(m_handle, &ptr, &size, &instructionLoadAddress, instruction)) { + if (!cs_disasm_iter(m_handle, &ptr, &size, &instructionLoadAddress, m_instruction)) { return std::nullopt; } ContentRegistry::Disassembler::Instruction disassembly = { }; - disassembly.address = instruction->address; + disassembly.address = m_instruction->address; disassembly.offset = instructionDataAddress - imageBaseAddress; - disassembly.size = instruction->size; - disassembly.mnemonic = instruction->mnemonic; - disassembly.operators = instruction->op_str; + disassembly.size = m_instruction->size; + disassembly.mnemonic = m_instruction->mnemonic; + disassembly.operators = m_instruction->op_str; - for (u16 j = 0; j < instruction->size; j++) - disassembly.bytes += hex::format("{0:02X} ", instruction->bytes[j]); + for (u16 j = 0; j < m_instruction->size; j++) + disassembly.bytes += hex::format("{0:02X} ", m_instruction->bytes[j]); disassembly.bytes.pop_back(); return disassembly; @@ -68,17 +76,21 @@ namespace hex::plugin::disasm { private: BuiltinArchitecture m_architecture; csh m_handle = 0; + cs_insn *m_instruction = nullptr; protected: cs_mode m_mode = cs_mode(0); int m_endian = false; + bool m_initialized = false; }; class ArchitectureARM : public CapstoneArchitecture { public: - ArchitectureARM() : CapstoneArchitecture(BuiltinArchitecture::ARM) {} + ArchitectureARM(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::ARM, mode) {} void drawSettings() override { + CapstoneArchitecture::drawSettings(); + ImGui::RadioButton("hex.disassembler.view.disassembler.arm.arm"_lang, &m_armMode, CS_MODE_ARM); ImGui::SameLine(); ImGui::RadioButton("hex.disassembler.view.disassembler.arm.thumb"_lang, &m_armMode, CS_MODE_THUMB); @@ -98,16 +110,18 @@ namespace hex::plugin::disasm { class ArchitectureARM64 : public CapstoneArchitecture { public: - ArchitectureARM64() : CapstoneArchitecture(BuiltinArchitecture::ARM64) {} + ArchitectureARM64(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::ARM64, mode) {} void drawSettings() override { } }; class ArchitectureMIPS : public CapstoneArchitecture { public: - ArchitectureMIPS() : CapstoneArchitecture(BuiltinArchitecture::MIPS) {} + ArchitectureMIPS(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::MIPS, mode) {} void drawSettings() override { + CapstoneArchitecture::drawSettings(); + ImGui::RadioButton("hex.disassembler.view.disassembler.mips.mips32"_lang, &m_mipsMode, CS_MODE_MIPS32); ImGui::SameLine(); ImGui::RadioButton("hex.disassembler.view.disassembler.mips.mips64"_lang, &m_mipsMode, CS_MODE_MIPS64); @@ -130,9 +144,11 @@ namespace hex::plugin::disasm { class ArchitectureX86 : public CapstoneArchitecture { public: - ArchitectureX86() : CapstoneArchitecture(BuiltinArchitecture::X86) {} + ArchitectureX86(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::X86, mode) {} void drawSettings() override { + CapstoneArchitecture::drawSettings(); + ImGui::RadioButton("hex.disassembler.view.disassembler.16bit"_lang, &m_x86Mode, CS_MODE_16); ImGui::SameLine(); ImGui::RadioButton("hex.disassembler.view.disassembler.32bit"_lang, &m_x86Mode, CS_MODE_32); @@ -148,9 +164,11 @@ namespace hex::plugin::disasm { class ArchitecturePowerPC : public CapstoneArchitecture { public: - ArchitecturePowerPC() : CapstoneArchitecture(BuiltinArchitecture::PPC) {} + ArchitecturePowerPC(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::PPC, mode) {} void drawSettings() override { + CapstoneArchitecture::drawSettings(); + ImGui::RadioButton("hex.disassembler.view.disassembler.32bit"_lang, &m_ppcMode, CS_MODE_32); ImGui::SameLine(); ImGui::RadioButton("hex.disassembler.view.disassembler.64bit"_lang, &m_ppcMode, CS_MODE_64); @@ -176,9 +194,11 @@ namespace hex::plugin::disasm { class ArchitectureSPARC : public CapstoneArchitecture { public: - ArchitectureSPARC() : CapstoneArchitecture(BuiltinArchitecture::SPARC) {} + ArchitectureSPARC(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::SPARC, mode) {} void drawSettings() override { + CapstoneArchitecture::drawSettings(); + ImGui::Checkbox("hex.disassembler.view.disassembler.sparc.v9"_lang, &m_v9Mode); m_mode = cs_mode(m_v9Mode ? CS_MODE_V9 : cs_mode(0)); @@ -190,23 +210,29 @@ namespace hex::plugin::disasm { class ArchitectureSystemZ : public CapstoneArchitecture { public: - ArchitectureSystemZ() : CapstoneArchitecture(BuiltinArchitecture::SYSZ) {} + ArchitectureSystemZ(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::SYSZ, mode) {} - void drawSettings() override { } + void drawSettings() override { + CapstoneArchitecture::drawSettings(); + } }; class ArchitectureXCore : public CapstoneArchitecture { public: - ArchitectureXCore() : CapstoneArchitecture(BuiltinArchitecture::XCORE) {} + ArchitectureXCore(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::XCORE, mode) {} - void drawSettings() override { } + void drawSettings() override { + CapstoneArchitecture::drawSettings(); + } }; class ArchitectureM68K : public CapstoneArchitecture { public: - ArchitectureM68K() : CapstoneArchitecture(BuiltinArchitecture::M68K) {} + ArchitectureM68K(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::M68K, mode) {} void drawSettings() override { + CapstoneArchitecture::drawSettings(); + std::pair modes[] = { {"hex.disassembler.view.disassembler.m68k.000"_lang, CS_MODE_M68K_000}, { "hex.disassembler.view.disassembler.m68k.010"_lang, CS_MODE_M68K_010}, @@ -233,15 +259,19 @@ namespace hex::plugin::disasm { class ArchitectureTMS320C64X : public CapstoneArchitecture { public: - ArchitectureTMS320C64X() : CapstoneArchitecture(BuiltinArchitecture::TMS320C64X) {} + ArchitectureTMS320C64X(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::TMS320C64X, mode) {} - void drawSettings() override { } + void drawSettings() override { + CapstoneArchitecture::drawSettings(); + } }; class ArchitectureM680X : public CapstoneArchitecture { public: - ArchitectureM680X() : CapstoneArchitecture(BuiltinArchitecture::M680X) {} + ArchitectureM680X(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::M680X, mode) {} void drawSettings() override { + CapstoneArchitecture::drawSettings(); + std::pair modes[] = { {"hex.disassembler.view.disassembler.m680x.6301"_lang, CS_MODE_M680X_6301 }, { "hex.disassembler.view.disassembler.m680x.6309"_lang, CS_MODE_M680X_6309 }, @@ -272,25 +302,31 @@ namespace hex::plugin::disasm { class ArchitectureEVM : public CapstoneArchitecture { public: - ArchitectureEVM() : CapstoneArchitecture(BuiltinArchitecture::EVM) {} + ArchitectureEVM(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::EVM, mode) {} - void drawSettings() override { } + void drawSettings() override { + CapstoneArchitecture::drawSettings(); + } }; #if CS_API_MAJOR >= 5 class ArchitectureWASM : public CapstoneArchitecture { public: - ArchitectureWASM() : CapstoneArchitecture(BuiltinArchitecture::WASM) {} + ArchitectureWASM(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::WASM, mode) {} - void drawSettings() override { } + void drawSettings() override { + CapstoneArchitecture::drawSettings(); + } }; class ArchitectureRISCV : public CapstoneArchitecture { public: - ArchitectureRISCV() : CapstoneArchitecture(BuiltinArchitecture::RISCV) {} + ArchitectureRISCV(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::RISCV, mode) {} void drawSettings() override { + CapstoneArchitecture::drawSettings(); + ImGui::RadioButton("hex.disassembler.view.disassembler.32bit"_lang, &m_riscvMode, CS_MODE_RISCV32); ImGui::SameLine(); ImGui::RadioButton("hex.disassembler.view.disassembler.64bit"_lang, &m_riscvMode, CS_MODE_RISCV64); @@ -307,9 +343,11 @@ namespace hex::plugin::disasm { class ArchitectureMOS65XX : public CapstoneArchitecture { public: - ArchitectureMOS65XX() : CapstoneArchitecture(BuiltinArchitecture::MOS65XX) {} + ArchitectureMOS65XX(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::MOS65XX, mode) {} void drawSettings() override { + CapstoneArchitecture::drawSettings(); + std::pair modes[] = { {"hex.disassembler.view.disassembler.mos65xx.6502"_lang, CS_MODE_MOS65XX_6502 }, { "hex.disassembler.view.disassembler.mos65xx.65c02"_lang, CS_MODE_MOS65XX_65C02 }, @@ -337,9 +375,11 @@ namespace hex::plugin::disasm { class ArchitectureBPF : public CapstoneArchitecture { public: - ArchitectureBPF() : CapstoneArchitecture(BuiltinArchitecture::BPF) {} + ArchitectureBPF(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::BPF, mode) {} void drawSettings() override { + CapstoneArchitecture::drawSettings(); + ImGui::RadioButton("hex.disassembler.view.disassembler.bpf.classic"_lang, &m_bpfMode, CS_MODE_BPF_CLASSIC); ImGui::SameLine(); ImGui::RadioButton("hex.disassembler.view.disassembler.bpf.extended"_lang, &m_bpfMode, CS_MODE_BPF_EXTENDED); @@ -353,9 +393,11 @@ namespace hex::plugin::disasm { class ArchitectureSuperH : public CapstoneArchitecture { public: - ArchitectureSuperH() : CapstoneArchitecture(BuiltinArchitecture::SH) {} + ArchitectureSuperH(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::SUPERH, mode) {} void drawSettings() override { + CapstoneArchitecture::drawSettings(); + std::pair modes[] = { { "hex.disassembler.view.disassembler.sh.sh2"_lang, CS_MODE_SH2 }, { "hex.disassembler.view.disassembler.sh.sh2a"_lang, CS_MODE_SH2A }, @@ -387,9 +429,11 @@ namespace hex::plugin::disasm { class ArchitectureTricore : public CapstoneArchitecture { public: - ArchitectureTricore() : CapstoneArchitecture(BuiltinArchitecture::TRICORE) {} + ArchitectureTricore(cs_mode mode = cs_mode(0)) : CapstoneArchitecture(BuiltinArchitecture::TRICORE, mode) {} void drawSettings() override { + CapstoneArchitecture::drawSettings(); + std::pair modes[] = { { "hex.disassembler.view.disassembler.tricore.110"_lang, CS_MODE_TRICORE_110 }, { "hex.disassembler.view.disassembler.tricore.120"_lang, CS_MODE_TRICORE_120 }, diff --git a/plugins/disassembler/source/content/disassemblers/custom_architectures.cpp b/plugins/disassembler/source/content/disassemblers/custom_architectures.cpp new file mode 100644 index 000000000..39c7fc498 --- /dev/null +++ b/plugins/disassembler/source/content/disassemblers/custom_architectures.cpp @@ -0,0 +1,72 @@ +#include +#include + +#include +#include +#include +#include + +namespace hex::plugin::disasm { + + class CustomArchitecture : public ContentRegistry::Disassembler::Architecture { + public: + CustomArchitecture(::disasm::spec::Spec spec) : Architecture(spec.getName()), m_spec(std::move(spec)) {} + + bool start() override { + return true; + } + + void end() override { + + } + + void drawSettings() override { + + } + + std::optional disassemble(u64 imageBaseAddress, u64 instructionLoadAddress, u64 instructionDataAddress, std::span code) override { + std::ignore = imageBaseAddress; + std::ignore = instructionDataAddress; + std::ignore = instructionLoadAddress; + std::ignore = code; + + auto instructions = m_spec.disassemble(code, 1); + if (instructions.empty()) { + return std::nullopt; + } + + const auto &instruction = instructions.front(); + + ContentRegistry::Disassembler::Instruction disassembly = { }; + disassembly.address = instructionDataAddress; + disassembly.offset = instructionDataAddress - imageBaseAddress; + disassembly.size = instruction.bytes.size(); + disassembly.mnemonic = instruction.mnemonic; + disassembly.operators = instruction.operands; + + for (u8 byte : instruction.bytes) + disassembly.bytes += hex::format("{0:02X} ", byte); + disassembly.bytes.pop_back(); + + return disassembly; + } + + private: + ::disasm::spec::Spec m_spec; + }; + + void registerCustomArchitectures() { + for (const auto &folder : hex::paths::Disassemblers.all()) { + for (const auto &entry : std::fs::directory_iterator(folder)) { + try { + auto spec = ::disasm::spec::Loader::load(entry.path(), { entry.path().parent_path() }); + + ContentRegistry::Disassembler::add(std::move(spec)); + } catch (const std::exception &e) { + log::error("Failed to load disassembler config '{}': {}", wolv::util::toUTF8String(entry.path()), e.what()); + } + } + } + } + +} diff --git a/plugins/disassembler/source/plugin_disassembler.cpp b/plugins/disassembler/source/plugin_disassembler.cpp index 27e1e9ac5..271c8ba88 100644 --- a/plugins/disassembler/source/plugin_disassembler.cpp +++ b/plugins/disassembler/source/plugin_disassembler.cpp @@ -18,6 +18,7 @@ namespace hex::plugin::disasm { void registerPatternLanguageTypes(); void registerCapstoneArchitectures(); + void registerCustomArchitectures(); } @@ -46,4 +47,5 @@ IMHEX_PLUGIN_SETUP("Disassembler", "WerWolv", "Disassembler support") { registerPatternLanguageTypes(); registerCapstoneArchitectures(); + registerCustomArchitectures(); }