From f8ed89ee2c5659464713a225efba9e521f6957f2 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Mon, 16 Aug 2021 23:05:23 +0200 Subject: [PATCH] patterns: Allow bitfield fields to be accessed as like other members --- .../include/hex/lang/pattern_data.hpp | 102 +++++++++++++----- plugins/libimhex/source/lang/evaluator.cpp | 25 ++++- 2 files changed, 96 insertions(+), 31 deletions(-) diff --git a/plugins/libimhex/include/hex/lang/pattern_data.hpp b/plugins/libimhex/include/hex/lang/pattern_data.hpp index 649f07721..e89e3dffc 100644 --- a/plugins/libimhex/include/hex/lang/pattern_data.hpp +++ b/plugins/libimhex/include/hex/lang/pattern_data.hpp @@ -940,12 +940,77 @@ namespace hex::lang { std::vector> m_enumValues; }; + + class PatternDataBitfieldField : public PatternData { + public: + PatternDataBitfieldField(u64 offset, u8 bitOffset, u8 bitSize, u32 color = 0) + : m_bitOffset(bitOffset), m_bitSize(bitSize), PatternData(offset, 0, color) { + + } + + PatternData* clone() override { + return new PatternDataBitfieldField(*this); + } + + void createEntry(prv::Provider* &provider) override { + std::vector value(this->getSize(), 0); + provider->read(this->getOffset(), &value[0], value.size()); + + if (this->m_endian != std::endian::native) + std::reverse(value.begin(), value.end()); + + ImGui::TableNextRow(); + ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap); + ImGui::TableNextColumn(); + ImGui::Text("%s", this->getVariableName().c_str()); + ImGui::TableNextColumn(); + ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight())); + ImGui::TableNextColumn(); + ImGui::Text("0x%08llX : 0x%08llX", this->getOffset() + (this->m_bitOffset >> 3), this->getOffset() + ((this->m_bitOffset + this->m_bitSize) >> 3)); + ImGui::TableNextColumn(); + if (this->m_bitSize == 1) + ImGui::Text("%u bit", this->m_bitSize); + else + ImGui::Text("%u bits", this->m_bitSize); + ImGui::TableNextColumn(); + ImGui::TextColored(ImColor(0xFF9BC64D), "bits"); + ImGui::TableNextColumn(); + { + u128 fieldValue = 0; + std::memcpy(&fieldValue, value.data() + (this->m_bitOffset / 8), (this->m_bitSize / 8) + 1); + u64 maskedValue = hex::extract((this->m_bitOffset + this->m_bitSize) - 1 - ((this->m_bitOffset / 8) * 8), this->m_bitOffset - ((this->m_bitOffset / 8) * 8), fieldValue); + ImGui::Text("%llu (0x%llX)", maskedValue, maskedValue); + } + + } + + [[nodiscard]] std::string getFormattedName() const override { + return "bits"; + } + + [[nodiscard]] u8 getBitOffset() const { + return this->m_bitOffset; + } + + [[nodiscard]] u8 getBitSize() const { + return this->m_bitSize; + } + + private: + u8 m_bitOffset, m_bitSize; + }; + class PatternDataBitfield : public PatternData { public: PatternDataBitfield(u64 offset, size_t size, u32 color = 0) : PatternData(offset, size, color) { } + ~PatternDataBitfield() override { + for (auto field : this->m_fields) + delete field; + } + PatternData* clone() override { return new PatternDataBitfield(*this); } @@ -954,7 +1019,7 @@ namespace hex::lang { std::vector value(this->getSize(), 0); provider->read(this->getOffset(), &value[0], value.size()); - if (this->m_endian == std::endian::big) + if (this->m_endian != std::endian::native) std::reverse(value.begin(), value.end()); ImGui::TableNextRow(); @@ -978,31 +1043,9 @@ namespace hex::lang { ImGui::TextUnformatted(valueString.c_str()); if (open) { - u16 bitOffset = 0; - for (auto &[entryName, entrySize] : this->m_fields) { - ImGui::TableNextRow(); - ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap); - ImGui::TableNextColumn(); - ImGui::Text("%s", entryName.c_str()); - ImGui::TableNextColumn(); - ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight())); - ImGui::TableNextColumn(); - ImGui::Text("0x%08llX : 0x%08llX", this->getOffset() + (bitOffset >> 3), this->getOffset() + ((bitOffset + entrySize) >> 3)); - ImGui::TableNextColumn(); - if (entrySize == 1) - ImGui::Text("%llu bit", entrySize); - else - ImGui::Text("%llu bits", entrySize); - ImGui::TableNextColumn(); - ImGui::TextColored(ImColor(0xFF9BC64D), "bits"); - ImGui::TableNextColumn(); - { - u128 fieldValue = 0; - std::memcpy(&fieldValue, value.data() + (bitOffset / 8), (entrySize / 8) + 1); - ImGui::Text("%llX", hex::extract((bitOffset + entrySize) - 1 - ((bitOffset / 8) * 8), bitOffset - ((bitOffset / 8) * 8), fieldValue)); - } - bitOffset += entrySize; - } + + for (auto &field : this->m_fields) + field->draw(provider); ImGui::TreePop(); } @@ -1017,12 +1060,15 @@ namespace hex::lang { return this->m_fields; } - void setFields(const std::vector> &fields) { + void setFields(const std::vector &fields) { this->m_fields = fields; + + for (auto &field : this->m_fields) + field->setSize(this->getSize()); } private: - std::vector> m_fields; + std::vector m_fields; }; } \ No newline at end of file diff --git a/plugins/libimhex/source/lang/evaluator.cpp b/plugins/libimhex/source/lang/evaluator.cpp index fe561bc26..fe3a45519 100644 --- a/plugins/libimhex/source/lang/evaluator.cpp +++ b/plugins/libimhex/source/lang/evaluator.cpp @@ -56,6 +56,9 @@ namespace hex::lang { currMembers = structPattern->getMembers(); else if (auto unionPattern = dynamic_cast(currPattern); unionPattern != nullptr) currMembers = unionPattern->getMembers(); + else if (auto bitfieldPattern = dynamic_cast(currPattern); bitfieldPattern != nullptr) { + currMembers = bitfieldPattern->getFields(); + } else if (auto arrayPattern = dynamic_cast(currPattern); arrayPattern != nullptr) { currMembers = arrayPattern->getEntries(); continue; @@ -201,6 +204,20 @@ namespace hex::lang { case 16: return new ASTNodeIntegerLiteral(hex::changeEndianess(*reinterpret_cast(value), 16, enumPattern->getEndian())); default: this->getConsole().abortEvaluation("invalid rvalue size"); } + } else if (auto bitfieldFieldPattern = dynamic_cast(currPattern); bitfieldFieldPattern != nullptr) { + u8 value[bitfieldFieldPattern->getSize()]; + if (currPattern->isLocal()) + std::memcpy(value, this->m_localStack.data() + bitfieldFieldPattern->getOffset(), bitfieldFieldPattern->getSize()); + else + this->m_provider->read(bitfieldFieldPattern->getOffset(), value, bitfieldFieldPattern->getSize()); + + u8 bitOffset = bitfieldFieldPattern->getBitOffset(); + u8 bitSize = bitfieldFieldPattern->getBitSize(); + + u128 fieldValue = 0; + std::memcpy(&fieldValue, value + (bitOffset / 8), (bitSize / 8) + 1); + + return new ASTNodeIntegerLiteral(hex::extract((bitOffset + bitSize) - 1 - ((bitOffset / 8) * 8), bitOffset - ((bitOffset / 8) * 8), fieldValue)); } else this->getConsole().abortEvaluation("tried to use non-integer value in numeric expression"); } @@ -787,7 +804,7 @@ namespace hex::lang { } PatternData* Evaluator::evaluateBitfield(ASTNodeBitfield *node) { - std::vector> entryPatterns; + std::vector entryPatterns; auto startOffset = this->m_currOffset; size_t bits = 0; @@ -809,9 +826,11 @@ namespace hex::lang { if (fieldBits > 64 || fieldBits <= 0) this->getConsole().abortEvaluation("bitfield entry must occupy between 1 and 64 bits"); - bits += fieldBits; + auto fieldPattern = new PatternDataBitfieldField(startOffset, bits, fieldBits); + fieldPattern->setVariableName(name); + entryPatterns.push_back(fieldPattern); - entryPatterns.emplace_back(name, fieldBits); + bits += fieldBits; } size_t size = (bits + 7) / 8;