Merge remote-tracking branch 'origin/GP-5262_AutoKilledByCall'

This commit is contained in:
Ryan Kurtz 2025-01-14 13:33:34 -05:00
commit 2589aae3a4
5 changed files with 49 additions and 38 deletions

View file

@ -586,6 +586,7 @@ ParamListStandard::ParamListStandard(const ParamListStandard &op2)
spacebase = op2.spacebase; spacebase = op2.spacebase;
maxdelay = op2.maxdelay; maxdelay = op2.maxdelay;
thisbeforeret = op2.thisbeforeret; thisbeforeret = op2.thisbeforeret;
autoKilledByCall = op2.autoKilledByCall;
resourceStart = op2.resourceStart; resourceStart = op2.resourceStart;
for(list<ModelRule>::const_iterator iter=op2.modelRules.begin();iter!=op2.modelRules.end();++iter) { for(list<ModelRule>::const_iterator iter=op2.modelRules.begin();iter!=op2.modelRules.end();++iter) {
modelRules.emplace_back(*iter,&op2); modelRules.emplace_back(*iter,&op2);
@ -1198,11 +1199,10 @@ void ParamListStandard::populateResolver(void)
/// \param effectlist holds any passed back effect records /// \param effectlist holds any passed back effect records
/// \param groupid is the group to which the new ParamEntry is assigned /// \param groupid is the group to which the new ParamEntry is assigned
/// \param normalstack is \b true if the parameters should be allocated from the front of the range /// \param normalstack is \b true if the parameters should be allocated from the front of the range
/// \param autokill is \b true if parameters are automatically added to the killedbycall list
/// \param splitFloat is \b true if floating-point parameters are in their own resource section /// \param splitFloat is \b true if floating-point parameters are in their own resource section
/// \param grouped is \b true if the new ParamEntry is grouped with other entries /// \param grouped is \b true if the new ParamEntry is grouped with other entries
void ParamListStandard::parsePentry(Decoder &decoder,vector<EffectRecord> &effectlist, void ParamListStandard::parsePentry(Decoder &decoder,vector<EffectRecord> &effectlist,
int4 groupid,bool normalstack,bool autokill,bool splitFloat,bool grouped) int4 groupid,bool normalstack,bool splitFloat,bool grouped)
{ {
type_class lastClass = TYPECLASS_CLASS4; type_class lastClass = TYPECLASS_CLASS4;
if (!entry.empty()) { if (!entry.empty()) {
@ -1221,7 +1221,7 @@ void ParamListStandard::parsePentry(Decoder &decoder,vector<EffectRecord> &effec
AddrSpace *spc = entry.back().getSpace(); AddrSpace *spc = entry.back().getSpace();
if (spc->getType() == IPTR_SPACEBASE) if (spc->getType() == IPTR_SPACEBASE)
spacebase = spc; spacebase = spc;
else if (autokill) // If a register parameter AND we automatically generate killedbycall else if (autoKilledByCall) // If a register parameter AND we automatically generate killedbycall
effectlist.push_back(EffectRecord(entry.back(),EffectRecord::killedbycall)); effectlist.push_back(EffectRecord(entry.back(),EffectRecord::killedbycall));
int4 maxgroup = entry.back().getAllGroups().back() + 1; int4 maxgroup = entry.back().getAllGroups().back() + 1;
@ -1236,17 +1236,16 @@ void ParamListStandard::parsePentry(Decoder &decoder,vector<EffectRecord> &effec
/// \param effectlist holds any passed back effect records /// \param effectlist holds any passed back effect records
/// \param groupid is the group to which all ParamEntry elements are assigned /// \param groupid is the group to which all ParamEntry elements are assigned
/// \param normalstack is \b true if the parameters should be allocated from the front of the range /// \param normalstack is \b true if the parameters should be allocated from the front of the range
/// \param autokill is \b true if parameters are automatically added to the killedbycall list
/// \param splitFloat is \b true if floating-point parameters are in their own resource section /// \param splitFloat is \b true if floating-point parameters are in their own resource section
void ParamListStandard::parseGroup(Decoder &decoder,vector<EffectRecord> &effectlist, void ParamListStandard::parseGroup(Decoder &decoder,vector<EffectRecord> &effectlist,
int4 groupid,bool normalstack,bool autokill,bool splitFloat) int4 groupid,bool normalstack,bool splitFloat)
{ {
int4 basegroup = numgroup; int4 basegroup = numgroup;
ParamEntry *previous1 = (ParamEntry *)0; ParamEntry *previous1 = (ParamEntry *)0;
ParamEntry *previous2 = (ParamEntry *)0; ParamEntry *previous2 = (ParamEntry *)0;
uint4 elemId = decoder.openElement(ELEM_GROUP); uint4 elemId = decoder.openElement(ELEM_GROUP);
while(decoder.peekElement() != 0) { while(decoder.peekElement() != 0) {
parsePentry(decoder, effectlist, basegroup, normalstack, autokill, splitFloat, true); parsePentry(decoder, effectlist, basegroup, normalstack, splitFloat, true);
ParamEntry &pentry( entry.back() ); ParamEntry &pentry( entry.back() );
if (pentry.getSpace()->getType() == IPTR_JOIN) if (pentry.getSpace()->getType() == IPTR_JOIN)
throw LowlevelError("<pentry> in the join space not allowed in <group> tag"); throw LowlevelError("<pentry> in the join space not allowed in <group> tag");
@ -1434,8 +1433,8 @@ void ParamListStandard::decode(Decoder &decoder,vector<EffectRecord> &effectlist
spacebase = (AddrSpace *)0; spacebase = (AddrSpace *)0;
int4 pointermax = 0; int4 pointermax = 0;
thisbeforeret = false; thisbeforeret = false;
autoKilledByCall = false;
bool splitFloat = true; // True if we should split FLOAT entries into their own resource section bool splitFloat = true; // True if we should split FLOAT entries into their own resource section
bool autokilledbycall = false;
uint4 elemId = decoder.openElement(); uint4 elemId = decoder.openElement();
for(;;) { for(;;) {
uint4 attribId = decoder.getNextAttributeId(); uint4 attribId = decoder.getNextAttributeId();
@ -1447,7 +1446,7 @@ void ParamListStandard::decode(Decoder &decoder,vector<EffectRecord> &effectlist
thisbeforeret = decoder.readBool(); thisbeforeret = decoder.readBool();
} }
else if (attribId == ATTRIB_KILLEDBYCALL) { else if (attribId == ATTRIB_KILLEDBYCALL) {
autokilledbycall = decoder.readBool(); autoKilledByCall = decoder.readBool();
} }
else if (attribId == ATTRIB_SEPARATEFLOAT) { else if (attribId == ATTRIB_SEPARATEFLOAT) {
splitFloat = decoder.readBool(); splitFloat = decoder.readBool();
@ -1457,10 +1456,10 @@ void ParamListStandard::decode(Decoder &decoder,vector<EffectRecord> &effectlist
uint4 subId = decoder.peekElement(); uint4 subId = decoder.peekElement();
if (subId == 0) break; if (subId == 0) break;
if (subId == ELEM_PENTRY) { if (subId == ELEM_PENTRY) {
parsePentry(decoder, effectlist, numgroup, normalstack, autokilledbycall, splitFloat, false); parsePentry(decoder, effectlist, numgroup, normalstack, splitFloat, false);
} }
else if (subId == ELEM_GROUP) { else if (subId == ELEM_GROUP) {
parseGroup(decoder, effectlist, numgroup, normalstack, autokilledbycall, splitFloat); parseGroup(decoder, effectlist, numgroup, normalstack, splitFloat);
} }
else if (subId == ELEM_RULE) { else if (subId == ELEM_RULE) {
break; break;
@ -1599,6 +1598,8 @@ void ParamListStandardOut::initialize(void)
break; break;
} }
} }
if (useFillinFallback)
autoKilledByCall = true; // Legacy behavior if there are no rules
} }
/// \brief Find the return value storage using the older \e fallback method /// \brief Find the return value storage using the older \e fallback method
@ -3778,8 +3779,8 @@ void FuncProto::setModel(ProtoModel *m)
flags |= has_thisptr; flags |= has_thisptr;
if (m->isConstructor()) if (m->isConstructor())
flags |= is_constructor; flags |= is_constructor;
if (m->isAutoKillByCall()) if (m->isAutoKilledByCall())
flags |= auto_killbycall; flags |= auto_killedbycall;
model = m; model = m;
} }
else { else {
@ -4557,13 +4558,13 @@ void FuncProto::printRaw(const string &funcname,ostream &s) const
/// This assumes the storage location has already been determined to be contained /// This assumes the storage location has already been determined to be contained
/// in standard return value location. /// in standard return value location.
/// \return \b true if the location should be considered killed by call /// \return \b true if the location should be considered killed by call
bool FuncProto::isAutoKillByCall(void) const bool FuncProto::isAutoKilledByCall(void) const
{ {
if ((flags & auto_killbycall)!=0) if ((flags & auto_killedbycall)!=0)
return true; // The ProtoModel always does killbycall return true; // The ProtoModel always does killedbycall
if (isOutputLocked()) if (isOutputLocked())
return true; // A locked output location is killbycall by definition return true; // A locked output location is killedbycall by definition
return false; return false;
} }

View file

@ -560,8 +560,8 @@ public:
/// \brief Return \b true if ParamEntry locations should automatically be considered killed by call /// \brief Return \b true if ParamEntry locations should automatically be considered killed by call
/// ///
/// \return \b true if automatically assume killbycall /// \return \b true if automatically assume \e killedbycall
virtual bool isAutoKillByCall(void) const=0; virtual bool isAutoKilledByCall(void) const=0;
/// \brief Restore the model from an \<input> or \<output> element in the stream /// \brief Restore the model from an \<input> or \<output> element in the stream
/// ///
@ -587,6 +587,7 @@ protected:
int4 numgroup; ///< Number of \e groups in this parameter convention int4 numgroup; ///< Number of \e groups in this parameter convention
int4 maxdelay; ///< Maximum heritage delay across all parameters int4 maxdelay; ///< Maximum heritage delay across all parameters
bool thisbeforeret; ///< Does a \b this parameter come before a hidden return parameter bool thisbeforeret; ///< Does a \b this parameter come before a hidden return parameter
bool autoKilledByCall; ///< Are storage locations in \b this list automatically \e killed \e by \e call
vector<int4> resourceStart; ///< The starting group for each resource section vector<int4> resourceStart; ///< The starting group for each resource section
list<ParamEntry> entry; ///< The ordered list of parameter entries list<ParamEntry> entry; ///< The ordered list of parameter entries
vector<ParamEntryResolver *> resolverMap; ///< Map from space id to resolver vector<ParamEntryResolver *> resolverMap; ///< Map from space id to resolver
@ -605,9 +606,9 @@ protected:
void addResolverRange(AddrSpace *spc,uintb first,uintb last,ParamEntry *paramEntry,int4 position); void addResolverRange(AddrSpace *spc,uintb first,uintb last,ParamEntry *paramEntry,int4 position);
void populateResolver(void); ///< Build the ParamEntry resolver maps void populateResolver(void); ///< Build the ParamEntry resolver maps
void parsePentry(Decoder &decoder,vector<EffectRecord> &effectlist, void parsePentry(Decoder &decoder,vector<EffectRecord> &effectlist,
int4 groupid,bool normalstack,bool autokill,bool splitFloat,bool grouped); int4 groupid,bool normalstack,bool splitFloat,bool grouped);
void parseGroup(Decoder &decoder,vector<EffectRecord> &effectlist, void parseGroup(Decoder &decoder,vector<EffectRecord> &effectlist,
int4 groupid,bool normalstack,bool autokill,bool splitFloat); int4 groupid,bool normalstack,bool splitFloat);
public: public:
ParamListStandard(void) {} ///< Construct for use with decode() ParamListStandard(void) {} ///< Construct for use with decode()
ParamListStandard(const ParamListStandard &op2); ///< Copy constructor ParamListStandard(const ParamListStandard &op2); ///< Copy constructor
@ -634,7 +635,7 @@ public:
virtual bool isThisBeforeRetPointer(void) const { return thisbeforeret; } virtual bool isThisBeforeRetPointer(void) const { return thisbeforeret; }
virtual void getRangeList(AddrSpace *spc,RangeList &res) const; virtual void getRangeList(AddrSpace *spc,RangeList &res) const;
virtual int4 getMaxDelay(void) const { return maxdelay; } virtual int4 getMaxDelay(void) const { return maxdelay; }
virtual bool isAutoKillByCall(void) const { return false; } virtual bool isAutoKilledByCall(void) const { return autoKilledByCall; }
virtual void decode(Decoder &decoder,vector<EffectRecord> &effectlist,bool normalstack); virtual void decode(Decoder &decoder,vector<EffectRecord> &effectlist,bool normalstack);
virtual ParamList *clone(void) const; virtual ParamList *clone(void) const;
}; };
@ -659,7 +660,6 @@ public:
virtual void assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<ParameterPieces> &res) const; virtual void assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector<ParameterPieces> &res) const;
virtual void fillinMap(ParamActive *active) const; virtual void fillinMap(ParamActive *active) const;
virtual bool possibleParam(const Address &loc,int4 size) const; virtual bool possibleParam(const Address &loc,int4 size) const;
virtual bool isAutoKillByCall(void) const { return useFillinFallback; }
virtual void decode(Decoder &decoder,vector<EffectRecord> &effectlist,bool normalstack); virtual void decode(Decoder &decoder,vector<EffectRecord> &effectlist,bool normalstack);
virtual ParamList *clone(void) const; virtual ParamList *clone(void) const;
}; };
@ -995,7 +995,7 @@ public:
/// \brief Does \b this model automatically consider potential output locations as killed by call /// \brief Does \b this model automatically consider potential output locations as killed by call
/// ///
/// \return \b true if output locations should be considered killed by call /// \return \b true if output locations should be considered killed by call
bool isAutoKillByCall(void) const { return output->isAutoKillByCall(); } bool isAutoKilledByCall(void) const { return output->isAutoKilledByCall(); }
/// \brief Is \b this a merged prototype model /// \brief Is \b this a merged prototype model
/// ///
@ -1350,7 +1350,7 @@ class FuncProto {
is_destructor = 0x400, ///< Function is an (object-oriented) destructor is_destructor = 0x400, ///< Function is an (object-oriented) destructor
has_thisptr= 0x800, ///< Function is a method with a 'this' pointer as an argument has_thisptr= 0x800, ///< Function is a method with a 'this' pointer as an argument
is_override = 0x1000, ///< Set if \b this prototype is created to override a single call site is_override = 0x1000, ///< Set if \b this prototype is created to override a single call site
auto_killbycall = 0x2000 ///< Potential output storage should always be considered \e killed \e by \e call auto_killedbycall = 0x2000 ///< Potential output storage should always be considered \e killed \e by \e call
}; };
ProtoModel *model; ///< Model of for \b this prototype ProtoModel *model; ///< Model of for \b this prototype
ProtoStore *store; ///< Storage interface for parameters ProtoStore *store; ///< Storage interface for parameters
@ -1612,7 +1612,7 @@ public:
/// \return the active set of flags for \b this prototype /// \return the active set of flags for \b this prototype
uint4 getComparableFlags(void) const { return (flags & (dotdotdot | is_constructor | is_destructor | has_thisptr )); } uint4 getComparableFlags(void) const { return (flags & (dotdotdot | is_constructor | is_destructor | has_thisptr )); }
bool isAutoKillByCall(void) const; ///< Is a potential output automatically considered \e killed \e by \e call bool isAutoKilledByCall(void) const; ///< Is a potential output automatically considered \e killed \e by \e call
void encode(Encoder &encoder) const; void encode(Encoder &encoder) const;
void decode(Decoder &decoder,Architecture *glb); void decode(Decoder &decoder,Architecture *glb);

View file

@ -1470,7 +1470,7 @@ void Heritage::guardCalls(uint4 fl,const Address &addr,int4 size,vector<Varnode
ParamActive *active = fc->getActiveOutput(); ParamActive *active = fc->getActiveOutput();
int4 outputCharacter = fc->characterizeAsOutput(transAddr, size); int4 outputCharacter = fc->characterizeAsOutput(transAddr, size);
if (outputCharacter != ParamEntry::no_containment) { if (outputCharacter != ParamEntry::no_containment) {
if (effecttype != EffectRecord::killedbycall && fc->isAutoKillByCall()) if (effecttype != EffectRecord::killedbycall && fc->isAutoKilledByCall())
effecttype = EffectRecord::killedbycall; effecttype = EffectRecord::killedbycall;
if (outputCharacter == ParamEntry::contained_by) { if (outputCharacter == ParamEntry::contained_by) {
if (tryOutputOverlapGuard(fc, addr, transAddr, size, write)) if (tryOutputOverlapGuard(fc, addr, transAddr, size, write))

View file

@ -205,8 +205,8 @@ class VarargsFilter : public QualifierFilter {
int4 firstPos; ///< Start of range to match (offset relative to first variable arg) int4 firstPos; ///< Start of range to match (offset relative to first variable arg)
int4 lastPos; ///< End of range to match int4 lastPos; ///< End of range to match
public: public:
VarargsFilter(void) { firstPos = 0x80000000; lastPos = 0x7fffffff; } VarargsFilter(void) { firstPos = 0x80000000; lastPos = 0x7fffffff; } ///< Constructor for use with decode
VarargsFilter(int4 first,int4 last) { firstPos = first; lastPos = last; } VarargsFilter(int4 first,int4 last) { firstPos = first; lastPos = last; } ///< Constructor
virtual QualifierFilter *clone(void) const { return new VarargsFilter(firstPos,lastPos); } virtual QualifierFilter *clone(void) const { return new VarargsFilter(firstPos,lastPos); }
virtual bool filter(const PrototypePieces &proto,int4 pos) const; virtual bool filter(const PrototypePieces &proto,int4 pos) const;
virtual void decode(Decoder &decoder); virtual void decode(Decoder &decoder);

View file

@ -42,6 +42,7 @@ public class ParamListStandard implements ParamList {
protected int numgroup; // Number of "groups" in this parameter convention protected int numgroup; // Number of "groups" in this parameter convention
// protected int maxdelay; // protected int maxdelay;
protected boolean thisbeforeret; // Do hidden return pointers usurp the storage of the this pointer protected boolean thisbeforeret; // Do hidden return pointers usurp the storage of the this pointer
protected boolean autoKilledByCall; // Is storage in this list automatically "killed by call"
protected boolean splitMetatype; // Are metatyped entries in separate resource sections protected boolean splitMetatype; // Are metatyped entries in separate resource sections
// protected int[] resourceStart; // The starting group for each resource section // protected int[] resourceStart; // The starting group for each resource section
protected ParamEntry[] entry; protected ParamEntry[] entry;
@ -235,6 +236,7 @@ public class ParamListStandard implements ParamList {
if (thisbeforeret) { if (thisbeforeret) {
encoder.writeBool(ATTRIB_THISBEFORERETPOINTER, true); encoder.writeBool(ATTRIB_THISBEFORERETPOINTER, true);
} }
encoder.writeBool(ATTRIB_KILLEDBYCALL, autoKilledByCall);
if (isInput && !splitMetatype) { if (isInput && !splitMetatype) {
encoder.writeBool(ATTRIB_SEPARATEFLOAT, false); encoder.writeBool(ATTRIB_SEPARATEFLOAT, false);
} }
@ -298,7 +300,7 @@ public class ParamListStandard implements ParamList {
private void parseGroup(XmlPullParser parser, CompilerSpec cspec, ArrayList<ParamEntry> pe, private void parseGroup(XmlPullParser parser, CompilerSpec cspec, ArrayList<ParamEntry> pe,
int groupid, boolean splitFloat) throws XmlParseException { int groupid, boolean splitFloat) throws XmlParseException {
XmlElement el = parser.start("group"); XmlElement el = parser.start(ELEM_GROUP.name());
int basegroup = numgroup; int basegroup = numgroup;
int count = 0; int count = 0;
while (parser.peek().isStart()) { while (parser.peek().isStart()) {
@ -327,17 +329,22 @@ public class ParamListStandard implements ParamList {
spacebase = null; spacebase = null;
int pointermax = 0; int pointermax = 0;
thisbeforeret = false; thisbeforeret = false;
autoKilledByCall = false;
splitMetatype = true; splitMetatype = true;
XmlElement mainel = parser.start(); XmlElement mainel = parser.start();
String attribute = mainel.getAttribute("pointermax"); String attribute = mainel.getAttribute(ATTRIB_POINTERMAX.name());
if (attribute != null) { if (attribute != null) {
pointermax = SpecXmlUtils.decodeInt(attribute); pointermax = SpecXmlUtils.decodeInt(attribute);
} }
attribute = mainel.getAttribute("thisbeforeretpointer"); attribute = mainel.getAttribute(ATTRIB_THISBEFORERETPOINTER.name());
if (attribute != null) { if (attribute != null) {
thisbeforeret = SpecXmlUtils.decodeBoolean(attribute); thisbeforeret = SpecXmlUtils.decodeBoolean(attribute);
} }
attribute = mainel.getAttribute("separatefloat"); attribute = mainel.getAttribute(ATTRIB_KILLEDBYCALL.name());
if (attribute != null) {
autoKilledByCall = SpecXmlUtils.decodeBoolean(attribute);
}
attribute = mainel.getAttribute(ATTRIB_SEPARATEFLOAT.name());
if (attribute != null) { if (attribute != null) {
splitMetatype = SpecXmlUtils.decodeBoolean(attribute); splitMetatype = SpecXmlUtils.decodeBoolean(attribute);
} }
@ -347,13 +354,13 @@ public class ParamListStandard implements ParamList {
if (!el.isStart()) { if (!el.isStart()) {
break; break;
} }
if (el.getName().equals("pentry")) { if (el.getName().equals(ELEM_PENTRY.name())) {
parsePentry(parser, cspec, pe, numgroup, splitMetatype, false); parsePentry(parser, cspec, pe, numgroup, splitMetatype, false);
} }
else if (el.getName().equals("group")) { else if (el.getName().equals(ELEM_GROUP.name())) {
parseGroup(parser, cspec, pe, numgroup, splitMetatype); parseGroup(parser, cspec, pe, numgroup, splitMetatype);
} }
else if (el.getName().equals("rule")) { else if (el.getName().equals(ELEM_RULE.name())) {
break; break;
} }
} }
@ -366,7 +373,7 @@ public class ParamListStandard implements ParamList {
if (!subId.isStart()) { if (!subId.isStart()) {
break; break;
} }
if (subId.getName().equals("rule")) { if (subId.getName().equals(ELEM_RULE.name())) {
ModelRule rule = new ModelRule(); ModelRule rule = new ModelRule();
rule.restoreXml(parser, this); rule.restoreXml(parser, this);
rules.add(rule); rules.add(rule);
@ -482,6 +489,9 @@ public class ParamListStandard implements ParamList {
if (thisbeforeret != op2.thisbeforeret) { if (thisbeforeret != op2.thisbeforeret) {
return false; return false;
} }
if (autoKilledByCall != op2.autoKilledByCall) {
return false;
}
return true; return true;
} }