mirror of https://github.com/WerWolv/ImHex.git
feat: Added various custom built-in types to the pattern language (#1991)
This commit is contained in:
parent
13e079d1b8
commit
040a606b39
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit ac9ab6ba727500ab1614e6d063797d78cd632222
|
||||
Subproject commit d387be8ad6b678b516f5cd0b848019a2ff498f1b
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,293 @@
|
|||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/helpers/encoding_file.hpp>
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/helpers/http_requests.hpp>
|
||||
|
||||
#include <pl/core/evaluator.hpp>
|
||||
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
#include <pl/patterns/pattern_unsigned.hpp>
|
||||
#include <pl/patterns/pattern_signed.hpp>
|
||||
#include <pl/patterns/pattern_float.hpp>
|
||||
#include <pl/patterns/pattern_boolean.hpp>
|
||||
#include <pl/patterns/pattern_string.hpp>
|
||||
#include <pl/patterns/pattern_struct.hpp>
|
||||
#include <pl/patterns/pattern_array_dynamic.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
|
||||
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<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternEncodedString(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getFormattedName() const override {
|
||||
return this->getTypeName();
|
||||
}
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override { return compareCommonProperties<decltype(*this)>(other); }
|
||||
void accept(pl::PatternVisitor &v) override {
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
std::vector<pl::u8> getRawBytes() override {
|
||||
std::vector<u8> 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<u8> 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<size_t>(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<u8> 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<std::shared_ptr<pl::ptrn::Pattern>> &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<pl::ptrn::PatternStruct>(evaluator, 0, 0, 0);
|
||||
object->setTypeName("Object");
|
||||
object->setSection(pl::ptrn::Pattern::PatternLocalSectionId);
|
||||
object->addAttribute("export");
|
||||
|
||||
std::vector<std::shared_ptr<pl::ptrn::Pattern>> objectEntries;
|
||||
jsonToPattern(evaluator, *it, objectEntries);
|
||||
object->setEntries(objectEntries);
|
||||
entries.emplace_back(std::move(object));
|
||||
break;
|
||||
}
|
||||
case ValueType::array: {
|
||||
auto object = std::make_shared<pl::ptrn::PatternArrayDynamic>(evaluator, 0, 0, 0);
|
||||
object->setTypeName("Array");
|
||||
object->setSection(pl::ptrn::Pattern::PatternLocalSectionId);
|
||||
object->addAttribute("export");
|
||||
|
||||
std::vector<std::shared_ptr<pl::ptrn::Pattern>> 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<pl::ptrn::PatternUnsigned>(evaluator, 0, sizeof(u64), 0);
|
||||
object->setTypeName("u64");
|
||||
|
||||
auto data = allocateSpace(evaluator, object);
|
||||
auto value = it->get<u64>();
|
||||
std::memcpy(data.data(), &value, sizeof(value));
|
||||
|
||||
entries.emplace_back(std::move(object));
|
||||
break;
|
||||
}
|
||||
case ValueType::number_integer: {
|
||||
auto object = std::make_shared<pl::ptrn::PatternSigned>(evaluator, 0, sizeof(i64), 0);
|
||||
object->setTypeName("s64");
|
||||
|
||||
auto data = allocateSpace(evaluator, object);
|
||||
auto value = it->get<i64>();
|
||||
std::memcpy(data.data(), &value, sizeof(value));
|
||||
|
||||
entries.emplace_back(std::move(object));
|
||||
break;
|
||||
}
|
||||
case ValueType::number_float: {
|
||||
auto object = std::make_shared<pl::ptrn::PatternFloat>(evaluator, 0, sizeof(double), 0);
|
||||
object->setTypeName("double");
|
||||
|
||||
auto data = allocateSpace(evaluator, object);
|
||||
auto value = it->get<double>();
|
||||
std::memcpy(data.data(), &value, sizeof(value));
|
||||
|
||||
entries.emplace_back(std::move(object));
|
||||
break;
|
||||
}
|
||||
case ValueType::boolean: {
|
||||
auto object = std::make_shared<pl::ptrn::PatternBoolean>(evaluator, 0, 0);
|
||||
|
||||
auto data = allocateSpace(evaluator, object);
|
||||
auto value = it->get<bool>();
|
||||
std::memcpy(data.data(), &value, sizeof(value));
|
||||
|
||||
entries.emplace_back(std::move(object));
|
||||
break;
|
||||
}
|
||||
case ValueType::string: {
|
||||
auto value = it->get<std::string>();
|
||||
|
||||
auto object = std::make_shared<pl::ptrn::PatternString>(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<pl::ptrn::Pattern> jsonToPattern(pl::core::Evaluator *evaluator, const nlohmann::json &json) {
|
||||
auto object = std::make_unique<pl::ptrn::PatternStruct>(evaluator, 0, 0, 0);
|
||||
std::vector<std::shared_ptr<pl::ptrn::Pattern>> 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<data_pattern> */
|
||||
ContentRegistry::PatternLanguage::addType(nsHexDec, "Json", FunctionParameterCount::exactly(1), [](Evaluator *evaluator, auto params) -> std::unique_ptr<pl::ptrn::Pattern> {
|
||||
auto data = params[0].toBytes();
|
||||
|
||||
auto result = jsonToPattern(evaluator, nlohmann::json::parse(data));
|
||||
result->setSize(data.size());
|
||||
return result;
|
||||
});
|
||||
|
||||
/* Bson<data_pattern> */
|
||||
ContentRegistry::PatternLanguage::addType(nsHexDec, "Bson", FunctionParameterCount::exactly(1), [](Evaluator *evaluator, auto params) -> std::unique_ptr<pl::ptrn::Pattern> {
|
||||
auto data = params[0].toBytes();
|
||||
|
||||
auto result = jsonToPattern(evaluator, nlohmann::json::from_bson(data));
|
||||
result->setSize(data.size());
|
||||
return result;
|
||||
});
|
||||
|
||||
/* Cbor<data_pattern> */
|
||||
ContentRegistry::PatternLanguage::addType(nsHexDec, "Cbor", FunctionParameterCount::exactly(1), [](Evaluator *evaluator, auto params) -> std::unique_ptr<pl::ptrn::Pattern> {
|
||||
auto data = params[0].toBytes();
|
||||
|
||||
auto result = jsonToPattern(evaluator, nlohmann::json::from_cbor(data));
|
||||
result->setSize(data.size());
|
||||
return result;
|
||||
});
|
||||
|
||||
/* Bjdata<data_pattern> */
|
||||
ContentRegistry::PatternLanguage::addType(nsHexDec, "Bjdata", FunctionParameterCount::exactly(1), [](Evaluator *evaluator, auto params) -> std::unique_ptr<pl::ptrn::Pattern> {
|
||||
auto data = params[0].toBytes();
|
||||
|
||||
auto result = jsonToPattern(evaluator, nlohmann::json::from_bjdata(data));
|
||||
result->setSize(data.size());
|
||||
return result;
|
||||
});
|
||||
|
||||
/* Msgpack<data_pattern> */
|
||||
ContentRegistry::PatternLanguage::addType(nsHexDec, "Msgpack", FunctionParameterCount::exactly(1), [](Evaluator *evaluator, auto params) -> std::unique_ptr<pl::ptrn::Pattern> {
|
||||
auto data = params[0].toBytes();
|
||||
|
||||
auto result = jsonToPattern(evaluator, nlohmann::json::from_msgpack(data));
|
||||
result->setSize(data.size());
|
||||
return result;
|
||||
});
|
||||
|
||||
/* Ubjson<data_pattern> */
|
||||
ContentRegistry::PatternLanguage::addType(nsHexDec, "Ubjson", FunctionParameterCount::exactly(1), [](Evaluator *evaluator, auto params) -> std::unique_ptr<pl::ptrn::Pattern> {
|
||||
auto data = params[0].toBytes();
|
||||
|
||||
auto result = jsonToPattern(evaluator, nlohmann::json::from_ubjson(data));
|
||||
result->setSize(data.size());
|
||||
return result;
|
||||
});
|
||||
|
||||
|
||||
/* EncodedString<data_pattern> */
|
||||
ContentRegistry::PatternLanguage::addType(nsHexDec, "EncodedString", FunctionParameterCount::exactly(2), [](Evaluator *evaluator, auto params) -> std::unique_ptr<pl::ptrn::Pattern> {
|
||||
auto bytes = params[0].toBytes();
|
||||
auto encodingDefinition = params[1].toString();
|
||||
|
||||
std::string value;
|
||||
EncodingFile encodingFile(EncodingFile::Type::Thingy, encodingDefinition);
|
||||
|
||||
auto pattern = std::make_unique<PatternEncodedString>(evaluator, evaluator->getReadOffset(), bytes.size(), 0);
|
||||
pattern->setEncodedString(encodingFile, bytes);
|
||||
|
||||
return pattern;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <array>
|
||||
|
||||
#include <capstone/capstone.h>
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
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<cs_arch, cs_mode> 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<std::pair<std::string_view, cs_mode>, 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) };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include <hex/helpers/http_requests.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
|
||||
#include <pl/core/evaluator.hpp>
|
||||
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
|
||||
#include <capstone/capstone.h>
|
||||
#include <content/helpers/disassembler.hpp>
|
||||
|
||||
|
||||
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<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternInstruction(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getFormattedName() const override {
|
||||
return this->getTypeName();
|
||||
}
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override { return compareCommonProperties<decltype(*this)>(other); }
|
||||
void accept(pl::PatternVisitor &v) override {
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
std::vector<pl::u8> getRawBytes() override {
|
||||
std::vector<u8> 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<data_pattern> */
|
||||
ContentRegistry::PatternLanguage::addType(nsHexDec, "Instruction", FunctionParameterCount::exactly(3), [](Evaluator *evaluator, auto params) -> std::unique_ptr<pl::ptrn::Pattern> {
|
||||
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<u8> data(std::min<u64>(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<PatternInstruction>(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");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
#include <imgui.h>
|
||||
|
||||
#include <capstone/capstone.h>
|
||||
#include <content/helpers/disassembler.hpp>
|
||||
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
|
@ -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<cs_arch>(architecture), static_cast<cs_mode>(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();
|
||||
|
|
|
@ -15,6 +15,7 @@ using namespace hex::plugin::disasm;
|
|||
namespace hex::plugin::disasm {
|
||||
|
||||
void drawDisassemblyVisualizer(pl::ptrn::Pattern &, bool, std::span<const pl::core::Token::Literal> 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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue