mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Support for per function unaffected/killedbycall/likelytrash
This commit is contained in:
parent
156ce7ef80
commit
75b7d5fe14
8 changed files with 703 additions and 245 deletions
|
@ -16,44 +16,65 @@
|
|||
#include "fspec.hh"
|
||||
#include "funcdata.hh"
|
||||
|
||||
void ParamEntry::resolveJoin(void)
|
||||
/// \brief Find a ParamEntry matching the given storage Varnode
|
||||
///
|
||||
/// Search through the list backward.
|
||||
/// \param entryList is the list of ParamEntry to search through
|
||||
/// \param vn is the storage to search for
|
||||
/// \return the matching ParamEntry or null
|
||||
const ParamEntry *ParamEntry::findEntryByStorage(const list<ParamEntry> &entryList,const VarnodeData &vn)
|
||||
|
||||
{
|
||||
if (spaceid->getType() == IPTR_JOIN)
|
||||
joinrec = spaceid->getManager()->findJoin(addressbase);
|
||||
else
|
||||
joinrec = (JoinRecord *)0;
|
||||
list<ParamEntry>::const_reverse_iterator iter = entryList.rbegin();
|
||||
for(;iter!=entryList.rend();++iter) {
|
||||
const ParamEntry &entry(*iter);
|
||||
if (entry.spaceid == vn.space && entry.addressbase == vn.offset && entry.size == vn.size) {
|
||||
return &entry;
|
||||
}
|
||||
}
|
||||
return (const ParamEntry *)0;
|
||||
}
|
||||
|
||||
/// \brief Construct entry from components
|
||||
///
|
||||
/// \param t is the data-type class (TYPE_UNKNOWN or TYPE_FLOAT)
|
||||
/// \param grp is the group id
|
||||
/// \param grpsize is the number of consecutive groups occupied
|
||||
/// \param loc is the starting address of the memory range
|
||||
/// \param sz is the number of bytes in the range
|
||||
/// \param mnsz is the smallest size of a logical value
|
||||
/// \param align is the alignment (0 means the memory range will hold one parameter exclusively)
|
||||
/// \param normalstack is \b true if parameters are allocated from the front of the range
|
||||
ParamEntry::ParamEntry(type_metatype t,int4 grp,int4 grpsize,const Address &loc,int4 sz,int4 mnsz,int4 align,bool normalstack)
|
||||
/// If the ParamEntry is initialized with a \e join address, cache the join record and
|
||||
/// adjust the group and groupsize based on the ParamEntrys being overlapped
|
||||
/// \param curList is the current list of ParamEntry
|
||||
void ParamEntry::resolveJoin(list<ParamEntry> &curList)
|
||||
|
||||
{
|
||||
flags = 0;
|
||||
type = t;
|
||||
group = grp;
|
||||
groupsize = grpsize;
|
||||
spaceid = loc.getSpace();
|
||||
addressbase = loc.getOffset();
|
||||
size = sz;
|
||||
minsize = mnsz;
|
||||
alignment = align;
|
||||
if (alignment != 0)
|
||||
numslots = size / alignment;
|
||||
else
|
||||
numslots = 1;
|
||||
if (!normalstack)
|
||||
flags |= reverse_stack;
|
||||
resolveJoin();
|
||||
if (spaceid->getType() != IPTR_JOIN) {
|
||||
joinrec = (JoinRecord *)0;
|
||||
return;
|
||||
}
|
||||
joinrec = spaceid->getManager()->findJoin(addressbase);
|
||||
int4 mingrp = 1000;
|
||||
int4 maxgrp = -1;
|
||||
for(int4 i=0;i<joinrec->numPieces();++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;
|
||||
}
|
||||
}
|
||||
if (maxgrp < 0 || mingrp >= 1000)
|
||||
throw LowlevelError("<pentry> join must overlap at least one previous entry");
|
||||
group = mingrp;
|
||||
groupsize = (maxgrp - mingrp);
|
||||
if (groupsize > joinrec->numPieces())
|
||||
throw LowlevelError("<pentry> join must overlap sequential entries");
|
||||
}
|
||||
|
||||
/// A ParamEntry with \e join storage must either overlap a single other ParamEntry or
|
||||
/// all pieces must overlap.
|
||||
/// \return \b true if \b this is a join whose pieces do not all overlap
|
||||
bool ParamEntry::isNonOverlappingJoin(void) const
|
||||
|
||||
{
|
||||
if (joinrec == (JoinRecord *)0)
|
||||
return false;
|
||||
return (joinrec->numPieces() != groupsize);
|
||||
}
|
||||
|
||||
/// This entry must properly contain the other memory range, and
|
||||
|
@ -299,7 +320,9 @@ Address ParamEntry::getAddrBySlot(int4 &slotnum,int4 sz) const
|
|||
/// \param el is the root \<pentry> element
|
||||
/// \param manage is a manager to resolve address space references
|
||||
/// \param normalstack is \b true if the parameters should be allocated from the front of the range
|
||||
void ParamEntry::restoreXml(const Element *el,const AddrSpaceManager *manage,bool normalstack)
|
||||
/// \param grouped is \b true if \b this will be grouped with other entries
|
||||
/// \param curList is the list of ParamEntry defined up to this point
|
||||
void ParamEntry::restoreXml(const Element *el,const AddrSpaceManager *manage,bool normalstack,bool grouped,list<ParamEntry> &curList)
|
||||
|
||||
{
|
||||
flags = 0;
|
||||
|
@ -334,16 +357,6 @@ void ParamEntry::restoreXml(const Element *el,const AddrSpaceManager *manage,boo
|
|||
}
|
||||
else if (attrname == "metatype")
|
||||
type = string2metatype(el->getAttributeValue(i));
|
||||
else if (attrname == "group") { // Override the group
|
||||
istringstream i5(el->getAttributeValue(i));
|
||||
i5.unsetf(ios::dec | ios::hex | ios::oct);
|
||||
i5 >> group;
|
||||
}
|
||||
else if (attrname == "groupsize") {
|
||||
istringstream i6(el->getAttributeValue(i));
|
||||
i6.unsetf(ios::dec | ios::hex | ios::oct);
|
||||
i6 >> groupsize;
|
||||
}
|
||||
else if (attrname == "extension") {
|
||||
flags &= ~((uint4)(smallsize_zext | smallsize_sext | smallsize_inttype));
|
||||
if (el->getAttributeValue(i) == "sign")
|
||||
|
@ -386,7 +399,9 @@ void ParamEntry::restoreXml(const Element *el,const AddrSpaceManager *manage,boo
|
|||
throw LowlevelError("For positive stack growth, <pentry> size must match alignment");
|
||||
}
|
||||
}
|
||||
resolveJoin();
|
||||
if (grouped)
|
||||
flags |= is_grouped;
|
||||
resolveJoin(curList);
|
||||
}
|
||||
|
||||
/// \brief Check if \b this entry represents a \e joined parameter and requires extra scrutiny
|
||||
|
@ -418,6 +433,43 @@ void ParamEntry::extraChecks(list<ParamEntry> &entry)
|
|||
flags |= extracheck_high; // The default is to do extra checks on the high
|
||||
}
|
||||
|
||||
/// If the storage is in the \e join space, we count the number of join pieces that overlap something
|
||||
/// in the given list of entries.
|
||||
/// \param curList is the list of entries to check
|
||||
/// \return the number of overlapping pieces
|
||||
int4 ParamEntry::countJoinOverlap(const list<ParamEntry> &curList) const
|
||||
|
||||
{
|
||||
if (joinrec == (JoinRecord *)0)
|
||||
return 0;
|
||||
|
||||
int count = 0;
|
||||
for (int4 i=0;i<joinrec->numPieces();++i) {
|
||||
const ParamEntry *match = findEntryByStorage(curList, joinrec->getPiece(i));
|
||||
if (match != (const ParamEntry *)0)
|
||||
count += 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/// Entries within a group must be distinguishable by size or by type.
|
||||
/// Throw an exception if the entries aren't distinguishable
|
||||
/// \param entry1 is the first ParamEntry to compare
|
||||
/// \param entry2 is the second ParamEntry to compare
|
||||
void ParamEntry::orderWithinGroup(const ParamEntry &entry1,const ParamEntry &entry2)
|
||||
|
||||
{
|
||||
if (entry2.minsize > entry1.size || entry1.minsize > entry2.size)
|
||||
return;
|
||||
if (entry1.type != entry2.type) {
|
||||
if (entry1.type == TYPE_UNKNOWN) {
|
||||
throw LowlevelError("<pentry> tags with a specific type must come before the general type");
|
||||
}
|
||||
return;
|
||||
}
|
||||
throw LowlevelError("<pentry> tags within a group must be distinguished by size or type");
|
||||
}
|
||||
|
||||
ParamListStandard::ParamListStandard(const ParamListStandard &op2)
|
||||
|
||||
{
|
||||
|
@ -427,7 +479,7 @@ ParamListStandard::ParamListStandard(const ParamListStandard &op2)
|
|||
maxdelay = op2.maxdelay;
|
||||
pointermax = op2.pointermax;
|
||||
thisbeforeret = op2.thisbeforeret;
|
||||
nonfloatgroup = op2.nonfloatgroup;
|
||||
resourceTwoStart = op2.resourceTwoStart;
|
||||
populateResolver();
|
||||
}
|
||||
|
||||
|
@ -677,30 +729,39 @@ void ParamListStandard::buildTrialMap(ParamActive *active) const
|
|||
active->sortTrials();
|
||||
}
|
||||
|
||||
/// \brief Calculate the range of floating-point entries within a given set of parameter \e trials
|
||||
/// \brief Calculate the range of trials in each of the two resource sections
|
||||
///
|
||||
/// The trials must already be mapped, which should put floating-point entries first.
|
||||
/// This method calculates the range of floating-point entries and the range of general purpose
|
||||
/// entries and passes them back.
|
||||
/// The trials must already be mapped, which should put them in group order. The sections
|
||||
/// split at the group given by \b resourceTwoStart. We pass back the range of trial indices
|
||||
/// for each section. If \b resourceTwoStart is 0, then there is really only one section, and
|
||||
/// the empty range [0,0] is passed back for the second section.
|
||||
/// \param active is the given set of parameter trials
|
||||
/// \param floatstart will pass back the index of the first floating-point trial
|
||||
/// \param floatstop will pass back the index (+1) of the last floating-point trial
|
||||
/// \param start will pass back the index of the first general purpose trial
|
||||
/// \param stop will pass back the index (+1) of the last general purpose trial
|
||||
void ParamListStandard::separateFloat(ParamActive *active,int4 &floatstart,int4 &floatstop,int4 &start,int4 &stop) const
|
||||
/// \param oneStart will pass back the index of the first trial in the first section
|
||||
/// \param oneStop will pass back the index (+1) of the last trial in the first section
|
||||
/// \param twoStart will pass back the index of the first trial in the second section
|
||||
/// \param twoStop will pass back the index (+1) of the last trial in the second section
|
||||
void ParamListStandard::separateSections(ParamActive *active,int4 &oneStart,int4 &oneStop,int4 &twoStart,int4 &twoStop) const
|
||||
|
||||
{
|
||||
int4 numtrials = active->getNumTrials();
|
||||
if (resourceTwoStart == 0) {
|
||||
// Only one section
|
||||
oneStart = 0;
|
||||
oneStop = numtrials;
|
||||
twoStart = 0;
|
||||
twoStop = 0;
|
||||
return;
|
||||
}
|
||||
int4 i=0;
|
||||
for(;i<numtrials;++i) {
|
||||
ParamTrial &curtrial(active->getTrial(i));
|
||||
if (curtrial.getEntry()==(const ParamEntry *)0) continue;
|
||||
if (curtrial.getEntry()->getType()!=TYPE_FLOAT) break;
|
||||
if (curtrial.getEntry()->getGroup() >= resourceTwoStart) break;
|
||||
}
|
||||
floatstart = 0;
|
||||
floatstop = i;
|
||||
start = i;
|
||||
stop = numtrials;
|
||||
oneStart = 0;
|
||||
oneStop = i;
|
||||
twoStart = i;
|
||||
twoStop = numtrials;
|
||||
}
|
||||
|
||||
/// \brief Enforce exclusion rules for the given set of parameter trials
|
||||
|
@ -768,14 +829,17 @@ void ParamListStandard::forceNoUse(ParamActive *active, int4 start, int4 stop) c
|
|||
///
|
||||
/// If there is a chain of slots whose length is greater than \b maxchain,
|
||||
/// where all trials are \e inactive, mark trials in any later slot as \e inactive.
|
||||
/// Mark any \e inactive trials before this (that aren't in a maximal chain)
|
||||
/// as active. Inspection and marking is restricted to a given range of trials
|
||||
/// to facilitate separate analysis of floating-point and general-purpose resources.
|
||||
/// Mark any \e inactive trials before this (that aren't in a maximal chain) as active.
|
||||
/// The parameter entries in the model may be split up into different resource sections,
|
||||
/// as in floating-point vs general purpose. This method must be called on a single
|
||||
/// section at a time. The \b start and \b stop indices describe the range of trials
|
||||
/// in the particular section.
|
||||
/// \param active is the set of trials, which must be sorted
|
||||
/// \param maxchain is the maximum number of \e inactive trials to allow in a chain
|
||||
/// \param start is the first index in the range of trials to consider
|
||||
/// \param stop is the last index (+1) in the range of trials to consider
|
||||
void ParamListStandard::forceInactiveChain(ParamActive *active,int4 maxchain,int4 start,int4 stop) const
|
||||
/// \param groupstart is the smallest group id in the particular section
|
||||
void ParamListStandard::forceInactiveChain(ParamActive *active,int4 maxchain,int4 start,int4 stop,int4 groupstart) const
|
||||
|
||||
{
|
||||
bool seenchain = false;
|
||||
|
@ -794,10 +858,7 @@ void ParamListStandard::forceInactiveChain(ParamActive *active,int4 maxchain,int
|
|||
seenchain = true; // Mark that we have already seen an inactive chain
|
||||
}
|
||||
if (i==start) {
|
||||
if (trial.getEntry()->getType() == TYPE_FLOAT)
|
||||
chainlength += (active->getTrial(0).slotGroup()+1);
|
||||
else
|
||||
chainlength += (trial.slotGroup() - nonfloatgroup + 1);
|
||||
chainlength += (trial.slotGroup() - groupstart + 1);
|
||||
}
|
||||
else
|
||||
chainlength += trial.slotGroup() - active->getTrial(i-1).slotGroup();
|
||||
|
@ -861,6 +922,76 @@ void ParamListStandard::populateResolver(void)
|
|||
}
|
||||
}
|
||||
|
||||
/// \brief Read a \<pentry> tag and add it to \b this list
|
||||
///
|
||||
/// \param el is the \<pentry element
|
||||
/// \param manage is manager for parsing address spaces
|
||||
/// \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(const Element *el,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist,
|
||||
int4 groupid,bool normalstack,bool autokill,bool splitFloat,bool grouped)
|
||||
{
|
||||
entry.emplace_back(groupid);
|
||||
entry.back().restoreXml(el,manage,normalstack,grouped,entry);
|
||||
if (splitFloat) {
|
||||
if (entry.back().getType() == TYPE_FLOAT) {
|
||||
if (resourceTwoStart >= 0)
|
||||
throw LowlevelError("parameter list floating-point entries must come first");
|
||||
}
|
||||
else if (resourceTwoStart < 0)
|
||||
resourceTwoStart = groupid; // First time we have seen an integer slot
|
||||
}
|
||||
AddrSpace *spc = entry.back().getSpace();
|
||||
if (spc->getType() == IPTR_SPACEBASE)
|
||||
spacebase = spc;
|
||||
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();
|
||||
if (maxgroup > numgroup)
|
||||
numgroup = maxgroup;
|
||||
}
|
||||
|
||||
/// \brief Read a group of \<pentry> tags that are allocated as a group
|
||||
///
|
||||
/// All ParamEntry objects will share the same \b group id.
|
||||
/// \param el is the \<pentry element
|
||||
/// \param manage is manager for parsing address spaces
|
||||
/// \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(const Element *el,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist,
|
||||
int4 groupid,bool normalstack,bool autokill,bool splitFloat)
|
||||
{
|
||||
const List &flist(el->getChildren());
|
||||
List::const_iterator iter = flist.begin();
|
||||
int4 basegroup = numgroup;
|
||||
ParamEntry *previous1 = (ParamEntry *)0;
|
||||
ParamEntry *previous2 = (ParamEntry *)0;
|
||||
for(;iter!=flist.end();++iter) {
|
||||
const Element *subel = *iter;
|
||||
if (subel->getName() != "pentry")
|
||||
throw LowlevelError("Expected <pentry> child of <group>: " + subel->getName());
|
||||
parsePentry(subel, manage, effectlist, basegroup, normalstack, autokill, splitFloat, true);
|
||||
ParamEntry &pentry( entry.back() );
|
||||
if (pentry.getSpace()->getType() == IPTR_JOIN)
|
||||
throw LowlevelError("<pentry> in the join space not allowed in <group> tag");
|
||||
if (previous1 != (ParamEntry *)0) {
|
||||
ParamEntry::orderWithinGroup(*previous1,pentry);
|
||||
if (previous2 != (ParamEntry *)0)
|
||||
ParamEntry::orderWithinGroup(*previous2,pentry);
|
||||
}
|
||||
previous2 = previous1;
|
||||
previous1 = &pentry;
|
||||
}
|
||||
}
|
||||
|
||||
void ParamListStandard::fillinMap(ParamActive *active) const
|
||||
|
||||
{
|
||||
|
@ -869,12 +1000,12 @@ void ParamListStandard::fillinMap(ParamActive *active) const
|
|||
buildTrialMap(active); // Associate varnodes with sorted list of parameter locations
|
||||
|
||||
forceExclusionGroup(active);
|
||||
int4 floatstart,floatstop,start,stop;
|
||||
separateFloat(active,floatstart,floatstop,start,stop);
|
||||
forceNoUse(active,floatstart,floatstop);
|
||||
forceNoUse(active,start,stop); // Definitely not used -- overrides active
|
||||
forceInactiveChain(active,2,floatstart,floatstop); // Chains of inactivity override later actives
|
||||
forceInactiveChain(active,2,start,stop);
|
||||
int4 oneStart,oneStop,twoStart,twoStop;
|
||||
separateSections(active,oneStart,oneStop,twoStart,twoStop);
|
||||
forceNoUse(active,oneStart,oneStop);
|
||||
forceNoUse(active,twoStart,twoStop); // Definitely not used -- overrides active
|
||||
forceInactiveChain(active,2,oneStart,oneStop,0); // Chains of inactivity override later actives
|
||||
forceInactiveChain(active,2,twoStart,twoStop,resourceTwoStart);
|
||||
|
||||
// Mark every active trial as used
|
||||
for(int4 i=0;i<active->getNumTrials();++i) {
|
||||
|
@ -1024,11 +1155,11 @@ void ParamListStandard::restoreXml(const Element *el,const AddrSpaceManager *man
|
|||
vector<EffectRecord> &effectlist,bool normalstack)
|
||||
|
||||
{
|
||||
int4 lastgroup = -1;
|
||||
numgroup = 0;
|
||||
spacebase = (AddrSpace *)0;
|
||||
pointermax = 0;
|
||||
thisbeforeret = false;
|
||||
bool splitFloat = true; // True if we should split FLOAT entries into their own resource section
|
||||
bool autokilledbycall = false;
|
||||
for(int4 i=0;i<el->getNumAttributes();++i) {
|
||||
const string &attrname( el->getAttributeName(i) );
|
||||
|
@ -1043,33 +1174,29 @@ void ParamListStandard::restoreXml(const Element *el,const AddrSpaceManager *man
|
|||
else if (attrname == "killedbycall") {
|
||||
autokilledbycall = xml_readbool( el->getAttributeValue(i) );
|
||||
}
|
||||
else if (attrname == "separatefloat") {
|
||||
splitFloat = xml_readbool( el->getAttributeValue(i) );
|
||||
}
|
||||
}
|
||||
nonfloatgroup = -1; // We haven't seen any integer slots yet
|
||||
resourceTwoStart = splitFloat ? -1 : 0;
|
||||
const List &flist(el->getChildren());
|
||||
List::const_iterator fiter;
|
||||
for(fiter=flist.begin();fiter!=flist.end();++fiter) {
|
||||
const Element *subel = *fiter;
|
||||
if (subel->getName() == "pentry") {
|
||||
entry.emplace_back(numgroup);
|
||||
entry.back().restoreXml(subel,manage,normalstack);
|
||||
if (entry.back().getType()==TYPE_FLOAT) {
|
||||
if (nonfloatgroup >= 0)
|
||||
throw LowlevelError("parameter list floating-point entries must come first");
|
||||
parsePentry(subel, manage, effectlist, numgroup, normalstack, autokilledbycall, splitFloat, false);
|
||||
}
|
||||
else if (subel->getName() == "group") {
|
||||
parseGroup(subel, manage, effectlist, numgroup, normalstack, autokilledbycall, splitFloat);
|
||||
}
|
||||
}
|
||||
// Check that any pentry tags with join storage don't overlap following tags
|
||||
for (list<ParamEntry>::const_iterator eiter=entry.begin();eiter!=entry.end();++eiter) {
|
||||
const ParamEntry &curEntry( *eiter );
|
||||
if (curEntry.isNonOverlappingJoin()) {
|
||||
if (curEntry.countJoinOverlap(entry) != 1) {
|
||||
throw LowlevelError("pentry tag must be listed after all its overlaps");
|
||||
}
|
||||
else if (nonfloatgroup < 0)
|
||||
nonfloatgroup = numgroup; // First time we have seen an integer slot
|
||||
AddrSpace *spc = entry.back().getSpace();
|
||||
if (spc->getType() == IPTR_SPACEBASE)
|
||||
spacebase = spc;
|
||||
else if (autokilledbycall) // 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();
|
||||
if (maxgroup > numgroup)
|
||||
numgroup = maxgroup;
|
||||
if (entry.back().getGroup() < lastgroup)
|
||||
throw LowlevelError("pentrys must come in group order");
|
||||
lastgroup = entry.back().getGroup();
|
||||
}
|
||||
}
|
||||
calcDelay();
|
||||
|
@ -1214,8 +1341,19 @@ void ParamListStandardOut::restoreXml(const Element *el,const AddrSpaceManager *
|
|||
ParamListStandard::restoreXml(el,manage,effectlist,normalstack);
|
||||
// Check for double precision entries
|
||||
list<ParamEntry>::iterator iter;
|
||||
for(iter=entry.begin();iter!=entry.end();++iter)
|
||||
(*iter).extraChecks(entry);
|
||||
ParamEntry *previous1 = (ParamEntry *)0;
|
||||
ParamEntry *previous2 = (ParamEntry *)0;
|
||||
for(iter=entry.begin();iter!=entry.end();++iter) {
|
||||
ParamEntry &curEntry(*iter);
|
||||
curEntry.extraChecks(entry);
|
||||
if (previous1 != (ParamEntry *)0) {
|
||||
ParamEntry::orderWithinGroup(*previous1, curEntry);
|
||||
if (previous2 != (ParamEntry *)0)
|
||||
ParamEntry::orderWithinGroup(*previous2, curEntry);
|
||||
}
|
||||
previous2 = previous1;
|
||||
previous1 = &curEntry;
|
||||
}
|
||||
}
|
||||
|
||||
ParamList *ParamListStandardOut::clone(void) const
|
||||
|
@ -1628,9 +1766,9 @@ void FspecSpace::restoreXml(const Element *el)
|
|||
EffectRecord::EffectRecord(const Address &addr,int4 size)
|
||||
|
||||
{
|
||||
address.space = addr.getSpace();
|
||||
address.offset = addr.getOffset();
|
||||
address.size = size;
|
||||
range.space = addr.getSpace();
|
||||
range.offset = addr.getOffset();
|
||||
range.size = size;
|
||||
type = unknown_effect;
|
||||
}
|
||||
|
||||
|
@ -1639,9 +1777,9 @@ EffectRecord::EffectRecord(const Address &addr,int4 size)
|
|||
EffectRecord::EffectRecord(const ParamEntry &entry,uint4 t)
|
||||
|
||||
{
|
||||
address.space = entry.getSpace();
|
||||
address.offset = entry.getBase();
|
||||
address.size = entry.getSize();
|
||||
range.space = entry.getSpace();
|
||||
range.offset = entry.getBase();
|
||||
range.size = entry.getSize();
|
||||
type = t;
|
||||
}
|
||||
|
||||
|
@ -1650,7 +1788,7 @@ EffectRecord::EffectRecord(const ParamEntry &entry,uint4 t)
|
|||
EffectRecord::EffectRecord(const VarnodeData &data,uint4 t)
|
||||
|
||||
{
|
||||
address = data;
|
||||
range = data;
|
||||
type = t;
|
||||
}
|
||||
|
||||
|
@ -1659,9 +1797,9 @@ EffectRecord::EffectRecord(const VarnodeData &data,uint4 t)
|
|||
void EffectRecord::saveXml(ostream &s) const
|
||||
|
||||
{
|
||||
Address addr(address.space,address.offset);
|
||||
Address addr(range.space,range.offset);
|
||||
if ((type == unaffected)||(type == killedbycall)||(type == return_address))
|
||||
addr.saveXml(s,address.size);
|
||||
addr.saveXml(s,range.size);
|
||||
else
|
||||
throw LowlevelError("Bad EffectRecord type");
|
||||
}
|
||||
|
@ -1674,7 +1812,7 @@ void EffectRecord::restoreXml(uint4 grouptype,const Element *el,const AddrSpaceM
|
|||
|
||||
{
|
||||
type = grouptype;
|
||||
address.restoreXml(el,manage);
|
||||
range.restoreXml(el,manage);
|
||||
}
|
||||
|
||||
void ProtoModel::defaultLocalRange(void)
|
||||
|
@ -1881,7 +2019,7 @@ uint4 ProtoModel::lookupEffect(const vector<EffectRecord> &efflist,const Address
|
|||
|
||||
vector<EffectRecord>::const_iterator iter;
|
||||
|
||||
iter = upper_bound(efflist.begin(),efflist.end(),cur);
|
||||
iter = upper_bound(efflist.begin(),efflist.end(),cur,EffectRecord::compareByAddress);
|
||||
// First element greater than cur (address must be greater)
|
||||
// go back one more, and we get first el less or equal to cur
|
||||
if (iter==efflist.begin()) return EffectRecord::unknown_effect; // Can't go back one
|
||||
|
@ -1896,6 +2034,44 @@ uint4 ProtoModel::lookupEffect(const vector<EffectRecord> &efflist,const Address
|
|||
return EffectRecord::unknown_effect;
|
||||
}
|
||||
|
||||
/// \brief Look up a particular EffectRecord from a given list by its Address and size
|
||||
///
|
||||
/// The index of the matching EffectRecord from the given list is returned. Only the first
|
||||
/// \e listSize elements are examined, which much be sorted by Address.
|
||||
/// If no matching range exists, a negative number is returned.
|
||||
/// - -1 if the Address and size don't overlap any other EffectRecord
|
||||
/// - -2 if there is overlap with another EffectRecord
|
||||
///
|
||||
/// \param efflist is the given list
|
||||
/// \param listSize is the number of records in the list to search through
|
||||
/// \param addr is the starting Address of the record to find
|
||||
/// \param size is the size of the record to find
|
||||
/// \return the index of the matching record or a negative number
|
||||
int4 ProtoModel::lookupRecord(const vector<EffectRecord> &efflist,int4 listSize,
|
||||
const Address &addr,int4 size)
|
||||
{
|
||||
if (listSize == 0) return -1;
|
||||
EffectRecord cur(addr,size);
|
||||
|
||||
vector<EffectRecord>::const_iterator begiter = efflist.begin();
|
||||
vector<EffectRecord>::const_iterator enditer = begiter + listSize;
|
||||
vector<EffectRecord>::const_iterator iter;
|
||||
|
||||
iter = upper_bound(begiter,enditer,cur,EffectRecord::compareByAddress);
|
||||
// First element greater than cur (address must be greater)
|
||||
// go back one more, and we get first el less or equal to cur
|
||||
if (iter==efflist.begin()) {
|
||||
Address closeAddr = (*iter).getAddress();
|
||||
return (closeAddr.overlap(0,addr,size) < 0) ? -1 : -2;
|
||||
}
|
||||
--iter;
|
||||
Address closeAddr =(*iter).getAddress();
|
||||
int4 sz = (*iter).getSize();
|
||||
if (addr == closeAddr && size == sz)
|
||||
return iter - begiter;
|
||||
return (addr.overlap(0,closeAddr,sz) < 0) ? -1 : -2;
|
||||
}
|
||||
|
||||
/// The model is searched for an EffectRecord matching the given range
|
||||
/// and the effect type is returned. If there is no EffectRecord or the
|
||||
/// effect generally isn't known, EffectRecord::unknown_effect is returned.
|
||||
|
@ -2054,7 +2230,7 @@ void ProtoModel::restoreXml(const Element *el)
|
|||
// Provide the default return address, if there isn't a specific one for the model
|
||||
effectlist.push_back(EffectRecord(glb->defaultReturnAddr,EffectRecord::return_address));
|
||||
}
|
||||
sort(effectlist.begin(),effectlist.end());
|
||||
sort(effectlist.begin(),effectlist.end(),EffectRecord::compareByAddress);
|
||||
sort(likelytrash.begin(),likelytrash.end());
|
||||
if (!sawlocalrange)
|
||||
defaultLocalRange();
|
||||
|
@ -2151,17 +2327,18 @@ void ProtoModelMerged::intersectEffects(const vector<EffectRecord> &efflist)
|
|||
const EffectRecord &eff1( effectlist[i] );
|
||||
const EffectRecord &eff2( efflist[j] );
|
||||
|
||||
if (eff1 < eff2)
|
||||
if (EffectRecord::compareByAddress(eff1, eff2))
|
||||
i += 1;
|
||||
else if (eff2 < eff1)
|
||||
else if (EffectRecord::compareByAddress(eff2, eff1))
|
||||
j += 1;
|
||||
else {
|
||||
newlist.push_back(eff1);
|
||||
if (eff1 == eff2)
|
||||
newlist.push_back(eff1);
|
||||
i += 1;
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
effectlist = newlist;
|
||||
effectlist.swap(newlist);
|
||||
}
|
||||
|
||||
/// The \e likely-trash locations are intersected. Anything in \b this that is not also in the
|
||||
|
@ -2918,6 +3095,126 @@ void FuncProto::updateThisPointer(void)
|
|||
param->setThisPointer(true);
|
||||
}
|
||||
|
||||
/// If the \e effectlist for \b this is non-empty, it contains the complete set of
|
||||
/// EffectRecords. Save just those that override the underlying list from ProtoModel
|
||||
/// \param s is the stream to write to
|
||||
void FuncProto::saveEffectXml(ostream &s) const
|
||||
|
||||
{
|
||||
if (effectlist.empty()) return;
|
||||
vector<const EffectRecord *> unaffectedList;
|
||||
vector<const EffectRecord *> killedByCallList;
|
||||
const EffectRecord *retAddr = (const EffectRecord *)0;
|
||||
for(vector<EffectRecord>::const_iterator iter=effectlist.begin();iter!=effectlist.end();++iter) {
|
||||
const EffectRecord &curRecord( *iter );
|
||||
uint4 type = model->hasEffect(curRecord.getAddress(), curRecord.getSize());
|
||||
if (type == curRecord.getType()) continue;
|
||||
if (curRecord.getType() == EffectRecord::unaffected)
|
||||
unaffectedList.push_back(&curRecord);
|
||||
else if (curRecord.getType() == EffectRecord::killedbycall)
|
||||
killedByCallList.push_back(&curRecord);
|
||||
else if (curRecord.getType() == EffectRecord::return_address)
|
||||
retAddr = &curRecord;
|
||||
}
|
||||
if (!unaffectedList.empty()) {
|
||||
s << " <unaffected>\n";
|
||||
for(int4 i=0;i<unaffectedList.size();++i) {
|
||||
s << " ";
|
||||
unaffectedList[i]->saveXml(s);
|
||||
s << '\n';
|
||||
}
|
||||
s << " </unaffected>\n";
|
||||
}
|
||||
if (!killedByCallList.empty()) {
|
||||
s << " <killedbycall>\n";
|
||||
for(int4 i=0;i<killedByCallList.size();++i) {
|
||||
s << " ";
|
||||
killedByCallList[i]->saveXml(s);
|
||||
s << '\n';
|
||||
}
|
||||
s << " </killedbycall>\n";
|
||||
}
|
||||
if (retAddr != (const EffectRecord *)0) {
|
||||
s << " <returnaddress>\n ";
|
||||
retAddr->saveXml(s);
|
||||
s << "\n </returnaddress>\n";
|
||||
}
|
||||
}
|
||||
|
||||
/// If the -likelytrash- list is not empty it overrides the underlying ProtoModel's list.
|
||||
/// Write any VarnodeData that does not appear in the ProtoModel to the XML stream.
|
||||
/// \param s is the stream to write to
|
||||
void FuncProto::saveLikelyTrashXml(ostream &s) const
|
||||
|
||||
{
|
||||
if (likelytrash.empty()) return;
|
||||
vector<VarnodeData>::const_iterator iter1,iter2;
|
||||
iter1 = model->trashBegin();
|
||||
iter2 = model->trashEnd();
|
||||
s << " <likelytrash>\n";
|
||||
for(vector<VarnodeData>::const_iterator iter=likelytrash.begin();iter!=likelytrash.end();++iter) {
|
||||
const VarnodeData &cur(*iter);
|
||||
if (binary_search(iter1,iter2,cur)) continue; // Already exists in ProtoModel
|
||||
s << " <addr";
|
||||
cur.space->saveXmlAttributes(s,cur.offset,cur.size);
|
||||
s << "/>\n";
|
||||
}
|
||||
s << " </likelytrash>\n";
|
||||
}
|
||||
|
||||
/// EffectRecords read into \e effectlist by restoreXml() override the list from ProtoModel.
|
||||
/// If this list is not empty, set up \e effectlist as a complete override containing
|
||||
/// all EffectRecords from ProtoModel plus all the overrides.
|
||||
void FuncProto::restoreEffectXml(void)
|
||||
|
||||
{
|
||||
if (effectlist.empty()) return;
|
||||
vector<EffectRecord> tmpList;
|
||||
tmpList.swap(effectlist);
|
||||
for(vector<EffectRecord>::const_iterator iter=model->effectBegin();iter!=model->effectEnd();++iter) {
|
||||
effectlist.push_back(*iter);
|
||||
}
|
||||
bool hasNew = false;
|
||||
int4 listSize = effectlist.size();
|
||||
for(vector<EffectRecord>::const_iterator iter=tmpList.begin();iter!=tmpList.end();++iter) {
|
||||
const EffectRecord &curRecord( *iter );
|
||||
int4 off = ProtoModel::lookupRecord(effectlist, listSize, curRecord.getAddress(), curRecord.getSize());
|
||||
if (off == -2)
|
||||
throw LowlevelError("Partial overlap of prototype override with existing effects");
|
||||
else if (off >= 0) {
|
||||
// Found matching record, change its type
|
||||
effectlist[off] = curRecord;
|
||||
}
|
||||
else {
|
||||
effectlist.push_back(curRecord);
|
||||
hasNew = true;
|
||||
}
|
||||
}
|
||||
if (hasNew)
|
||||
sort(effectlist.begin(),effectlist.end(),EffectRecord::compareByAddress);
|
||||
}
|
||||
|
||||
/// VarnodeData read into \e likelytrash by restoreXml() are additional registers over
|
||||
/// what is already in ProtoModel. Make \e likelytrash in \b this a complete list by
|
||||
/// merging in everything from ProtoModel.
|
||||
void FuncProto::restoreLikelyTrashXml(void)
|
||||
|
||||
{
|
||||
if (likelytrash.empty()) return;
|
||||
vector<VarnodeData> tmpList;
|
||||
tmpList.swap(likelytrash);
|
||||
vector<VarnodeData>::const_iterator iter1,iter2;
|
||||
iter1 = model->trashBegin();
|
||||
iter2 = model->trashEnd();
|
||||
for(vector<VarnodeData>::const_iterator iter=iter1;iter!=iter2;++iter)
|
||||
likelytrash.push_back(*iter);
|
||||
for(vector<VarnodeData>::const_iterator iter=tmpList.begin();iter!=tmpList.end();++iter) {
|
||||
if (!binary_search(iter1,iter2,*iter))
|
||||
likelytrash.push_back(*iter); // Add in the new register
|
||||
}
|
||||
sort(likelytrash.begin(),likelytrash.end());
|
||||
}
|
||||
|
||||
/// Prepend the indicated number of input parameters to \b this.
|
||||
/// The new parameters have a data-type of xunknown4. If they were
|
||||
/// originally locked, the existing parameters are preserved.
|
||||
|
@ -3472,23 +3769,22 @@ vector<EffectRecord>::const_iterator FuncProto::effectEnd(void) const
|
|||
return effectlist.end();
|
||||
}
|
||||
|
||||
/// \return the number of individual storage locations
|
||||
int4 FuncProto::numLikelyTrash(void) const
|
||||
/// \return the iterator to the start of the list
|
||||
vector<VarnodeData>::const_iterator FuncProto::trashBegin(void) const
|
||||
|
||||
{
|
||||
if (likelytrash.empty())
|
||||
return model->numLikelyTrash();
|
||||
return likelytrash.size();
|
||||
return model->trashBegin();
|
||||
return likelytrash.begin();
|
||||
}
|
||||
|
||||
/// \param i is the index of the storage location
|
||||
/// \return the storage location which may hold a trash value
|
||||
const VarnodeData &FuncProto::getLikelyTrash(int4 i) const
|
||||
/// \return the iterator to the end of the list
|
||||
vector<VarnodeData>::const_iterator FuncProto::trashEnd(void) const
|
||||
|
||||
{
|
||||
if (likelytrash.empty())
|
||||
return model->getLikelyTrash(i);
|
||||
return likelytrash[i];
|
||||
return model->trashEnd();
|
||||
return likelytrash.end();
|
||||
}
|
||||
|
||||
/// \brief Decide whether a given storage location could be, or could hold, an input parameter
|
||||
|
@ -3772,57 +4068,8 @@ void FuncProto::saveXml(ostream &s) const
|
|||
outparam->getAddress().saveXml(s,outparam->getSize());
|
||||
outparam->getType()->saveXml(s);
|
||||
s << " </returnsym>\n";
|
||||
if (!effectlist.empty()) {
|
||||
int4 othercount = 0;
|
||||
s << " <unaffected>\n";
|
||||
for(uint4 i=0;i<effectlist.size();++i) {
|
||||
uint4 tp = effectlist[i].getType();
|
||||
if (tp!=EffectRecord::unaffected) {
|
||||
othercount += 1;
|
||||
continue;
|
||||
}
|
||||
s << " ";
|
||||
effectlist[i].saveXml(s);
|
||||
s << '\n';
|
||||
}
|
||||
s << " </unaffected>\n";
|
||||
if (othercount > 0) {
|
||||
othercount = 0;
|
||||
s << " <killedbycall>\n";
|
||||
for(uint4 i=0;i<effectlist.size();++i) {
|
||||
uint4 tp = effectlist[i].getType();
|
||||
if (tp != EffectRecord::killedbycall) {
|
||||
othercount += 1;
|
||||
continue;
|
||||
}
|
||||
s << " ";
|
||||
effectlist[i].saveXml(s);
|
||||
s << '\n';
|
||||
}
|
||||
s << " </killedbycall>\n";
|
||||
}
|
||||
if (othercount > 0) {
|
||||
s << " <returnaddress>\n";
|
||||
for(uint4 i=0;i<effectlist.size();++i) {
|
||||
uint4 tp = effectlist[i].getType();
|
||||
if (tp != EffectRecord::return_address) continue;
|
||||
s << " ";
|
||||
effectlist[i].saveXml(s);
|
||||
s << '\n';
|
||||
}
|
||||
s << " </returnaddress>\n";
|
||||
}
|
||||
}
|
||||
if (!likelytrash.empty()) {
|
||||
s << " <likelytrash>\n";
|
||||
for(uint4 i=0;i<likelytrash.size();++i) {
|
||||
s << " <addr";
|
||||
const VarnodeData &vdata(likelytrash[i]);
|
||||
vdata.space->saveXmlAttributes(s,vdata.offset,vdata.size);
|
||||
s << "/>\n";
|
||||
}
|
||||
s << " </likelytrash>\n";
|
||||
}
|
||||
saveEffectXml(s);
|
||||
saveLikelyTrashXml(s);
|
||||
if (injectid >= 0) {
|
||||
Architecture *glb = model->getArch();
|
||||
s << " <inject>" << glb->pcodeinjectlib->getCallFixupName(injectid) << "</inject>\n";
|
||||
|
@ -4006,8 +4253,8 @@ void FuncProto::restoreXml(const Element *el,Architecture *glb)
|
|||
store->restoreXml(*iter,model);
|
||||
}
|
||||
}
|
||||
sort(effectlist.begin(),effectlist.end());
|
||||
sort(likelytrash.begin(),likelytrash.end());
|
||||
restoreEffectXml();
|
||||
restoreLikelyTrashXml();
|
||||
if (!isModelLocked()) {
|
||||
if (isInputLocked())
|
||||
flags |= modellock;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue