patterns: Allow bitfield fields to be accessed as like other members

This commit is contained in:
WerWolv 2021-08-16 23:05:23 +02:00
parent c75659db82
commit f8ed89ee2c
2 changed files with 96 additions and 31 deletions

View File

@ -940,12 +940,77 @@ namespace hex::lang {
std::vector<std::pair<Token::IntegerLiteral, std::string>> m_enumValues; std::vector<std::pair<Token::IntegerLiteral, std::string>> 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<u8> 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 { class PatternDataBitfield : public PatternData {
public: public:
PatternDataBitfield(u64 offset, size_t size, u32 color = 0) : PatternData(offset, size, color) { 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 { PatternData* clone() override {
return new PatternDataBitfield(*this); return new PatternDataBitfield(*this);
} }
@ -954,7 +1019,7 @@ namespace hex::lang {
std::vector<u8> value(this->getSize(), 0); std::vector<u8> value(this->getSize(), 0);
provider->read(this->getOffset(), &value[0], value.size()); 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()); std::reverse(value.begin(), value.end());
ImGui::TableNextRow(); ImGui::TableNextRow();
@ -978,31 +1043,9 @@ namespace hex::lang {
ImGui::TextUnformatted(valueString.c_str()); ImGui::TextUnformatted(valueString.c_str());
if (open) { if (open) {
u16 bitOffset = 0;
for (auto &[entryName, entrySize] : this->m_fields) { for (auto &field : this->m_fields)
ImGui::TableNextRow(); field->draw(provider);
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;
}
ImGui::TreePop(); ImGui::TreePop();
} }
@ -1017,12 +1060,15 @@ namespace hex::lang {
return this->m_fields; return this->m_fields;
} }
void setFields(const std::vector<std::pair<std::string, size_t>> &fields) { void setFields(const std::vector<PatternData*> &fields) {
this->m_fields = fields; this->m_fields = fields;
for (auto &field : this->m_fields)
field->setSize(this->getSize());
} }
private: private:
std::vector<std::pair<std::string, size_t>> m_fields; std::vector<PatternData*> m_fields;
}; };
} }

View File

@ -56,6 +56,9 @@ namespace hex::lang {
currMembers = structPattern->getMembers(); currMembers = structPattern->getMembers();
else if (auto unionPattern = dynamic_cast<PatternDataUnion*>(currPattern); unionPattern != nullptr) else if (auto unionPattern = dynamic_cast<PatternDataUnion*>(currPattern); unionPattern != nullptr)
currMembers = unionPattern->getMembers(); currMembers = unionPattern->getMembers();
else if (auto bitfieldPattern = dynamic_cast<PatternDataBitfield*>(currPattern); bitfieldPattern != nullptr) {
currMembers = bitfieldPattern->getFields();
}
else if (auto arrayPattern = dynamic_cast<PatternDataArray*>(currPattern); arrayPattern != nullptr) { else if (auto arrayPattern = dynamic_cast<PatternDataArray*>(currPattern); arrayPattern != nullptr) {
currMembers = arrayPattern->getEntries(); currMembers = arrayPattern->getEntries();
continue; continue;
@ -201,6 +204,20 @@ namespace hex::lang {
case 16: return new ASTNodeIntegerLiteral(hex::changeEndianess(*reinterpret_cast<u128*>(value), 16, enumPattern->getEndian())); case 16: return new ASTNodeIntegerLiteral(hex::changeEndianess(*reinterpret_cast<u128*>(value), 16, enumPattern->getEndian()));
default: this->getConsole().abortEvaluation("invalid rvalue size"); default: this->getConsole().abortEvaluation("invalid rvalue size");
} }
} else if (auto bitfieldFieldPattern = dynamic_cast<PatternDataBitfieldField*>(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 } else
this->getConsole().abortEvaluation("tried to use non-integer value in numeric expression"); this->getConsole().abortEvaluation("tried to use non-integer value in numeric expression");
} }
@ -787,7 +804,7 @@ namespace hex::lang {
} }
PatternData* Evaluator::evaluateBitfield(ASTNodeBitfield *node) { PatternData* Evaluator::evaluateBitfield(ASTNodeBitfield *node) {
std::vector<std::pair<std::string, size_t>> entryPatterns; std::vector<PatternData*> entryPatterns;
auto startOffset = this->m_currOffset; auto startOffset = this->m_currOffset;
size_t bits = 0; size_t bits = 0;
@ -809,9 +826,11 @@ namespace hex::lang {
if (fieldBits > 64 || fieldBits <= 0) if (fieldBits > 64 || fieldBits <= 0)
this->getConsole().abortEvaluation("bitfield entry must occupy between 1 and 64 bits"); 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; size_t size = (bits + 7) / 8;