diff --git a/dist/rpm/imhex.spec b/dist/rpm/imhex.spec index 56c67ee75..dffe1e58e 100644 --- a/dist/rpm/imhex.spec +++ b/dist/rpm/imhex.spec @@ -35,7 +35,7 @@ BuildRequires: zlib-devel BuildRequires: bzip2-devel BuildRequires: xz-devel %if 0%{?rhel} -BuildRequires: gcc-toolset-12 +BuildRequires: gcc-toolset-14 %endif Provides: bundled(gnulib) @@ -71,9 +71,9 @@ rm -rf lib/third_party/{fmt,nlohmann_json,yara} %build %if 0%{?rhel} -. /opt/rh/gcc-toolset-12/enable +. /opt/rh/gcc-toolset-14/enable %set_build_flags -CXXFLAGS+=" -std=gnu++2b" +CXXFLAGS+=" -std=gnu++23" %endif %cmake \ -D CMAKE_BUILD_TYPE=Release \ @@ -94,9 +94,9 @@ CXXFLAGS+=" -std=gnu++2b" %check %if 0%{?rhel} -. /opt/rh/gcc-toolset-12/enable +. /opt/rh/gcc-toolset-14/enable %set_build_flags -CXXFLAGS+=" -std=gnu++2b" +CXXFLAGS+=" -std=gnu++23" %endif diff --git a/lib/external/pattern_language b/lib/external/pattern_language index ac9ab6ba7..d387be8ad 160000 --- a/lib/external/pattern_language +++ b/lib/external/pattern_language @@ -1 +1 @@ -Subproject commit ac9ab6ba727500ab1614e6d063797d78cd632222 +Subproject commit d387be8ad6b678b516f5cd0b848019a2ff498f1b diff --git a/lib/libimhex/include/hex/helpers/utils.hpp b/lib/libimhex/include/hex/helpers/utils.hpp index eee48a012..0404ebf0f 100644 --- a/lib/libimhex/include/hex/helpers/utils.hpp +++ b/lib/libimhex/include/hex/helpers/utils.hpp @@ -285,13 +285,13 @@ namespace hex { [[nodiscard]] float float16ToFloat32(u16 float16); - [[nodiscard]] inline bool equalsIgnoreCase(const std::string &left, const std::string &right) { + [[nodiscard]] inline bool equalsIgnoreCase(std::string_view left, std::string_view right) { return std::equal(left.begin(), left.end(), right.begin(), right.end(), [](char a, char b) { return tolower(a) == tolower(b); }); } - [[nodiscard]] inline bool containsIgnoreCase(const std::string &a, const std::string &b) { + [[nodiscard]] inline bool containsIgnoreCase(std::string_view a, std::string_view b) { auto iter = std::search(a.begin(), a.end(), b.begin(), b.end(), [](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); }); diff --git a/plugins/builtin/CMakeLists.txt b/plugins/builtin/CMakeLists.txt index 38a488ec2..f12797a46 100644 --- a/plugins/builtin/CMakeLists.txt +++ b/plugins/builtin/CMakeLists.txt @@ -20,6 +20,7 @@ add_imhex_plugin( source/content/communication_interface.cpp source/content/data_inspector.cpp source/content/pl_builtin_functions.cpp + source/content/pl_builtin_types.cpp source/content/pl_pragmas.cpp source/content/settings_entries.cpp source/content/tools_entries.cpp diff --git a/plugins/builtin/source/content/pl_builtin_types.cpp b/plugins/builtin/source/content/pl_builtin_types.cpp new file mode 100644 index 000000000..e0e011cc8 --- /dev/null +++ b/plugins/builtin/source/content/pl_builtin_types.cpp @@ -0,0 +1,293 @@ +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace hex::plugin::builtin { + + class PatternEncodedString : public pl::ptrn::Pattern { + public: + PatternEncodedString(pl::core::Evaluator *evaluator, u64 offset, size_t size, u32 line) + : Pattern(evaluator, offset, size, line) { } + + [[nodiscard]] std::unique_ptr clone() const override { + return std::unique_ptr(new PatternEncodedString(*this)); + } + + [[nodiscard]] std::string getFormattedName() const override { + return this->getTypeName(); + } + [[nodiscard]] bool operator==(const Pattern &other) const override { return compareCommonProperties(other); } + void accept(pl::PatternVisitor &v) override { + v.visit(*this); + } + + std::vector getRawBytes() override { + std::vector result; + result.resize(this->getSize()); + + this->getEvaluator()->readData(this->getOffset(), result.data(), result.size(), this->getSection()); + if (this->getEndian() != std::endian::native) + std::reverse(result.begin(), result.end()); + + return result; + } + + void setEncodedString(const EncodingFile &encodingFile, std::span bytes) { + m_encodedString.clear(); + + u64 offset = 0; + while (offset < bytes.size()) { + auto [character, size] = encodingFile.getEncodingFor(std::span(bytes).subspan(offset)); + m_encodedString += std::string(character); + + if (size == 0) + break; + + offset += size; + } + } + + protected: + [[nodiscard]] std::string formatDisplayValue() override { + auto size = std::min(this->getSize(), 0x7F); + + if (size == 0) + return "\"\""; + + std::string buffer(size, 0x00); + this->getEvaluator()->readData(this->getOffset(), buffer.data(), size, this->getSection()); + + return Pattern::callUserFormatFunc(buffer).value_or(fmt::format("\"{0}\" {1}", buffer, size > this->getSize() ? "(truncated)" : "")); + } + + private: + std::string m_encodedString; + }; + + namespace { + + std::span allocateSpace(pl::core::Evaluator *evaluator, const auto &pattern) { + auto &patternLocalStorage = evaluator->getPatternLocalStorage(); + auto patternLocalAddress = patternLocalStorage.empty() ? 0 : patternLocalStorage.rbegin()->first + 1; + pattern->setSection(pl::ptrn::Pattern::PatternLocalSectionId); + pattern->addAttribute("export"); + + pattern->setOffset(u64(patternLocalAddress) << 32); + patternLocalStorage.insert({ patternLocalAddress, { } }); + + auto &data = patternLocalStorage[patternLocalAddress].data; + data.resize(pattern->getSize()); + + return data; + } + + void jsonToPattern(pl::core::Evaluator *evaluator, const nlohmann::json &json, std::vector> &entries) { + u64 index = 0; + for (auto it = json.begin(); it != json.end(); ++it, ++index) { + using ValueType = nlohmann::json::value_t; + switch (it->type()) { + case ValueType::object: { + auto object = std::make_shared(evaluator, 0, 0, 0); + object->setTypeName("Object"); + object->setSection(pl::ptrn::Pattern::PatternLocalSectionId); + object->addAttribute("export"); + + std::vector> objectEntries; + jsonToPattern(evaluator, *it, objectEntries); + object->setEntries(objectEntries); + entries.emplace_back(std::move(object)); + break; + } + case ValueType::array: { + auto object = std::make_shared(evaluator, 0, 0, 0); + object->setTypeName("Array"); + object->setSection(pl::ptrn::Pattern::PatternLocalSectionId); + object->addAttribute("export"); + + std::vector> objectEntries; + jsonToPattern(evaluator, *it, objectEntries); + object->setEntries(objectEntries); + entries.emplace_back(std::move(object)); + break; + } + case ValueType::binary: + case ValueType::number_unsigned: { + auto object = std::make_shared(evaluator, 0, sizeof(u64), 0); + object->setTypeName("u64"); + + auto data = allocateSpace(evaluator, object); + auto value = it->get(); + std::memcpy(data.data(), &value, sizeof(value)); + + entries.emplace_back(std::move(object)); + break; + } + case ValueType::number_integer: { + auto object = std::make_shared(evaluator, 0, sizeof(i64), 0); + object->setTypeName("s64"); + + auto data = allocateSpace(evaluator, object); + auto value = it->get(); + std::memcpy(data.data(), &value, sizeof(value)); + + entries.emplace_back(std::move(object)); + break; + } + case ValueType::number_float: { + auto object = std::make_shared(evaluator, 0, sizeof(double), 0); + object->setTypeName("double"); + + auto data = allocateSpace(evaluator, object); + auto value = it->get(); + std::memcpy(data.data(), &value, sizeof(value)); + + entries.emplace_back(std::move(object)); + break; + } + case ValueType::boolean: { + auto object = std::make_shared(evaluator, 0, 0); + + auto data = allocateSpace(evaluator, object); + auto value = it->get(); + std::memcpy(data.data(), &value, sizeof(value)); + + entries.emplace_back(std::move(object)); + break; + } + case ValueType::string: { + auto value = it->get(); + + auto object = std::make_shared(evaluator, 0, value.size(), 0); + + auto data = allocateSpace(evaluator, object); + std::memcpy(data.data(), value.data(), value.size()); + + entries.emplace_back(std::move(object)); + break; + } + case ValueType::null: + case ValueType::discarded: + break; + } + + auto &lastEntry = entries.back(); + if (json.is_object()) { + lastEntry->setVariableName(it.key()); + } else { + lastEntry->setArrayIndex(index); + } + } + } + + + std::unique_ptr jsonToPattern(pl::core::Evaluator *evaluator, const nlohmann::json &json) { + auto object = std::make_unique(evaluator, 0, 0, 0); + std::vector> patterns; + + try { + jsonToPattern(evaluator, json, patterns); + object->setEntries(patterns); + + return object; + } catch (const nlohmann::json::exception &e) { + pl::core::err::E0012.throwError(e.what()); + } + } + + } + + void registerPatternLanguageTypes() { + using namespace pl::core; + using FunctionParameterCount = pl::api::FunctionParameterCount; + + { + const pl::api::Namespace nsHexDec = { "builtin", "hex", "dec" }; + + /* Json */ + ContentRegistry::PatternLanguage::addType(nsHexDec, "Json", FunctionParameterCount::exactly(1), [](Evaluator *evaluator, auto params) -> std::unique_ptr { + auto data = params[0].toBytes(); + + auto result = jsonToPattern(evaluator, nlohmann::json::parse(data)); + result->setSize(data.size()); + return result; + }); + + /* Bson */ + ContentRegistry::PatternLanguage::addType(nsHexDec, "Bson", FunctionParameterCount::exactly(1), [](Evaluator *evaluator, auto params) -> std::unique_ptr { + auto data = params[0].toBytes(); + + auto result = jsonToPattern(evaluator, nlohmann::json::from_bson(data)); + result->setSize(data.size()); + return result; + }); + + /* Cbor */ + ContentRegistry::PatternLanguage::addType(nsHexDec, "Cbor", FunctionParameterCount::exactly(1), [](Evaluator *evaluator, auto params) -> std::unique_ptr { + auto data = params[0].toBytes(); + + auto result = jsonToPattern(evaluator, nlohmann::json::from_cbor(data)); + result->setSize(data.size()); + return result; + }); + + /* Bjdata */ + ContentRegistry::PatternLanguage::addType(nsHexDec, "Bjdata", FunctionParameterCount::exactly(1), [](Evaluator *evaluator, auto params) -> std::unique_ptr { + auto data = params[0].toBytes(); + + auto result = jsonToPattern(evaluator, nlohmann::json::from_bjdata(data)); + result->setSize(data.size()); + return result; + }); + + /* Msgpack */ + ContentRegistry::PatternLanguage::addType(nsHexDec, "Msgpack", FunctionParameterCount::exactly(1), [](Evaluator *evaluator, auto params) -> std::unique_ptr { + auto data = params[0].toBytes(); + + auto result = jsonToPattern(evaluator, nlohmann::json::from_msgpack(data)); + result->setSize(data.size()); + return result; + }); + + /* Ubjson */ + ContentRegistry::PatternLanguage::addType(nsHexDec, "Ubjson", FunctionParameterCount::exactly(1), [](Evaluator *evaluator, auto params) -> std::unique_ptr { + auto data = params[0].toBytes(); + + auto result = jsonToPattern(evaluator, nlohmann::json::from_ubjson(data)); + result->setSize(data.size()); + return result; + }); + + + /* EncodedString */ + ContentRegistry::PatternLanguage::addType(nsHexDec, "EncodedString", FunctionParameterCount::exactly(2), [](Evaluator *evaluator, auto params) -> std::unique_ptr { + auto bytes = params[0].toBytes(); + auto encodingDefinition = params[1].toString(); + + std::string value; + EncodingFile encodingFile(EncodingFile::Type::Thingy, encodingDefinition); + + auto pattern = std::make_unique(evaluator, evaluator->getReadOffset(), bytes.size(), 0); + pattern->setEncodedString(encodingFile, bytes); + + return pattern; + }); + } + } +} diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index 67b168a6c..4e1898cff 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -1482,7 +1482,7 @@ namespace hex::plugin::builtin { for (const auto &frame : **m_callStack | std::views::reverse) { auto location = frame->getLocation(); std::string message; - if (location.source->mainSource) { + if (location.source != nullptr && location.source->mainSource) { if (m_lastEvaluationError->has_value()) message = processMessage((*m_lastEvaluationError)->message); auto key = TextEditor::Coordinates(location.line, location.column); diff --git a/plugins/builtin/source/plugin_builtin.cpp b/plugins/builtin/source/plugin_builtin.cpp index 97e658abb..2b8d0d8fe 100644 --- a/plugins/builtin/source/plugin_builtin.cpp +++ b/plugins/builtin/source/plugin_builtin.cpp @@ -19,6 +19,7 @@ namespace hex::plugin::builtin { void registerDataInspectorEntries(); void registerToolEntries(); void registerPatternLanguageFunctions(); + void registerPatternLanguageTypes(); void registerPatternLanguagePragmas(); void registerPatternLanguageVisualizers(); void registerCommandPaletteCommands(); @@ -95,6 +96,7 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") { registerDataInspectorEntries(); registerToolEntries(); registerPatternLanguageFunctions(); + registerPatternLanguageTypes(); registerPatternLanguagePragmas(); registerPatternLanguageVisualizers(); registerCommandPaletteCommands(); diff --git a/plugins/disassembler/CMakeLists.txt b/plugins/disassembler/CMakeLists.txt index 0360de874..8888027c8 100644 --- a/plugins/disassembler/CMakeLists.txt +++ b/plugins/disassembler/CMakeLists.txt @@ -24,6 +24,7 @@ add_imhex_plugin( source/content/views/view_disassembler.cpp source/content/pl_visualizers/disassembler.cpp + source/content/pl_builtin_types.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 a3d796db2..bfe27372e 100644 --- a/plugins/disassembler/include/content/helpers/disassembler.hpp +++ b/plugins/disassembler/include/content/helpers/disassembler.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace hex::plugin::disasm { @@ -91,5 +92,174 @@ namespace hex::plugin::disasm { return supportedCount; } + + // string has to be in the form of `arch;option1,option2,option3,no-option4` + // Not all results might make sense for capstone + static std::pair stringToSettings(std::string_view string) { + const auto archSeparator = string.find_first_of(';'); + + std::string_view archName; + std::string_view options; + if (archSeparator == std::string_view::npos) { + archName = wolv::util::trim(string); + options = ""; + } else { + archName = wolv::util::trim(string.substr(0, archSeparator - 1)); + options = wolv::util::trim(string.substr(archSeparator + 1)); + } + + u32 arch = {}; + u32 mode = {}; + + if (archName.ends_with("be") || archName.ends_with("eb")) { + mode |= CS_MODE_BIG_ENDIAN; + archName.remove_suffix(2); + } else if (archName.ends_with("le") || archName.ends_with("el")) { + mode |= CS_MODE_LITTLE_ENDIAN; + archName.remove_suffix(2); + } + + if (equalsIgnoreCase(archName, "arm")) { + arch = CS_ARCH_ARM; + mode |= CS_MODE_ARM; + } + else if (equalsIgnoreCase(archName, "thumb")) { + arch = CS_ARCH_ARM; + mode |= CS_MODE_THUMB; + } + else if (equalsIgnoreCase(archName, "aarch64") || equalsIgnoreCase(archName, "arm64")) + arch = CS_ARCH_ARM64; + else if (equalsIgnoreCase(archName, "mips")) + arch = CS_ARCH_MIPS; + else if (equalsIgnoreCase(archName, "x86")) + arch = CS_ARCH_X86; + else if (equalsIgnoreCase(archName, "x86_64") || equalsIgnoreCase(archName, "x64")) { + arch = CS_ARCH_X86; + mode = CS_MODE_64; + } + else if (equalsIgnoreCase(archName, "ppc") || equalsIgnoreCase(archName, "powerpc")) + arch = CS_ARCH_PPC; + else if (equalsIgnoreCase(archName, "sparc")) + arch = CS_ARCH_SPARC; + else if (equalsIgnoreCase(archName, "sysz")) + arch = CS_ARCH_SYSZ; + else if (equalsIgnoreCase(archName, "xcore")) + arch = CS_ARCH_XCORE; + else if (equalsIgnoreCase(archName, "m68k")) + arch = CS_ARCH_M68K; + else if (equalsIgnoreCase(archName, "m680x")) + arch = CS_ARCH_M680X; + else if (equalsIgnoreCase(archName, "tms320c64x")) + arch = CS_ARCH_TMS320C64X; + else if (equalsIgnoreCase(archName, "evm")) + arch = CS_ARCH_EVM; + #if CS_API_MAJOR >= 5 + else if (equalsIgnoreCase(archName, "wasm")) + arch = CS_ARCH_WASM; + else if (equalsIgnoreCase(archName, "riscv")) + arch = CS_ARCH_RISCV; + else if (equalsIgnoreCase(archName, "mos65xx")) + arch = CS_ARCH_MOS65XX; + else if (equalsIgnoreCase(archName, "bpf")) + arch = CS_ARCH_BPF; + else if (equalsIgnoreCase(archName, "sh")) + arch = CS_ARCH_SH; + else if (equalsIgnoreCase(archName, "tricore")) + arch = CS_ARCH_TRICORE; + #endif + else + throw std::runtime_error("Invalid disassembler architecture"); + + while (!options.empty()) { + std::string_view option; + auto separatorPos = options.find_first_of(','); + if (separatorPos == std::string_view::npos) + option = options; + else + option = options.substr(0, separatorPos - 1); + + options.remove_prefix(option.size() + 1); + option = wolv::util::trim(option); + + bool shouldAdd = true; + if (option.starts_with("no-")) { + shouldAdd = false; + option.remove_prefix(3); + } + + constexpr static std::array, 53> Options = {{ + { "16bit", CS_MODE_16 }, + { "32bit", CS_MODE_32 }, + { "64bit", CS_MODE_64 }, + { "cortex-m", CS_MODE_MCLASS }, + { "armv8", CS_MODE_V8 }, + { "micromips", CS_MODE_MICRO }, + { "mips2", CS_MODE_MIPS2 }, + { "mips3", CS_MODE_MIPS3 }, + { "mips32r6", CS_MODE_MIPS32R6 }, + { "sparcv9", CS_MODE_V9 }, + { "qpx", CS_MODE_QPX }, + { "spe", CS_MODE_SPE }, + { "ps", CS_MODE_PS }, + { "68000", CS_MODE_M68K_000 }, + { "68010", CS_MODE_M68K_010 }, + { "68020", CS_MODE_M68K_020 }, + { "68030", CS_MODE_M68K_030 }, + { "68040", CS_MODE_M68K_040 }, + { "68060", CS_MODE_M68K_060 }, + { "6301", CS_MODE_M680X_6301 }, + { "6309", CS_MODE_M680X_6309 }, + { "6800", CS_MODE_M680X_6800 }, + { "6801", CS_MODE_M680X_6801 }, + { "6805", CS_MODE_M680X_6805 }, + { "6808", CS_MODE_M680X_6808 }, + { "6809", CS_MODE_M680X_6809 }, + { "6811", CS_MODE_M680X_6811 }, + { "cpu12", CS_MODE_M680X_CPU12 }, + { "hcs08", CS_MODE_M680X_HCS08 }, + { "bpfe", CS_MODE_BPF_EXTENDED }, + { "rv32g", CS_MODE_RISCV32 }, + { "rv64g", CS_MODE_RISCV64 }, + { "riscvc", CS_MODE_RISCVC }, + { "6502", CS_MODE_MOS65XX_6502 }, + { "65c02", CS_MODE_MOS65XX_65C02 }, + { "w65c02", CS_MODE_MOS65XX_W65C02 }, + { "65816", CS_MODE_MOS65XX_65816 }, + { "long-m", CS_MODE_MOS65XX_65816_LONG_M }, + { "long-x", CS_MODE_MOS65XX_65816_LONG_X }, + { "sh2", CS_MODE_SH2 }, + { "sh2a", CS_MODE_SH2A }, + { "sh3", CS_MODE_SH3 }, + { "sh4", CS_MODE_SH4 }, + { "sh4a", CS_MODE_SH4A }, + { "shfpu", CS_MODE_SHFPU }, + { "shdsp", CS_MODE_SHDSP }, + { "1.1", CS_MODE_TRICORE_110 }, + { "1.2", CS_MODE_TRICORE_120 }, + { "1.3", CS_MODE_TRICORE_130 }, + { "1.3.1", CS_MODE_TRICORE_131 }, + { "1.6", CS_MODE_TRICORE_160 }, + { "1.6.1", CS_MODE_TRICORE_161 }, + { "1.6.2", CS_MODE_TRICORE_162 }, + }}; + + bool optionFound = false; + for (const auto &[optionName, optionValue] : Options) { + if (equalsIgnoreCase(option, optionName)) { + if (shouldAdd) mode |= optionValue; + else mode &= ~optionValue; + + optionFound = true; + break; + } + } + + if (!optionFound) { + throw std::runtime_error(fmt::format("Unknown disassembler option '{}'", option)); + } + } + + return { cs_arch(arch), cs_mode(mode) }; + } }; } diff --git a/plugins/disassembler/source/content/pl_builtin_types.cpp b/plugins/disassembler/source/content/pl_builtin_types.cpp new file mode 100644 index 000000000..8cb6bbe60 --- /dev/null +++ b/plugins/disassembler/source/content/pl_builtin_types.cpp @@ -0,0 +1,129 @@ +#include +#include + +#include +#include +#include + +#include + +#include + +#include +#include + + +namespace hex::plugin::disasm { + + class PatternInstruction : public pl::ptrn::Pattern { + public: + PatternInstruction(pl::core::Evaluator *evaluator, u64 offset, size_t size, u32 line) + : Pattern(evaluator, offset, size, line) { } + + [[nodiscard]] std::unique_ptr clone() const override { + return std::unique_ptr(new PatternInstruction(*this)); + } + + [[nodiscard]] std::string getFormattedName() const override { + return this->getTypeName(); + } + [[nodiscard]] bool operator==(const Pattern &other) const override { return compareCommonProperties(other); } + void accept(pl::PatternVisitor &v) override { + v.visit(*this); + } + + std::vector getRawBytes() override { + std::vector result; + result.resize(this->getSize()); + + this->getEvaluator()->readData(this->getOffset(), result.data(), result.size(), this->getSection()); + if (this->getEndian() != std::endian::native) + std::reverse(result.begin(), result.end()); + + return result; + } + + void setInstructionString(std::string instructionString) { + m_instructionString = std::move(instructionString); + } + + protected: + [[nodiscard]] std::string formatDisplayValue() override { + return m_instructionString; + } + + private: + std::string m_instructionString; + }; + + void registerPatternLanguageTypes() { + using namespace pl::core; + using FunctionParameterCount = pl::api::FunctionParameterCount; + + { + const pl::api::Namespace nsHexDec = { "builtin", "hex", "dec" }; + + /* Json */ + ContentRegistry::PatternLanguage::addType(nsHexDec, "Instruction", FunctionParameterCount::exactly(3), [](Evaluator *evaluator, auto params) -> std::unique_ptr { + cs_arch arch; + cs_mode mode; + + try { + std::tie(arch, mode) = Disassembler::stringToSettings(params[0].toString()); + } catch (const std::exception &e) { + err::E0012.throwError(e.what()); + } + const auto syntaxString = params[1].toString(); + const auto relocatedAddress = params[2].toUnsigned(); + + const auto address = evaluator->getReadOffset(); + + csh capstone; + if (cs_open(arch, mode, &capstone) == CS_ERR_OK) { + cs_opt_value syntax; + if (equalsIgnoreCase(syntaxString, "intel")) + syntax = CS_OPT_SYNTAX_INTEL; + else if (equalsIgnoreCase(syntaxString, "at&t")) + syntax = CS_OPT_SYNTAX_ATT; + else if (equalsIgnoreCase(syntaxString, "masm")) + syntax = CS_OPT_SYNTAX_MASM; + else if (equalsIgnoreCase(syntaxString, "motorola")) + syntax = CS_OPT_SYNTAX_MOTOROLA; + else + err::E0012.throwError(hex::format("Invalid disassembler syntax name '{}'", syntaxString)); + + cs_option(capstone, CS_OPT_SYNTAX, syntax); + cs_option(capstone, CS_OPT_SKIPDATA, CS_OPT_ON); + + const auto sectionId = evaluator->getSectionId(); + std::vector data(std::min(32, evaluator->getSectionSize(sectionId) - address)); + evaluator->readData(address, data.data(), data.size(), sectionId); + + cs_insn *instruction = nullptr; + size_t instructionCount = cs_disasm(capstone, data.data(), data.size(), relocatedAddress, 1, &instruction); + if (instructionCount != 1) { + err::E0012.throwError("Failed to disassemble instruction"); + } + + auto result = std::make_unique(evaluator, address, instruction->size, 0); + + std::string instructionString; + if (instruction->mnemonic[0] != '\x00') + instructionString += instruction->mnemonic; + if (instruction->op_str[0] != '\x00') { + instructionString += ' '; + instructionString += instruction->op_str; + } + result->setInstructionString(instructionString); + + cs_free(instruction, instructionCount); + cs_close(&capstone); + + return result; + } else { + err::E0012.throwError("Failed to disassemble instruction"); + } + }); + } + } +} diff --git a/plugins/disassembler/source/content/pl_visualizers/disassembler.cpp b/plugins/disassembler/source/content/pl_visualizers/disassembler.cpp index 021320ff0..56187b58f 100644 --- a/plugins/disassembler/source/content/pl_visualizers/disassembler.cpp +++ b/plugins/disassembler/source/content/pl_visualizers/disassembler.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -23,13 +24,12 @@ namespace hex::plugin::disasm { if (shouldReset) { auto pattern = arguments[0].toPattern(); auto baseAddress = arguments[1].toUnsigned(); - auto architecture = arguments[2].toUnsigned(); - auto mode = arguments[3].toUnsigned(); + const auto [arch, mode] = Disassembler::stringToSettings(arguments[2].toString()); disassembly.clear(); csh capstone; - if (cs_open(static_cast(architecture), static_cast(mode), &capstone) == CS_ERR_OK) { + if (cs_open(arch, mode, &capstone) == CS_ERR_OK) { cs_option(capstone, CS_OPT_SKIPDATA, CS_OPT_ON); auto data = pattern->getBytes(); diff --git a/plugins/disassembler/source/plugin_disassembler.cpp b/plugins/disassembler/source/plugin_disassembler.cpp index 2392ca15e..4e7c22077 100644 --- a/plugins/disassembler/source/plugin_disassembler.cpp +++ b/plugins/disassembler/source/plugin_disassembler.cpp @@ -15,6 +15,7 @@ using namespace hex::plugin::disasm; namespace hex::plugin::disasm { void drawDisassemblyVisualizer(pl::ptrn::Pattern &, bool, std::span arguments); + void registerPatternLanguageTypes(); } @@ -27,7 +28,7 @@ namespace { void registerPlVisualizers() { using ParamCount = pl::api::FunctionParameterCount; - ContentRegistry::PatternLanguage::addVisualizer("disassembler", drawDisassemblyVisualizer, ParamCount::exactly(4)); + ContentRegistry::PatternLanguage::addVisualizer("disassembler", drawDisassemblyVisualizer, ParamCount::exactly(3)); } } @@ -40,4 +41,5 @@ IMHEX_PLUGIN_SETUP("Disassembler", "WerWolv", "Disassembler support") { registerViews(); registerPlVisualizers(); + registerPatternLanguageTypes(); } diff --git a/plugins/ui/include/ui/pattern_drawer.hpp b/plugins/ui/include/ui/pattern_drawer.hpp index 5a78cb01f..3dc3e586f 100644 --- a/plugins/ui/include/ui/pattern_drawer.hpp +++ b/plugins/ui/include/ui/pattern_drawer.hpp @@ -62,6 +62,7 @@ namespace hex::ui { void visit(pl::ptrn::PatternUnsigned& pattern) override; void visit(pl::ptrn::PatternWideCharacter& pattern) override; void visit(pl::ptrn::PatternWideString& pattern) override; + void visit(pl::ptrn::Pattern& pattern) override; private: constexpr static auto ChunkSize = 512; diff --git a/plugins/ui/source/ui/pattern_drawer.cpp b/plugins/ui/source/ui/pattern_drawer.cpp index ba3b043ec..a867b6ff0 100644 --- a/plugins/ui/source/ui/pattern_drawer.cpp +++ b/plugins/ui/source/ui/pattern_drawer.cpp @@ -963,6 +963,12 @@ namespace hex::ui { } } + void PatternDrawer::visit(pl::ptrn::Pattern& pattern) { + createDefaultEntry(pattern); + drawValueColumn(pattern); + drawCommentColumn(pattern); + } + void PatternDrawer::draw(pl::ptrn::Pattern& pattern) { if (pattern.getVisibility() == pl::ptrn::Visibility::Hidden) return;