From 3067d3e61f98d195060be8c2ee65922d16bd29f6 Mon Sep 17 00:00:00 2001 From: ghintern Date: Mon, 14 Jul 2025 17:21:02 +0000 Subject: [PATCH] GP-5367: Filter by max_primitives on homogeneous aggregate types in cspec --- .../Decompiler/src/decompile/cpp/marshal.cc | 3 +- .../src/decompile/cpp/modelrules.cc | 28 +++++++++++--- .../src/decompile/cpp/modelrules.hh | 4 +- .../data/languages/compiler_spec.rxg | 1 + .../model/lang/protorules/DatatypeFilter.java | 10 ++--- .../lang/protorules/HomogeneousAggregate.java | 37 ++++++++++++++++--- .../program/model/pcode/AttributeId.java | 4 +- 7 files changed, 67 insertions(+), 20 deletions(-) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc index 3610a7da36..d6cea451eb 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc @@ -1254,7 +1254,8 @@ AttributeId ATTRIB_WORDSIZE = AttributeId("wordsize",26); AttributeId ATTRIB_STORAGE = AttributeId("storage",149); AttributeId ATTRIB_STACKSPILL = AttributeId("stackspill",150); -AttributeId ATTRIB_UNKNOWN = AttributeId("XMLunknown",152); // Number serves as next open index +AttributeId ATTRIB_UNKNOWN = AttributeId("XMLunknown",154); // Number serves as next open index + ElementId ELEM_DATA = ElementId("data",1); ElementId ELEM_INPUT = ElementId("input",2); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.cc index f93b95061e..96b543531e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.cc @@ -19,6 +19,7 @@ namespace ghidra { AttributeId ATTRIB_SIZES = AttributeId("sizes",151); +AttributeId ATTRIB_MAX_PRIMITIVES = AttributeId("maxprimitives", 153); ElementId ELEM_DATATYPE = ElementId("datatype",273); ElementId ELEM_CONSUME = ElementId("consume",274); @@ -224,9 +225,9 @@ bool PrimitiveExtractor::extract(Datatype *dt,int4 max,int4 offset) if (!extract(compDt,max,curOff)) return false; expectedOff = curOff + compDt->getAlignSize(); - } + } return true; -} +} /// \param dt is data-type extract from /// \param unionIllegal is \b true if unions encountered during extraction are considered illegal @@ -385,11 +386,11 @@ HomogeneousAggregate::HomogeneousAggregate(type_metatype meta) { metaType = meta; - maxPrimitives = 2; + maxPrimitives = 4; } -HomogeneousAggregate::HomogeneousAggregate(type_metatype meta,int4 maxPrim,int4 min,int4 max) - : SizeRestrictedFilter(min,max) +HomogeneousAggregate::HomogeneousAggregate(type_metatype meta,int4 maxPrim,int4 minSize,int4 maxSize) + : SizeRestrictedFilter(minSize, maxSize) { metaType = meta; maxPrimitives = maxPrim; @@ -408,7 +409,7 @@ bool HomogeneousAggregate::filter(Datatype *dt) const type_metatype meta = dt->getMetatype(); if (meta != TYPE_ARRAY && meta != TYPE_STRUCT) return false; - PrimitiveExtractor primitives(dt,true,0,4); + PrimitiveExtractor primitives(dt,true,0,maxPrimitives); if (!primitives.isValid() || primitives.size() == 0 || primitives.containsUnknown() || !primitives.isAligned() || primitives.containsHoles()) return false; @@ -422,6 +423,21 @@ bool HomogeneousAggregate::filter(Datatype *dt) const return true; } +void HomogeneousAggregate::decode(Decoder &decoder) +{ + SizeRestrictedFilter::decode(decoder); + decoder.rewindAttributes(); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_MAX_PRIMITIVES) { + uint4 xmlMaxPrim = decoder.readUnsignedInteger(); + if (xmlMaxPrim > 0) maxPrimitives = xmlMaxPrim; + } + } + +} + /// If the next element is a qualifier filter, decode it from the stream and return it. /// Otherwise return null /// \param decoder is the given stream decoder diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.hh index cdc1847465..e581ecc41d 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.hh @@ -29,6 +29,7 @@ class ParamEntry; class ParamActive; extern AttributeId ATTRIB_SIZES; ///< Marshaling attribute "sizes" +extern AttributeId ATTRIB_MAX_PRIMITIVES; ///< Marshaling attribute "maxprimitives" extern ElementId ELEM_DATATYPE; ///< Marshaling element \ extern ElementId ELEM_CONSUME; ///< Marshaling element \ @@ -151,10 +152,11 @@ class HomogeneousAggregate : public SizeRestrictedFilter { int4 maxPrimitives; ///< Maximum number of primitives in the aggregate public: HomogeneousAggregate(type_metatype meta); ///< Constructor for use with decode() - HomogeneousAggregate(type_metatype meta,int4 maxPrim,int4 min,int4 max); ///< Constructor + HomogeneousAggregate(type_metatype meta,int4 maxPrim,int4 minSize,int4 maxSize); ///< Constructor HomogeneousAggregate(const HomogeneousAggregate &op2); ///< Copy constructor virtual DatatypeFilter *clone(void) const { return new HomogeneousAggregate(*this); } virtual bool filter(Datatype *dt) const; + virtual void decode(Decoder &decoder); }; /// \brief A filter on some aspect of a specific function prototype diff --git a/Ghidra/Framework/SoftwareModeling/data/languages/compiler_spec.rxg b/Ghidra/Framework/SoftwareModeling/data/languages/compiler_spec.rxg index fb8febbf93..37d7842e45 100644 --- a/Ghidra/Framework/SoftwareModeling/data/languages/compiler_spec.rxg +++ b/Ghidra/Framework/SoftwareModeling/data/languages/compiler_spec.rxg @@ -344,6 +344,7 @@ + diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/DatatypeFilter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/DatatypeFilter.java index e025023f54..f42241fe36 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/DatatypeFilter.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/DatatypeFilter.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -78,9 +78,9 @@ public interface DatatypeFilter { if (nm.equals(SizeRestrictedFilter.NAME)) { filter = new SizeRestrictedFilter(); } - else if (nm.equals(HomogeneousAggregate.NAME_FLOAT4)) { - filter = new HomogeneousAggregate(HomogeneousAggregate.NAME_FLOAT4, - PcodeDataTypeManager.TYPE_FLOAT, 4, 0, 0); + else if (nm.equals(HomogeneousAggregate.NAME_FLOAT)) { + filter = new HomogeneousAggregate(HomogeneousAggregate.NAME_FLOAT, + PcodeDataTypeManager.TYPE_FLOAT, HomogeneousAggregate.DEFAULT_MAX_PRIMITIVES, 0, 0); } else { // If no other name matches, assume this is a decompiler metatype diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/HomogeneousAggregate.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/HomogeneousAggregate.java index 81dc8ede0e..98158aa4fb 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/HomogeneousAggregate.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/HomogeneousAggregate.java @@ -19,10 +19,13 @@ import static ghidra.program.model.pcode.AttributeId.*; import static ghidra.program.model.pcode.ElementId.*; import java.io.IOException; +import java.util.Iterator; +import java.util.Map.Entry; import ghidra.program.model.data.DataType; import ghidra.program.model.pcode.Encoder; import ghidra.program.model.pcode.PcodeDataTypeManager; +import ghidra.util.xml.SpecXmlUtils; import ghidra.xml.*; /** @@ -31,8 +34,8 @@ import ghidra.xml.*; */ public class HomogeneousAggregate extends SizeRestrictedFilter { - public static final String NAME_FLOAT4 = "homogeneous-float-aggregate"; - public static final int MAX_PRIMITIVES = 4; // Maximum number of primitives in aggregate data-type + public static final String NAME_FLOAT = "homogeneous-float-aggregate"; + public static final int DEFAULT_MAX_PRIMITIVES = 4; // Maximum number of primitives in aggregate data-type private String name; private int metaType; // The expected meta-type private int maxPrimitives; // Maximum number of primitives in the aggregate @@ -45,11 +48,11 @@ public class HomogeneousAggregate extends SizeRestrictedFilter { public HomogeneousAggregate(String nm, int meta) { name = nm; metaType = meta; - maxPrimitives = 2; + maxPrimitives = DEFAULT_MAX_PRIMITIVES; } - public HomogeneousAggregate(String nm, int meta, int maxPrim, int min, int max) { - super(min, max); + public HomogeneousAggregate(String nm, int meta, int maxPrim, int minSize, int maxSize) { + super(minSize, maxSize); name = nm; metaType = meta; maxPrimitives = maxPrim; @@ -77,7 +80,7 @@ public class HomogeneousAggregate extends SizeRestrictedFilter { if (meta != PcodeDataTypeManager.TYPE_ARRAY && meta != PcodeDataTypeManager.TYPE_STRUCT) { return false; } - PrimitiveExtractor primitives = new PrimitiveExtractor(dt, true, 0, MAX_PRIMITIVES); + PrimitiveExtractor primitives = new PrimitiveExtractor(dt, true, 0, maxPrimitives); if (!primitives.isValid() || primitives.size() == 0 || primitives.containsUnknown() || !primitives.isAligned() || primitives.containsHoles()) { return false; @@ -95,6 +98,12 @@ public class HomogeneousAggregate extends SizeRestrictedFilter { return true; } + @Override + protected void encodeAttributes(Encoder encoder) throws IOException { + super.encodeAttributes(encoder); + encoder.writeUnsignedInteger(ATTRIB_MAX_PRIMITIVES, maxPrimitives); + } + @Override public void encode(Encoder encoder) throws IOException { encoder.openElement(ELEM_DATATYPE); @@ -103,6 +112,22 @@ public class HomogeneousAggregate extends SizeRestrictedFilter { encoder.closeElement(ELEM_DATATYPE); } + @Override + protected void restoreAttributesXml(XmlElement el) throws XmlParseException { + super.restoreAttributesXml(el); + Iterator> iter = el.getAttributes().entrySet().iterator(); + while (iter.hasNext()) { + Entry attrib = iter.next(); + String nm = attrib.getKey(); + if (nm.equals(ATTRIB_MAX_PRIMITIVES.name())) { + int xmlMaxPrim = SpecXmlUtils.decodeInt(attrib.getValue()); + if (xmlMaxPrim > 0) { + maxPrimitives = xmlMaxPrim; + } + } + } + } + @Override public void restoreXml(XmlPullParser parser) throws XmlParseException { XmlElement elem = parser.start(ELEM_DATATYPE.name()); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/AttributeId.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/AttributeId.java index 5944e0371c..a2eda1b9aa 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/AttributeId.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/AttributeId.java @@ -248,5 +248,7 @@ public record AttributeId(String name, int id) { public static final AttributeId ATTRIB_SIZES = new AttributeId("sizes", 151); public static final AttributeId ATTRIB_BACKFILL = new AttributeId("backfill", 152); - public static final AttributeId ATTRIB_UNKNOWN = new AttributeId("XMLunknown", 153); + public static final AttributeId ATTRIB_MAX_PRIMITIVES = new AttributeId("maxprimitives", 153); + + public static final AttributeId ATTRIB_UNKNOWN = new AttributeId("XMLunknown", 154); }