diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc index c1c8d4b739..779c952630 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc @@ -78,28 +78,20 @@ void ParamEntry::resolveJoin(list &curList) return; } joinrec = spaceid->getManager()->findJoin(addressbase); - int4 mingrp = 1000; - int4 maxgrp = -1; + groupSet.clear(); for(int4 i=0;inumPieces();++i) { const ParamEntry *entry = findEntryByStorage(curList, joinrec->getPiece(i)); if (entry != (const ParamEntry *)0) { - if (entry->group < mingrp) - mingrp = entry->group; - int4 max = entry->group + entry->groupsize; - if (max > maxgrp) - maxgrp = max; + groupSet.insert(groupSet.end(),entry->groupSet.begin(),entry->groupSet.end()); // For output , if the most signifigant part overlaps with an earlier // the least signifigant part is marked for extra checks, and vice versa. flags |= (i==0) ? extracheck_low : extracheck_high; } } - if (maxgrp < 0 || mingrp >= 1000) + if (groupSet.empty()) throw LowlevelError(" join must overlap at least one previous entry"); - group = mingrp; - groupsize = (maxgrp - mingrp); + sort(groupSet.begin(),groupSet.end()); flags |= overlapping; - if (groupsize > joinrec->numPieces()) - throw LowlevelError(" join must overlap sequential entries"); } /// Search for overlaps of \b this with any previous entry. If an overlap is discovered, @@ -111,9 +103,7 @@ void ParamEntry::resolveOverlap(list &curList) { if (joinrec != (JoinRecord *)0) return; // Overlaps with join records dealt with in resolveJoin - int4 grpsize = 0; - int4 mingrp = 1000; - int4 maxgrp = -1; + vector overlapSet; list::const_iterator iter,enditer; Address addr(spaceid,addressbase); enditer = curList.end(); @@ -123,12 +113,7 @@ void ParamEntry::resolveOverlap(list &curList) if (!entry.intersects(addr, size)) continue; if (contains(entry)) { // If this contains the intersecting entry if (entry.isOverlap()) continue; // Don't count resources (already counted overlapped entry) - if (entry.group < mingrp) - mingrp = entry.group; - int4 max = entry.group + entry.groupsize; - if (max > maxgrp) - maxgrp = max; - grpsize += entry.groupsize; + overlapSet.insert(overlapSet.end(),entry.groupSet.begin(),entry.groupSet.end()); // For output , if the most signifigant part overlaps with an earlier // the least signifigant part is marked for extra checks, and vice versa. if (addressbase == entry.addressbase) @@ -140,14 +125,36 @@ void ParamEntry::resolveOverlap(list &curList) throw LowlevelError("Illegal overlap of in compiler spec"); } - if (grpsize == 0) return; // No overlaps - if (grpsize != (maxgrp - mingrp)) - throw LowlevelError(" must overlap sequential entries"); - group = mingrp; - groupsize = grpsize; + if (overlapSet.empty()) return; // No overlaps + sort(overlapSet.begin(),overlapSet.end()); + groupSet = overlapSet; flags |= overlapping; } +/// \param op2 is the other entry to compare +/// \return \b true if the group sets associated with each ParamEntry intersect at all +bool ParamEntry::groupOverlap(const ParamEntry &op2) const + +{ + int4 i = 0; + int4 j = 0; + int4 valThis = groupSet[i]; + int4 valOther = op2.groupSet[j]; + while(valThis != valOther) { + if (valThis < valOther) { + i += 1; + if (i >= groupSet.size()) return false; + valThis = groupSet[i]; + } + else { + j += 1; + if (j >= op2.groupSet.size()) return false; + valOther = op2.groupSet[j]; + } + } + return true; +} + /// This entry must properly contain the other memory range, and /// the entry properties must be compatible. A \e join ParamEntry can /// subsume another \e join ParamEntry, but we expect the addressbase to be identical. @@ -379,7 +386,7 @@ OpCode ParamEntry::assumedExtension(const Address &addr,int4 sz,VarnodeData &res int4 ParamEntry::getSlot(const Address &addr,int4 skip) const { - int4 res = group; + int4 res = groupSet[0]; if (alignment != 0) { uintb diff = addr.getOffset() + skip - addressbase; int4 baseslot = (int4)diff / alignment; @@ -389,7 +396,7 @@ int4 ParamEntry::getSlot(const Address &addr,int4 skip) const res += baseslot; } else if (skip != 0) { - res += (groupsize-1); + res = groupSet.back(); } return res; } @@ -456,7 +463,6 @@ void ParamEntry::decode(Decoder &decoder,bool normalstack,bool grouped,list &status const ParamEntry &curEntry( *iter ); int4 grp = curEntry.getGroup(); if (status[grp]<0) continue; - if ((curEntry.getType() != TYPE_UNKNOWN)&& - tp->getMetatype() != curEntry.getType()) + if ((curEntry.getType() != TYPE_UNKNOWN) && tp->getMetatype() != curEntry.getType()) continue; // Wrong type Address res = curEntry.getAddrBySlot(status[grp],tp->getSize()); if (res.isInvalid()) continue; // If -tp- doesn't fit an invalid address is returned if (curEntry.isExclusion()) { - int4 maxgrp = grp + curEntry.getGroupSize(); - for(int4 j=grp;j &groupSet(curEntry.getAllGroups()); + for(int4 j=0;j &trial /// /// Only one trial within an exclusion group can have active use, mark all others as unused. /// \param active is the set of trials, which must be sorted on group -/// \param groupUpper is the biggest group number to be marked -/// \param groupStart is the index of the first trial in the smallest group to be marked -/// \param index is the specified trial index that is \e not to be marked -void ParamListStandard::markGroupNoUse(ParamActive *active,int4 groupUpper,int4 groupStart,int4 index) +/// \param activeTrial is the index of the trial whose groups are to be considered active +/// \param trialStart is the index of the first trial to mark +void ParamListStandard::markGroupNoUse(ParamActive *active,int4 activeTrial,int4 trialStart) { int4 numTrials = active->getNumTrials(); - for(int4 i=groupStart;igetTrial(activeTrial).getEntry(); + for(int4 i=trialStart;igetTrial(i)); if (othertrial.isDefinitelyNotUsed()) continue; - if (othertrial.getEntry()->getGroup() > groupUpper) break; + if (!othertrial.getEntry()->groupOverlap(*activeEntry)) break; othertrial.markNoUse(); } } @@ -889,7 +894,7 @@ void ParamListStandard::markBestInactive(ParamActive *active,int4 group,int4 gro const ParamEntry *entry = trial.getEntry(); int4 grp = entry->getGroup(); if (grp != group) break; - if (entry->getGroupSize() > 1) continue; // Covering multiple slots automatically give low score + if (entry->getAllGroups().size() > 1) continue; // Covering multiple slots automatically give low score int4 score = 0; if (trial.hasAncestorRealistic()) { score += 5; @@ -904,7 +909,7 @@ void ParamListStandard::markBestInactive(ParamActive *active,int4 group,int4 gro } } if (bestTrial >= 0) - markGroupNoUse(active, group, groupStart, bestTrial); + markGroupNoUse(active, bestTrial, groupStart); } /// \brief Enforce exclusion rules for the given set of parameter trials @@ -932,8 +937,7 @@ void ParamListStandard::forceExclusionGroup(ParamActive *active) inactiveCount = 0; } if (curtrial.isActive()) { - int4 groupUpper = grp + curtrial.getEntry()->getGroupSize() - 1; // This entry covers some number of groups - markGroupNoUse(active, groupUpper, groupStart, i); + markGroupNoUse(active, i, groupStart); } else { inactiveCount += 1; @@ -969,9 +973,9 @@ void ParamListStandard::forceNoUse(ParamActive *active, int4 start, int4 stop) } else { // First trial in a new group (or next element in same non-exclusion group) if (alldefnouse) // If all in the last group were defnotused - seendefnouse = true;// then force everything afterword to be defnotused + seendefnouse = true;// then force everything afterward to be defnotused alldefnouse = curtrial.isDefinitelyNotUsed(); - curgroup = grp + curtrial.getEntry()->getGroupSize() - 1; + curgroup = grp; } if (seendefnouse) curtrial.markInactive(); @@ -1131,7 +1135,7 @@ void ParamListStandard::parsePentry(Decoder &decoder,vector &effec else if (autokill) // If a register parameter AND we automatically generate killedbycall effectlist.push_back(EffectRecord(entry.back(),EffectRecord::killedbycall)); - int4 maxgroup = entry.back().getGroup() + entry.back().getGroupSize(); + int4 maxgroup = entry.back().getAllGroups().back() + 1; if (maxgroup > numgroup) numgroup = maxgroup; } @@ -1250,7 +1254,7 @@ bool ParamListStandard::possibleParamWithSlot(const Address &loc,int4 size,int4 if (entryNum == (const ParamEntry *)0) return false; slot = entryNum->getSlot(loc,0); if (entryNum->isExclusion()) { - slotsize = entryNum->getGroupSize(); + slotsize = entryNum->getAllGroups().size(); } else { slotsize = ((size-1) / entryNum->getAlign()) + 1; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh index 50c54824ea..64ec45e2cd 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh @@ -101,8 +101,7 @@ public: private: uint4 flags; ///< Boolean properties of the parameter type_metatype type; ///< Data-type class that this entry must match - int4 group; ///< Group of (mutually exclusive) entries that this entry belongs to - int4 groupsize; ///< The number of consecutive groups taken by the entry + vector groupSet; ///< Group(s) \b this entry belongs to AddrSpace *spaceid; ///< Address space containing the range uintb addressbase; ///< Starting offset of the range int4 size; ///< Size of the range in bytes @@ -117,9 +116,10 @@ private: /// \brief Is the logical value left-justified within its container bool isLeftJustified(void) const { return (((flags&force_left_justify)!=0)||(!spaceid->isBigEndian())); } public: - ParamEntry(int4 grp) { group=grp; } ///< Constructor for use with decode - int4 getGroup(void) const { return group; } ///< Get the group id \b this belongs to - int4 getGroupSize(void) const { return groupsize; } ///< Get the number of groups occupied by \b this + ParamEntry(int4 grp) { groupSet.push_back(grp); } ///< Constructor for use with decode + int4 getGroup(void) const { return groupSet[0]; } ///< Get the group id \b this belongs to + const vector &getAllGroups(void) const { return groupSet; } ///< Get all group numbers \b this overlaps + bool groupOverlap(const ParamEntry &op2) const; ///< Check if \b this and op2 occupy any of the same groups int4 getSize(void) const { return size; } ///< Get the size of the memory range in bytes. int4 getMinSize(void) const { return minsize; } ///< Get the minimum size of a logical value contained in \b this int4 getAlign(void) const { return alignment; } ///< Get the alignment of \b this entry @@ -567,7 +567,7 @@ protected: const ParamEntry *selectUnreferenceEntry(int4 grp,type_metatype prefType) const; ///< Select entry to fill an unreferenced param void buildTrialMap(ParamActive *active) const; ///< Build map from parameter trials to model ParamEntrys void separateSections(ParamActive *active,vector &trialStart) const; - static void markGroupNoUse(ParamActive *active,int4 groupUpper,int4 groupStart,int4 index); + static void markGroupNoUse(ParamActive *active,int4 activeTrial,int4 trialStart); static void markBestInactive(ParamActive *active,int4 group,int4 groupStart,type_metatype prefType); static void forceExclusionGroup(ParamActive *active); static void forceNoUse(ParamActive *active,int4 start,int4 stop); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamEntry.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamEntry.java index f8adecb9c8..ab85ddee19 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamEntry.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamEntry.java @@ -50,8 +50,7 @@ public class ParamEntry { private int flags; private int type; // Restriction on DataType this entry must match - private int group; // Group of (mutually exclusive) entries that this entry belongs to - private int groupsize; // The number of consecutive groups taken by the entry + private int[] groupSet; // Group(s) this entry belongs to private AddressSpace spaceid; // Space of this range private long addressbase; // Start of the range private int size; // size of the range @@ -61,15 +60,16 @@ public class ParamEntry { private Varnode[] joinrec; public ParamEntry(int grp) { // For use with restoreXml - group = grp; + groupSet = new int[1]; + groupSet[0] = grp; } public int getGroup() { - return group; + return groupSet[0]; } - public int getGroupSize() { - return groupsize; + public int[] getAllGroups() { + return groupSet; } public int getSize() { @@ -265,7 +265,7 @@ public class ParamEntry { * @return the slot index */ public int getSlot(Address addr, int skip) { - int res = group; + int res = groupSet[0]; if (alignment != 0) { long diff = addr.getOffset() + skip - addressbase; int baseslot = (int) diff / alignment; @@ -277,7 +277,7 @@ public class ParamEntry { } } else if (skip != 0) { - res += (groupsize - 1); + res = groupSet[groupSet.length - 1]; } return res; } @@ -366,29 +366,24 @@ public class ParamEntry { if (joinrec == null) { return; } - int mingrp = 1000; - int maxgrp = -1; + ArrayList newGroupSet = new ArrayList<>(); for (Varnode piece : joinrec) { ParamEntry entry = findEntryByStorage(curList, piece); if (entry != null) { - if (entry.group < mingrp) { - mingrp = entry.group; - } - int max = entry.group + entry.groupsize; - if (max > maxgrp) { - maxgrp = max; + for (int group : entry.groupSet) { + newGroupSet.add(group); } } } - if (maxgrp < 0 || mingrp >= 1000) { + if (newGroupSet.isEmpty()) { throw new XmlParseException(" join must overlap at least one previous entry"); } - group = mingrp; - groupsize = (maxgrp - mingrp); - flags |= OVERLAPPING; - if (groupsize > joinrec.length) { - throw new XmlParseException(" join must overlap sequential entries"); + newGroupSet.sort(null); + groupSet = new int[newGroupSet.size()]; + for (int i = 0; i < groupSet.length; ++i) { + groupSet[i] = newGroupSet.get(i); } + flags |= OVERLAPPING; } /** @@ -401,9 +396,7 @@ public class ParamEntry { if (joinrec != null) { return; } - int grpsize = 0; - int mingrp = 1000; - int maxgrp = -1; + ArrayList newGroupSet = new ArrayList<>(); Address addr = spaceid.getAddress(addressbase); for (ParamEntry entry : curList) { if (entry == this) { @@ -416,27 +409,22 @@ public class ParamEntry { if (entry.isOverlap()) { continue; // Don't count resources (already counted overlapped pentry) } - if (entry.group < mingrp) { - mingrp = entry.group; + for (int group : entry.groupSet) { + newGroupSet.add(group); } - int max = entry.group + entry.groupsize; - if (max > maxgrp) { - maxgrp = max; - } - grpsize += entry.groupsize; } else { throw new XmlParseException("Illegal overlap of in compiler spec"); } } - if (grpsize == 0) { + if (newGroupSet.isEmpty()) { return; // No overlaps } - if (grpsize != (maxgrp - mingrp)) { - throw new XmlParseException(" must overlap sequential entries"); + newGroupSet.sort(null); + groupSet = new int[newGroupSet.size()]; + for (int i = 0; i < groupSet.length; ++i) { + groupSet[i] = newGroupSet.get(i); } - group = mingrp; - groupsize = grpsize; flags |= OVERLAPPING; } @@ -486,7 +474,6 @@ public class ParamEntry { size = minsize = -1; // Must be filled in alignment = 0; // default numslots = 1; - groupsize = 1; // default XmlElement el = parser.start("pentry"); Iterator> iter = el.getAttributes().entrySet().iterator(); @@ -606,9 +593,14 @@ public class ParamEntry { if (numslots != obj.numslots) { return false; } - if (group != obj.group || groupsize != obj.groupsize) { + if (groupSet.length != obj.groupSet.length) { return false; } + for (int i = 0; i < groupSet.length; ++i) { + if (groupSet[i] != obj.groupSet[i]) { + return false; + } + } if (!SystemUtilities.isArrayEqual(joinrec, obj.joinrec)) { return false; } 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 2f712fdb7e..56665b0010 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 @@ -107,10 +107,9 @@ public class ParamListStandard implements ParamList { continue; // -tp- does not fit in this entry } if (element.isExclusion()) { - int maxgrp = grp + element.getGroupSize(); - for (int j = grp; j < maxgrp; ++j) { + for (int group : element.getAllGroups()) { // For an exclusion entry - status[j] = -1; // some number of groups are taken up + status[group] = -1; // some number of groups are taken up } if (element.isFloatExtended()) { sz = element.getSize(); // Still use the entire container size, when assigning storage @@ -264,7 +263,8 @@ public class ParamListStandard implements ParamList { if (pentry.getSpace().isStackSpace()) { spacebase = pentry.getSpace(); } - int maxgroup = pentry.getGroup() + pentry.getGroupSize(); + int[] groupSet = pentry.getAllGroups(); + int maxgroup = groupSet[groupSet.length - 1] + 1; if (maxgroup > numgroup) { numgroup = maxgroup; } @@ -379,7 +379,7 @@ public class ParamListStandard implements ParamList { ParamEntry curentry = entry[num]; res.slot = curentry.getSlot(loc, 0); if (curentry.isExclusion()) { - res.slotsize = curentry.getGroupSize(); + res.slotsize = curentry.getAllGroups().length; } else { res.slotsize = ((size - 1) / curentry.getAlign()) + 1;