diff --git a/lib/libimhex/include/hex/api/content_registry.hpp b/lib/libimhex/include/hex/api/content_registry.hpp index 9323c93e5..372d65794 100644 --- a/lib/libimhex/include/hex/api/content_registry.hpp +++ b/lib/libimhex/include/hex/api/content_registry.hpp @@ -43,7 +43,6 @@ namespace hex { plugins when needed. */ namespace ContentRegistry { - /* Settings Registry. Allows adding of new entries into the ImHex preferences window. */ namespace Settings { @@ -1354,6 +1353,7 @@ namespace hex { } + /* Data Information Registry. Allows adding new analyzers to the data information view */ namespace DataInformation { class InformationSection { @@ -1420,6 +1420,54 @@ namespace hex { } + /* Disassembler Registry. Allows adding new disassembler architectures */ + namespace Disassembler { + + struct Instruction { + u64 address; + u64 offset; + size_t size; + std::string bytes; + std::string mnemonic; + std::string operators; + }; + + class Architecture { + public: + explicit Architecture(std::string name) : m_name(std::move(name)) {} + virtual ~Architecture() = default; + + virtual bool start() = 0; + virtual void end() = 0; + + virtual std::optional disassemble(u64 imageBaseAddress, u64 instructionLoadAddress, u64 instructionDataAddress, std::span code) = 0; + virtual void drawSettings() = 0; + + [[nodiscard]] const std::string& getName() const { return m_name; } + + private: + std::string m_name; + }; + + namespace impl { + + using CreatorFunction = std::function()>; + + void addArchitectureCreator(CreatorFunction function); + + const std::map& getArchitectures(); + + } + + template T> + void add(auto && ...args) { + impl::addArchitectureCreator([args...] { + return std::make_unique(std::forward(args)...); + }); + } + + } + } } diff --git a/lib/libimhex/source/api/content_registry.cpp b/lib/libimhex/source/api/content_registry.cpp index 078b38947..70c8d5877 100644 --- a/lib/libimhex/source/api/content_registry.cpp +++ b/lib/libimhex/source/api/content_registry.cpp @@ -1391,4 +1391,23 @@ namespace hex { } + namespace ContentRegistry::Disassembler { + + namespace impl { + + static AutoReset> s_architectures; + + void addArchitectureCreator(impl::CreatorFunction function) { + const auto arch = function(); + (*s_architectures)[arch->getName()] = std::move(function); + } + + const std::map& getArchitectures() { + return *s_architectures; + } + + } + + } + } diff --git a/plugins/builtin/include/content/popups/popup_crash_recovered.hpp b/plugins/builtin/include/content/popups/popup_crash_recovered.hpp index 962f57a06..f3446c957 100644 --- a/plugins/builtin/include/content/popups/popup_crash_recovered.hpp +++ b/plugins/builtin/include/content/popups/popup_crash_recovered.hpp @@ -20,7 +20,7 @@ namespace hex::plugin::builtin { void drawContent() override { ImGuiExt::TextFormattedWrapped("hex.builtin.popup.crash_recover.message"_lang); - ImGuiExt::TextFormattedWrapped(hex::format("Error: {}: {}", llvm::itaniumDemangle(this->m_errorType), this->m_errorMessage)); + ImGuiExt::TextFormattedWrapped(hex::format("Error: {}: {}", llvm::demangle(this->m_errorType), this->m_errorMessage)); if (ImGui::Button("hex.ui.common.okay"_lang)) { this->close(); diff --git a/plugins/disassembler/CMakeLists.txt b/plugins/disassembler/CMakeLists.txt index 8888027c8..dcef2c154 100644 --- a/plugins/disassembler/CMakeLists.txt +++ b/plugins/disassembler/CMakeLists.txt @@ -25,6 +25,8 @@ add_imhex_plugin( source/content/pl_visualizers/disassembler.cpp source/content/pl_builtin_types.cpp + + source/content/disassemblers/capstone_architectures.cpp INCLUDES include ${CAPSTONE_INCLUDE_DIR} diff --git a/plugins/disassembler/include/content/helpers/disassembler.hpp b/plugins/disassembler/include/content/helpers/disassembler.hpp index bfe27372e..c5b9fa813 100644 --- a/plugins/disassembler/include/content/helpers/disassembler.hpp +++ b/plugins/disassembler/include/content/helpers/disassembler.hpp @@ -6,10 +6,11 @@ #include #include +#include namespace hex::plugin::disasm { - enum class Architecture : i32 + enum class BuiltinArchitecture : i32 { ARM = CS_ARCH_ARM, ARM64 = CS_ARCH_ARM64, @@ -39,18 +40,18 @@ namespace hex::plugin::disasm { MIN = ARM }; - class Disassembler { + class CapstoneDisassembler { public: - constexpr static cs_arch toCapstoneArchitecture(Architecture architecture) { + constexpr static cs_arch toCapstoneArchitecture(BuiltinArchitecture architecture) { return static_cast(architecture); } - static bool isSupported(Architecture architecture) { + static bool isSupported(BuiltinArchitecture architecture) { return cs_support(toCapstoneArchitecture(architecture)); } constexpr static auto ArchitectureNames = []{ - std::array(Architecture::MAX) + 1> names = { }; + std::array(BuiltinArchitecture::MAX) + 1> names = { }; names[CS_ARCH_ARM] = "ARM"; names[CS_ARCH_ARM64] = "AArch64"; @@ -84,7 +85,7 @@ namespace hex::plugin::disasm { return supportedCount; } - for (supportedCount = static_cast(Architecture::MIN); supportedCount < static_cast(Architecture::MAX) + 1; supportedCount++) { + for (supportedCount = static_cast(BuiltinArchitecture::MIN); supportedCount < static_cast(BuiltinArchitecture::MAX) + 1; supportedCount++) { if (!cs_support(supportedCount)) { break; } diff --git a/plugins/disassembler/include/content/views/view_disassembler.hpp b/plugins/disassembler/include/content/views/view_disassembler.hpp index 5fce2d71c..25bada587 100644 --- a/plugins/disassembler/include/content/views/view_disassembler.hpp +++ b/plugins/disassembler/include/content/views/view_disassembler.hpp @@ -9,18 +9,10 @@ #include #include +#include namespace hex::plugin::disasm { - struct Disassembly { - u64 address; - u64 offset; - size_t size; - std::string bytes; - std::string mnemonic; - std::string operators; - }; - class ViewDisassembler : public View::Window { public: explicit ViewDisassembler(); @@ -36,13 +28,12 @@ namespace hex::plugin::disasm { ui::RegionType m_range = ui::RegionType::EntireData; Region m_regionToDisassemble = { }; - Architecture m_architecture = Architecture::ARM; - cs_mode m_mode = cs_mode(0); + std::unique_ptr m_currArchitecture = nullptr; - std::vector m_disassembly; + std::vector m_disassembly; void disassemble(); void exportToFile(); }; -} \ No newline at end of file +} diff --git a/plugins/disassembler/source/content/disassemblers/capstone_architectures.cpp b/plugins/disassembler/source/content/disassemblers/capstone_architectures.cpp new file mode 100644 index 000000000..7b8023466 --- /dev/null +++ b/plugins/disassembler/source/content/disassemblers/capstone_architectures.cpp @@ -0,0 +1,444 @@ +#include + +#include +#include + +#include + +namespace hex::plugin::disasm { + + class CapstoneArchitecture : public ContentRegistry::Disassembler::Architecture { + public: + explicit CapstoneArchitecture(BuiltinArchitecture architecture) + : Architecture(CapstoneDisassembler::ArchitectureNames[u32(architecture)]), + m_architecture(architecture) { } + + bool start() override { + auto mode = m_mode; + if (m_endian == true) { + mode = cs_mode(u32(mode) | CS_MODE_LITTLE_ENDIAN); + } else { + mode = cs_mode(u32(mode) | CS_MODE_BIG_ENDIAN); + } + + if (cs_open(CapstoneDisassembler::toCapstoneArchitecture(m_architecture), mode, &m_handle) != CS_ERR_OK) { + return false; + } + + cs_option(m_handle, CS_OPT_SKIPDATA, CS_OPT_ON); + + return true; + } + + void end() override { + cs_close(&m_handle); + } + + 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); + } + + 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)) { + return std::nullopt; + } + + ContentRegistry::Disassembler::Instruction disassembly = { }; + disassembly.address = instruction->address; + disassembly.offset = instructionDataAddress - imageBaseAddress; + disassembly.size = instruction->size; + disassembly.mnemonic = instruction->mnemonic; + disassembly.operators = instruction->op_str; + + for (u16 j = 0; j < instruction->size; j++) + disassembly.bytes += hex::format("{0:02X} ", instruction->bytes[j]); + disassembly.bytes.pop_back(); + + return disassembly; + } + + private: + BuiltinArchitecture m_architecture; + csh m_handle = 0; + + protected: + cs_mode m_mode = cs_mode(0); + int m_endian = false; + }; + + class ArchitectureARM : public CapstoneArchitecture { + public: + ArchitectureARM() : CapstoneArchitecture(BuiltinArchitecture::ARM) {} + + void drawSettings() override { + 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); + + ImGui::RadioButton("hex.disassembler.view.disassembler.arm.default"_lang, &m_extraMode, 0); + ImGui::SameLine(); + ImGui::RadioButton("hex.disassembler.view.disassembler.arm.cortex_m"_lang, &m_extraMode, CS_MODE_MCLASS); + ImGui::SameLine(); + ImGui::RadioButton("hex.disassembler.view.disassembler.arm.armv8"_lang, &m_extraMode, CS_MODE_V8); + + m_mode = cs_mode(m_armMode | m_extraMode); + } + + private: + int m_armMode = CS_MODE_ARM, m_extraMode = 0; + }; + + class ArchitectureARM64 : public CapstoneArchitecture { + public: + ArchitectureARM64() : CapstoneArchitecture(BuiltinArchitecture::ARM64) {} + + void drawSettings() override { } + }; + + class ArchitectureMIPS : public CapstoneArchitecture { + public: + ArchitectureMIPS() : CapstoneArchitecture(BuiltinArchitecture::MIPS) {} + + void drawSettings() override { + 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); + ImGui::SameLine(); + ImGui::RadioButton("hex.disassembler.view.disassembler.mips.mips32R6"_lang, &m_mipsMode, CS_MODE_MIPS32R6); + + ImGui::RadioButton("hex.disassembler.view.disassembler.mips.mips2"_lang, &m_mipsMode, CS_MODE_MIPS2); + ImGui::SameLine(); + ImGui::RadioButton("hex.disassembler.view.disassembler.mips.mips3"_lang, &m_mipsMode, CS_MODE_MIPS3); + + ImGui::Checkbox("hex.disassembler.view.disassembler.mips.micro"_lang, &m_microMode); + + m_mode = cs_mode(m_mipsMode | (m_microMode ? CS_MODE_MICRO : cs_mode(0))); + } + + private: + int m_mipsMode = CS_MODE_MIPS32; + bool m_microMode = false; + }; + + class ArchitectureX86 : public CapstoneArchitecture { + public: + ArchitectureX86() : CapstoneArchitecture(BuiltinArchitecture::X86) {} + + void drawSettings() override { + 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); + ImGui::SameLine(); + ImGui::RadioButton("hex.disassembler.view.disassembler.64bit"_lang, &m_x86Mode, CS_MODE_64); + + m_mode = cs_mode(m_x86Mode); + } + + private: + int m_x86Mode = CS_MODE_32; + }; + + class ArchitecturePowerPC : public CapstoneArchitecture { + public: + ArchitecturePowerPC() : CapstoneArchitecture(BuiltinArchitecture::PPC) {} + + void drawSettings() override { + 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); + + ImGui::Checkbox("hex.disassembler.view.disassembler.ppc.qpx"_lang, &m_qpx); + + #if CS_API_MAJOR >= 5 + ImGui::Checkbox("hex.disassembler.view.disassembler.ppc.spe"_lang, &m_spe); + ImGui::Checkbox("hex.disassembler.view.disassembler.ppc.booke"_lang, &m_booke); + + m_mode = cs_mode(m_ppcMode | (m_qpx ? CS_MODE_QPX : cs_mode(0)) | (m_spe ? CS_MODE_SPE : cs_mode(0)) | (m_booke ? CS_MODE_BOOKE : cs_mode(0))); + #else + m_mode = cs_mode(mode | (qpx ? CS_MODE_QPX : cs_mode(0))); + #endif + } + + private: + int m_ppcMode = CS_MODE_32; + bool m_qpx = false; + bool m_spe = false; + bool m_booke = false; + }; + + class ArchitectureSPARC : public CapstoneArchitecture { + public: + ArchitectureSPARC() : CapstoneArchitecture(BuiltinArchitecture::SPARC) {} + + void drawSettings() override { + ImGui::Checkbox("hex.disassembler.view.disassembler.sparc.v9"_lang, &m_v9Mode); + + m_mode = cs_mode(m_v9Mode ? CS_MODE_V9 : cs_mode(0)); + } + + private: + bool m_v9Mode = false; + }; + + class ArchitectureSystemZ : public CapstoneArchitecture { + public: + ArchitectureSystemZ() : CapstoneArchitecture(BuiltinArchitecture::SYSZ) {} + + void drawSettings() override { } + }; + + class ArchitectureXCore : public CapstoneArchitecture { + public: + ArchitectureXCore() : CapstoneArchitecture(BuiltinArchitecture::XCORE) {} + + void drawSettings() override { } + }; + + class ArchitectureM68K : public CapstoneArchitecture { + public: + ArchitectureM68K() : CapstoneArchitecture(BuiltinArchitecture::M68K) {} + + void drawSettings() override { + 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}, + { "hex.disassembler.view.disassembler.m68k.020"_lang, CS_MODE_M68K_020}, + { "hex.disassembler.view.disassembler.m68k.030"_lang, CS_MODE_M68K_030}, + { "hex.disassembler.view.disassembler.m68k.040"_lang, CS_MODE_M68K_040}, + { "hex.disassembler.view.disassembler.m68k.060"_lang, CS_MODE_M68K_060}, + }; + + if (ImGui::BeginCombo("hex.disassembler.view.disassembler.settings.mode"_lang, modes[m_selectedMode].first)) { + for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) { + if (ImGui::Selectable(modes[i].first)) + m_selectedMode = i; + } + ImGui::EndCombo(); + } + + m_mode = cs_mode(modes[m_selectedMode].second); + } + + private: + int m_selectedMode = 0; + }; + + class ArchitectureTMS320C64X : public CapstoneArchitecture { + public: + ArchitectureTMS320C64X() : CapstoneArchitecture(BuiltinArchitecture::TMS320C64X) {} + + void drawSettings() override { } + }; + class ArchitectureM680X : public CapstoneArchitecture { + public: + ArchitectureM680X() : CapstoneArchitecture(BuiltinArchitecture::M680X) {} + + void drawSettings() override { + 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 }, + { "hex.disassembler.view.disassembler.m680x.6800"_lang, CS_MODE_M680X_6800 }, + { "hex.disassembler.view.disassembler.m680x.6801"_lang, CS_MODE_M680X_6801 }, + { "hex.disassembler.view.disassembler.m680x.6805"_lang, CS_MODE_M680X_6805 }, + { "hex.disassembler.view.disassembler.m680x.6808"_lang, CS_MODE_M680X_6808 }, + { "hex.disassembler.view.disassembler.m680x.6809"_lang, CS_MODE_M680X_6809 }, + { "hex.disassembler.view.disassembler.m680x.6811"_lang, CS_MODE_M680X_6811 }, + { "hex.disassembler.view.disassembler.m680x.cpu12"_lang, CS_MODE_M680X_CPU12}, + { "hex.disassembler.view.disassembler.m680x.hcs08"_lang, CS_MODE_M680X_HCS08}, + }; + + if (ImGui::BeginCombo("hex.disassembler.view.disassembler.settings.mode"_lang, modes[m_selectedMode].first)) { + for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) { + if (ImGui::Selectable(modes[i].first)) + m_selectedMode = i; + } + ImGui::EndCombo(); + } + + m_mode = cs_mode(modes[m_selectedMode].second); + } + + private: + int m_selectedMode = 0; + }; + + class ArchitectureEVM : public CapstoneArchitecture { + public: + ArchitectureEVM() : CapstoneArchitecture(BuiltinArchitecture::EVM) {} + + void drawSettings() override { } + }; + +#if CS_API_MAJOR >= 5 + + class ArchitectureWASM : public CapstoneArchitecture { + public: + ArchitectureWASM() : CapstoneArchitecture(BuiltinArchitecture::WASM) {} + + void drawSettings() override { } + }; + + class ArchitectureRISCV : public CapstoneArchitecture { + public: + ArchitectureRISCV() : CapstoneArchitecture(BuiltinArchitecture::RISCV) {} + + void drawSettings() override { + 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); + + ImGui::Checkbox("hex.disassembler.view.disassembler.riscv.compressed"_lang, &m_compressed); + + m_mode = cs_mode(m_riscvMode | (m_compressed ? CS_MODE_RISCVC : cs_mode(0))); + } + + private: + int m_riscvMode = CS_MODE_RISCV32; + bool m_compressed = false; + }; + + class ArchitectureMOS65XX : public CapstoneArchitecture { + public: + ArchitectureMOS65XX() : CapstoneArchitecture(BuiltinArchitecture::MOS65XX) {} + + void drawSettings() override { + 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 }, + { "hex.disassembler.view.disassembler.mos65xx.w65c02"_lang, CS_MODE_MOS65XX_W65C02 }, + { "hex.disassembler.view.disassembler.mos65xx.65816"_lang, CS_MODE_MOS65XX_65816 }, + { "hex.disassembler.view.disassembler.mos65xx.65816_long_m"_lang, CS_MODE_MOS65XX_65816_LONG_M }, + { "hex.disassembler.view.disassembler.mos65xx.65816_long_x"_lang, CS_MODE_MOS65XX_65816_LONG_X }, + { "hex.disassembler.view.disassembler.mos65xx.65816_long_mx"_lang, CS_MODE_MOS65XX_65816_LONG_MX}, + }; + + if (ImGui::BeginCombo("hex.disassembler.view.disassembler.settings.mode"_lang, modes[m_selectedMode].first)) { + for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) { + if (ImGui::Selectable(modes[i].first)) + m_selectedMode = i; + } + ImGui::EndCombo(); + } + + m_mode = cs_mode(modes[m_selectedMode].second); + } + + private: + int m_selectedMode = 0; + }; + + class ArchitectureBPF : public CapstoneArchitecture { + public: + ArchitectureBPF() : CapstoneArchitecture(BuiltinArchitecture::BPF) {} + + void drawSettings() override { + 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); + + m_mode = cs_mode(m_bpfMode); + } + + private: + int m_bpfMode = CS_MODE_BPF_CLASSIC; + }; + + class ArchitectureSuperH : public CapstoneArchitecture { + public: + ArchitectureSuperH() : CapstoneArchitecture(BuiltinArchitecture::SH) {} + + void drawSettings() override { + std::pair modes[] = { + { "hex.disassembler.view.disassembler.sh.sh2"_lang, CS_MODE_SH2 }, + { "hex.disassembler.view.disassembler.sh.sh2a"_lang, CS_MODE_SH2A }, + { "hex.disassembler.view.disassembler.sh.sh3"_lang, CS_MODE_SH3 }, + { "hex.disassembler.view.disassembler.sh.sh4"_lang, CS_MODE_SH4 }, + { "hex.disassembler.view.disassembler.sh.sh4a"_lang, CS_MODE_SH4A }, + }; + + if (ImGui::BeginCombo("hex.disassembler.view.disassembler.settings.mode"_lang, modes[m_selectedMode].first)) { + for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) { + if (ImGui::Selectable(modes[i].first)) + m_selectedMode = i; + } + ImGui::EndCombo(); + } + + ImGui::Checkbox("hex.disassembler.view.disassembler.sh.fpu"_lang, &m_fpu); + ImGui::SameLine(); + ImGui::Checkbox("hex.disassembler.view.disassembler.sh.dsp"_lang, &m_dsp); + + m_mode = cs_mode(modes[m_selectedMode].second | (m_fpu ? CS_MODE_SHFPU : cs_mode(0)) | (m_dsp ? CS_MODE_SHDSP : cs_mode(0))); + } + + private: + int m_selectedMode = 0; + bool m_fpu = false; + bool m_dsp = false; + }; + + class ArchitectureTricore : public CapstoneArchitecture { + public: + ArchitectureTricore() : CapstoneArchitecture(BuiltinArchitecture::TRICORE) {} + + void drawSettings() override { + 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 }, + { "hex.disassembler.view.disassembler.tricore.130"_lang, CS_MODE_TRICORE_130 }, + { "hex.disassembler.view.disassembler.tricore.131"_lang, CS_MODE_TRICORE_131 }, + { "hex.disassembler.view.disassembler.tricore.160"_lang, CS_MODE_TRICORE_160 }, + { "hex.disassembler.view.disassembler.tricore.161"_lang, CS_MODE_TRICORE_161 }, + { "hex.disassembler.view.disassembler.tricore.162"_lang, CS_MODE_TRICORE_162 }, + }; + + if (ImGui::BeginCombo("hex.disassembler.view.disassembler.settings.mode"_lang, modes[m_selectedMode].first)) { + for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) { + if (ImGui::Selectable(modes[i].first)) + m_selectedMode = i; + } + ImGui::EndCombo(); + } + + m_mode = cs_mode(modes[m_selectedMode].second); + } + + private: + int m_selectedMode = 0; + }; + +#endif + + void registerCapstoneArchitectures() { + ContentRegistry::Disassembler::add(); + ContentRegistry::Disassembler::add(); + ContentRegistry::Disassembler::add(); + ContentRegistry::Disassembler::add(); + ContentRegistry::Disassembler::add(); + ContentRegistry::Disassembler::add(); + ContentRegistry::Disassembler::add(); + ContentRegistry::Disassembler::add(); + ContentRegistry::Disassembler::add(); + ContentRegistry::Disassembler::add(); + ContentRegistry::Disassembler::add(); + ContentRegistry::Disassembler::add(); + + #if CS_API_MAJOR >= 5 + ContentRegistry::Disassembler::add(); + ContentRegistry::Disassembler::add(); + ContentRegistry::Disassembler::add(); + ContentRegistry::Disassembler::add(); + ContentRegistry::Disassembler::add(); + ContentRegistry::Disassembler::add(); + #endif + } + +} diff --git a/plugins/disassembler/source/content/pl_builtin_types.cpp b/plugins/disassembler/source/content/pl_builtin_types.cpp index dbbacdc29..f50614bb1 100644 --- a/plugins/disassembler/source/content/pl_builtin_types.cpp +++ b/plugins/disassembler/source/content/pl_builtin_types.cpp @@ -69,7 +69,7 @@ namespace hex::plugin::disasm { cs_mode mode; try { - std::tie(arch, mode) = Disassembler::stringToSettings(params[0].toString()); + std::tie(arch, mode) = CapstoneDisassembler::stringToSettings(params[0].toString()); } catch (const std::exception &e) { err::E0012.throwError(e.what()); } diff --git a/plugins/disassembler/source/content/pl_visualizers/disassembler.cpp b/plugins/disassembler/source/content/pl_visualizers/disassembler.cpp index 56187b58f..93fa7a93f 100644 --- a/plugins/disassembler/source/content/pl_visualizers/disassembler.cpp +++ b/plugins/disassembler/source/content/pl_visualizers/disassembler.cpp @@ -24,7 +24,7 @@ namespace hex::plugin::disasm { if (shouldReset) { auto pattern = arguments[0].toPattern(); auto baseAddress = arguments[1].toUnsigned(); - const auto [arch, mode] = Disassembler::stringToSettings(arguments[2].toString()); + const auto [arch, mode] = CapstoneDisassembler::stringToSettings(arguments[2].toString()); disassembly.clear(); diff --git a/plugins/disassembler/source/content/views/view_disassembler.cpp b/plugins/disassembler/source/content/views/view_disassembler.cpp index ae81c42ad..e4205ca54 100644 --- a/plugins/disassembler/source/content/views/view_disassembler.cpp +++ b/plugins/disassembler/source/content/views/view_disassembler.cpp @@ -47,19 +47,8 @@ namespace hex::plugin::disasm { return; m_disassemblerTask = TaskManager::createTask("hex.disassembler.view.disassembler.disassembling"_lang, m_regionToDisassemble.getSize(), [this](auto &task) { - csh capstoneHandle; - - cs_mode mode = m_mode; - // Create a capstone disassembler instance - if (cs_open(Disassembler::toCapstoneArchitecture(m_architecture), mode, &capstoneHandle) == CS_ERR_OK) { - auto *instruction = cs_malloc(capstoneHandle); - ON_SCOPE_EXIT { cs_free(instruction, 1); }; - - - // Tell capstone to skip data bytes - cs_option(capstoneHandle, CS_OPT_SKIPDATA, CS_OPT_ON); - + if (m_currArchitecture->start()) { auto provider = ImHexApi::Provider::get(); std::vector buffer(1_MiB, 0x00); @@ -75,34 +64,32 @@ namespace hex::plugin::disasm { size_t bufferSize = std::min(buffer.size(), (m_regionToDisassemble.getEndAddress() - instructionDataAddress)); provider->read(instructionDataAddress, buffer.data(), bufferSize); + auto code = std::span(buffer.data(), bufferSize); + // Ask capstone to disassemble the data - const u8 *code = buffer.data(); - while (cs_disasm_iter(capstoneHandle, &code, &bufferSize, &instructionLoadAddress, instruction)) { + while (true) { + auto instruction = m_currArchitecture->disassemble(m_imageBaseAddress, instructionLoadAddress, instructionDataAddress, code); + if (!instruction.has_value()) + break; + task.update(instructionDataAddress); - // Convert the capstone instructions to our disassembly format - Disassembly disassembly = { }; - disassembly.address = instruction->address; - disassembly.offset = instructionDataAddress - m_imageBaseAddress; - disassembly.size = instruction->size; - disassembly.mnemonic = instruction->mnemonic; - disassembly.operators = instruction->op_str; - - for (u16 j = 0; j < instruction->size; j++) - disassembly.bytes += hex::format("{0:02X} ", instruction->bytes[j]); - disassembly.bytes.pop_back(); - - m_disassembly.push_back(disassembly); + m_disassembly.push_back(instruction.value()); + code = code.subspan(instruction->size); instructionDataAddress += instruction->size; + instructionLoadAddress += instruction->size; hadError = false; + + if (code.empty()) + break; } if (hadError) break; hadError = true; } - cs_close(&capstoneHandle); + m_currArchitecture->end(); } }); } @@ -122,15 +109,15 @@ namespace hex::plugin::disasm { } // As disassembly code can be quite long, we prefer writing each disassembled instruction to file - for (const Disassembly& d : m_disassembly) { + for (const ContentRegistry::Disassembler::Instruction& instruction : m_disassembly) { // We test for a "bugged" case that should never happen - the instruction should always have a mnemonic - if (d.mnemonic.empty()) + if (instruction.mnemonic.empty()) continue; - if (d.operators.empty()) - file.writeString(hex::format("{}\n", d.mnemonic)); + if (instruction.operators.empty()) + file.writeString(hex::format("{}\n", instruction.mnemonic)); else - file.writeString(hex::format("{} {}\n", d.mnemonic, d.operators)); + file.writeString(hex::format("{} {}\n", instruction.mnemonic, instruction.operators)); } }); }); @@ -164,278 +151,29 @@ namespace hex::plugin::disasm { ImGuiExt::Header("hex.ui.common.settings"_lang); // Draw architecture selector - if (ImGui::Combo("hex.disassembler.view.disassembler.arch"_lang, reinterpret_cast(&m_architecture), Disassembler::ArchitectureNames.data(), Disassembler::getArchitectureSupportedCount())) - m_mode = cs_mode(0); - - // Draw sub-settings for each architecture - if (ImGuiExt::BeginBox()) { - - // Draw endian radio buttons. This setting is available for all architectures - static int littleEndian = true; - ImGui::RadioButton("hex.ui.common.little_endian"_lang, &littleEndian, true); - ImGui::SameLine(); - ImGui::RadioButton("hex.ui.common.big_endian"_lang, &littleEndian, false); - - ImGui::NewLine(); - - // Draw architecture specific settings - switch (m_architecture) { - case Architecture::ARM: - { - static int mode = CS_MODE_ARM; - ImGui::RadioButton("hex.disassembler.view.disassembler.arm.arm"_lang, &mode, CS_MODE_ARM); - ImGui::SameLine(); - ImGui::RadioButton("hex.disassembler.view.disassembler.arm.thumb"_lang, &mode, CS_MODE_THUMB); - - static int extraMode = 0; - ImGui::RadioButton("hex.disassembler.view.disassembler.arm.default"_lang, &extraMode, 0); - ImGui::SameLine(); - ImGui::RadioButton("hex.disassembler.view.disassembler.arm.cortex_m"_lang, &extraMode, CS_MODE_MCLASS); - ImGui::SameLine(); - ImGui::RadioButton("hex.disassembler.view.disassembler.arm.armv8"_lang, &extraMode, CS_MODE_V8); - - m_mode = cs_mode(mode | extraMode); - } - break; - case Architecture::MIPS: - { - static int mode = CS_MODE_MIPS32; - ImGui::RadioButton("hex.disassembler.view.disassembler.mips.mips32"_lang, &mode, CS_MODE_MIPS32); - ImGui::SameLine(); - ImGui::RadioButton("hex.disassembler.view.disassembler.mips.mips64"_lang, &mode, CS_MODE_MIPS64); - ImGui::SameLine(); - ImGui::RadioButton("hex.disassembler.view.disassembler.mips.mips32R6"_lang, &mode, CS_MODE_MIPS32R6); - - ImGui::RadioButton("hex.disassembler.view.disassembler.mips.mips2"_lang, &mode, CS_MODE_MIPS2); - ImGui::SameLine(); - ImGui::RadioButton("hex.disassembler.view.disassembler.mips.mips3"_lang, &mode, CS_MODE_MIPS3); - - static bool microMode; - ImGui::Checkbox("hex.disassembler.view.disassembler.mips.micro"_lang, µMode); - - m_mode = cs_mode(mode | (microMode ? CS_MODE_MICRO : cs_mode(0))); - } - break; - case Architecture::X86: - { - static int mode = CS_MODE_32; - ImGui::RadioButton("hex.disassembler.view.disassembler.16bit"_lang, &mode, CS_MODE_16); - ImGui::SameLine(); - ImGui::RadioButton("hex.disassembler.view.disassembler.32bit"_lang, &mode, CS_MODE_32); - ImGui::SameLine(); - ImGui::RadioButton("hex.disassembler.view.disassembler.64bit"_lang, &mode, CS_MODE_64); - - m_mode = cs_mode(mode); - } - break; - case Architecture::PPC: - { - static int mode = CS_MODE_32; - ImGui::RadioButton("hex.disassembler.view.disassembler.32bit"_lang, &mode, CS_MODE_32); - ImGui::SameLine(); - ImGui::RadioButton("hex.disassembler.view.disassembler.64bit"_lang, &mode, CS_MODE_64); - - static bool qpx = false; - ImGui::Checkbox("hex.disassembler.view.disassembler.ppc.qpx"_lang, &qpx); - - #if CS_API_MAJOR >= 5 - static bool spe = false; - ImGui::Checkbox("hex.disassembler.view.disassembler.ppc.spe"_lang, &spe); - static bool booke = false; - ImGui::Checkbox("hex.disassembler.view.disassembler.ppc.booke"_lang, &booke); - - m_mode = cs_mode(mode | (qpx ? CS_MODE_QPX : cs_mode(0)) | (spe ? CS_MODE_SPE : cs_mode(0)) | (booke ? CS_MODE_BOOKE : cs_mode(0))); - #else - m_mode = cs_mode(mode | (qpx ? CS_MODE_QPX : cs_mode(0))); - #endif - } - break; - case Architecture::SPARC: - { - static bool v9Mode = false; - ImGui::Checkbox("hex.disassembler.view.disassembler.sparc.v9"_lang, &v9Mode); - - m_mode = cs_mode(v9Mode ? CS_MODE_V9 : cs_mode(0)); - } - break; - #if CS_API_MAJOR >= 5 - case Architecture::RISCV: - { - static int mode = CS_MODE_RISCV32; - ImGui::RadioButton("hex.disassembler.view.disassembler.32bit"_lang, &mode, CS_MODE_RISCV32); - ImGui::SameLine(); - ImGui::RadioButton("hex.disassembler.view.disassembler.64bit"_lang, &mode, CS_MODE_RISCV64); - - static bool compressed = false; - ImGui::Checkbox("hex.disassembler.view.disassembler.riscv.compressed"_lang, &compressed); - - m_mode = cs_mode(mode | (compressed ? CS_MODE_RISCVC : cs_mode(0))); - } - break; - #endif - case Architecture::M68K: - { - static int selectedMode = 0; - - 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}, - { "hex.disassembler.view.disassembler.m68k.020"_lang, CS_MODE_M68K_020}, - { "hex.disassembler.view.disassembler.m68k.030"_lang, CS_MODE_M68K_030}, - { "hex.disassembler.view.disassembler.m68k.040"_lang, CS_MODE_M68K_040}, - { "hex.disassembler.view.disassembler.m68k.060"_lang, CS_MODE_M68K_060}, - }; - - if (ImGui::BeginCombo("hex.disassembler.view.disassembler.settings.mode"_lang, modes[selectedMode].first)) { - for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) { - if (ImGui::Selectable(modes[i].first)) - selectedMode = i; - } - ImGui::EndCombo(); - } - - m_mode = cs_mode(modes[selectedMode].second); - } - break; - case Architecture::M680X: - { - static int selectedMode = 0; - - 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 }, - { "hex.disassembler.view.disassembler.m680x.6800"_lang, CS_MODE_M680X_6800 }, - { "hex.disassembler.view.disassembler.m680x.6801"_lang, CS_MODE_M680X_6801 }, - { "hex.disassembler.view.disassembler.m680x.6805"_lang, CS_MODE_M680X_6805 }, - { "hex.disassembler.view.disassembler.m680x.6808"_lang, CS_MODE_M680X_6808 }, - { "hex.disassembler.view.disassembler.m680x.6809"_lang, CS_MODE_M680X_6809 }, - { "hex.disassembler.view.disassembler.m680x.6811"_lang, CS_MODE_M680X_6811 }, - { "hex.disassembler.view.disassembler.m680x.cpu12"_lang, CS_MODE_M680X_CPU12}, - { "hex.disassembler.view.disassembler.m680x.hcs08"_lang, CS_MODE_M680X_HCS08}, - }; - - if (ImGui::BeginCombo("hex.disassembler.view.disassembler.settings.mode"_lang, modes[selectedMode].first)) { - for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) { - if (ImGui::Selectable(modes[i].first)) - selectedMode = i; - } - ImGui::EndCombo(); - } - - m_mode = cs_mode(modes[selectedMode].second); - } - break; - #if CS_API_MAJOR >= 5 - case Architecture::MOS65XX: - { - static int selectedMode = 0; - - 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 }, - { "hex.disassembler.view.disassembler.mos65xx.w65c02"_lang, CS_MODE_MOS65XX_W65C02 }, - { "hex.disassembler.view.disassembler.mos65xx.65816"_lang, CS_MODE_MOS65XX_65816 }, - { "hex.disassembler.view.disassembler.mos65xx.65816_long_m"_lang, CS_MODE_MOS65XX_65816_LONG_M }, - { "hex.disassembler.view.disassembler.mos65xx.65816_long_x"_lang, CS_MODE_MOS65XX_65816_LONG_X }, - { "hex.disassembler.view.disassembler.mos65xx.65816_long_mx"_lang, CS_MODE_MOS65XX_65816_LONG_MX}, - }; - - if (ImGui::BeginCombo("hex.disassembler.view.disassembler.settings.mode"_lang, modes[selectedMode].first)) { - for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) { - if (ImGui::Selectable(modes[i].first)) - selectedMode = i; - } - ImGui::EndCombo(); - } - - m_mode = cs_mode(modes[selectedMode].second); - } - break; - #endif - #if CS_API_MAJOR >= 5 - case Architecture::BPF: - { - static int mode = CS_MODE_BPF_CLASSIC; - ImGui::RadioButton("hex.disassembler.view.disassembler.bpf.classic"_lang, &mode, CS_MODE_BPF_CLASSIC); - ImGui::SameLine(); - ImGui::RadioButton("hex.disassembler.view.disassembler.bpf.extended"_lang, &mode, CS_MODE_BPF_EXTENDED); - - m_mode = cs_mode(mode); - } - break; - case Architecture::SH: - { - static u32 selectionMode = 0; - static bool fpu = false; - static bool dsp = false; - - std::pair modes[] = { - { "hex.disassembler.view.disassembler.sh.sh2"_lang, CS_MODE_SH2 }, - { "hex.disassembler.view.disassembler.sh.sh2a"_lang, CS_MODE_SH2A }, - { "hex.disassembler.view.disassembler.sh.sh3"_lang, CS_MODE_SH3 }, - { "hex.disassembler.view.disassembler.sh.sh4"_lang, CS_MODE_SH4 }, - { "hex.disassembler.view.disassembler.sh.sh4a"_lang, CS_MODE_SH4A }, - }; - - if (ImGui::BeginCombo("hex.disassembler.view.disassembler.settings.mode"_lang, modes[selectionMode].first)) { - for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) { - if (ImGui::Selectable(modes[i].first)) - selectionMode = i; - } - ImGui::EndCombo(); - } - - ImGui::Checkbox("hex.disassembler.view.disassembler.sh.fpu"_lang, &fpu); - ImGui::SameLine(); - ImGui::Checkbox("hex.disassembler.view.disassembler.sh.dsp"_lang, &dsp); - - m_mode = cs_mode(modes[selectionMode].second | (fpu ? CS_MODE_SHFPU : cs_mode(0)) | (dsp ? CS_MODE_SHDSP : cs_mode(0))); - } - break; - case Architecture::TRICORE: - { - static u32 selectionMode = 0; - - 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 }, - { "hex.disassembler.view.disassembler.tricore.130"_lang, CS_MODE_TRICORE_130 }, - { "hex.disassembler.view.disassembler.tricore.131"_lang, CS_MODE_TRICORE_131 }, - { "hex.disassembler.view.disassembler.tricore.160"_lang, CS_MODE_TRICORE_160 }, - { "hex.disassembler.view.disassembler.tricore.161"_lang, CS_MODE_TRICORE_161 }, - { "hex.disassembler.view.disassembler.tricore.162"_lang, CS_MODE_TRICORE_162 }, - }; - - if (ImGui::BeginCombo("hex.disassembler.view.disassembler.settings.mode"_lang, modes[selectionMode].first)) { - for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) { - if (ImGui::Selectable(modes[i].first)) - selectionMode = i; - } - ImGui::EndCombo(); - } - - m_mode = cs_mode(modes[selectionMode].second); - } - break; - case Architecture::WASM: - #endif - case Architecture::EVM: - case Architecture::TMS320C64X: - case Architecture::ARM64: - case Architecture::SYSZ: - case Architecture::XCORE: - m_mode = cs_mode(0); - break; + const auto &architectures = ContentRegistry::Disassembler::impl::getArchitectures(); + if (architectures.empty()) { + ImGuiExt::TextSpinner("hex.disassembler.view.disassembler.arch"_lang); + } else { + if (m_currArchitecture == nullptr) { + m_currArchitecture = architectures.begin()->second(); } - if (littleEndian) { - m_mode = cs_mode(u32(m_mode) | CS_MODE_LITTLE_ENDIAN); - } else { - m_mode = cs_mode(u32(m_mode) | CS_MODE_BIG_ENDIAN); + if (ImGui::BeginCombo("hex.disassembler.view.disassembler.arch"_lang, m_currArchitecture->getName().c_str())) { + for (const auto &[name, creator] : architectures) { + if (ImGui::Selectable(name.c_str(), name == m_currArchitecture->getName())) { + m_currArchitecture = creator(); + } + } + ImGui::EndCombo(); } + // Draw sub-settings for each architecture + if (ImGuiExt::BeginBox()) { + m_currArchitecture->drawSettings(); + } + ImGuiExt::EndBox(); } - ImGuiExt::EndBox(); } // Draw disassemble button diff --git a/plugins/disassembler/source/plugin_disassembler.cpp b/plugins/disassembler/source/plugin_disassembler.cpp index 4e7c22077..27e1e9ac5 100644 --- a/plugins/disassembler/source/plugin_disassembler.cpp +++ b/plugins/disassembler/source/plugin_disassembler.cpp @@ -17,6 +17,8 @@ namespace hex::plugin::disasm { void drawDisassemblyVisualizer(pl::ptrn::Pattern &, bool, std::span arguments); void registerPatternLanguageTypes(); + void registerCapstoneArchitectures(); + } namespace { @@ -42,4 +44,6 @@ IMHEX_PLUGIN_SETUP("Disassembler", "WerWolv", "Disassembler support") { registerViews(); registerPlVisualizers(); registerPatternLanguageTypes(); + + registerCapstoneArchitectures(); }