diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc index 3e9f310446..3ef7833055 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc @@ -586,6 +586,7 @@ ParamListStandard::ParamListStandard(const ParamListStandard &op2) spacebase = op2.spacebase; maxdelay = op2.maxdelay; thisbeforeret = op2.thisbeforeret; + autoKilledByCall = op2.autoKilledByCall; resourceStart = op2.resourceStart; for(list::const_iterator iter=op2.modelRules.begin();iter!=op2.modelRules.end();++iter) { modelRules.emplace_back(*iter,&op2); @@ -1198,11 +1199,10 @@ void ParamListStandard::populateResolver(void) /// \param effectlist holds any passed back effect records /// \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 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 grouped is \b true if the new ParamEntry is grouped with other entries void ParamListStandard::parsePentry(Decoder &decoder,vector &effectlist, - int4 groupid,bool normalstack,bool autokill,bool splitFloat,bool grouped) + int4 groupid,bool normalstack,bool splitFloat,bool grouped) { type_class lastClass = TYPECLASS_CLASS4; if (!entry.empty()) { @@ -1221,7 +1221,7 @@ void ParamListStandard::parsePentry(Decoder &decoder,vector &effec AddrSpace *spc = entry.back().getSpace(); if (spc->getType() == IPTR_SPACEBASE) 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)); int4 maxgroup = entry.back().getAllGroups().back() + 1; @@ -1236,17 +1236,16 @@ void ParamListStandard::parsePentry(Decoder &decoder,vector &effec /// \param effectlist holds any passed back effect records /// \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 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 void ParamListStandard::parseGroup(Decoder &decoder,vector &effectlist, - int4 groupid,bool normalstack,bool autokill,bool splitFloat) + int4 groupid,bool normalstack,bool splitFloat) { int4 basegroup = numgroup; ParamEntry *previous1 = (ParamEntry *)0; ParamEntry *previous2 = (ParamEntry *)0; uint4 elemId = decoder.openElement(ELEM_GROUP); while(decoder.peekElement() != 0) { - parsePentry(decoder, effectlist, basegroup, normalstack, autokill, splitFloat, true); + parsePentry(decoder, effectlist, basegroup, normalstack, splitFloat, true); ParamEntry &pentry( entry.back() ); if (pentry.getSpace()->getType() == IPTR_JOIN) throw LowlevelError(" in the join space not allowed in tag"); @@ -1434,8 +1433,8 @@ void ParamListStandard::decode(Decoder &decoder,vector &effectlist spacebase = (AddrSpace *)0; int4 pointermax = 0; thisbeforeret = false; + autoKilledByCall = false; bool splitFloat = true; // True if we should split FLOAT entries into their own resource section - bool autokilledbycall = false; uint4 elemId = decoder.openElement(); for(;;) { uint4 attribId = decoder.getNextAttributeId(); @@ -1447,7 +1446,7 @@ void ParamListStandard::decode(Decoder &decoder,vector &effectlist thisbeforeret = decoder.readBool(); } else if (attribId == ATTRIB_KILLEDBYCALL) { - autokilledbycall = decoder.readBool(); + autoKilledByCall = decoder.readBool(); } else if (attribId == ATTRIB_SEPARATEFLOAT) { splitFloat = decoder.readBool(); @@ -1457,10 +1456,10 @@ void ParamListStandard::decode(Decoder &decoder,vector &effectlist uint4 subId = decoder.peekElement(); if (subId == 0) break; if (subId == ELEM_PENTRY) { - parsePentry(decoder, effectlist, numgroup, normalstack, autokilledbycall, splitFloat, false); + parsePentry(decoder, effectlist, numgroup, normalstack, splitFloat, false); } else if (subId == ELEM_GROUP) { - parseGroup(decoder, effectlist, numgroup, normalstack, autokilledbycall, splitFloat); + parseGroup(decoder, effectlist, numgroup, normalstack, splitFloat); } else if (subId == ELEM_RULE) { break; @@ -1599,6 +1598,8 @@ void ParamListStandardOut::initialize(void) break; } } + if (useFillinFallback) + autoKilledByCall = true; // Legacy behavior if there are no rules } /// \brief Find the return value storage using the older \e fallback method @@ -3778,8 +3779,8 @@ void FuncProto::setModel(ProtoModel *m) flags |= has_thisptr; if (m->isConstructor()) flags |= is_constructor; - if (m->isAutoKillByCall()) - flags |= auto_killbycall; + if (m->isAutoKilledByCall()) + flags |= auto_killedbycall; model = m; } 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 /// in standard return value location. /// \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) - return true; // The ProtoModel always does killbycall + if ((flags & auto_killedbycall)!=0) + return true; // The ProtoModel always does killedbycall if (isOutputLocked()) - return true; // A locked output location is killbycall by definition + return true; // A locked output location is killedbycall by definition return false; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh index 9509fe7f34..59c0c04098 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh @@ -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. @@ -560,8 +560,8 @@ public: /// \brief Return \b true if ParamEntry locations should automatically be considered killed by call /// - /// \return \b true if automatically assume killbycall - virtual bool isAutoKillByCall(void) const=0; + /// \return \b true if automatically assume \e killedbycall + virtual bool isAutoKilledByCall(void) const=0; /// \brief Restore the model from an \ or \ element in the stream /// @@ -587,6 +587,7 @@ protected: int4 numgroup; ///< Number of \e groups in this parameter convention int4 maxdelay; ///< Maximum heritage delay across all parameters 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 resourceStart; ///< The starting group for each resource section list entry; ///< The ordered list of parameter entries vector 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 populateResolver(void); ///< Build the ParamEntry resolver maps void parsePentry(Decoder &decoder,vector &effectlist, - int4 groupid,bool normalstack,bool autokill,bool splitFloat,bool grouped); + int4 groupid,bool normalstack,bool splitFloat,bool grouped); void parseGroup(Decoder &decoder,vector &effectlist, - int4 groupid,bool normalstack,bool autokill,bool splitFloat); + int4 groupid,bool normalstack,bool splitFloat); public: ParamListStandard(void) {} ///< Construct for use with decode() ParamListStandard(const ParamListStandard &op2); ///< Copy constructor @@ -634,7 +635,7 @@ public: virtual bool isThisBeforeRetPointer(void) const { return thisbeforeret; } virtual void getRangeList(AddrSpace *spc,RangeList &res) const; 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 &effectlist,bool normalstack); virtual ParamList *clone(void) const; }; @@ -659,7 +660,6 @@ public: virtual void assignMap(const PrototypePieces &proto,TypeFactory &typefactory,vector &res) const; virtual void fillinMap(ParamActive *active) const; virtual bool possibleParam(const Address &loc,int4 size) const; - virtual bool isAutoKillByCall(void) const { return useFillinFallback; } virtual void decode(Decoder &decoder,vector &effectlist,bool normalstack); virtual ParamList *clone(void) const; }; @@ -995,7 +995,7 @@ public: /// \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 - bool isAutoKillByCall(void) const { return output->isAutoKillByCall(); } + bool isAutoKilledByCall(void) const { return output->isAutoKilledByCall(); } /// \brief Is \b this a merged prototype model /// @@ -1350,7 +1350,7 @@ class FuncProto { is_destructor = 0x400, ///< Function is an (object-oriented) destructor 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 - 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 ProtoStore *store; ///< Storage interface for parameters @@ -1612,7 +1612,7 @@ public: /// \return the active set of flags for \b this prototype 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 decode(Decoder &decoder,Architecture *glb); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc index 3d05b1c221..d9d999d06e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc @@ -1470,7 +1470,7 @@ void Heritage::guardCalls(uint4 fl,const Address &addr,int4 size,vectorgetActiveOutput(); int4 outputCharacter = fc->characterizeAsOutput(transAddr, size); if (outputCharacter != ParamEntry::no_containment) { - if (effecttype != EffectRecord::killedbycall && fc->isAutoKillByCall()) + if (effecttype != EffectRecord::killedbycall && fc->isAutoKilledByCall()) effecttype = EffectRecord::killedbycall; if (outputCharacter == ParamEntry::contained_by) { if (tryOutputOverlapGuard(fc, addr, transAddr, size, write)) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.hh index 608892104e..bec9546fb5 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.hh @@ -205,8 +205,8 @@ class VarargsFilter : public QualifierFilter { int4 firstPos; ///< Start of range to match (offset relative to first variable arg) int4 lastPos; ///< End of range to match public: - VarargsFilter(void) { firstPos = 0x80000000; lastPos = 0x7fffffff; } - VarargsFilter(int4 first,int4 last) { firstPos = first; lastPos = last; } + VarargsFilter(void) { firstPos = 0x80000000; lastPos = 0x7fffffff; } ///< Constructor for use with decode + VarargsFilter(int4 first,int4 last) { firstPos = first; lastPos = last; } ///< Constructor virtual QualifierFilter *clone(void) const { return new VarargsFilter(firstPos,lastPos); } virtual bool filter(const PrototypePieces &proto,int4 pos) const; virtual void decode(Decoder &decoder); 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 7a4bcadd14..014b6a32b5 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 @@ -42,6 +42,7 @@ public class ParamListStandard implements ParamList { protected int numgroup; // Number of "groups" in this parameter convention // protected int maxdelay; 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 int[] resourceStart; // The starting group for each resource section protected ParamEntry[] entry; @@ -235,6 +236,7 @@ public class ParamListStandard implements ParamList { if (thisbeforeret) { encoder.writeBool(ATTRIB_THISBEFORERETPOINTER, true); } + encoder.writeBool(ATTRIB_KILLEDBYCALL, autoKilledByCall); if (isInput && !splitMetatype) { encoder.writeBool(ATTRIB_SEPARATEFLOAT, false); } @@ -298,7 +300,7 @@ public class ParamListStandard implements ParamList { private void parseGroup(XmlPullParser parser, CompilerSpec cspec, ArrayList pe, int groupid, boolean splitFloat) throws XmlParseException { - XmlElement el = parser.start("group"); + XmlElement el = parser.start(ELEM_GROUP.name()); int basegroup = numgroup; int count = 0; while (parser.peek().isStart()) { @@ -327,17 +329,22 @@ public class ParamListStandard implements ParamList { spacebase = null; int pointermax = 0; thisbeforeret = false; + autoKilledByCall = false; splitMetatype = true; XmlElement mainel = parser.start(); - String attribute = mainel.getAttribute("pointermax"); + String attribute = mainel.getAttribute(ATTRIB_POINTERMAX.name()); if (attribute != null) { pointermax = SpecXmlUtils.decodeInt(attribute); } - attribute = mainel.getAttribute("thisbeforeretpointer"); + attribute = mainel.getAttribute(ATTRIB_THISBEFORERETPOINTER.name()); if (attribute != null) { 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) { splitMetatype = SpecXmlUtils.decodeBoolean(attribute); } @@ -347,13 +354,13 @@ public class ParamListStandard implements ParamList { if (!el.isStart()) { break; } - if (el.getName().equals("pentry")) { + if (el.getName().equals(ELEM_PENTRY.name())) { 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); } - else if (el.getName().equals("rule")) { + else if (el.getName().equals(ELEM_RULE.name())) { break; } } @@ -366,7 +373,7 @@ public class ParamListStandard implements ParamList { if (!subId.isStart()) { break; } - if (subId.getName().equals("rule")) { + if (subId.getName().equals(ELEM_RULE.name())) { ModelRule rule = new ModelRule(); rule.restoreXml(parser, this); rules.add(rule); @@ -482,6 +489,9 @@ public class ParamListStandard implements ParamList { if (thisbeforeret != op2.thisbeforeret) { return false; } + if (autoKilledByCall != op2.autoKilledByCall) { + return false; + } return true; }