From 8297e22f106579cff942daf883bca475b384c73c Mon Sep 17 00:00:00 2001 From: WerWolv Date: Sun, 22 Nov 2020 16:22:02 +0100 Subject: [PATCH] Added global big and little endian support to the pattern parser --- include/lang/evaluator.hpp | 5 ++++- include/lang/pattern_data.hpp | 19 +++++++++++++++++++ include/utils.hpp | 17 +++++++++++++++++ source/lang/evaluator.cpp | 20 ++++++++++++++++---- source/lang/preprocessor.cpp | 3 +++ source/views/view_pattern.cpp | 26 ++++++++++++++++++++------ 6 files changed, 79 insertions(+), 11 deletions(-) diff --git a/include/lang/evaluator.hpp b/include/lang/evaluator.hpp index 44399a7d7..6abd3bc4d 100644 --- a/include/lang/evaluator.hpp +++ b/include/lang/evaluator.hpp @@ -6,6 +6,7 @@ #include "lang/pattern_data.hpp" #include "ast_node.hpp" +#include #include #include #include @@ -14,13 +15,15 @@ namespace hex::lang { class Evaluator { public: - Evaluator(prv::Provider* &provider); + Evaluator(prv::Provider* &provider, std::endian dataEndianess); std::pair> evaluate(const std::vector& ast); private: std::unordered_map m_types; prv::Provider* &m_provider; + std::endian m_dataEndianess; + std::pair createStructPattern(ASTNodeVariableDecl *varDeclNode, u64 offset); std::pair createUnionPattern(ASTNodeVariableDecl *varDeclNode, u64 offset); diff --git a/include/lang/pattern_data.hpp b/include/lang/pattern_data.hpp index 77f5efa94..d611b42e8 100644 --- a/include/lang/pattern_data.hpp +++ b/include/lang/pattern_data.hpp @@ -95,6 +95,11 @@ namespace hex::lang { provider->read(left->getOffset(), leftBuffer.data(), left->getSize()); provider->read(right->getOffset(), rightBuffer.data(), right->getSize()); + if (PatternData::s_endianess != std::endian::native) { + std::reverse(leftBuffer.begin(), leftBuffer.end()); + std::reverse(rightBuffer.begin(), rightBuffer.end()); + } + if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) return leftBuffer > rightBuffer; else @@ -117,6 +122,7 @@ namespace hex::lang { } static void resetPalette() { PatternData::s_paletteOffset = 0; } + static void setEndianess(std::endian endianess) { PatternData::s_endianess = endianess; } protected: void createDefaultEntry(std::string value) { @@ -136,6 +142,9 @@ namespace hex::lang { ImGui::Text("%s", value.c_str()); } + protected: + static inline std::endian s_endianess = std::endian::native; + private: Type m_type; u64 m_offset; @@ -145,6 +154,7 @@ namespace hex::lang { std::string m_name; static inline u8 s_paletteOffset = 0; + }; class PatternDataPadding : public PatternData { @@ -169,6 +179,7 @@ namespace hex::lang { void createEntry(prv::Provider* &provider) override { u64 data = 0; provider->read(this->getOffset(), &data, this->getSize()); + data = hex::changeEndianess(data, this->getSize(), PatternData::s_endianess); ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); @@ -215,6 +226,7 @@ namespace hex::lang { void createEntry(prv::Provider* &provider) override { u64 data = 0; provider->read(this->getOffset(), &data, this->getSize()); + data = hex::changeEndianess(data, this->getSize(), PatternData::s_endianess); this->createDefaultEntry(hex::format("%lu (0x%0*lx)", data, this->getSize() * 2, data)); } @@ -238,6 +250,7 @@ namespace hex::lang { void createEntry(prv::Provider* &provider) override { u64 data = 0; provider->read(this->getOffset(), &data, this->getSize()); + data = hex::changeEndianess(data, this->getSize(), PatternData::s_endianess); s64 signedData = signedData = hex::signExtend(data, this->getSize(), 64); @@ -265,10 +278,14 @@ namespace hex::lang { if (this->getSize() == 4) { float data = 0; provider->read(this->getOffset(), &data, 4); + data = hex::changeEndianess(data, 4, PatternData::s_endianess); + formatData = data; } else if (this->getSize() == 8) { double data = 0; provider->read(this->getOffset(), &data, 8); + data = hex::changeEndianess(data, 8, PatternData::s_endianess); + formatData = data; } @@ -488,6 +505,7 @@ namespace hex::lang { void createEntry(prv::Provider* &provider) override { u64 value = 0; provider->read(this->getOffset(), &value, this->getSize()); + value = hex::changeEndianess(value, this->getSize(), PatternData::s_endianess); std::string valueString = this->m_enumName + "::"; @@ -523,6 +541,7 @@ namespace hex::lang { void createEntry(prv::Provider* &provider) override { u64 value = 0; provider->read(this->getOffset(), &value, this->getSize()); + value = hex::changeEndianess(value, this->getSize(), PatternData::s_endianess); ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); diff --git a/include/utils.hpp b/include/utils.hpp index 0eb420db6..f9384827a 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -106,6 +106,23 @@ namespace hex { static_assert(always_false::value, "Invalid type provided!"); } + template + constexpr T changeEndianess(T value, size_t size, std::endian endian) { + if (endian == std::endian::native) + return value; + + if (size == 1) + return value; + else if (size == 2) + return __builtin_bswap16(value); + else if (size == 4) + return __builtin_bswap32(value); + else if (size == 8) + return __builtin_bswap64(value); + else + throw std::invalid_argument("Invalid value size!"); + } + class ScopeExit { public: diff --git a/source/lang/evaluator.cpp b/source/lang/evaluator.cpp index 68ccbb630..70fa0dad9 100644 --- a/source/lang/evaluator.cpp +++ b/source/lang/evaluator.cpp @@ -5,8 +5,8 @@ namespace hex::lang { - Evaluator::Evaluator(prv::Provider* &provider) : m_provider(provider) { - + Evaluator::Evaluator(prv::Provider* &provider, std::endian dataEndianess) : m_provider(provider), m_dataEndianess(dataEndianess) { + PatternData::setEndianess(dataEndianess); } std::pair Evaluator::createStructPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) { @@ -23,8 +23,11 @@ namespace hex::lang { u64 memberOffset = 0; - if (member->getPointerSize().has_value()) + if (member->getPointerSize().has_value()) { this->m_provider->read(offset + structSize, &memberOffset, member->getPointerSize().value()); + + memberOffset = hex::changeEndianess(memberOffset, member->getPointerSize().value(), this->m_dataEndianess); + } else memberOffset = offset + structSize; @@ -52,6 +55,9 @@ namespace hex::lang { if (prevMember->getPatternType() == PatternData::Type::Unsigned && prevMember->getName() == member->getArraySizeVariable()) { u64 value = 0; this->m_provider->read(prevMember->getOffset(), &value, prevMember->getSize()); + + value = hex::changeEndianess(value, prevMember->getSize(), this->m_dataEndianess); + arraySize = value; } } @@ -100,8 +106,11 @@ namespace hex::lang { u64 memberOffset = 0; - if (member->getPointerSize().has_value()) + if (member->getPointerSize().has_value()) { this->m_provider->read(offset + unionSize, &memberOffset, member->getPointerSize().value()); + + memberOffset = hex::changeEndianess(memberOffset, member->getPointerSize().value(), this->m_dataEndianess); + } else memberOffset = offset; @@ -132,6 +141,9 @@ namespace hex::lang { if (prevMember->getPatternType() == PatternData::Type::Unsigned && prevMember->getName() == member->getArraySizeVariable()) { u64 value = 0; this->m_provider->read(prevMember->getOffset(), &value, prevMember->getSize()); + + value = hex::changeEndianess(value, prevMember->getSize(), this->m_dataEndianess); + arraySize = value; } } diff --git a/source/lang/preprocessor.cpp b/source/lang/preprocessor.cpp index 4000328da..80a0ee83e 100644 --- a/source/lang/preprocessor.cpp +++ b/source/lang/preprocessor.cpp @@ -172,6 +172,9 @@ namespace hex::lang { this->addPragmaHandler("MIME", [](std::string value) { return !std::all_of(value.begin(), value.end(), isspace) && !value.ends_with('\n') && !value.ends_with('\r'); }); + this->addPragmaHandler("endian", [](std::string value) { + return value == "big" || value == "little" || value == "native"; + }); } } \ No newline at end of file diff --git a/source/views/view_pattern.cpp b/source/views/view_pattern.cpp index b1496f918..efdb09961 100644 --- a/source/views/view_pattern.cpp +++ b/source/views/view_pattern.cpp @@ -237,26 +237,38 @@ namespace hex { } void ViewPattern::parsePattern(char *buffer) { - hex::lang::Preprocessor preprocessor; - hex::lang::Lexer lexer; - hex::lang::Parser parser; - hex::lang::Validator validator; - hex::lang::Evaluator evaluator(this->m_dataProvider); - this->clearPatternData(); this->postEvent(Events::PatternChanged); + hex::lang::Preprocessor preprocessor; + std::endian dataEndianess = std::endian::native; + + preprocessor.addPragmaHandler("endian", [&dataEndianess](std::string value) { + if (value == "big") { + dataEndianess = std::endian::big; + return true; + } else if (value == "little") { + dataEndianess = std::endian::little; + return true; + } else if (value == "native") { + dataEndianess = std::endian::native; + return true; + } else + return false; + }); preprocessor.addDefaultPragramHandlers(); auto [preprocessingResult, preprocesedCode] = preprocessor.preprocess(buffer); if (preprocessingResult.failed()) return; + hex::lang::Lexer lexer; auto [lexResult, tokens] = lexer.lex(preprocesedCode); if (lexResult.failed()) { return; } + hex::lang::Parser parser; auto [parseResult, ast] = parser.parse(tokens); if (parseResult.failed()) { return; @@ -264,11 +276,13 @@ namespace hex { hex::ScopeExit deleteAst([&ast]{ for(auto &node : ast) delete node; }); + hex::lang::Validator validator; auto validatorResult = validator.validate(ast); if (!validatorResult) { return; } + hex::lang::Evaluator evaluator(this->m_dataProvider, dataEndianess); auto [evaluateResult, patternData] = evaluator.evaluate(ast); if (evaluateResult.failed()) { return;