From 021c5b7af356b206629f831d7aa8d4d09774c848 Mon Sep 17 00:00:00 2001 From: caheckman <48068198+caheckman@users.noreply.github.com> Date: Wed, 3 Jan 2024 00:00:01 +0000 Subject: [PATCH] GP-4169 Adjustments to extractPrimitives --- .../src/decompile/cpp/modelrules.cc | 39 +++++++++---------- .../src/decompile/cpp/modelrules.hh | 2 +- .../program/model/lang/ParamListStandard.java | 15 ++++++- .../model/lang/protorules/DatatypeFilter.java | 39 +++++++++---------- .../lang/protorules/HomogeneousAggregate.java | 2 +- .../lang/protorules/MultiMemberAssign.java | 2 +- 6 files changed, 55 insertions(+), 44 deletions(-) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.cc index 9f87ae78da..903c4739f2 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.cc @@ -33,20 +33,20 @@ ElementId ELEM_JOIN_PER_PRIMITIVE = ElementId("join_per_primitive",283); /// \brief Extract an ordered list of primitive data-types making up the given data-type /// /// The primitive data-types are passed back in an array. If the given data-type is already -/// primitive, it is passed back as is. Otherwise if it is composite, its components are recursively -/// listed. If a filler data-type is provided, it is used to fill \e holes in structures. If -/// a maximum number of extracted primitives is exceeded, or if no filler is provided and a hole -/// is encountered, or if a non-primitive non-composite data-type is encountered, \b false is returned. +/// primitive, it is passed back as is. Otherwise if it is composite, its components are +/// recursively listed. If a maximum number of extracted primitives is exceeded, or if the +/// primitives are not properly aligned, or if a non-primitive non-composite data-type is +/// encountered, false is returned. /// \param dt is the given data-type to extract primitives from /// \param max is the maximum number of primitives to extract before giving up -/// \param filler is the data-type to use as filler (or null) /// \param res will hold the list of primitives /// \return \b true if all primitives were extracted -bool DatatypeFilter::extractPrimitives(Datatype *dt,int4 max,Datatype *filler,vector &res) +bool DatatypeFilter::extractPrimitives(Datatype *dt,int4 max,vector &res) { switch(dt->getMetatype()) { case TYPE_UNKNOWN: + return false; // Do not consider undefined data-types as primitive case TYPE_INT: case TYPE_UINT: case TYPE_BOOL: @@ -63,7 +63,7 @@ bool DatatypeFilter::extractPrimitives(Datatype *dt,int4 max,Datatype *filler,ve int4 numEls = ((TypeArray *)dt)->numElements(); Datatype *base = ((TypeArray *)dt)->getBase(); for(int4 i=0;i::const_iterator enditer = structPtr->endField(); for(vector::const_iterator iter=structPtr->beginField();iter!=enditer;++iter) { + Datatype *compDt = (*iter).type; int4 nextOff = (*iter).offset; - if (nextOff > curOff) { - if (filler == (Datatype *)0) - return false; - while(curOff < nextOff) { - if (res.size() >= max) - return false; - res.push_back(filler); - curOff += filler->getSize(); - } + int4 align = dt->getAlignment(); + int4 rem = curOff % align; + if (rem != 0) { + curOff += (align - rem); } - if (!extractPrimitives((*iter).type,max,filler,res)) + if (curOff != nextOff) { + return false; + } + curOff = nextOff + compDt->getAlignSize(); + if (!extractPrimitives(compDt,max,res)) return false; - curOff += (*iter).type->getSize(); } return true; } @@ -198,7 +197,7 @@ bool HomogeneousAggregate::filter(Datatype *dt) const if (meta != TYPE_ARRAY && meta != TYPE_STRUCT) return false; vector res; - if (!extractPrimitives(dt, 4, (Datatype *)0, res)) + if (!extractPrimitives(dt, 4, res) || res.empty()) return false; Datatype *base = res[0]; if (base->getMetatype() != metaType) @@ -657,7 +656,7 @@ uint4 MultiMemberAssign::assignAddress(Datatype *dt,const PrototypePieces &proto vector tmpStatus = status; vector pieces; vector primitives; - if (!DatatypeFilter::extractPrimitives(dt,16,(Datatype *)0,primitives)) + if (!DatatypeFilter::extractPrimitives(dt,16,primitives) || primitives.empty()) return fail; ParameterPieces param; for(int4 i=0;i &res); + static bool extractPrimitives(Datatype *dt,int4 max,vector &res); static DatatypeFilter *decodeFilter(Decoder &decoder); ///< Instantiate a filter from the given stream }; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandard.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandard.java index a3a70cca37..32c9af05e3 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandard.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandard.java @@ -130,6 +130,9 @@ public class ParamListStandard implements ParamList { int[] status, ParameterPieces res) { + if (dt.isZeroLength()) { + return AssignAction.FAIL; + } for (ModelRule modelRule : modelRules) { int responseCode = modelRule.assignAddress(dt, proto, pos, dtManager, status, res); if (responseCode != AssignAction.FAIL) { @@ -178,8 +181,18 @@ public class ParamListStandard implements ParamList { } for (int i = 0; i < proto.intypes.size(); ++i) { ParameterPieces store = new ParameterPieces(); - assignAddress(proto.intypes.get(i), proto, i, dtManager, status, store); res.add(store); + int resCode = assignAddress(proto.intypes.get(i), proto, i, dtManager, status, store); + if (resCode == AssignAction.FAIL) { + // Do not continue to assign after first failure + ++i; + while (i < proto.intypes.size()) { + store = new ParameterPieces(); // Fill out with UNASSIGNED pieces + res.add(store); + ++i; + } + return; + } } } 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 11c792f302..ecb29b93dc 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 @@ -70,24 +70,23 @@ public interface DatatypeFilter { * Extract an ordered list of primitive data-types making up the given data-type * * The primitive data-types are passed back in an ArrayList. If the given data-type is already - * primitive, it is passed back as is. Otherwise if it is composite, its components are recursively - * listed. If a filler data-type is provided, it is used to fill holes in structures. If - * a maximum number of extracted primitives is exceeded, or if no filler is provided and a hole - * is encountered, or if a non-primitive non-composite data-type is encountered, false is returned. + * primitive, it is passed back as is. Otherwise if it is composite, its components are + * recursively listed. If a maximum number of extracted primitives is exceeded, or if the + * primitives are not properly aligned, or if a non-primitive non-composite data-type is + * encountered, false is returned. * @param dt is the given data-type to extract primitives from * @param max is the maximum number of primitives to extract before giving up - * @param filler is the data-type to use as filler (or null) * @param res will hold the list of primitives * @return true if all primitives were extracted */ - public static boolean extractPrimitives(DataType dt, int max, DataType filler, - ArrayList res) { + public static boolean extractPrimitives(DataType dt, int max, ArrayList res) { if (dt instanceof TypeDef) { dt = ((TypeDef) dt).getBaseDataType(); } int metaType = PcodeDataTypeManager.getMetatype(dt); switch (metaType) { case PcodeDataTypeManager.TYPE_UNKNOWN: + return false; // Do not consider undefined data-types as primitive case PcodeDataTypeManager.TYPE_INT: case PcodeDataTypeManager.TYPE_UINT: case PcodeDataTypeManager.TYPE_BOOL: @@ -104,7 +103,7 @@ public interface DatatypeFilter { int numEls = ((Array) dt).getNumElements(); DataType base = ((Array) dt).getDataType(); for (int i = 0; i < numEls; ++i) { - if (!extractPrimitives(base, max, filler, res)) { + if (!extractPrimitives(base, max, res)) { return false; } } @@ -116,26 +115,26 @@ public interface DatatypeFilter { return false; } Structure structPtr = (Structure) dt; + boolean isPacked = structPtr.isPackingEnabled(); int curOff = 0; DataTypeComponent[] components = structPtr.getDefinedComponents(); for (DataTypeComponent component : components) { - int nextOff = component.getOffset(); - if (nextOff > curOff) { - if (filler == null) { + DataType compDT = component.getDataType(); + if (!isPacked) { + int nextOff = component.getOffset(); + int align = dt.getAlignment(); + int rem = curOff % align; + if (rem != 0) { + curOff += (align - rem); + } + if (curOff != nextOff) { return false; } - while (curOff < nextOff) { - if (res.size() >= max) { - return false; - } - res.add(filler); - curOff += filler.getLength(); - } + curOff = nextOff + compDT.getAlignedLength(); } - if (!extractPrimitives(component.getDataType(), max, filler, res)) { + if (!extractPrimitives(compDT, max, res)) { return false; } - curOff += component.getDataType().getLength(); } return true; } 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 5290a885c9..d114fd5717 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 @@ -68,7 +68,7 @@ public class HomogeneousAggregate extends SizeRestrictedFilter { return false; } ArrayList res = new ArrayList<>(); - if (!DatatypeFilter.extractPrimitives(dt, MAX_PRIMITIVES, null, res)) { + if (!DatatypeFilter.extractPrimitives(dt, MAX_PRIMITIVES, res) || res.isEmpty()) { return false; } DataType base = res.get(0); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/MultiMemberAssign.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/MultiMemberAssign.java index b9056f526a..30bf32a66d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/MultiMemberAssign.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/MultiMemberAssign.java @@ -78,7 +78,7 @@ public class MultiMemberAssign extends AssignAction { ArrayList pieces = new ArrayList<>(); ParameterPieces param = new ParameterPieces(); ArrayList primitives = new ArrayList<>(); - if (!DatatypeFilter.extractPrimitives(dt, 16, null, primitives)) { + if (!DatatypeFilter.extractPrimitives(dt, 16, primitives) || primitives.isEmpty()) { return FAIL; } for (int i = 0; i < primitives.size(); ++i) {