mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-5256 ExtraStack, sizes attribute, merge join sequence
This commit is contained in:
parent
acbda8b076
commit
00f9789116
40 changed files with 1015 additions and 411 deletions
|
@ -604,20 +604,21 @@ ParamListStandard::~ParamListStandard(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The entry must have a unique group.
|
/// \param tiles will contain the set of matching entries
|
||||||
/// If no matching entry is found, the \b end iterator is returned.
|
|
||||||
/// \param type is the storage class
|
/// \param type is the storage class
|
||||||
/// \return the first matching iterator
|
/// \return the first matching iterator
|
||||||
list<ParamEntry>::const_iterator ParamListStandard::getFirstIter(type_class type) const
|
void ParamListStandard::extractTiles(vector<const ParamEntry *> &tiles,type_class type) const
|
||||||
|
|
||||||
{
|
{
|
||||||
list<ParamEntry>::const_iterator iter;
|
list<ParamEntry>::const_iterator iter;
|
||||||
for(iter=entry.begin();iter!=entry.end();++iter) {
|
for(iter=entry.begin();iter!=entry.end();++iter) {
|
||||||
const ParamEntry &curEntry( *iter );
|
const ParamEntry &curEntry( *iter );
|
||||||
if (curEntry.getType() == type && curEntry.getAllGroups().size() == 1)
|
if (!curEntry.isExclusion())
|
||||||
return iter;
|
continue;
|
||||||
|
if (curEntry.getType() != type || curEntry.getAllGroups().size() != 1)
|
||||||
|
continue;
|
||||||
|
tiles.push_back(&curEntry);
|
||||||
}
|
}
|
||||||
return iter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the stack entry is not present, null is returned
|
/// If the stack entry is not present, null is returned
|
||||||
|
@ -2157,6 +2158,29 @@ void ParameterPieces::swapMarkup(ParameterPieces &op)
|
||||||
op.type = tmpType;
|
op.type = tmpType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Generate a parameter address given the list of Varnodes making up the parameter
|
||||||
|
///
|
||||||
|
/// \param pieces is the given list of Varnodes
|
||||||
|
/// \param mostToLeast is \b true if the list is ordered \e most significant to \e least
|
||||||
|
/// \param glb is the Architecture
|
||||||
|
void ParameterPieces::assignAddressFromPieces(vector<VarnodeData> &pieces,bool mostToLeast,Architecture *glb)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (!mostToLeast && pieces.size() > 1) {
|
||||||
|
vector<VarnodeData> reverse;
|
||||||
|
for(int4 i=pieces.size()-1;i>=0;--i)
|
||||||
|
reverse.push_back(pieces[i]);
|
||||||
|
pieces.swap(reverse);
|
||||||
|
}
|
||||||
|
JoinRecord::mergeSequence(pieces,glb->translate);
|
||||||
|
if (pieces.size() == 1) {
|
||||||
|
addr = pieces[0].getAddr();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JoinRecord *joinRecord = glb->findAddJoin(pieces, 0);
|
||||||
|
addr = joinRecord->getUnified().getAddr();
|
||||||
|
}
|
||||||
|
|
||||||
/// The type is set to \e unknown_effect
|
/// The type is set to \e unknown_effect
|
||||||
/// \param addr is the start of the memory range
|
/// \param addr is the start of the memory range
|
||||||
/// \param size is the number of bytes in the memory range
|
/// \param size is the number of bytes in the memory range
|
||||||
|
|
|
@ -367,6 +367,7 @@ struct ParameterPieces {
|
||||||
Datatype *type; ///< The datatype of the parameter
|
Datatype *type; ///< The datatype of the parameter
|
||||||
uint4 flags; ///< additional attributes of the parameter
|
uint4 flags; ///< additional attributes of the parameter
|
||||||
void swapMarkup(ParameterPieces &op); ///< Swap data-type markup between \b this and another parameter
|
void swapMarkup(ParameterPieces &op); ///< Swap data-type markup between \b this and another parameter
|
||||||
|
void assignAddressFromPieces(vector<VarnodeData> &pieces,bool mostToLeast,Architecture *glb);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Raw components of a function prototype (obtained from parsing source code)
|
/// \brief Raw components of a function prototype (obtained from parsing source code)
|
||||||
|
@ -614,7 +615,7 @@ public:
|
||||||
ParamListStandard(const ParamListStandard &op2); ///< Copy constructor
|
ParamListStandard(const ParamListStandard &op2); ///< Copy constructor
|
||||||
virtual ~ParamListStandard(void);
|
virtual ~ParamListStandard(void);
|
||||||
const list<ParamEntry> &getEntry(void) const { return entry; } ///< Get the list of parameter entries
|
const list<ParamEntry> &getEntry(void) const { return entry; } ///< Get the list of parameter entries
|
||||||
list<ParamEntry>::const_iterator getFirstIter(type_class type) const; ///< Get iterator to first entry in a storage class
|
void extractTiles(vector<const ParamEntry *> &tiles,type_class type) const; ///< Get registers of given storage class
|
||||||
const ParamEntry *getStackEntry(void) const; ///< Get the stack entry
|
const ParamEntry *getStackEntry(void) const; ///< Get the stack entry
|
||||||
uint4 assignAddressFallback(type_class resource,Datatype *tp,bool matchExact,vector<int4> &status,
|
uint4 assignAddressFallback(type_class resource,Datatype *tp,bool matchExact,vector<int4> &status,
|
||||||
ParameterPieces ¶m) const;
|
ParameterPieces ¶m) const;
|
||||||
|
|
|
@ -627,7 +627,7 @@ class CloneBlockOps {
|
||||||
PcodeOp *origOp; ///< Original op that was cloned
|
PcodeOp *origOp; ///< Original op that was cloned
|
||||||
ClonePair(PcodeOp *c,PcodeOp *o) { cloneOp = c; origOp = o; } ///< Constructor
|
ClonePair(PcodeOp *c,PcodeOp *o) { cloneOp = c; origOp = o; } ///< Constructor
|
||||||
};
|
};
|
||||||
Funcdata &data;
|
Funcdata &data; ///< Function containing ops to clone
|
||||||
vector<ClonePair> cloneList; ///< List of cloned ops
|
vector<ClonePair> cloneList; ///< List of cloned ops
|
||||||
map<PcodeOp *,PcodeOp *> origToClone; ///< Map from original p-code op to its clone
|
map<PcodeOp *,PcodeOp *> origToClone; ///< Map from original p-code op to its clone
|
||||||
PcodeOp *buildOpClone(PcodeOp *op); ///< Produce a skeleton copy of the given PcodeOp
|
PcodeOp *buildOpClone(PcodeOp *op); ///< Produce a skeleton copy of the given PcodeOp
|
||||||
|
|
|
@ -971,10 +971,10 @@ PcodeOp *CloneBlockOps::buildOpClone(PcodeOp *op)
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make a basic clone of the Varnode and its flags. The clone is created
|
/// Make a basic clone of a Varnode and its flags. The clone is created
|
||||||
/// as an output of a previously cloned PcodeOp.
|
/// as an output Varnode of a previously cloned PcodeOp.
|
||||||
/// \param op is the given op whose output should be cloned
|
/// \param origOp is the given op whose output should be cloned
|
||||||
/// \param newop is the cloned version
|
/// \param cloneOp is the cloned version
|
||||||
void CloneBlockOps::buildVarnodeOutput(PcodeOp *origOp,PcodeOp *cloneOp)
|
void CloneBlockOps::buildVarnodeOutput(PcodeOp *origOp,PcodeOp *cloneOp)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -555,6 +555,7 @@ Varnode *Funcdata::opStackLoad(AddrSpace *spc,uintb off,uint4 sz,PcodeOp *op,Var
|
||||||
///
|
///
|
||||||
/// \param vn is the given Varnode
|
/// \param vn is the given Varnode
|
||||||
/// \param op is the point at which to insert the BOOL_NEGATE op
|
/// \param op is the point at which to insert the BOOL_NEGATE op
|
||||||
|
/// \param insertafter is \b true if the BOOL_NEGATE is inserted after, otherwise its inserted before
|
||||||
/// \return the result Varnode
|
/// \return the result Varnode
|
||||||
Varnode *Funcdata::opBoolNegate(Varnode *vn,PcodeOp *op,bool insertafter)
|
Varnode *Funcdata::opBoolNegate(Varnode *vn,PcodeOp *op,bool insertafter)
|
||||||
|
|
||||||
|
@ -1273,7 +1274,6 @@ int4 Funcdata::opFlipInPlaceTest(PcodeOp *op,vector<PcodeOp *> &fliplist)
|
||||||
///
|
///
|
||||||
/// The precomputed list of PcodeOps have their op-codes modified to
|
/// The precomputed list of PcodeOps have their op-codes modified to
|
||||||
/// facilitate the flip.
|
/// facilitate the flip.
|
||||||
/// \param data is the function being modified
|
|
||||||
/// \param fliplist is the list of PcodeOps to modify
|
/// \param fliplist is the list of PcodeOps to modify
|
||||||
void Funcdata::opFlipInPlaceExecute(vector<PcodeOp *> &fliplist)
|
void Funcdata::opFlipInPlaceExecute(vector<PcodeOp *> &fliplist)
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,25 @@ string GhidraTranslate::getRegisterName(AddrSpace *base,uintb off,int4 size) con
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string GhidraTranslate::getExactRegisterName(AddrSpace *base,uintb off,int4 size) const
|
||||||
|
|
||||||
|
{
|
||||||
|
if (base->getType() != IPTR_PROCESSOR) return "";
|
||||||
|
VarnodeData vndata;
|
||||||
|
vndata.space = base;
|
||||||
|
vndata.offset = off;
|
||||||
|
vndata.size = size;
|
||||||
|
map<VarnodeData,string>::const_iterator iter = addr2nm.find(vndata);
|
||||||
|
if (iter != addr2nm.end())
|
||||||
|
return (*iter).second;
|
||||||
|
string res = glb->getRegisterName(vndata);
|
||||||
|
if (res.size()!=0) { // Cause this register to be cached if not already
|
||||||
|
if (getRegister(res).size == size)
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
void GhidraTranslate::getUserOpNames(vector<string> &res) const
|
void GhidraTranslate::getUserOpNames(vector<string> &res) const
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace ghidra {
|
||||||
class GhidraTranslate : public Translate {
|
class GhidraTranslate : public Translate {
|
||||||
ArchitectureGhidra *glb; ///< The Ghidra Architecture and connection to the client
|
ArchitectureGhidra *glb; ///< The Ghidra Architecture and connection to the client
|
||||||
mutable map<string,VarnodeData> nm2addr; ///< Mapping from register name to Varnode
|
mutable map<string,VarnodeData> nm2addr; ///< Mapping from register name to Varnode
|
||||||
mutable map<VarnodeData,string> addr2nm; ///< Mapping rom Varnode to register name
|
mutable map<VarnodeData,string> addr2nm; ///< Mapping from Varnode to register name
|
||||||
const VarnodeData &cacheRegister(const string &nm,const VarnodeData &data) const;
|
const VarnodeData &cacheRegister(const string &nm,const VarnodeData &data) const;
|
||||||
void decode(Decoder &decoder); ///< Initialize \b this Translate from a stream
|
void decode(Decoder &decoder); ///< Initialize \b this Translate from a stream
|
||||||
public:
|
public:
|
||||||
|
@ -45,6 +45,7 @@ public:
|
||||||
virtual void initialize(DocumentStorage &store);
|
virtual void initialize(DocumentStorage &store);
|
||||||
virtual const VarnodeData &getRegister(const string &nm) const;
|
virtual const VarnodeData &getRegister(const string &nm) const;
|
||||||
virtual string getRegisterName(AddrSpace *base,uintb off,int4 size) const;
|
virtual string getRegisterName(AddrSpace *base,uintb off,int4 size) const;
|
||||||
|
virtual string getExactRegisterName(AddrSpace *base,uintb off,int4 size) const;
|
||||||
virtual void getAllRegisters(map<VarnodeData,string> ®list) const {
|
virtual void getAllRegisters(map<VarnodeData,string> ®list) const {
|
||||||
throw LowlevelError("Cannot currently get all registers through this interface"); }
|
throw LowlevelError("Cannot currently get all registers through this interface"); }
|
||||||
virtual void getUserOpNames(vector<string> &res) const;
|
virtual void getUserOpNames(vector<string> &res) const;
|
||||||
|
|
|
@ -1254,7 +1254,7 @@ AttributeId ATTRIB_WORDSIZE = AttributeId("wordsize",26);
|
||||||
AttributeId ATTRIB_STORAGE = AttributeId("storage",149);
|
AttributeId ATTRIB_STORAGE = AttributeId("storage",149);
|
||||||
AttributeId ATTRIB_STACKSPILL = AttributeId("stackspill",150);
|
AttributeId ATTRIB_STACKSPILL = AttributeId("stackspill",150);
|
||||||
|
|
||||||
AttributeId ATTRIB_UNKNOWN = AttributeId("XMLunknown",151); // Number serves as next open index
|
AttributeId ATTRIB_UNKNOWN = AttributeId("XMLunknown",152); // Number serves as next open index
|
||||||
|
|
||||||
ElementId ELEM_DATA = ElementId("data",1);
|
ElementId ELEM_DATA = ElementId("data",1);
|
||||||
ElementId ELEM_INPUT = ElementId("input",2);
|
ElementId ELEM_INPUT = ElementId("input",2);
|
||||||
|
@ -1267,6 +1267,6 @@ ElementId ELEM_VAL = ElementId("val",8);
|
||||||
ElementId ELEM_VALUE = ElementId("value",9);
|
ElementId ELEM_VALUE = ElementId("value",9);
|
||||||
ElementId ELEM_VOID = ElementId("void",10);
|
ElementId ELEM_VOID = ElementId("void",10);
|
||||||
|
|
||||||
ElementId ELEM_UNKNOWN = ElementId("XMLunknown",287); // Number serves as next open index
|
ElementId ELEM_UNKNOWN = ElementId("XMLunknown",288); // Number serves as next open index
|
||||||
|
|
||||||
} // End namespace ghidra
|
} // End namespace ghidra
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
|
|
||||||
namespace ghidra {
|
namespace ghidra {
|
||||||
|
|
||||||
|
AttributeId ATTRIB_SIZES = AttributeId("sizes",151);
|
||||||
|
|
||||||
ElementId ELEM_DATATYPE = ElementId("datatype",273);
|
ElementId ELEM_DATATYPE = ElementId("datatype",273);
|
||||||
ElementId ELEM_CONSUME = ElementId("consume",274);
|
ElementId ELEM_CONSUME = ElementId("consume",274);
|
||||||
ElementId ELEM_CONSUME_EXTRA = ElementId("consume_extra",275);
|
ElementId ELEM_CONSUME_EXTRA = ElementId("consume_extra",275);
|
||||||
|
@ -30,6 +32,7 @@ ElementId ELEM_VARARGS = ElementId("varargs",281);
|
||||||
ElementId ELEM_HIDDEN_RETURN = ElementId("hidden_return",282);
|
ElementId ELEM_HIDDEN_RETURN = ElementId("hidden_return",282);
|
||||||
ElementId ELEM_JOIN_PER_PRIMITIVE = ElementId("join_per_primitive",283);
|
ElementId ELEM_JOIN_PER_PRIMITIVE = ElementId("join_per_primitive",283);
|
||||||
ElementId ELEM_JOIN_DUAL_CLASS = ElementId("join_dual_class",285);
|
ElementId ELEM_JOIN_DUAL_CLASS = ElementId("join_dual_class",285);
|
||||||
|
ElementId ELEM_EXTRA_STACK = ElementId("extra_stack",287);
|
||||||
|
|
||||||
/// \brief Check that a big Primitive properly overlaps smaller Primitives
|
/// \brief Check that a big Primitive properly overlaps smaller Primitives
|
||||||
///
|
///
|
||||||
|
@ -261,6 +264,35 @@ DatatypeFilter *DatatypeFilter::decodeFilter(Decoder &decoder)
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse the given string as a comma or space separated list of decimal integers,
|
||||||
|
/// populating the \b sizes set.
|
||||||
|
/// \param str is the given string to parse
|
||||||
|
void SizeRestrictedFilter::initFromSizeList(const string &str)
|
||||||
|
|
||||||
|
{
|
||||||
|
istringstream s(str);
|
||||||
|
int4 val;
|
||||||
|
for(;;) {
|
||||||
|
val = -1;
|
||||||
|
s >> ws;
|
||||||
|
if (s.eof()) break;
|
||||||
|
if (s.peek() == ',') {
|
||||||
|
char punc;
|
||||||
|
s >> punc >> ws;
|
||||||
|
}
|
||||||
|
s >> val;
|
||||||
|
if (val <= 0)
|
||||||
|
throw DecoderError("Bad filter size");
|
||||||
|
sizes.insert(val);
|
||||||
|
}
|
||||||
|
if (!sizes.empty()) {
|
||||||
|
minSize = *sizes.begin();
|
||||||
|
set<int4>::const_iterator iter = sizes.end();
|
||||||
|
--iter;
|
||||||
|
maxSize = *iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SizeRestrictedFilter::SizeRestrictedFilter(int4 min,int4 max)
|
SizeRestrictedFilter::SizeRestrictedFilter(int4 min,int4 max)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -272,14 +304,26 @@ SizeRestrictedFilter::SizeRestrictedFilter(int4 min,int4 max)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SizeRestrictedFilter::SizeRestrictedFilter(const SizeRestrictedFilter &op2)
|
||||||
|
|
||||||
|
{
|
||||||
|
minSize = op2.minSize;
|
||||||
|
maxSize = op2.maxSize;
|
||||||
|
sizes = op2.sizes;
|
||||||
|
}
|
||||||
|
|
||||||
/// If \b maxSize is not zero, the data-type is checked to see if its size in bytes
|
/// If \b maxSize is not zero, the data-type is checked to see if its size in bytes
|
||||||
/// falls between \b minSize and \b maxSize inclusive.
|
/// falls between \b minSize and \b maxSize inclusive. If enumerated sizes are present,
|
||||||
|
/// also check that the particular size is in the enumerated set.
|
||||||
/// \param dt is the data-type to test
|
/// \param dt is the data-type to test
|
||||||
/// \return \b true if the data-type meets the size restrictions
|
/// \return \b true if the data-type meets the size restrictions
|
||||||
bool SizeRestrictedFilter::filterOnSize(Datatype *dt) const
|
bool SizeRestrictedFilter::filterOnSize(Datatype *dt) const
|
||||||
|
|
||||||
{
|
{
|
||||||
if (maxSize == 0) return true; // maxSize of 0 means no size filtering is performed
|
if (maxSize == 0) return true; // maxSize of 0 means no size filtering is performed
|
||||||
|
if (!sizes.empty()) {
|
||||||
|
return (sizes.find(dt->getSize()) != sizes.end());
|
||||||
|
}
|
||||||
return (dt->getSize() >= minSize && dt->getSize() <= maxSize);
|
return (dt->getSize() >= minSize && dt->getSize() <= maxSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,10 +333,22 @@ void SizeRestrictedFilter::decode(Decoder &decoder)
|
||||||
for(;;) {
|
for(;;) {
|
||||||
uint4 attribId = decoder.getNextAttributeId();
|
uint4 attribId = decoder.getNextAttributeId();
|
||||||
if (attribId == 0) break;
|
if (attribId == 0) break;
|
||||||
if (attribId == ATTRIB_MINSIZE)
|
if (attribId == ATTRIB_MINSIZE) {
|
||||||
|
if (!sizes.empty())
|
||||||
|
throw DecoderError("Mixing \"sizes\" with \"minsize\" and \"maxsize\"");
|
||||||
minSize = decoder.readUnsignedInteger();
|
minSize = decoder.readUnsignedInteger();
|
||||||
else if (attribId == ATTRIB_MAXSIZE)
|
}
|
||||||
|
else if (attribId == ATTRIB_MAXSIZE) {
|
||||||
|
if (!sizes.empty())
|
||||||
|
throw DecoderError("Mixing \"sizes\" with \"minsize\" and \"maxsize\"");
|
||||||
maxSize = decoder.readUnsignedInteger();
|
maxSize = decoder.readUnsignedInteger();
|
||||||
|
}
|
||||||
|
else if (attribId == ATTRIB_SIZES) {
|
||||||
|
if (minSize != 0 || maxSize != 0)
|
||||||
|
throw DecoderError("Mixing \"sizes\" with \"minsize\" and \"maxsize\"");
|
||||||
|
string sizeList = decoder.readString();
|
||||||
|
initFromSizeList(sizeList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (maxSize == 0 && minSize >= 0) {
|
if (maxSize == 0 && minSize >= 0) {
|
||||||
// If no ATTRIB_MAXSIZE is given, assume there is no upper bound on size
|
// If no ATTRIB_MAXSIZE is given, assume there is no upper bound on size
|
||||||
|
@ -312,6 +368,12 @@ MetaTypeFilter::MetaTypeFilter(type_metatype meta,int4 min,int4 max)
|
||||||
metaType = meta;
|
metaType = meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetaTypeFilter::MetaTypeFilter(const MetaTypeFilter &op2)
|
||||||
|
: SizeRestrictedFilter(op2)
|
||||||
|
{
|
||||||
|
metaType = op2.metaType;
|
||||||
|
}
|
||||||
|
|
||||||
bool MetaTypeFilter::filter(Datatype *dt) const
|
bool MetaTypeFilter::filter(Datatype *dt) const
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -333,6 +395,13 @@ HomogeneousAggregate::HomogeneousAggregate(type_metatype meta,int4 maxPrim,int4
|
||||||
maxPrimitives = maxPrim;
|
maxPrimitives = maxPrim;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HomogeneousAggregate::HomogeneousAggregate(const HomogeneousAggregate &op2)
|
||||||
|
: SizeRestrictedFilter(op2)
|
||||||
|
{
|
||||||
|
metaType = op2.metaType;
|
||||||
|
maxPrimitives = op2.maxPrimitives;
|
||||||
|
}
|
||||||
|
|
||||||
bool HomogeneousAggregate::filter(Datatype *dt) const
|
bool HomogeneousAggregate::filter(Datatype *dt) const
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -550,6 +619,9 @@ AssignAction *AssignAction::decodeSideeffect(Decoder &decoder,const ParamListSta
|
||||||
if (elemId == ELEM_CONSUME_EXTRA) {
|
if (elemId == ELEM_CONSUME_EXTRA) {
|
||||||
action = new ConsumeExtra(res);
|
action = new ConsumeExtra(res);
|
||||||
}
|
}
|
||||||
|
else if (elemId == ELEM_EXTRA_STACK) {
|
||||||
|
action = new ExtraStack(res,0);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
throw DecoderError("Expecting model rule sideeffect");
|
throw DecoderError("Expecting model rule sideeffect");
|
||||||
action->decode(decoder);
|
action->decode(decoder);
|
||||||
|
@ -561,7 +633,7 @@ void GotoStack::initializeEntry(void)
|
||||||
{
|
{
|
||||||
stackEntry = resource->getStackEntry();
|
stackEntry = resource->getStackEntry();
|
||||||
if (stackEntry == (const ParamEntry *)0)
|
if (stackEntry == (const ParamEntry *)0)
|
||||||
throw LowlevelError("Cannot find matching <pentry> for action: gotostack");
|
throw LowlevelError("Cannot find matching <pentry> for action: goto_stack");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \param res is the new resource set to associate with \b this action
|
/// \param res is the new resource set to associate with \b this action
|
||||||
|
@ -650,9 +722,9 @@ void ConvertToPointer::decode(Decoder &decoder)
|
||||||
void MultiSlotAssign::initializeEntries(void)
|
void MultiSlotAssign::initializeEntries(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
firstIter = resource->getFirstIter(resourceType);
|
resource->extractTiles(tiles,resourceType);
|
||||||
stackEntry = resource->getStackEntry();
|
stackEntry = resource->getStackEntry();
|
||||||
if (firstIter == resource->getEntry().end())
|
if (tiles.size() == 0)
|
||||||
throw LowlevelError("Could not find matching resources for action: join");
|
throw LowlevelError("Could not find matching resources for action: join");
|
||||||
if (consumeFromStack && stackEntry == (const ParamEntry *)0)
|
if (consumeFromStack && stackEntry == (const ParamEntry *)0)
|
||||||
throw LowlevelError("Cannot find matching <pentry> for action: join");
|
throw LowlevelError("Cannot find matching <pentry> for action: join");
|
||||||
|
@ -699,38 +771,29 @@ uint4 MultiSlotAssign::assignAddress(Datatype *dt,const PrototypePieces &proto,i
|
||||||
vector<VarnodeData> pieces;
|
vector<VarnodeData> pieces;
|
||||||
int4 sizeLeft = dt->getSize();
|
int4 sizeLeft = dt->getSize();
|
||||||
int4 align = dt->getAlignment();
|
int4 align = dt->getAlignment();
|
||||||
list<ParamEntry>::const_iterator iter = firstIter;
|
int4 iter = 0;
|
||||||
list<ParamEntry>::const_iterator endIter = resource->getEntry().end();
|
|
||||||
if (enforceAlignment) {
|
if (enforceAlignment) {
|
||||||
int4 resourcesConsumed = 0;
|
int4 resourcesConsumed = 0;
|
||||||
while(iter != endIter) {
|
while(iter != tiles.size()) {
|
||||||
const ParamEntry &entry( *iter );
|
const ParamEntry *entry = tiles[iter];
|
||||||
if (!entry.isExclusion())
|
if (tmpStatus[entry->getGroup()] == 0) { // Not consumed
|
||||||
break; // Reached end of resource list
|
int4 regSize = entry->getSize();
|
||||||
if (entry.getType() == resourceType && entry.getAllGroups().size() == 1) { // Single register
|
if (align <= regSize || (resourcesConsumed % align) == 0)
|
||||||
if (tmpStatus[entry.getGroup()] == 0) { // Not consumed
|
break;
|
||||||
int4 regSize = entry.getSize();
|
tmpStatus[entry->getGroup()] = -1; // Consume unaligned register
|
||||||
if (align <= regSize || (resourcesConsumed % align) == 0)
|
|
||||||
break;
|
|
||||||
tmpStatus[entry.getGroup()] = -1; // Consume unaligned register
|
|
||||||
}
|
|
||||||
resourcesConsumed += entry.getSize();
|
|
||||||
}
|
}
|
||||||
|
resourcesConsumed += entry->getSize();
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while(sizeLeft > 0 && iter != endIter) {
|
while(sizeLeft > 0 && iter != tiles.size()) {
|
||||||
const ParamEntry &entry( *iter );
|
const ParamEntry *entry = tiles[iter];
|
||||||
++iter;
|
++iter;
|
||||||
if (!entry.isExclusion())
|
if (tmpStatus[entry->getGroup()] != 0)
|
||||||
break; // Reached end of resource list
|
|
||||||
if (entry.getType() != resourceType || entry.getAllGroups().size() != 1)
|
|
||||||
continue; // Not a single register from desired resource list
|
|
||||||
if (tmpStatus[entry.getGroup()] != 0)
|
|
||||||
continue; // Already consumed
|
continue; // Already consumed
|
||||||
int4 trialSize = entry.getSize();
|
int4 trialSize = entry->getSize();
|
||||||
Address addr = entry.getAddrBySlot(tmpStatus[entry.getGroup()], trialSize,align);
|
Address addr = entry->getAddrBySlot(tmpStatus[entry->getGroup()], trialSize,align);
|
||||||
tmpStatus[entry.getGroup()] = -1; // Consume the register
|
tmpStatus[entry->getGroup()] = -1; // Consume the register
|
||||||
pieces.push_back(VarnodeData());
|
pieces.push_back(VarnodeData());
|
||||||
pieces.back().space = addr.getSpace();
|
pieces.back().space = addr.getSpace();
|
||||||
pieces.back().offset = addr.getOffset();
|
pieces.back().offset = addr.getOffset();
|
||||||
|
@ -770,18 +833,7 @@ uint4 MultiSlotAssign::assignAddress(Datatype *dt,const PrototypePieces &proto,i
|
||||||
status = tmpStatus; // Commit resource usage for all the pieces
|
status = tmpStatus; // Commit resource usage for all the pieces
|
||||||
res.flags = 0;
|
res.flags = 0;
|
||||||
res.type = dt;
|
res.type = dt;
|
||||||
if (pieces.size() == 1) {
|
res.assignAddressFromPieces(pieces, consumeMostSig, tlist.getArch());
|
||||||
res.addr = pieces[0].getAddr();
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
if (!consumeMostSig) {
|
|
||||||
vector<VarnodeData> reverse;
|
|
||||||
for(int4 i=pieces.size()-1;i>=0;--i)
|
|
||||||
reverse.push_back(pieces[i]);
|
|
||||||
pieces.swap(reverse);
|
|
||||||
}
|
|
||||||
JoinRecord *joinRecord = tlist.getArch()->findAddJoin(pieces, 0);
|
|
||||||
res.addr = joinRecord->getUnified().getAddr();
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -891,18 +943,7 @@ uint4 MultiMemberAssign::assignAddress(Datatype *dt,const PrototypePieces &proto
|
||||||
status = tmpStatus; // Commit resource usage for all the pieces
|
status = tmpStatus; // Commit resource usage for all the pieces
|
||||||
res.flags = 0;
|
res.flags = 0;
|
||||||
res.type = dt;
|
res.type = dt;
|
||||||
if (pieces.size() == 1) {
|
res.assignAddressFromPieces(pieces, consumeMostSig, tlist.getArch());
|
||||||
res.addr = pieces[0].getAddr();
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
if (!consumeMostSig) {
|
|
||||||
vector<VarnodeData> reverse;
|
|
||||||
for(int4 i=pieces.size()-1;i>=0;--i)
|
|
||||||
reverse.push_back(pieces[i]);
|
|
||||||
pieces.swap(reverse);
|
|
||||||
}
|
|
||||||
JoinRecord *joinRecord = tlist.getArch()->findAddJoin(pieces, 0);
|
|
||||||
res.addr = joinRecord->getUnified().getAddr();
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -951,37 +992,30 @@ void MultiMemberAssign::decode(Decoder &decoder)
|
||||||
void MultiSlotDualAssign::initializeEntries(void)
|
void MultiSlotDualAssign::initializeEntries(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
baseIter = resource->getFirstIter(baseType);
|
resource->extractTiles(baseTiles,baseType);
|
||||||
altIter = resource->getFirstIter(altType);
|
resource->extractTiles(altTiles,altType);
|
||||||
list<ParamEntry>::const_iterator enditer = resource->getEntry().end();
|
if (baseTiles.size() == 0 || altTiles.size() == 0)
|
||||||
if (baseIter == enditer || altIter == enditer)
|
|
||||||
throw LowlevelError("Could not find matching resources for action: join_dual_class");
|
throw LowlevelError("Could not find matching resources for action: join_dual_class");
|
||||||
tileSize = (*baseIter).getSize();
|
tileSize = baseTiles[0]->getSize();
|
||||||
if (tileSize != (*altIter).getSize())
|
if (tileSize != altTiles[0]->getSize())
|
||||||
throw LowlevelError("Storage class register sizes do not match for action: join_dual_class");
|
throw LowlevelError("Storage class register sizes do not match for action: join_dual_class");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Get the first unused ParamEntry that matches the given storage class
|
/// \brief Get the index of the first unused ParamEntry in the given list
|
||||||
///
|
///
|
||||||
/// \param iter points to the starting entry to search
|
/// \param iter is the index of the starting entry to search
|
||||||
/// \param storage is the given storage class to match
|
/// \param tiles is the given list to search
|
||||||
/// \param status is the usage information for the entries
|
/// \param status is the usage information for the entries
|
||||||
/// \return the iterator to the unused ParamEntry
|
/// \return the index of the unused ParamEntry
|
||||||
list<ParamEntry>::const_iterator MultiSlotDualAssign::getFirstUnused(list<ParamEntry>::const_iterator iter,
|
int4 MultiSlotDualAssign::getFirstUnused(int4 iter,const vector<const ParamEntry *> &tiles,vector<int4> &status) const
|
||||||
type_class storage,vector<int4> &status) const
|
|
||||||
{
|
{
|
||||||
list<ParamEntry>::const_iterator endIter = resource->getEntry().end();
|
for(;iter != tiles.size(); ++iter) {
|
||||||
for(;iter != endIter; ++iter) {
|
const ParamEntry *entry = tiles[iter];
|
||||||
const ParamEntry &entry( *iter );
|
if (status[entry->getGroup()] != 0)
|
||||||
if (!entry.isExclusion())
|
|
||||||
break; // Reached end of resource list
|
|
||||||
if (entry.getType() != storage || entry.getAllGroups().size() != 1)
|
|
||||||
continue; // Not a single register from desired resource
|
|
||||||
if (status[entry.getGroup()] != 0)
|
|
||||||
continue; // Already consumed
|
continue; // Already consumed
|
||||||
return iter;
|
return iter;
|
||||||
}
|
}
|
||||||
return endIter;
|
return tiles.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Get the storage class to use for the specific section of the data-type
|
/// \brief Get the storage class to use for the specific section of the data-type
|
||||||
|
@ -1057,26 +1091,28 @@ uint4 MultiSlotDualAssign::assignAddress(Datatype *dt,const PrototypePieces &pro
|
||||||
vector<VarnodeData> pieces;
|
vector<VarnodeData> pieces;
|
||||||
int4 typeSize = dt->getSize();
|
int4 typeSize = dt->getSize();
|
||||||
int4 sizeLeft = typeSize;
|
int4 sizeLeft = typeSize;
|
||||||
list<ParamEntry>::const_iterator iterBase = baseIter;
|
int4 iterBase = 0;
|
||||||
list<ParamEntry>::const_iterator iterAlt = altIter;
|
int4 iterAlt = 0;
|
||||||
list<ParamEntry>::const_iterator endIter = resource->getEntry().end();
|
|
||||||
while(sizeLeft > 0) {
|
while(sizeLeft > 0) {
|
||||||
list<ParamEntry>::const_iterator iter;
|
const ParamEntry *entry;
|
||||||
int4 iterType = getTileClass(primitives, typeSize-sizeLeft, primitiveIndex);
|
int4 iterType = getTileClass(primitives, typeSize-sizeLeft, primitiveIndex);
|
||||||
if (iterType < 0)
|
if (iterType < 0)
|
||||||
return fail;
|
return fail;
|
||||||
if (iterType == 0) {
|
if (iterType == 0) {
|
||||||
iter = iterBase = getFirstUnused(iterBase, baseType, tmpStatus);
|
iterBase = getFirstUnused(iterBase, baseTiles, tmpStatus);
|
||||||
|
if (iterBase == baseTiles.size())
|
||||||
|
return fail; // Out of general purpose registers
|
||||||
|
entry = baseTiles[iterBase];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
iter = iterAlt = getFirstUnused(iterAlt, altType, tmpStatus);
|
iterAlt = getFirstUnused(iterAlt, altTiles, tmpStatus);
|
||||||
|
if (iterAlt == altTiles.size())
|
||||||
|
return fail; // Out of alternate registers
|
||||||
|
entry = altTiles[iterAlt];
|
||||||
}
|
}
|
||||||
if (iter == endIter)
|
int4 trialSize = entry->getSize();
|
||||||
return fail; // Out of the particular resource
|
Address addr = entry->getAddrBySlot(tmpStatus[entry->getGroup()], trialSize,1);
|
||||||
const ParamEntry &entry( *iter );
|
tmpStatus[entry->getGroup()] = -1; // Consume the register
|
||||||
int4 trialSize = entry.getSize();
|
|
||||||
Address addr = entry.getAddrBySlot(tmpStatus[entry.getGroup()], trialSize,1);
|
|
||||||
tmpStatus[entry.getGroup()] = -1; // Consume the register
|
|
||||||
pieces.push_back(VarnodeData());
|
pieces.push_back(VarnodeData());
|
||||||
pieces.back().space = addr.getSpace();
|
pieces.back().space = addr.getSpace();
|
||||||
pieces.back().offset = addr.getOffset();
|
pieces.back().offset = addr.getOffset();
|
||||||
|
@ -1095,18 +1131,7 @@ uint4 MultiSlotDualAssign::assignAddress(Datatype *dt,const PrototypePieces &pro
|
||||||
status = tmpStatus; // Commit resource usage for all the pieces
|
status = tmpStatus; // Commit resource usage for all the pieces
|
||||||
res.flags = 0;
|
res.flags = 0;
|
||||||
res.type = dt;
|
res.type = dt;
|
||||||
if (pieces.size() == 1) {
|
res.assignAddressFromPieces(pieces, consumeMostSig, tlist.getArch());
|
||||||
res.addr = pieces[0].getAddr();
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
if (!consumeMostSig) {
|
|
||||||
vector<VarnodeData> reverse;
|
|
||||||
for(int4 i=pieces.size()-1;i>=0;--i)
|
|
||||||
reverse.push_back(pieces[i]);
|
|
||||||
pieces.swap(reverse);
|
|
||||||
}
|
|
||||||
JoinRecord *joinRecord = tlist.getArch()->findAddJoin(pieces, 0);
|
|
||||||
res.addr = joinRecord->getUnified().getAddr();
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1270,9 +1295,9 @@ void HiddenReturnAssign::decode(Decoder &decoder)
|
||||||
void ConsumeExtra::initializeEntries(void)
|
void ConsumeExtra::initializeEntries(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
firstIter = resource->getFirstIter(resourceType);
|
resource->extractTiles(tiles,resourceType);
|
||||||
if (firstIter == resource->getEntry().end())
|
if (tiles.size() == 0)
|
||||||
throw LowlevelError("Could not find matching resources for action: consumeextra");
|
throw LowlevelError("Could not find matching resources for action: consume_extra");
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsumeExtra::ConsumeExtra(const ParamListStandard *res)
|
ConsumeExtra::ConsumeExtra(const ParamListStandard *res)
|
||||||
|
@ -1293,20 +1318,15 @@ ConsumeExtra::ConsumeExtra(type_class store,bool match,const ParamListStandard *
|
||||||
uint4 ConsumeExtra::assignAddress(Datatype *dt,const PrototypePieces &proto,int4 pos,TypeFactory &tlist,
|
uint4 ConsumeExtra::assignAddress(Datatype *dt,const PrototypePieces &proto,int4 pos,TypeFactory &tlist,
|
||||||
vector<int4> &status,ParameterPieces &res) const
|
vector<int4> &status,ParameterPieces &res) const
|
||||||
{
|
{
|
||||||
list<ParamEntry>::const_iterator iter = firstIter;
|
int4 iter = 0;
|
||||||
list<ParamEntry>::const_iterator endIter = resource->getEntry().end();
|
|
||||||
int4 sizeLeft = dt->getSize();
|
int4 sizeLeft = dt->getSize();
|
||||||
while(sizeLeft > 0 && iter != endIter) {
|
while(sizeLeft > 0 && iter != tiles.size()) {
|
||||||
const ParamEntry &entry(*iter);
|
const ParamEntry *entry = tiles[iter];
|
||||||
++iter;
|
++iter;
|
||||||
if (!entry.isExclusion())
|
if (status[entry->getGroup()] != 0)
|
||||||
break; // Reached end of resource list
|
|
||||||
if (entry.getType() != resourceType || entry.getAllGroups().size() != 1)
|
|
||||||
continue; // Not a single register in desired list
|
|
||||||
if (status[entry.getGroup()] != 0)
|
|
||||||
continue; // Already consumed
|
continue; // Already consumed
|
||||||
status[entry.getGroup()] = -1; // Consume the slot/register
|
status[entry->getGroup()] = -1; // Consume the slot/register
|
||||||
sizeLeft -= entry.getSize();
|
sizeLeft -= entry->getSize();
|
||||||
if (!matchSize)
|
if (!matchSize)
|
||||||
break; // Only consume a single register
|
break; // Only consume a single register
|
||||||
}
|
}
|
||||||
|
@ -1322,6 +1342,49 @@ void ConsumeExtra::decode(Decoder &decoder)
|
||||||
initializeEntries();
|
initializeEntries();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExtraStack::initializeEntry(void)
|
||||||
|
|
||||||
|
{
|
||||||
|
stackEntry = resource->getStackEntry();
|
||||||
|
if (stackEntry == (const ParamEntry *)0)
|
||||||
|
throw LowlevelError("Cannot find matching <pentry> for action: extra_stack");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \param res is the new resource set to associate with \b this action
|
||||||
|
/// \param val is a dummy value
|
||||||
|
ExtraStack::ExtraStack(const ParamListStandard *res,int4 val)
|
||||||
|
: AssignAction(res)
|
||||||
|
{
|
||||||
|
stackEntry = (const ParamEntry *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtraStack::ExtraStack(const ParamListStandard *res)
|
||||||
|
: AssignAction(res)
|
||||||
|
{
|
||||||
|
stackEntry = (const ParamEntry *)0;
|
||||||
|
initializeEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint4 ExtraStack::assignAddress(Datatype *dt,const PrototypePieces &proto,int4 pos,TypeFactory &tlst,
|
||||||
|
vector<int4> &status,ParameterPieces &res) const
|
||||||
|
{
|
||||||
|
if (res.addr.getSpace() == stackEntry->getSpace())
|
||||||
|
return success; // Parameter was already assigned to the stack
|
||||||
|
int4 grp = stackEntry->getGroup();
|
||||||
|
// We assign the stack address (but ignore the actual address) updating the status for the stack,
|
||||||
|
// which consumes the stack resources.
|
||||||
|
stackEntry->getAddrBySlot(status[grp],dt->getSize(),dt->getAlignment());
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtraStack::decode(Decoder &decoder)
|
||||||
|
|
||||||
|
{
|
||||||
|
uint4 elemId = decoder.openElement(ELEM_EXTRA_STACK);
|
||||||
|
decoder.closeElement(elemId);
|
||||||
|
initializeEntry();
|
||||||
|
}
|
||||||
|
|
||||||
ModelRule::ModelRule(const ModelRule &op2,const ParamListStandard *res)
|
ModelRule::ModelRule(const ModelRule &op2,const ParamListStandard *res)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,6 +28,8 @@ class ParamListStandard;
|
||||||
class ParamEntry;
|
class ParamEntry;
|
||||||
class ParamActive;
|
class ParamActive;
|
||||||
|
|
||||||
|
extern AttributeId ATTRIB_SIZES; ///< Marshaling attribute "sizes"
|
||||||
|
|
||||||
extern ElementId ELEM_DATATYPE; ///< Marshaling element \<datatype>
|
extern ElementId ELEM_DATATYPE; ///< Marshaling element \<datatype>
|
||||||
extern ElementId ELEM_CONSUME; ///< Marshaling element \<consume>
|
extern ElementId ELEM_CONSUME; ///< Marshaling element \<consume>
|
||||||
extern ElementId ELEM_CONSUME_EXTRA; ///< Marshaling element \<consume_extra>
|
extern ElementId ELEM_CONSUME_EXTRA; ///< Marshaling element \<consume_extra>
|
||||||
|
@ -40,6 +42,7 @@ extern ElementId ELEM_VARARGS; ///< Marshaling element \<varargs>
|
||||||
extern ElementId ELEM_HIDDEN_RETURN; ///< Marshaling element \<hidden_return>
|
extern ElementId ELEM_HIDDEN_RETURN; ///< Marshaling element \<hidden_return>
|
||||||
extern ElementId ELEM_JOIN_PER_PRIMITIVE; ///< Marshaling element \<join_per_primitive>
|
extern ElementId ELEM_JOIN_PER_PRIMITIVE; ///< Marshaling element \<join_per_primitive>
|
||||||
extern ElementId ELEM_JOIN_DUAL_CLASS; ///< Marshaling element \<join_dual_class>
|
extern ElementId ELEM_JOIN_DUAL_CLASS; ///< Marshaling element \<join_dual_class>
|
||||||
|
extern ElementId ELEM_EXTRA_STACK; ///< Marshaling element \<extra_stack>
|
||||||
|
|
||||||
/// \brief Class for extracting primitive elements of a data-type
|
/// \brief Class for extracting primitive elements of a data-type
|
||||||
///
|
///
|
||||||
|
@ -105,20 +108,23 @@ public:
|
||||||
static DatatypeFilter *decodeFilter(Decoder &decoder); ///< Instantiate a filter from the given stream
|
static DatatypeFilter *decodeFilter(Decoder &decoder); ///< Instantiate a filter from the given stream
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief A common base class for data-type filters that tests for a size range
|
/// \brief A base class for data-type filters that tests for either a range or an enumerated list of sizes
|
||||||
///
|
///
|
||||||
/// Any filter that inherits from \b this, can use ATTRIB_MINSIZE and ATTRIB_MAXSIZE
|
/// Any filter that inherits from \b this, can use ATTRIB_MINSIZE, ATTRIB_MAXSIZE, or ATTRIB_SIZES
|
||||||
/// to place bounds on the possible sizes of data-types. The bounds are enforced
|
/// to place bounds on the possible sizes of data-types. The bounds are enforced
|
||||||
/// by calling filterOnSize() within the inheriting classes filter() method.
|
/// by calling filterOnSize() within the inheriting classes filter() method.
|
||||||
class SizeRestrictedFilter : public DatatypeFilter {
|
class SizeRestrictedFilter : public DatatypeFilter {
|
||||||
protected:
|
protected:
|
||||||
int4 minSize; ///< Minimum size of the data-type in bytes
|
int4 minSize; ///< Minimum size of the data-type in bytes
|
||||||
int4 maxSize; ///< Maximum size of the data-type in bytes
|
int4 maxSize; ///< Maximum size of the data-type in bytes
|
||||||
|
set<int4> sizes; ///< An enumerated list of sizes (if not empty)
|
||||||
|
void initFromSizeList(const string &str); ///< Initialize filter from enumerated list of sizes
|
||||||
public:
|
public:
|
||||||
SizeRestrictedFilter(void) { minSize=0; maxSize=0; } ///< Constructor for use with decode()
|
SizeRestrictedFilter(void) { minSize=0; maxSize=0; } ///< Constructor for use with decode()
|
||||||
SizeRestrictedFilter(int4 min,int4 max); ///< Constructor
|
SizeRestrictedFilter(int4 min,int4 max); ///< Constructor
|
||||||
|
SizeRestrictedFilter(const SizeRestrictedFilter &op2); ///< Copy constructor
|
||||||
bool filterOnSize(Datatype *dt) const; ///< Enforce any size bounds on a given data-type
|
bool filterOnSize(Datatype *dt) const; ///< Enforce any size bounds on a given data-type
|
||||||
virtual DatatypeFilter *clone(void) const { return new SizeRestrictedFilter(minSize,maxSize); }
|
virtual DatatypeFilter *clone(void) const { return new SizeRestrictedFilter(*this); }
|
||||||
virtual bool filter(Datatype *dt) const { return filterOnSize(dt); }
|
virtual bool filter(Datatype *dt) const { return filterOnSize(dt); }
|
||||||
virtual void decode(Decoder &decoder);
|
virtual void decode(Decoder &decoder);
|
||||||
};
|
};
|
||||||
|
@ -132,7 +138,8 @@ protected:
|
||||||
public:
|
public:
|
||||||
MetaTypeFilter(type_metatype meta); ///< Constructor for use with decode()
|
MetaTypeFilter(type_metatype meta); ///< Constructor for use with decode()
|
||||||
MetaTypeFilter(type_metatype meta,int4 min,int4 max); ///< Constructor
|
MetaTypeFilter(type_metatype meta,int4 min,int4 max); ///< Constructor
|
||||||
virtual DatatypeFilter *clone(void) const { return new MetaTypeFilter(metaType,minSize,maxSize); }
|
MetaTypeFilter(const MetaTypeFilter &op2); ///< Copy constructor
|
||||||
|
virtual DatatypeFilter *clone(void) const { return new MetaTypeFilter(*this); }
|
||||||
virtual bool filter(Datatype *dt) const;
|
virtual bool filter(Datatype *dt) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -145,7 +152,8 @@ class HomogeneousAggregate : public SizeRestrictedFilter {
|
||||||
public:
|
public:
|
||||||
HomogeneousAggregate(type_metatype meta); ///< Constructor for use with decode()
|
HomogeneousAggregate(type_metatype meta); ///< Constructor for use with decode()
|
||||||
HomogeneousAggregate(type_metatype meta,int4 maxPrim,int4 min,int4 max); ///< Constructor
|
HomogeneousAggregate(type_metatype meta,int4 maxPrim,int4 min,int4 max); ///< Constructor
|
||||||
virtual DatatypeFilter *clone(void) const { return new HomogeneousAggregate(metaType,maxPrimitives, minSize,maxSize); }
|
HomogeneousAggregate(const HomogeneousAggregate &op2); ///< Copy constructor
|
||||||
|
virtual DatatypeFilter *clone(void) const { return new HomogeneousAggregate(*this); }
|
||||||
virtual bool filter(Datatype *dt) const;
|
virtual bool filter(Datatype *dt) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -310,7 +318,7 @@ class GotoStack : public AssignAction {
|
||||||
void initializeEntry(void); ///< Find stack entry in resource list
|
void initializeEntry(void); ///< Find stack entry in resource list
|
||||||
public:
|
public:
|
||||||
GotoStack(const ParamListStandard *res,int4 val); ///< Constructor for use with decode
|
GotoStack(const ParamListStandard *res,int4 val); ///< Constructor for use with decode
|
||||||
GotoStack(const ParamListStandard *res); ///< Constructor for use with decode()
|
GotoStack(const ParamListStandard *res); ///< Constructor
|
||||||
virtual AssignAction *clone(const ParamListStandard *newResource) const { return new GotoStack(newResource); }
|
virtual AssignAction *clone(const ParamListStandard *newResource) const { return new GotoStack(newResource); }
|
||||||
virtual uint4 assignAddress(Datatype *dt,const PrototypePieces &proto,int4 pos,TypeFactory &tlist,
|
virtual uint4 assignAddress(Datatype *dt,const PrototypePieces &proto,int4 pos,TypeFactory &tlist,
|
||||||
vector<int4> &status,ParameterPieces &res) const;
|
vector<int4> &status,ParameterPieces &res) const;
|
||||||
|
@ -342,8 +350,8 @@ class MultiSlotAssign : public AssignAction {
|
||||||
bool consumeMostSig; ///< True if resources are consumed starting with most significant bytes
|
bool consumeMostSig; ///< True if resources are consumed starting with most significant bytes
|
||||||
bool enforceAlignment; ///< True if register resources are discarded to match alignment
|
bool enforceAlignment; ///< True if register resources are discarded to match alignment
|
||||||
bool justifyRight; ///< True if initial bytes are padding for odd data-type sizes
|
bool justifyRight; ///< True if initial bytes are padding for odd data-type sizes
|
||||||
|
vector<const ParamEntry *> tiles; ///< List of registers that can be joined
|
||||||
const ParamEntry *stackEntry; ///< The stack resource
|
const ParamEntry *stackEntry; ///< The stack resource
|
||||||
list<ParamEntry>::const_iterator firstIter; ///< Iterator to first element in the resource list
|
|
||||||
void initializeEntries(void); ///< Cache specific ParamEntry needed by the action
|
void initializeEntries(void); ///< Cache specific ParamEntry needed by the action
|
||||||
public:
|
public:
|
||||||
MultiSlotAssign(const ParamListStandard *res); ///< Constructor for use with decode
|
MultiSlotAssign(const ParamListStandard *res); ///< Constructor for use with decode
|
||||||
|
@ -385,11 +393,10 @@ class MultiSlotDualAssign : public AssignAction {
|
||||||
bool consumeMostSig; ///< True if resources are consumed starting with most significant bytes
|
bool consumeMostSig; ///< True if resources are consumed starting with most significant bytes
|
||||||
bool justifyRight; ///< True if initial bytes are padding for odd data-type sizes
|
bool justifyRight; ///< True if initial bytes are padding for odd data-type sizes
|
||||||
int4 tileSize; ///< Number of bytes in a tile
|
int4 tileSize; ///< Number of bytes in a tile
|
||||||
list<ParamEntry>::const_iterator baseIter; ///< Iterator to first element in the base resource list
|
vector<const ParamEntry *> baseTiles; ///< General registers to be joined
|
||||||
list<ParamEntry>::const_iterator altIter; ///< Iterator to first element in alternate resource list
|
vector<const ParamEntry *> altTiles; ///< Alternate registers to be joined
|
||||||
void initializeEntries(void); ///< Cache specific ParamEntry needed by the action
|
void initializeEntries(void); ///< Cache specific ParamEntry needed by the action
|
||||||
list<ParamEntry>::const_iterator getFirstUnused(list<ParamEntry>::const_iterator iter,type_class storage,
|
int4 getFirstUnused(int4 iter,const vector<const ParamEntry *> &tiles,vector<int4> &status) const;
|
||||||
vector<int4> &status) const;
|
|
||||||
int4 getTileClass(const PrimitiveExtractor &primitives,int4 off,int4 &index) const;
|
int4 getTileClass(const PrimitiveExtractor &primitives,int4 off,int4 &index) const;
|
||||||
public:
|
public:
|
||||||
MultiSlotDualAssign(const ParamListStandard *res); ///< Constructor for use with decode
|
MultiSlotDualAssign(const ParamListStandard *res); ///< Constructor for use with decode
|
||||||
|
@ -451,8 +458,8 @@ public:
|
||||||
/// only a single register is consumed. If all registers are already consumed, no action is taken.
|
/// only a single register is consumed. If all registers are already consumed, no action is taken.
|
||||||
class ConsumeExtra : public AssignAction {
|
class ConsumeExtra : public AssignAction {
|
||||||
type_class resourceType; ///< The other resource list to consume from
|
type_class resourceType; ///< The other resource list to consume from
|
||||||
list<ParamEntry>::const_iterator firstIter; ///< Iterator to first element in the resource list
|
|
||||||
bool matchSize; ///< \b false, if side-effect only consumes a single register
|
bool matchSize; ///< \b false, if side-effect only consumes a single register
|
||||||
|
vector<const ParamEntry *> tiles; ///< List of registers that can be consumed
|
||||||
void initializeEntries(void); ///< Cache specific ParamEntry needed by the action
|
void initializeEntries(void); ///< Cache specific ParamEntry needed by the action
|
||||||
public:
|
public:
|
||||||
ConsumeExtra(const ParamListStandard *res); ///< Constructor for use with decode
|
ConsumeExtra(const ParamListStandard *res); ///< Constructor for use with decode
|
||||||
|
@ -464,6 +471,25 @@ public:
|
||||||
virtual void decode(Decoder &decoder);
|
virtual void decode(Decoder &decoder);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \brief Consume stack resources as a side-effect
|
||||||
|
///
|
||||||
|
/// This action is a side-effect and doesn't assign an address for the current parameter.
|
||||||
|
/// If the current parameter has been assigned a address that is not on the stack, this action consumes
|
||||||
|
/// stack resources as if the parameter were allocated to the stack. If the current parameter was
|
||||||
|
/// already assigned a stack address, no additional action is taken.
|
||||||
|
class ExtraStack : public AssignAction {
|
||||||
|
const ParamEntry *stackEntry; ///< Parameter Entry corresponding to the stack
|
||||||
|
void initializeEntry(void); ///< Find stack entry in resource list
|
||||||
|
public:
|
||||||
|
ExtraStack(const ParamListStandard *res,int4 val); ///< Constructor for use with decode
|
||||||
|
ExtraStack(const ParamListStandard *res); ///< Constructor
|
||||||
|
virtual AssignAction *clone(const ParamListStandard *newResource) const {
|
||||||
|
return new ExtraStack(newResource); }
|
||||||
|
virtual uint4 assignAddress(Datatype *dt,const PrototypePieces &proto,int4 pos,TypeFactory &tlist,
|
||||||
|
vector<int4> &status,ParameterPieces &res) const;
|
||||||
|
virtual void decode(Decoder &decoder);
|
||||||
|
};
|
||||||
|
|
||||||
/// \brief A rule controlling how parameters are assigned addresses
|
/// \brief A rule controlling how parameters are assigned addresses
|
||||||
///
|
///
|
||||||
/// Rules are applied to a parameter in the context of a full function prototype.
|
/// Rules are applied to a parameter in the context of a full function prototype.
|
||||||
|
|
|
@ -66,6 +66,25 @@ bool VarnodeData::contains(const VarnodeData &op2) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If \b this and \b lo form a contiguous range of bytes, where \b this makes up the most significant
|
||||||
|
/// bytes and \b lo makes up the least significant bytes, return \b true.
|
||||||
|
/// \param lo is the given VarnodeData to compare with
|
||||||
|
/// \return \b true if the two byte ranges are contiguous and in order
|
||||||
|
bool VarnodeData::isContiguous(const VarnodeData &lo) const
|
||||||
|
|
||||||
|
{
|
||||||
|
if (space != lo.space) return false;
|
||||||
|
if (space->isBigEndian()) {
|
||||||
|
uintb nextoff = space->wrapOffset(offset+size);
|
||||||
|
if (nextoff == lo.offset) return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uintb nextoff = space->wrapOffset(lo.offset+lo.size);
|
||||||
|
if (nextoff == offset) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// This assumes the \<op> element is already open.
|
/// This assumes the \<op> element is already open.
|
||||||
/// Decode info suitable for call to PcodeEmit::dump. The output pointer is changed to null if there
|
/// Decode info suitable for call to PcodeEmit::dump. The output pointer is changed to null if there
|
||||||
/// is no output for this op, otherwise the existing pointer is used to store the output.
|
/// is no output for this op, otherwise the existing pointer is used to store the output.
|
||||||
|
|
|
@ -54,6 +54,9 @@ struct VarnodeData {
|
||||||
|
|
||||||
/// Does \b this container another given VarnodeData
|
/// Does \b this container another given VarnodeData
|
||||||
bool contains(const VarnodeData &op2) const;
|
bool contains(const VarnodeData &op2) const;
|
||||||
|
|
||||||
|
/// Is \b this contiguous (as the most significant piece) with the given VarnodeData
|
||||||
|
bool isContiguous(const VarnodeData &lo) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// VarnodeData can be sorted in terms of the space its in
|
/// VarnodeData can be sorted in terms of the space its in
|
||||||
|
|
|
@ -2797,6 +2797,16 @@ void RuleBooleanDedup::getOpList(vector<uint4> &oplist) const
|
||||||
oplist.push_back(CPUI_BOOL_OR);
|
oplist.push_back(CPUI_BOOL_OR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Determine if the two given boolean Varnodes always contain matching values
|
||||||
|
///
|
||||||
|
/// The boolean values can either always be equal or can always be complements of each other, and
|
||||||
|
/// \b true will be returned. In this case \b isFlip passes back \b false if the values are always equal
|
||||||
|
/// or passes back \b true if the values are complements. The method returns \b false if the values are
|
||||||
|
/// uncorrelated.
|
||||||
|
/// \param leftVn is the first given boolean Varnode to compare
|
||||||
|
/// \param rightVn is the second given boolean Varnode to compare
|
||||||
|
/// \param isFlip will pass back the type of correlation
|
||||||
|
/// \return \b true if the Varnodes are correlated and \b false otherwise
|
||||||
bool RuleBooleanDedup::isMatch(Varnode *leftVn,Varnode *rightVn,bool &isFlip)
|
bool RuleBooleanDedup::isMatch(Varnode *leftVn,Varnode *rightVn,bool &isFlip)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -9245,12 +9255,16 @@ bool RuleConditionalMove::gatherExpression(Varnode *vn,vector<PcodeOp *> &ops,Fl
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reproduce the bolean expression resulting in the given Varnode.
|
/// \brief Construct the expression after the merge
|
||||||
|
///
|
||||||
|
/// Reproduce the boolean expression resulting in the given Varnode.
|
||||||
/// Either reuse the existing Varnode or reconstruct it,
|
/// Either reuse the existing Varnode or reconstruct it,
|
||||||
/// making sure the expression does not depend on data in the branch.
|
/// making sure the expression does not depend on data in the branch.
|
||||||
|
/// \param vn is the given boolean Varnode at the base of the expression
|
||||||
|
/// \param ops is the set of PcodeOps in the expression
|
||||||
/// \param insertop is point at which any reconstruction should be inserted
|
/// \param insertop is point at which any reconstruction should be inserted
|
||||||
/// \param data is the function being analyzed
|
/// \param data is the function being analyzed
|
||||||
/// \return the Varnode representing the boolean expression
|
/// \return the Varnode representing the (possible reproduced) boolean expression
|
||||||
Varnode *RuleConditionalMove::constructBool(Varnode *vn,PcodeOp *insertop,vector<PcodeOp *> &ops,Funcdata &data)
|
Varnode *RuleConditionalMove::constructBool(Varnode *vn,PcodeOp *insertop,vector<PcodeOp *> &ops,Funcdata &data)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -1418,7 +1418,8 @@ public:
|
||||||
class RuleConditionalMove : public Rule {
|
class RuleConditionalMove : public Rule {
|
||||||
static Varnode *checkBoolean(Varnode *vn); ///< Check for boolean expression
|
static Varnode *checkBoolean(Varnode *vn); ///< Check for boolean expression
|
||||||
static bool gatherExpression(Varnode *vn,vector<PcodeOp *> &ops,FlowBlock *root,FlowBlock *branch);
|
static bool gatherExpression(Varnode *vn,vector<PcodeOp *> &ops,FlowBlock *root,FlowBlock *branch);
|
||||||
static Varnode *constructBool(Varnode *vn,PcodeOp *insertop,vector<PcodeOp *> &ops,Funcdata &data); ///< Construct the expression after the merge
|
static Varnode *constructBool(Varnode *vn,PcodeOp *insertop,vector<PcodeOp *> &ops,Funcdata &data);
|
||||||
|
/// \brief Sort PcodeOps based only on order within a basic block
|
||||||
static bool compareOp(PcodeOp *op0,PcodeOp *op1) { return op0->getSeqNum().getOrder() < op1->getSeqNum().getOrder(); }
|
static bool compareOp(PcodeOp *op0,PcodeOp *op1) { return op0->getSeqNum().getOrder() < op1->getSeqNum().getOrder(); }
|
||||||
public:
|
public:
|
||||||
RuleConditionalMove(const string &g) : Rule( g, 0, "conditionalmove") {} ///< Constructor
|
RuleConditionalMove(const string &g) : Rule( g, 0, "conditionalmove") {} ///< Constructor
|
||||||
|
|
|
@ -65,6 +65,7 @@ public:
|
||||||
virtual void initialize(DocumentStorage &store) {}
|
virtual void initialize(DocumentStorage &store) {}
|
||||||
virtual const VarnodeData &getRegister(const string &nm) const { throw LowlevelError("Cannot add register to DummyTranslate"); }
|
virtual const VarnodeData &getRegister(const string &nm) const { throw LowlevelError("Cannot add register to DummyTranslate"); }
|
||||||
virtual string getRegisterName(AddrSpace *base,uintb off,int4 size) const { return ""; }
|
virtual string getRegisterName(AddrSpace *base,uintb off,int4 size) const { return ""; }
|
||||||
|
virtual string getExactRegisterName(AddrSpace *base,uintb off,int4 size) const { return ""; }
|
||||||
virtual void getAllRegisters(map<VarnodeData,string> ®list) const {}
|
virtual void getAllRegisters(map<VarnodeData,string> ®list) const {}
|
||||||
virtual void getUserOpNames(vector<string> &res) const {}
|
virtual void getUserOpNames(vector<string> &res) const {}
|
||||||
virtual int4 instructionLength(const Address &baseaddr) const { return -1; }
|
virtual int4 instructionLength(const Address &baseaddr) const { return -1; }
|
||||||
|
|
|
@ -167,6 +167,18 @@ string SleighBase::getRegisterName(AddrSpace *base,uintb off,int4 size) const
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string SleighBase::getExactRegisterName(AddrSpace *base,uintb off,int4 size) const
|
||||||
|
|
||||||
|
{
|
||||||
|
VarnodeData sym;
|
||||||
|
sym.space = base;
|
||||||
|
sym.offset = off;
|
||||||
|
sym.size = size;
|
||||||
|
map<VarnodeData,string>::const_iterator iter = varnode_xref.find(sym);
|
||||||
|
if (iter == varnode_xref.end()) return "";
|
||||||
|
return (*iter).second;
|
||||||
|
}
|
||||||
|
|
||||||
void SleighBase::getAllRegisters(map<VarnodeData,string> ®list) const
|
void SleighBase::getAllRegisters(map<VarnodeData,string> ®list) const
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -79,6 +79,7 @@ public:
|
||||||
virtual ~SleighBase(void) {} ///< Destructor
|
virtual ~SleighBase(void) {} ///< Destructor
|
||||||
virtual const VarnodeData &getRegister(const string &nm) const;
|
virtual const VarnodeData &getRegister(const string &nm) const;
|
||||||
virtual string getRegisterName(AddrSpace *base,uintb off,int4 size) const;
|
virtual string getRegisterName(AddrSpace *base,uintb off,int4 size) const;
|
||||||
|
virtual string getExactRegisterName(AddrSpace *base,uintb off,int4 size) const;
|
||||||
virtual void getAllRegisters(map<VarnodeData,string> ®list) const;
|
virtual void getAllRegisters(map<VarnodeData,string> ®list) const;
|
||||||
virtual void getUserOpNames(vector<string> &res) const;
|
virtual void getUserOpNames(vector<string> &res) const;
|
||||||
|
|
||||||
|
|
|
@ -188,6 +188,49 @@ bool JoinRecord::operator<(const JoinRecord &op2) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Assuming the given list of VarnodeData go from most significant to least significant,
|
||||||
|
/// merge any contiguous elements in the list. Varnodes that are not in the \e stack address space
|
||||||
|
/// are only merged if the resulting byte range has a formal register name.
|
||||||
|
/// \param seq is the given list of VarnodeData
|
||||||
|
/// \param trans is the language to use for register names
|
||||||
|
void JoinRecord::mergeSequence(vector<VarnodeData> &seq,const Translate *trans)
|
||||||
|
|
||||||
|
{
|
||||||
|
int4 i=1;
|
||||||
|
while(i<seq.size()) {
|
||||||
|
VarnodeData &hi(seq[i-1]);
|
||||||
|
VarnodeData &lo(seq[i]);
|
||||||
|
if (hi.isContiguous(lo))
|
||||||
|
break;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
if (i >= seq.size()) return;
|
||||||
|
vector<VarnodeData> res;
|
||||||
|
i = 1;
|
||||||
|
res.push_back(seq.front());
|
||||||
|
bool lastIsInformal = false;
|
||||||
|
while(i<seq.size()) {
|
||||||
|
VarnodeData &hi(res.back());
|
||||||
|
VarnodeData &lo(seq[i]);
|
||||||
|
if (hi.isContiguous(lo)) {
|
||||||
|
hi.offset = hi.space->isBigEndian() ? hi.offset : lo.offset;
|
||||||
|
hi.size += lo.size;
|
||||||
|
if (hi.space->getType() != IPTR_SPACEBASE) {
|
||||||
|
lastIsInformal = trans->getExactRegisterName(hi.space, hi.offset, hi.size).size() == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (lastIsInformal)
|
||||||
|
break;
|
||||||
|
res.push_back(lo);
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
if (lastIsInformal) // If the merge contains an informal register
|
||||||
|
return; // throw it out and keep the original sequence
|
||||||
|
seq = res;
|
||||||
|
}
|
||||||
|
|
||||||
/// Initialize manager containing no address spaces. All the cached space slots are set to null
|
/// Initialize manager containing no address spaces. All the cached space slots are set to null
|
||||||
AddrSpaceManager::AddrSpaceManager(void)
|
AddrSpaceManager::AddrSpaceManager(void)
|
||||||
|
|
||||||
|
|
|
@ -204,6 +204,7 @@ public:
|
||||||
const VarnodeData &getUnified(void) const { return unified; } ///< Get the Varnode whole
|
const VarnodeData &getUnified(void) const { return unified; } ///< Get the Varnode whole
|
||||||
Address getEquivalentAddress(uintb offset,int4 &pos) const; ///< Given offset in \e join space, get equivalent address of piece
|
Address getEquivalentAddress(uintb offset,int4 &pos) const; ///< Given offset in \e join space, get equivalent address of piece
|
||||||
bool operator<(const JoinRecord &op2) const; ///< Compare records lexigraphically by pieces
|
bool operator<(const JoinRecord &op2) const; ///< Compare records lexigraphically by pieces
|
||||||
|
static void mergeSequence(vector<VarnodeData> &seq,const Translate *trans); ///< Merge any contiguous ranges in a sequence
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Comparator for JoinRecord objects
|
/// \brief Comparator for JoinRecord objects
|
||||||
|
@ -368,18 +369,26 @@ public:
|
||||||
/// \return the VarnodeData for the register
|
/// \return the VarnodeData for the register
|
||||||
virtual const VarnodeData &getRegister(const string &nm) const=0;
|
virtual const VarnodeData &getRegister(const string &nm) const=0;
|
||||||
|
|
||||||
/// \brief Get the name of a register given its location
|
/// \brief Get the name of the smallest containing register given a location and size
|
||||||
///
|
///
|
||||||
/// Generic references to locations in a \e register space can
|
/// Generic references to locations in a \e register space are translated into the
|
||||||
/// be translated into the associated register \e name. If the
|
/// register \e name. If a containing register isn't found, an empty string is returned.
|
||||||
/// location doesn't match a register \e exactly, an empty string
|
|
||||||
/// is returned.
|
|
||||||
/// \param base is the address space containing the location
|
/// \param base is the address space containing the location
|
||||||
/// \param off is the offset of the location
|
/// \param off is the offset of the location
|
||||||
/// \param size is the size of the location
|
/// \param size is the size of the location
|
||||||
/// \return the name of the register, or an empty string
|
/// \return the name of the register, or an empty string
|
||||||
virtual string getRegisterName(AddrSpace *base,uintb off,int4 size) const=0;
|
virtual string getRegisterName(AddrSpace *base,uintb off,int4 size) const=0;
|
||||||
|
|
||||||
|
/// \brief Get the name of a register with an exact location and size
|
||||||
|
///
|
||||||
|
/// If a register exists with the given location and size, return the name of the register.
|
||||||
|
/// Otherwise return the empty string.
|
||||||
|
/// \param base is the address space containing the location
|
||||||
|
/// \param off is the offset of the location
|
||||||
|
/// \param size is the size of the location
|
||||||
|
/// \return the name of the register, or an empty string
|
||||||
|
virtual string getExactRegisterName(AddrSpace *base,uintb off,int4 size) const=0;
|
||||||
|
|
||||||
/// \brief Get a list of all register names and the corresponding location
|
/// \brief Get a list of all register names and the corresponding location
|
||||||
///
|
///
|
||||||
/// Most processors have a list of named registers and possibly other memory locations
|
/// Most processors have a list of named registers and possibly other memory locations
|
||||||
|
|
|
@ -28,6 +28,7 @@ public:
|
||||||
virtual void initialize(DocumentStorage &store) {}
|
virtual void initialize(DocumentStorage &store) {}
|
||||||
virtual const VarnodeData &getRegister(const string &nm) const { throw LowlevelError("Cannot add register to DummyTranslate"); }
|
virtual const VarnodeData &getRegister(const string &nm) const { throw LowlevelError("Cannot add register to DummyTranslate"); }
|
||||||
virtual string getRegisterName(AddrSpace *base,uintb off,int4 size) const { return ""; }
|
virtual string getRegisterName(AddrSpace *base,uintb off,int4 size) const { return ""; }
|
||||||
|
virtual string getExactRegisterName(AddrSpace *base,uintb off,int4 size) const { return ""; }
|
||||||
virtual void getAllRegisters(map<VarnodeData,string> ®list) const {}
|
virtual void getAllRegisters(map<VarnodeData,string> ®list) const {}
|
||||||
virtual void getUserOpNames(vector<string> &res) const {}
|
virtual void getUserOpNames(vector<string> &res) const {}
|
||||||
virtual int4 instructionLength(const Address &baseaddr) const { return -1; }
|
virtual int4 instructionLength(const Address &baseaddr) const { return -1; }
|
||||||
|
|
|
@ -346,6 +346,7 @@
|
||||||
<attribute name="name"/>
|
<attribute name="name"/>
|
||||||
<optional><attribute name="minsize"/></optional>
|
<optional><attribute name="minsize"/></optional>
|
||||||
<optional><attribute name="maxsize"/></optional>
|
<optional><attribute name="maxsize"/></optional>
|
||||||
|
<optional><attribute name="sizes"/></optional>
|
||||||
</define>
|
</define>
|
||||||
|
|
||||||
<define name="modelrule_type">
|
<define name="modelrule_type">
|
||||||
|
@ -439,6 +440,11 @@
|
||||||
<attribute name="storage"/>
|
<attribute name="storage"/>
|
||||||
</element>
|
</element>
|
||||||
</zeroOrMore>
|
</zeroOrMore>
|
||||||
|
<zeroOrMore>
|
||||||
|
<element name="extra_stack">
|
||||||
|
<empty/>
|
||||||
|
</element>
|
||||||
|
</zeroOrMore>
|
||||||
</define>
|
</define>
|
||||||
|
|
||||||
<define name="prototype_type">
|
<define name="prototype_type">
|
||||||
|
|
|
@ -81,6 +81,11 @@ public interface ParamList {
|
||||||
*/
|
*/
|
||||||
public boolean possibleParamWithSlot(Address loc, int size, WithSlotRec res);
|
public boolean possibleParamWithSlot(Address loc, int size, WithSlotRec res);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the associated Language
|
||||||
|
*/
|
||||||
|
public Language getLanguage();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the address space associated with any stack based parameters in this list.
|
* Get the address space associated with any stack based parameters in this list.
|
||||||
*
|
*
|
||||||
|
|
|
@ -39,7 +39,8 @@ import ghidra.xml.*;
|
||||||
*/
|
*/
|
||||||
public class ParamListStandard implements ParamList {
|
public class ParamListStandard implements ParamList {
|
||||||
|
|
||||||
protected int numgroup; // Number of "groups" in this parameter convention
|
protected Language language; // The language associate with this 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 autoKilledByCall; // Is storage in this list automatically "killed by call"
|
||||||
|
@ -326,6 +327,7 @@ public class ParamListStandard implements ParamList {
|
||||||
public void restoreXml(XmlPullParser parser, CompilerSpec cspec) throws XmlParseException {
|
public void restoreXml(XmlPullParser parser, CompilerSpec cspec) throws XmlParseException {
|
||||||
ArrayList<ParamEntry> pe = new ArrayList<>();
|
ArrayList<ParamEntry> pe = new ArrayList<>();
|
||||||
numgroup = 0;
|
numgroup = 0;
|
||||||
|
language = cspec.getLanguage();
|
||||||
spacebase = null;
|
spacebase = null;
|
||||||
int pointermax = 0;
|
int pointermax = 0;
|
||||||
thisbeforeret = false;
|
thisbeforeret = false;
|
||||||
|
@ -453,6 +455,11 @@ public class ParamListStandard implements ParamList {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Language getLanguage() {
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AddressSpace getSpacebase() {
|
public AddressSpace getSpacebase() {
|
||||||
return spacebase;
|
return spacebase;
|
||||||
|
@ -499,4 +506,38 @@ public class ParamListStandard implements ParamList {
|
||||||
public boolean isThisBeforeRetPointer() {
|
public boolean isThisBeforeRetPointer() {
|
||||||
return thisbeforeret;
|
return thisbeforeret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract all ParamEntry that have the given storage class and are single registers.
|
||||||
|
* @param resType is the given storage class
|
||||||
|
* @return the array of registers
|
||||||
|
*/
|
||||||
|
public ParamEntry[] extractTiles(StorageClass resType) {
|
||||||
|
ArrayList<ParamEntry> buffer = new ArrayList<>();
|
||||||
|
for (int i = 0; i < entry.length; ++i) {
|
||||||
|
ParamEntry pentry = entry[i];
|
||||||
|
if (!pentry.isExclusion() || pentry.getAllGroups().length != 1 ||
|
||||||
|
pentry.getType() != resType) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
buffer.add(pentry);
|
||||||
|
}
|
||||||
|
ParamEntry[] res = new ParamEntry[buffer.size()];
|
||||||
|
buffer.toArray(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If there is a ParamEntry corresponding to the stack resource in this list, return it.
|
||||||
|
* @return the stack ParamEntry or null
|
||||||
|
*/
|
||||||
|
public ParamEntry extractStack() {
|
||||||
|
for (int i = entry.length - 1; i >= 0; --i) {
|
||||||
|
ParamEntry pentry = entry[i];
|
||||||
|
if (!pentry.isExclusion() && pentry.getSpace().isStackSpace()) {
|
||||||
|
return pentry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.program.model.lang;
|
package ghidra.program.model.lang;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.data.VoidDataType;
|
import ghidra.program.model.data.VoidDataType;
|
||||||
|
@ -109,4 +111,81 @@ public class ParameterPieces {
|
||||||
}
|
}
|
||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assuming the given list of Varnodes go from most significant to least significant,
|
||||||
|
* merge any contiguous elements in the list. Merges in a register space are only allowed
|
||||||
|
* if the bigger Varnode exists as a formal register.
|
||||||
|
* @param seq is the given list of Varnodes
|
||||||
|
* @param language is the Language associated with the calling convention.
|
||||||
|
* @return the merged list (which may be the original list)
|
||||||
|
*/
|
||||||
|
public static ArrayList<Varnode> mergeSequence(ArrayList<Varnode> seq, Language language) {
|
||||||
|
int i = 1;
|
||||||
|
boolean bigEndian = language.isBigEndian();
|
||||||
|
while (i < seq.size()) {
|
||||||
|
Varnode hi = seq.get(i - 1);
|
||||||
|
Varnode lo = seq.get(i);
|
||||||
|
if (hi.isContiguous(lo, bigEndian))
|
||||||
|
break;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
if (i >= seq.size())
|
||||||
|
return seq;
|
||||||
|
ArrayList<Varnode> buffer = new ArrayList<>();
|
||||||
|
i = 1;
|
||||||
|
buffer.add(seq.getFirst());
|
||||||
|
boolean lastIsInformal = false;
|
||||||
|
while (i < seq.size()) {
|
||||||
|
Varnode hi = buffer.getLast();
|
||||||
|
Varnode lo = seq.get(i);
|
||||||
|
if (hi.isContiguous(lo, bigEndian)) {
|
||||||
|
long off = bigEndian ? hi.getOffset() : lo.getOffset();
|
||||||
|
int sz = hi.getSize() + lo.getSize();
|
||||||
|
Varnode newVn = new Varnode(hi.getAddress().getAddressSpace().getAddress(off), sz);
|
||||||
|
buffer.removeLast();
|
||||||
|
buffer.add(newVn);
|
||||||
|
// Test if new Varnode is a formal register
|
||||||
|
if (!newVn.getAddress().isStackAddress()) {
|
||||||
|
lastIsInformal =
|
||||||
|
language.getRegister(newVn.getAddress(), newVn.getSize()) == null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (lastIsInformal)
|
||||||
|
break;
|
||||||
|
buffer.add(lo);
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
if (lastIsInformal) // If the merge contains an informal register
|
||||||
|
return seq; // throw it out and keep original sequence
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a parameter address given the list of Varnodes making up the parameter.
|
||||||
|
* @param pieces is the given list of Varnodes
|
||||||
|
* @param mostToLeast is true if the list is ordered most significant to least
|
||||||
|
* @param onePieceJoin is true if the address should be considered a join of one piece
|
||||||
|
* @param language is the Language associated with the calling convention
|
||||||
|
*/
|
||||||
|
public void assignAddressFromPieces(ArrayList<Varnode> pieces, boolean mostToLeast,
|
||||||
|
boolean onePieceJoin, Language language) {
|
||||||
|
if (!mostToLeast && pieces.size() > 1) {
|
||||||
|
ArrayList<Varnode> reverse = new ArrayList<Varnode>();
|
||||||
|
for (int i = pieces.size() - 1; i >= 0; --i) {
|
||||||
|
reverse.add(pieces.get(i));
|
||||||
|
}
|
||||||
|
pieces = reverse;
|
||||||
|
}
|
||||||
|
pieces = mergeSequence(pieces, language);
|
||||||
|
if (pieces.size() == 1 && !onePieceJoin) {
|
||||||
|
address = pieces.get(0).getAddress();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
joinPieces = new Varnode[pieces.size()];
|
||||||
|
pieces.toArray(joinPieces);
|
||||||
|
address = Address.NO_ADDRESS; // Placeholder for join space address
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -627,44 +627,44 @@ public class PrototypeModel {
|
||||||
inputParams = null;
|
inputParams = null;
|
||||||
outputParams = null;
|
outputParams = null;
|
||||||
XmlElement protoElement = parser.start();
|
XmlElement protoElement = parser.start();
|
||||||
name = protoElement.getAttribute("name");
|
name = protoElement.getAttribute(ATTRIB_NAME.name());
|
||||||
if (!SpecExtension.isValidFormalName(name)) {
|
if (!SpecExtension.isValidFormalName(name)) {
|
||||||
throw new XmlParseException("Prototype name uses illegal characters");
|
throw new XmlParseException("Prototype name uses illegal characters");
|
||||||
}
|
}
|
||||||
extrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
|
extrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
|
||||||
String extpopStr = protoElement.getAttribute("extrapop");
|
String extpopStr = protoElement.getAttribute(ATTRIB_EXTRAPOP.name());
|
||||||
if (!extpopStr.equals("unknown")) {
|
if (!extpopStr.equals("unknown")) {
|
||||||
extrapop = SpecXmlUtils.decodeInt(extpopStr);
|
extrapop = SpecXmlUtils.decodeInt(extpopStr);
|
||||||
}
|
}
|
||||||
stackshift = SpecXmlUtils.decodeInt(protoElement.getAttribute("stackshift"));
|
stackshift = SpecXmlUtils.decodeInt(protoElement.getAttribute(ATTRIB_STACKSHIFT.name()));
|
||||||
hasThis = false;
|
hasThis = false;
|
||||||
isConstruct = false;
|
isConstruct = false;
|
||||||
String thisString = protoElement.getAttribute("hasthis");
|
String thisString = protoElement.getAttribute(ATTRIB_HASTHIS.name());
|
||||||
if (thisString != null) {
|
if (thisString != null) {
|
||||||
hasThis = SpecXmlUtils.decodeBoolean(thisString);
|
hasThis = SpecXmlUtils.decodeBoolean(thisString);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
hasThis = name.equals(CompilerSpec.CALLING_CONVENTION_thiscall);
|
hasThis = name.equals(CompilerSpec.CALLING_CONVENTION_thiscall);
|
||||||
}
|
}
|
||||||
String constructString = protoElement.getAttribute("constructor");
|
String constructString = protoElement.getAttribute(ATTRIB_CONSTRUCTOR.name());
|
||||||
if (constructString != null) {
|
if (constructString != null) {
|
||||||
isConstruct = SpecXmlUtils.decodeBoolean(constructString);
|
isConstruct = SpecXmlUtils.decodeBoolean(constructString);
|
||||||
}
|
}
|
||||||
|
|
||||||
buildParamList(protoElement.getAttribute("strategy"));
|
buildParamList(protoElement.getAttribute(ATTRIB_STRATEGY.name()));
|
||||||
while (parser.peek().isStart()) {
|
while (parser.peek().isStart()) {
|
||||||
XmlElement subel = parser.peek();
|
XmlElement subel = parser.peek();
|
||||||
String elName = subel.getName();
|
String elName = subel.getName();
|
||||||
if (elName.equals("input")) {
|
if (elName.equals(ELEM_INPUT.name())) {
|
||||||
inputParams.restoreXml(parser, cspec);
|
inputParams.restoreXml(parser, cspec);
|
||||||
}
|
}
|
||||||
else if (elName.equals("output")) {
|
else if (elName.equals(ELEM_OUTPUT.name())) {
|
||||||
outputParams.restoreXml(parser, cspec);
|
outputParams.restoreXml(parser, cspec);
|
||||||
}
|
}
|
||||||
else if (elName.equals("pcode")) {
|
else if (elName.equals(ELEM_PCODE.name())) {
|
||||||
XmlElement el = parser.peek();
|
XmlElement el = parser.peek();
|
||||||
String source = "Compiler spec=" + cspec.getCompilerSpecID().getIdAsString();
|
String source = "Compiler spec=" + cspec.getCompilerSpecID().getIdAsString();
|
||||||
if (el.getAttribute("inject").equals("uponentry")) {
|
if (el.getAttribute(ATTRIB_INJECT.name()).equals("uponentry")) {
|
||||||
hasUponEntry = true;
|
hasUponEntry = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -674,25 +674,25 @@ public class PrototypeModel {
|
||||||
.restoreXmlInject(source, getInjectName(), InjectPayload.CALLMECHANISM_TYPE,
|
.restoreXmlInject(source, getInjectName(), InjectPayload.CALLMECHANISM_TYPE,
|
||||||
parser);
|
parser);
|
||||||
}
|
}
|
||||||
else if (elName.equals("unaffected")) {
|
else if (elName.equals(ELEM_UNAFFECTED.name())) {
|
||||||
unaffected = readVarnodes(parser, cspec);
|
unaffected = readVarnodes(parser, cspec);
|
||||||
}
|
}
|
||||||
else if (elName.equals("killedbycall")) {
|
else if (elName.equals(ELEM_KILLEDBYCALL.name())) {
|
||||||
killedbycall = readVarnodes(parser, cspec);
|
killedbycall = readVarnodes(parser, cspec);
|
||||||
}
|
}
|
||||||
else if (elName.equals("returnaddress")) {
|
else if (elName.equals(ELEM_RETURNADDRESS.name())) {
|
||||||
returnaddress = readVarnodes(parser, cspec);
|
returnaddress = readVarnodes(parser, cspec);
|
||||||
}
|
}
|
||||||
else if (elName.equals("likelytrash")) {
|
else if (elName.equals(ELEM_LIKELYTRASH.name())) {
|
||||||
likelytrash = readVarnodes(parser, cspec);
|
likelytrash = readVarnodes(parser, cspec);
|
||||||
}
|
}
|
||||||
else if (elName.equals("internal_storage")) {
|
else if (elName.equals(ELEM_INTERNAL_STORAGE.name())) {
|
||||||
internalstorage = readVarnodes(parser, cspec);
|
internalstorage = readVarnodes(parser, cspec);
|
||||||
}
|
}
|
||||||
else if (elName.equals("localrange")) {
|
else if (elName.equals(ELEM_LOCALRANGE.name())) {
|
||||||
localRange = readAddressSet(parser, cspec);
|
localRange = readAddressSet(parser, cspec);
|
||||||
}
|
}
|
||||||
else if (elName.equals("paramrange")) {
|
else if (elName.equals(ELEM_PARAMRANGE.name())) {
|
||||||
paramRange = readAddressSet(parser, cspec);
|
paramRange = readAddressSet(parser, cspec);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -154,11 +154,13 @@ public abstract class AssignAction {
|
||||||
if (nm.equals(ELEM_CONSUME_EXTRA.name())) {
|
if (nm.equals(ELEM_CONSUME_EXTRA.name())) {
|
||||||
action = new ConsumeExtra(res);
|
action = new ConsumeExtra(res);
|
||||||
}
|
}
|
||||||
|
else if (nm.equals(ELEM_EXTRA_STACK.name())) {
|
||||||
|
action = new ExtraStack(res, 0);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
throw new XmlParseException("Unknown model rule sideeffect: " + nm);
|
throw new XmlParseException("Unknown model rule sideeffect: " + nm);
|
||||||
}
|
}
|
||||||
action.restoreXml(parser);
|
action.restoreXml(parser);
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,8 +39,8 @@ import ghidra.xml.*;
|
||||||
public class ConsumeExtra extends AssignAction {
|
public class ConsumeExtra extends AssignAction {
|
||||||
|
|
||||||
private StorageClass resourceType; // The other resource list to consume from
|
private StorageClass resourceType; // The other resource list to consume from
|
||||||
private int firstIter; // Iterator to first element in the resource list
|
|
||||||
private boolean matchSize; // false, if side-effect only consumes a single register
|
private boolean matchSize; // false, if side-effect only consumes a single register
|
||||||
|
private ParamEntry[] tiles; // Registers that can be consumed
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache specific ParamEntry needed by the action.
|
* Cache specific ParamEntry needed by the action.
|
||||||
|
@ -48,18 +48,10 @@ public class ConsumeExtra extends AssignAction {
|
||||||
* @throws InvalidInputException if it cannot find the configured ParamEntry objects
|
* @throws InvalidInputException if it cannot find the configured ParamEntry objects
|
||||||
*/
|
*/
|
||||||
private void initializeEntries() throws InvalidInputException {
|
private void initializeEntries() throws InvalidInputException {
|
||||||
firstIter = -1;
|
tiles = resource.extractTiles(resourceType);
|
||||||
for (int i = 0; i < resource.getNumParamEntry(); ++i) {
|
if (tiles.length == 0) {
|
||||||
ParamEntry entry = resource.getEntry(i);
|
|
||||||
if (entry.isExclusion() && entry.getType() == resourceType &&
|
|
||||||
entry.getAllGroups().length == 1) {
|
|
||||||
firstIter = i; // First matching resource size
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (firstIter == -1) {
|
|
||||||
throw new InvalidInputException(
|
throw new InvalidInputException(
|
||||||
"Could not find matching resources for action: consumeextra");
|
"Could not find matching resources for action: consume_extra");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,28 +80,29 @@ public class ConsumeExtra extends AssignAction {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ConsumeExtra otherAction = (ConsumeExtra) op;
|
ConsumeExtra otherAction = (ConsumeExtra) op;
|
||||||
if (firstIter != otherAction.firstIter || matchSize != otherAction.matchSize ||
|
if (matchSize != otherAction.matchSize ||
|
||||||
resourceType != otherAction.resourceType) {
|
resourceType != otherAction.resourceType) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (tiles.length != otherAction.tiles.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < tiles.length; ++i) {
|
||||||
|
if (!tiles[i].isEquivalent(otherAction.tiles[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int assignAddress(DataType dt, PrototypePieces proto, int pos, DataTypeManager dtManager,
|
public int assignAddress(DataType dt, PrototypePieces proto, int pos, DataTypeManager dtManager,
|
||||||
int[] status, ParameterPieces res) {
|
int[] status, ParameterPieces res) {
|
||||||
int iter = firstIter;
|
int iter = 0;
|
||||||
int endIter = resource.getNumParamEntry();
|
|
||||||
int sizeLeft = dt.getLength();
|
int sizeLeft = dt.getLength();
|
||||||
while (sizeLeft > 0 && iter != endIter) {
|
while (sizeLeft > 0 && iter != tiles.length) {
|
||||||
ParamEntry entry = resource.getEntry(iter);
|
ParamEntry entry = tiles[iter];
|
||||||
++iter;
|
++iter;
|
||||||
if (!entry.isExclusion()) {
|
|
||||||
break; // Reached end of resource list
|
|
||||||
}
|
|
||||||
if (entry.getType() != resourceType || entry.getAllGroups().length != 1) {
|
|
||||||
continue; // Not a single register in desired list
|
|
||||||
}
|
|
||||||
if (status[entry.getGroup()] != 0) {
|
if (status[entry.getGroup()] != 0) {
|
||||||
continue; // Already consumed
|
continue; // Already consumed
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.program.model.lang.protorules;
|
||||||
|
|
||||||
|
import static ghidra.program.model.pcode.ElementId.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
|
import ghidra.program.model.data.DataTypeManager;
|
||||||
|
import ghidra.program.model.lang.*;
|
||||||
|
import ghidra.program.model.pcode.Encoder;
|
||||||
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
import ghidra.xml.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Consume stack resources as a side-effect
|
||||||
|
*
|
||||||
|
* This action is a side-effect and doesn't assign an address for the current parameter.
|
||||||
|
* If the current parameter has been assigned a address that is not on the stack, this action consumes
|
||||||
|
* stack resources as if the parameter were allocated to the stack. If the current parameter was
|
||||||
|
* already assigned a stack address, no additional action is taken.
|
||||||
|
*/
|
||||||
|
public class ExtraStack extends AssignAction {
|
||||||
|
|
||||||
|
private ParamEntry stackEntry; // Parameter entry corresponding to the stack
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find stack entry in resource list
|
||||||
|
* @throws InvalidInputException if there is no stack entry
|
||||||
|
*/
|
||||||
|
private void initializeEntry() throws InvalidInputException {
|
||||||
|
for (int i = 0; i < resource.getNumParamEntry(); ++i) {
|
||||||
|
ParamEntry entry = resource.getEntry(i);
|
||||||
|
if (!entry.isExclusion() && entry.getSpace().isStackSpace()) {
|
||||||
|
stackEntry = entry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stackEntry == null) {
|
||||||
|
throw new InvalidInputException(
|
||||||
|
"Cannot find matching <pentry> for action: extra_stack");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for use with restoreXml
|
||||||
|
* @param res is the resource list
|
||||||
|
* @param val is a dummy variable
|
||||||
|
*/
|
||||||
|
public ExtraStack(ParamListStandard res, int val) {
|
||||||
|
super(res);
|
||||||
|
stackEntry = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExtraStack(ParamListStandard res) throws InvalidInputException {
|
||||||
|
super(res);
|
||||||
|
stackEntry = null;
|
||||||
|
initializeEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AssignAction clone(ParamListStandard newResource) throws InvalidInputException {
|
||||||
|
return new ExtraStack(newResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEquivalent(AssignAction op) {
|
||||||
|
if (this.getClass() != op.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ExtraStack otherAction = (ExtraStack) op;
|
||||||
|
return stackEntry.isEquivalent(otherAction.stackEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int assignAddress(DataType dt, PrototypePieces proto, int pos, DataTypeManager dtManager,
|
||||||
|
int[] status, ParameterPieces res) {
|
||||||
|
if (res.address.getAddressSpace() == stackEntry.getSpace()) {
|
||||||
|
return SUCCESS; // Parameter was already assigned to the stack
|
||||||
|
}
|
||||||
|
int grp = stackEntry.getGroup();
|
||||||
|
// We assign the stack address (but ignore the actual address) updating the status for the stack,
|
||||||
|
// which consumes the stack resources.
|
||||||
|
ParameterPieces unused = new ParameterPieces();
|
||||||
|
status[grp] =
|
||||||
|
stackEntry.getAddrBySlot(status[grp], dt.getLength(), dt.getAlignment(), unused);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(Encoder encoder) throws IOException {
|
||||||
|
encoder.openElement(ELEM_EXTRA_STACK);
|
||||||
|
encoder.closeElement(ELEM_EXTRA_STACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreXml(XmlPullParser parser) throws XmlParseException {
|
||||||
|
XmlElement elem = parser.start(ELEM_EXTRA_STACK.name());
|
||||||
|
parser.end(elem);
|
||||||
|
try {
|
||||||
|
initializeEntry();
|
||||||
|
}
|
||||||
|
catch (InvalidInputException e) {
|
||||||
|
throw new XmlParseException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -42,7 +42,7 @@ public class GotoStack extends AssignAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (stackEntry == null) {
|
if (stackEntry == null) {
|
||||||
throw new InvalidInputException("Cannot find matching <pentry> for action: gotostack");
|
throw new InvalidInputException("Cannot find matching <pentry> for action: goto_stack");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,9 +55,20 @@ public class HomogeneousAggregate extends SizeRestrictedFilter {
|
||||||
maxPrimitives = maxPrim;
|
maxPrimitives = maxPrim;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy constructor
|
||||||
|
* @param op2 is the filter to copy
|
||||||
|
*/
|
||||||
|
public HomogeneousAggregate(HomogeneousAggregate op2) {
|
||||||
|
super(op2);
|
||||||
|
name = op2.name;
|
||||||
|
metaType = op2.metaType;
|
||||||
|
maxPrimitives = op2.maxPrimitives;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DatatypeFilter clone() {
|
public DatatypeFilter clone() {
|
||||||
return new HomogeneousAggregate(name, metaType, maxPrimitives, minSize, maxSize);
|
return new HomogeneousAggregate(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -52,6 +52,15 @@ public class MetaTypeFilter extends SizeRestrictedFilter {
|
||||||
metaType = meta;
|
metaType = meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy constructor
|
||||||
|
* @param op2 is the filter to copy
|
||||||
|
*/
|
||||||
|
public MetaTypeFilter(MetaTypeFilter op2) {
|
||||||
|
super(op2);
|
||||||
|
metaType = op2.metaType;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEquivalent(DatatypeFilter op) {
|
public boolean isEquivalent(DatatypeFilter op) {
|
||||||
if (!super.isEquivalent(op)) {
|
if (!super.isEquivalent(op)) {
|
||||||
|
@ -69,7 +78,7 @@ public class MetaTypeFilter extends SizeRestrictedFilter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DatatypeFilter clone() {
|
public DatatypeFilter clone() {
|
||||||
return new MetaTypeFilter(metaType, minSize, maxSize);
|
return new MetaTypeFilter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -21,7 +21,6 @@ import static ghidra.program.model.pcode.ElementId.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import ghidra.program.model.address.Address;
|
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.data.DataTypeManager;
|
import ghidra.program.model.data.DataTypeManager;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
|
@ -94,22 +93,7 @@ public class MultiMemberAssign extends AssignAction {
|
||||||
|
|
||||||
System.arraycopy(tmpStatus, 0, status, 0, tmpStatus.length); // Commit resource usage for all the pieces
|
System.arraycopy(tmpStatus, 0, status, 0, tmpStatus.length); // Commit resource usage for all the pieces
|
||||||
res.type = dt;
|
res.type = dt;
|
||||||
if (pieces.size() == 1) {
|
res.assignAddressFromPieces(pieces, consumeMostSig, false, resource.getLanguage());
|
||||||
res.address = pieces.get(0).getAddress();
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
res.joinPieces = new Varnode[pieces.size()];
|
|
||||||
if (!consumeMostSig) {
|
|
||||||
for (int i = 0; i < res.joinPieces.length; ++i) {
|
|
||||||
res.joinPieces[i] = pieces.get(pieces.size() - 1 - i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (int i = 0; i < pieces.size(); ++i) {
|
|
||||||
res.joinPieces[i] = pieces.get(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res.address = Address.NO_ADDRESS; // Placeholder for join space address
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,10 @@ public class MultiSlotAssign extends AssignAction {
|
||||||
private boolean consumeMostSig; // True if resources are consumed starting with most significant bytes
|
private boolean consumeMostSig; // True if resources are consumed starting with most significant bytes
|
||||||
private boolean enforceAlignment; // True if register resources are discarded to match alignment
|
private boolean enforceAlignment; // True if register resources are discarded to match alignment
|
||||||
private boolean justifyRight; // True if initial bytes are padding for odd data-type sizes
|
private boolean justifyRight; // True if initial bytes are padding for odd data-type sizes
|
||||||
|
private boolean adjacentEntries; // True if an assignment should only consume adjacent entries in the list
|
||||||
|
private boolean allowBackfill; // True if entries skipped for alignment can be reused for later params
|
||||||
|
private ParamEntry[] tiles; // Registers that can be joined
|
||||||
private ParamEntry stackEntry; // The stack resource
|
private ParamEntry stackEntry; // The stack resource
|
||||||
private int firstIter; // Iterator to first element in the resource list
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache specific ParamEntry needed by the action
|
* Cache specific ParamEntry needed by the action
|
||||||
|
@ -56,19 +58,9 @@ public class MultiSlotAssign extends AssignAction {
|
||||||
* @throws InvalidInputException if the required elements are not available in the resource list
|
* @throws InvalidInputException if the required elements are not available in the resource list
|
||||||
*/
|
*/
|
||||||
private void initializeEntries() throws InvalidInputException {
|
private void initializeEntries() throws InvalidInputException {
|
||||||
firstIter = -1;
|
tiles = resource.extractTiles(resourceType);
|
||||||
for (int i = 0; i < resource.getNumParamEntry(); ++i) {
|
stackEntry = resource.extractStack();
|
||||||
ParamEntry entry = resource.getEntry(i);
|
if (tiles.length == 0) {
|
||||||
if (firstIter == -1 && entry.isExclusion() && entry.getType() == resourceType &&
|
|
||||||
entry.getAllGroups().length == 1) {
|
|
||||||
firstIter = i; // First matching resource size
|
|
||||||
}
|
|
||||||
if (!entry.isExclusion() && entry.getSpace().isStackSpace()) {
|
|
||||||
stackEntry = entry;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (firstIter == -1) {
|
|
||||||
throw new InvalidInputException("Could not find matching resources for action: join");
|
throw new InvalidInputException("Could not find matching resources for action: join");
|
||||||
}
|
}
|
||||||
if (consumeFromStack && stackEntry == null) {
|
if (consumeFromStack && stackEntry == null) {
|
||||||
|
@ -87,6 +79,8 @@ public class MultiSlotAssign extends AssignAction {
|
||||||
consumeMostSig = false;
|
consumeMostSig = false;
|
||||||
enforceAlignment = false;
|
enforceAlignment = false;
|
||||||
justifyRight = false;
|
justifyRight = false;
|
||||||
|
adjacentEntries = true;
|
||||||
|
allowBackfill = false;
|
||||||
if (res.getEntry(0).isBigEndian()) {
|
if (res.getEntry(0).isBigEndian()) {
|
||||||
consumeMostSig = true;
|
consumeMostSig = true;
|
||||||
justifyRight = true;
|
justifyRight = true;
|
||||||
|
@ -95,13 +89,16 @@ public class MultiSlotAssign extends AssignAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
public MultiSlotAssign(StorageClass store, boolean stack, boolean mostSig, boolean align,
|
public MultiSlotAssign(StorageClass store, boolean stack, boolean mostSig, boolean align,
|
||||||
boolean justRight, ParamListStandard res) throws InvalidInputException {
|
boolean justRight, boolean backfill, ParamListStandard res)
|
||||||
|
throws InvalidInputException {
|
||||||
super(res);
|
super(res);
|
||||||
resourceType = store;
|
resourceType = store;
|
||||||
consumeFromStack = stack;
|
consumeFromStack = stack;
|
||||||
consumeMostSig = mostSig;
|
consumeMostSig = mostSig;
|
||||||
enforceAlignment = align;
|
enforceAlignment = align;
|
||||||
justifyRight = justRight;
|
justifyRight = justRight;
|
||||||
|
adjacentEntries = true;
|
||||||
|
allowBackfill = backfill;
|
||||||
stackEntry = null;
|
stackEntry = null;
|
||||||
initializeEntries();
|
initializeEntries();
|
||||||
}
|
}
|
||||||
|
@ -109,7 +106,7 @@ public class MultiSlotAssign extends AssignAction {
|
||||||
@Override
|
@Override
|
||||||
public AssignAction clone(ParamListStandard newResource) throws InvalidInputException {
|
public AssignAction clone(ParamListStandard newResource) throws InvalidInputException {
|
||||||
return new MultiSlotAssign(resourceType, consumeFromStack, consumeMostSig, enforceAlignment,
|
return new MultiSlotAssign(resourceType, consumeFromStack, consumeMostSig, enforceAlignment,
|
||||||
justifyRight, newResource);
|
justifyRight, allowBackfill, newResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -120,15 +117,23 @@ public class MultiSlotAssign extends AssignAction {
|
||||||
MultiSlotAssign otherAction = (MultiSlotAssign) op;
|
MultiSlotAssign otherAction = (MultiSlotAssign) op;
|
||||||
if (consumeFromStack != otherAction.consumeFromStack ||
|
if (consumeFromStack != otherAction.consumeFromStack ||
|
||||||
consumeMostSig != otherAction.consumeMostSig ||
|
consumeMostSig != otherAction.consumeMostSig ||
|
||||||
enforceAlignment != otherAction.enforceAlignment) {
|
enforceAlignment != otherAction.enforceAlignment ||
|
||||||
return false;
|
justifyRight != otherAction.justifyRight ||
|
||||||
}
|
adjacentEntries != otherAction.adjacentEntries ||
|
||||||
if (firstIter != otherAction.firstIter || justifyRight != otherAction.justifyRight) {
|
allowBackfill != otherAction.allowBackfill) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (resourceType != otherAction.resourceType) {
|
if (resourceType != otherAction.resourceType) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (tiles.length != otherAction.tiles.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < tiles.length; ++i) {
|
||||||
|
if (!tiles[i].isEquivalent(otherAction.tiles[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (stackEntry == null && otherAction.stackEntry == null) {
|
if (stackEntry == null && otherAction.stackEntry == null) {
|
||||||
// Nothing to compare
|
// Nothing to compare
|
||||||
}
|
}
|
||||||
|
@ -143,6 +148,44 @@ public class MultiSlotAssign extends AssignAction {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if a data-type of the given size will fit starting at a particular entry within
|
||||||
|
* the resource list. If necessary, check
|
||||||
|
* 1) If the type will be properly aligned
|
||||||
|
* 2) If there are enough remaining registers, up to the end of the resource list, to
|
||||||
|
* cover the data-type and that have not been consumed.
|
||||||
|
* @param iter is the first resource entry to use for the data-type
|
||||||
|
* @param sizeLeft initially holds the size of the data-type to cover in bytes
|
||||||
|
* @param align is the alignment requirement for the data-type
|
||||||
|
* @param resourcesConsumed is the number of bytes in resources already consumed/skipped
|
||||||
|
* @param tmpStatus is the current consumption status for the resource list
|
||||||
|
* @return true if the data-type will fit
|
||||||
|
*/
|
||||||
|
private boolean checkFit(int iter, int sizeLeft, int align, int resourcesConsumed,
|
||||||
|
int[] tmpStatus) {
|
||||||
|
ParamEntry entry = tiles[iter];
|
||||||
|
if (tmpStatus[entry.getGroup()] != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (enforceAlignment) {
|
||||||
|
int regSize = entry.getSize();
|
||||||
|
if (align > regSize && (resourcesConsumed % align) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!adjacentEntries) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
while (iter != tiles.length && sizeLeft > 0) {
|
||||||
|
entry = tiles[iter];
|
||||||
|
if (tmpStatus[entry.getGroup()] != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sizeLeft -= entry.getSize();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int assignAddress(DataType dt, PrototypePieces proto, int pos, DataTypeManager dtManager,
|
public int assignAddress(DataType dt, PrototypePieces proto, int pos, DataTypeManager dtManager,
|
||||||
int[] status, ParameterPieces res) {
|
int[] status, ParameterPieces res) {
|
||||||
|
@ -151,37 +194,22 @@ public class MultiSlotAssign extends AssignAction {
|
||||||
ParameterPieces param = new ParameterPieces();
|
ParameterPieces param = new ParameterPieces();
|
||||||
int sizeLeft = dt.getLength();
|
int sizeLeft = dt.getLength();
|
||||||
int align = dt.getAlignment();
|
int align = dt.getAlignment();
|
||||||
int iter = firstIter;
|
int iter = 0;
|
||||||
int endIter = resource.getNumParamEntry();
|
int resourcesConsumed = 0;
|
||||||
if (enforceAlignment) {
|
while (iter != tiles.length) {
|
||||||
int resourcesConsumed = 0;
|
if (checkFit(iter, sizeLeft, align, resourcesConsumed, tmpStatus)) {
|
||||||
while (iter != endIter) {
|
|
||||||
ParamEntry entry = resource.getEntry(iter);
|
|
||||||
if (!entry.isExclusion()) {
|
|
||||||
break;
|
|
||||||
} // Reached end of resource list
|
|
||||||
if (entry.getType() == resourceType && entry.getAllGroups().length == 1) { // Single register
|
|
||||||
if (tmpStatus[entry.getGroup()] == 0) { // Not consumed
|
|
||||||
int regSize = entry.getSize();
|
|
||||||
if (align <= regSize || (resourcesConsumed % align) == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
tmpStatus[entry.getGroup()] = -1; // Consume unaligned register
|
|
||||||
}
|
|
||||||
resourcesConsumed += entry.getSize();
|
|
||||||
}
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (sizeLeft > 0 && iter != endIter) {
|
|
||||||
ParamEntry entry = resource.getEntry(iter);
|
|
||||||
++iter;
|
|
||||||
if (!entry.isExclusion()) {
|
|
||||||
break;
|
break;
|
||||||
} // Reached end of resource list
|
}
|
||||||
if (entry.getType() != resourceType || entry.getAllGroups().length != 1) {
|
ParamEntry entry = tiles[iter];
|
||||||
continue;
|
if (!allowBackfill) {
|
||||||
} // Not a single register from desired resource list
|
tmpStatus[entry.getGroup()] = -1; // Consume unaligned register
|
||||||
|
}
|
||||||
|
resourcesConsumed += entry.getSize();
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
while (sizeLeft > 0 && iter != tiles.length) {
|
||||||
|
ParamEntry entry = tiles[iter];
|
||||||
|
++iter;
|
||||||
if (tmpStatus[entry.getGroup()] != 0) {
|
if (tmpStatus[entry.getGroup()] != 0) {
|
||||||
continue;
|
continue;
|
||||||
} // Already consumed
|
} // Already consumed
|
||||||
|
@ -229,22 +257,7 @@ public class MultiSlotAssign extends AssignAction {
|
||||||
}
|
}
|
||||||
System.arraycopy(tmpStatus, 0, status, 0, tmpStatus.length); // Commit resource usage for all the pieces
|
System.arraycopy(tmpStatus, 0, status, 0, tmpStatus.length); // Commit resource usage for all the pieces
|
||||||
res.type = dt;
|
res.type = dt;
|
||||||
if (pieces.size() == 1 && !onePieceJoin) {
|
res.assignAddressFromPieces(pieces, consumeMostSig, onePieceJoin, resource.getLanguage());
|
||||||
res.address = pieces.get(0).getAddress();
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
res.joinPieces = new Varnode[pieces.size()];
|
|
||||||
if (!consumeMostSig) {
|
|
||||||
for (int i = 0; i < res.joinPieces.length; ++i) {
|
|
||||||
res.joinPieces[i] = pieces.get(pieces.size() - 1 - i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (int i = 0; i < pieces.size(); ++i) {
|
|
||||||
res.joinPieces[i] = pieces.get(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res.address = Address.NO_ADDRESS; // Placeholder for join space address
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,6 +272,7 @@ public class MultiSlotAssign extends AssignAction {
|
||||||
}
|
}
|
||||||
encoder.writeBool(ATTRIB_ALIGN, enforceAlignment);
|
encoder.writeBool(ATTRIB_ALIGN, enforceAlignment);
|
||||||
encoder.writeBool(ATTRIB_STACKSPILL, consumeFromStack);
|
encoder.writeBool(ATTRIB_STACKSPILL, consumeFromStack);
|
||||||
|
encoder.writeBool(ATTRIB_BACKFILL, allowBackfill);
|
||||||
encoder.closeElement(ELEM_JOIN);
|
encoder.closeElement(ELEM_JOIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,6 +295,9 @@ public class MultiSlotAssign extends AssignAction {
|
||||||
else if (name.equals(ATTRIB_STACKSPILL.name())) {
|
else if (name.equals(ATTRIB_STACKSPILL.name())) {
|
||||||
consumeFromStack = SpecXmlUtils.decodeBoolean(attrib.getValue());
|
consumeFromStack = SpecXmlUtils.decodeBoolean(attrib.getValue());
|
||||||
}
|
}
|
||||||
|
else if (name.equals(ATTRIB_BACKFILL.name())) {
|
||||||
|
allowBackfill = SpecXmlUtils.decodeBoolean(attrib.getValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
parser.end(elem);
|
parser.end(elem);
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -45,61 +45,43 @@ public class MultiSlotDualAssign extends AssignAction {
|
||||||
private boolean consumeMostSig; // True if resources are consumed starting with most significant bytes
|
private boolean consumeMostSig; // True if resources are consumed starting with most significant bytes
|
||||||
private boolean justifyRight; // True if initial bytes are padding for odd data-type sizes
|
private boolean justifyRight; // True if initial bytes are padding for odd data-type sizes
|
||||||
private int tileSize; // Number of bytes in a tile
|
private int tileSize; // Number of bytes in a tile
|
||||||
private int baseIter; // Iterator to first element in the base resource list
|
private ParamEntry[] baseTiles; // General registers for joining
|
||||||
private int altIter; // Iterator to first element in alternate resource list
|
private ParamEntry[] altTiles; // Alternate registers for joininig
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the first ParamEntry matching the baseType, and the first matching altType.
|
* Find the first ParamEntry matching the baseType, and the first matching altType.
|
||||||
* @throws InvalidInputException if the required elements are not available in the resource list
|
* @throws InvalidInputException if the required elements are not available in the resource list
|
||||||
*/
|
*/
|
||||||
private void initializeEntries() throws InvalidInputException {
|
private void initializeEntries() throws InvalidInputException {
|
||||||
baseIter = -1;
|
baseTiles = resource.extractTiles(baseType);
|
||||||
altIter = -1;
|
altTiles = resource.extractTiles(altType);
|
||||||
for (int i = 0; i < resource.getNumParamEntry(); ++i) {
|
if (baseTiles.length == 0 || altTiles.length == 0) {
|
||||||
ParamEntry entry = resource.getEntry(i);
|
|
||||||
if (baseIter == -1 && entry.isExclusion() && entry.getType() == baseType &&
|
|
||||||
entry.getAllGroups().length == 1) {
|
|
||||||
baseIter = i; // First matching base resource type
|
|
||||||
}
|
|
||||||
if (altIter == -1 && entry.isExclusion() && entry.getType() == altType &&
|
|
||||||
entry.getAllGroups().length == 1) {
|
|
||||||
altIter = i; // First matching alt resource type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (baseIter == -1 || altIter == -1) {
|
|
||||||
throw new InvalidInputException(
|
throw new InvalidInputException(
|
||||||
"Could not find matching resources for action: join_dual_class");
|
"Could not find matching resources for action: join_dual_class");
|
||||||
}
|
}
|
||||||
tileSize = resource.getEntry(baseIter).getSize();
|
tileSize = baseTiles[0].getSize();
|
||||||
if (tileSize != resource.getEntry(altIter).getSize()) {
|
if (tileSize != altTiles[0].getSize()) {
|
||||||
throw new InvalidInputException(
|
throw new InvalidInputException(
|
||||||
"Storage class register sizes do not match for action: join_dual_class");
|
"Storage class register sizes do not match for action: join_dual_class");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the first unused ParamEntry that matches the given storage class
|
* Get the first unused ParamEntry within a given tileset
|
||||||
* @param iter points to the starting entry to search
|
* @param iter points to the starting entry to search
|
||||||
* @param storage is the given storage class to match
|
* @param tiles is the given tileset
|
||||||
* @param status is the usage information for the entries
|
* @param status is the usage information for the entries
|
||||||
* @return the iterator to the unused ParamEntry
|
* @return the iterator to the unused ParamEntry
|
||||||
*/
|
*/
|
||||||
private int getFirstUnused(int iter, StorageClass storage, int[] status) {
|
private int getFirstUnused(int iter, ParamEntry[] tiles, int[] status) {
|
||||||
int endIter = resource.getNumParamEntry();
|
for (; iter != tiles.length; ++iter) {
|
||||||
for (; iter != endIter; ++iter) {
|
ParamEntry entry = tiles[iter];
|
||||||
ParamEntry entry = resource.getEntry(iter);
|
|
||||||
if (!entry.isExclusion()) {
|
|
||||||
break; // Reached end of resource list
|
|
||||||
}
|
|
||||||
if (entry.getType() != storage || entry.getAllGroups().length != 1) {
|
|
||||||
continue; // Not a single register from desired resource
|
|
||||||
}
|
|
||||||
if (status[entry.getGroup()] != 0) {
|
if (status[entry.getGroup()] != 0) {
|
||||||
continue; // Already consumed
|
continue; // Already consumed
|
||||||
}
|
}
|
||||||
return iter;
|
return iter;
|
||||||
}
|
}
|
||||||
return endIter;
|
return tiles.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -186,12 +168,25 @@ public class MultiSlotDualAssign extends AssignAction {
|
||||||
justifyRight != otherAction.justifyRight) {
|
justifyRight != otherAction.justifyRight) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (baseIter != otherAction.baseIter || altIter != otherAction.altIter) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (baseType != otherAction.baseType || altType != otherAction.altType) {
|
if (baseType != otherAction.baseType || altType != otherAction.altType) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (baseTiles.length != otherAction.baseTiles.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < baseTiles.length; ++i) {
|
||||||
|
if (!baseTiles[i].isEquivalent(otherAction.baseTiles[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (altTiles.length != otherAction.altTiles.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < altTiles.length; ++i) {
|
||||||
|
if (!altTiles[i].isEquivalent(otherAction.altTiles[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,25 +204,28 @@ public class MultiSlotDualAssign extends AssignAction {
|
||||||
ArrayList<Varnode> pieces = new ArrayList<>();
|
ArrayList<Varnode> pieces = new ArrayList<>();
|
||||||
int typeSize = dt.getLength();
|
int typeSize = dt.getLength();
|
||||||
int sizeLeft = typeSize;
|
int sizeLeft = typeSize;
|
||||||
int iterBase = baseIter;
|
int iterBase = 0;
|
||||||
int iterAlt = altIter;
|
int iterAlt = 0;
|
||||||
int endIter = resource.getNumParamEntry();
|
|
||||||
while (sizeLeft > 0) {
|
while (sizeLeft > 0) {
|
||||||
int iter;
|
|
||||||
int iterType = getTileClass(primitives, typeSize - sizeLeft, primitiveIndex);
|
int iterType = getTileClass(primitives, typeSize - sizeLeft, primitiveIndex);
|
||||||
if (iterType < 0) {
|
if (iterType < 0) {
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
ParamEntry entry;
|
||||||
if (iterType == 0) {
|
if (iterType == 0) {
|
||||||
iter = iterBase = getFirstUnused(iterBase, baseType, tmpStatus);
|
iterBase = getFirstUnused(iterBase, baseTiles, tmpStatus);
|
||||||
|
if (iterBase == baseTiles.length) {
|
||||||
|
return FAIL; // Out of general registers
|
||||||
|
}
|
||||||
|
entry = baseTiles[iterBase];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
iter = iterAlt = getFirstUnused(iterAlt, altType, tmpStatus);
|
iterAlt = getFirstUnused(iterAlt, altTiles, tmpStatus);
|
||||||
|
if (iterAlt == altTiles.length) {
|
||||||
|
return FAIL; // Out of alternate registers
|
||||||
|
}
|
||||||
|
entry = altTiles[iterAlt];
|
||||||
}
|
}
|
||||||
if (iter == endIter) {
|
|
||||||
return FAIL; // Out of the particular resource
|
|
||||||
}
|
|
||||||
ParamEntry entry = resource.getEntry(iter);
|
|
||||||
int trialSize = entry.getSize();
|
int trialSize = entry.getSize();
|
||||||
entry.getAddrBySlot(tmpStatus[entry.getGroup()], trialSize, 1, param);
|
entry.getAddrBySlot(tmpStatus[entry.getGroup()], trialSize, 1, param);
|
||||||
tmpStatus[entry.getGroup()] = -1; // Consume the register
|
tmpStatus[entry.getGroup()] = -1; // Consume the register
|
||||||
|
@ -254,22 +252,7 @@ public class MultiSlotDualAssign extends AssignAction {
|
||||||
}
|
}
|
||||||
System.arraycopy(tmpStatus, 0, status, 0, tmpStatus.length); // Commit resource usage for all the pieces
|
System.arraycopy(tmpStatus, 0, status, 0, tmpStatus.length); // Commit resource usage for all the pieces
|
||||||
res.type = dt;
|
res.type = dt;
|
||||||
if (pieces.size() == 1) {
|
res.assignAddressFromPieces(pieces, consumeMostSig, false, resource.getLanguage());
|
||||||
res.address = pieces.get(0).getAddress();
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
res.joinPieces = new Varnode[pieces.size()];
|
|
||||||
if (!consumeMostSig) {
|
|
||||||
for (int i = 0; i < res.joinPieces.length; ++i) {
|
|
||||||
res.joinPieces[i] = pieces.get(pieces.size() - 1 - i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (int i = 0; i < pieces.size(); ++i) {
|
|
||||||
res.joinPieces[i] = pieces.get(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res.address = Address.NO_ADDRESS;
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import static ghidra.program.model.pcode.AttributeId.*;
|
||||||
import static ghidra.program.model.pcode.ElementId.*;
|
import static ghidra.program.model.pcode.ElementId.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
@ -28,8 +29,8 @@ import ghidra.util.xml.SpecXmlUtils;
|
||||||
import ghidra.xml.*;
|
import ghidra.xml.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A common base class for data-type filters that tests for a size range.
|
* A base class for data-type filters that tests either for either a range or an enumerated list of sizes.
|
||||||
* Any filter that inherits from this, can use ATTRIB_MINSIZE and ATTRIB_MAXSIZE
|
* Any filter that inherits from this, can use ATTRIB_MINSIZE, ATTRIB_MAXSIZE, or ATTRIB_SIZES
|
||||||
* to place bounds on the possible sizes of data-types. The bounds are enforced
|
* to place bounds on the possible sizes of data-types. The bounds are enforced
|
||||||
* by calling filterOnSize() within the inheriting classes filter() method.
|
* by calling filterOnSize() within the inheriting classes filter() method.
|
||||||
*/
|
*/
|
||||||
|
@ -39,6 +40,7 @@ public class SizeRestrictedFilter implements DatatypeFilter {
|
||||||
|
|
||||||
protected int minSize; // Minimum size of the data-type in bytes
|
protected int minSize; // Minimum size of the data-type in bytes
|
||||||
protected int maxSize; // Maximum size of the data-type in bytes
|
protected int maxSize; // Maximum size of the data-type in bytes
|
||||||
|
protected HashSet<Integer> sizes = null;
|
||||||
|
|
||||||
public SizeRestrictedFilter() {
|
public SizeRestrictedFilter() {
|
||||||
minSize = 0;
|
minSize = 0;
|
||||||
|
@ -54,10 +56,57 @@ public class SizeRestrictedFilter implements DatatypeFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy constructor
|
||||||
|
* @param op2 is the filter to copy
|
||||||
|
*/
|
||||||
|
public SizeRestrictedFilter(SizeRestrictedFilter op2) {
|
||||||
|
minSize = op2.minSize;
|
||||||
|
maxSize = op2.maxSize;
|
||||||
|
if (op2.sizes != null) {
|
||||||
|
sizes = new HashSet<Integer>(op2.sizes);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sizes = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the given string as a comma or space separated list of decimal integers,
|
||||||
|
* populating the sizes set.
|
||||||
|
* @param str is the given string to parse
|
||||||
|
* @throws XmlParseException if the string does not valid (positive) integers
|
||||||
|
*/
|
||||||
|
protected void initFromSizeList(String str) throws XmlParseException {
|
||||||
|
String[] numStrings = str.split(" +|,");
|
||||||
|
sizes = new HashSet<Integer>();
|
||||||
|
minSize = Integer.MAX_VALUE;
|
||||||
|
maxSize = 0;
|
||||||
|
for (String valString : numStrings) {
|
||||||
|
int val = Integer.parseInt(valString);
|
||||||
|
if (val <= 0) {
|
||||||
|
throw new XmlParseException("Bad filter size");
|
||||||
|
}
|
||||||
|
sizes.add(val);
|
||||||
|
if (val < minSize) {
|
||||||
|
minSize = val;
|
||||||
|
}
|
||||||
|
if (val > maxSize) {
|
||||||
|
maxSize = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sizes.isEmpty()) {
|
||||||
|
sizes = null;
|
||||||
|
minSize = 0;
|
||||||
|
maxSize = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enforce any size bounds on a given data-type.
|
* Enforce any size bounds on a given data-type.
|
||||||
* If \b maxSize is not zero, the data-type is checked to see if its size in bytes
|
* If \b maxSize is not zero, the data-type is checked to see if its size in bytes
|
||||||
* falls between \b minSize and \b maxSize inclusive.
|
* falls between \b minSize and \b maxSize inclusive. If enumerated sizes are present,
|
||||||
|
* also check that the particular size is in the enumerated set.
|
||||||
* @param dt is the data-type to test
|
* @param dt is the data-type to test
|
||||||
* @return true if the data-type meets the size restrictions
|
* @return true if the data-type meets the size restrictions
|
||||||
*/
|
*/
|
||||||
|
@ -65,12 +114,15 @@ public class SizeRestrictedFilter implements DatatypeFilter {
|
||||||
if (maxSize == 0) {
|
if (maxSize == 0) {
|
||||||
return true; // maxSize of 0 means no size filtering is performed
|
return true; // maxSize of 0 means no size filtering is performed
|
||||||
}
|
}
|
||||||
|
if (sizes != null) {
|
||||||
|
return sizes.contains(Integer.valueOf(dt.getLength()));
|
||||||
|
}
|
||||||
return (dt.getLength() >= minSize && dt.getLength() <= maxSize);
|
return (dt.getLength() >= minSize && dt.getLength() <= maxSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DatatypeFilter clone() {
|
public DatatypeFilter clone() {
|
||||||
return new SizeRestrictedFilter(minSize, maxSize);
|
return new SizeRestrictedFilter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -82,6 +134,13 @@ public class SizeRestrictedFilter implements DatatypeFilter {
|
||||||
if (maxSize != otherFilter.maxSize || minSize != otherFilter.minSize) {
|
if (maxSize != otherFilter.maxSize || minSize != otherFilter.minSize) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (sizes != null && otherFilter.sizes != null) {
|
||||||
|
if (!sizes.equals(otherFilter.sizes))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (sizes != null || otherFilter.sizes != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,21 +150,49 @@ public class SizeRestrictedFilter implements DatatypeFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void encodeAttributes(Encoder encoder) throws IOException {
|
protected void encodeAttributes(Encoder encoder) throws IOException {
|
||||||
encoder.writeUnsignedInteger(ATTRIB_MINSIZE, minSize);
|
if (sizes != null) {
|
||||||
encoder.writeUnsignedInteger(ATTRIB_MAXSIZE, maxSize);
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
Iterator<Integer> iter = sizes.iterator();
|
||||||
|
buffer.append(iter.next().intValue());
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
buffer.append(',');
|
||||||
|
buffer.append(iter.next().intValue());
|
||||||
|
}
|
||||||
|
encoder.writeString(ATTRIB_SIZES, buffer.toString());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
encoder.writeUnsignedInteger(ATTRIB_MINSIZE, minSize);
|
||||||
|
encoder.writeUnsignedInteger(ATTRIB_MAXSIZE, maxSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void restoreAttributesXml(XmlElement el) {
|
protected void restoreAttributesXml(XmlElement el) throws XmlParseException {
|
||||||
Iterator<Entry<String, String>> iter = el.getAttributes().entrySet().iterator();
|
Iterator<Entry<String, String>> iter = el.getAttributes().entrySet().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
Entry<String, String> attrib = iter.next();
|
Entry<String, String> attrib = iter.next();
|
||||||
String nm = attrib.getKey();
|
String nm = attrib.getKey();
|
||||||
if (nm.equals(ATTRIB_MINSIZE.name())) {
|
if (nm.equals(ATTRIB_MINSIZE.name())) {
|
||||||
|
if (sizes != null) {
|
||||||
|
throw new XmlParseException(
|
||||||
|
"Mixing \"sizes\" with \"minsize\" and \"maxsize\"");
|
||||||
|
}
|
||||||
minSize = SpecXmlUtils.decodeInt(attrib.getValue());
|
minSize = SpecXmlUtils.decodeInt(attrib.getValue());
|
||||||
}
|
}
|
||||||
else if (nm.equals(ATTRIB_MAXSIZE.name())) {
|
else if (nm.equals(ATTRIB_MAXSIZE.name())) {
|
||||||
|
if (sizes != null) {
|
||||||
|
throw new XmlParseException(
|
||||||
|
"Mixing \"sizes\" with \"minsize\" and \"maxsize\"");
|
||||||
|
}
|
||||||
maxSize = SpecXmlUtils.decodeInt(attrib.getValue());
|
maxSize = SpecXmlUtils.decodeInt(attrib.getValue());
|
||||||
}
|
}
|
||||||
|
else if (nm.equals(ATTRIB_SIZES.name())) {
|
||||||
|
if (minSize != 0 || maxSize != 0) {
|
||||||
|
throw new XmlParseException(
|
||||||
|
"Mixing \"sizes\" with \"minsize\" and \"maxsize\"");
|
||||||
|
}
|
||||||
|
String sizeList = attrib.getValue();
|
||||||
|
initFromSizeList(sizeList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (maxSize == 0 && minSize >= 0) {
|
if (maxSize == 0 && minSize >= 0) {
|
||||||
// If no ATTRIB_MAXSIZE is given, assume there is no upper bound on size
|
// If no ATTRIB_MAXSIZE is given, assume there is no upper bound on size
|
||||||
|
|
|
@ -244,5 +244,9 @@ public record AttributeId(String name, int id) {
|
||||||
public static final AttributeId ATTRIB_STORAGE = new AttributeId("storage", 149);
|
public static final AttributeId ATTRIB_STORAGE = new AttributeId("storage", 149);
|
||||||
public static final AttributeId ATTRIB_STACKSPILL = new AttributeId("stackspill", 150);
|
public static final AttributeId ATTRIB_STACKSPILL = new AttributeId("stackspill", 150);
|
||||||
|
|
||||||
public static final AttributeId ATTRIB_UNKNOWN = new AttributeId("XMLunknown", 151);
|
// modelrules
|
||||||
|
public static final AttributeId ATTRIB_SIZES = new AttributeId("sizes", 151);
|
||||||
|
public static final AttributeId ATTRIB_BACKFILL = new AttributeId("backfill", 152);
|
||||||
|
|
||||||
|
public static final AttributeId ATTRIB_UNKNOWN = new AttributeId("XMLunknown", 153);
|
||||||
}
|
}
|
||||||
|
|
|
@ -456,6 +456,7 @@ public record ElementId(String name, int id) {
|
||||||
public static final ElementId ELEM_JOIN_PER_PRIMITIVE =
|
public static final ElementId ELEM_JOIN_PER_PRIMITIVE =
|
||||||
new ElementId("join_per_primitive", 283);
|
new ElementId("join_per_primitive", 283);
|
||||||
public static final ElementId ELEM_JOIN_DUAL_CLASS = new ElementId("join_dual_class", 285);
|
public static final ElementId ELEM_JOIN_DUAL_CLASS = new ElementId("join_dual_class", 285);
|
||||||
|
public static final ElementId ELEM_EXTRA_STACK = new ElementId("extra_stack", 287);
|
||||||
|
|
||||||
public static final ElementId ELEM_UNKNOWN = new ElementId("XMLunknown", 287);
|
public static final ElementId ELEM_UNKNOWN = new ElementId("XMLunknown", 288);
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,6 +175,29 @@ public class Varnode {
|
||||||
return rangeIntersects(varnode.offset, endOtherOffset);
|
return rangeIntersects(varnode.offset, endOtherOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this contiguous (as the most significant piece) with the given Varnode
|
||||||
|
* @param lo is the other Varnode to compare with
|
||||||
|
* @param bigEndian is true for big endian significance ordering
|
||||||
|
* @return true if the two byte ranges are contiguous and in order
|
||||||
|
*/
|
||||||
|
public boolean isContiguous(Varnode lo, boolean bigEndian) {
|
||||||
|
AddressSpace spc = address.getAddressSpace();
|
||||||
|
if (spc != lo.address.getAddressSpace())
|
||||||
|
return false;
|
||||||
|
if (bigEndian) {
|
||||||
|
long nextoff = spc.truncateOffset(offset + size);
|
||||||
|
if (nextoff == lo.offset)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
long nextoff = spc.truncateOffset(lo.offset + lo.size);
|
||||||
|
if (nextoff == offset)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean rangeIntersects(long otherOffset, long otherEndOffset) {
|
private boolean rangeIntersects(long otherOffset, long otherEndOffset) {
|
||||||
long endOffset = offset;
|
long endOffset = offset;
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
|
|
|
@ -29,10 +29,10 @@ public class Sparc32ProtoModelTest extends AbstractProtoModelTest {
|
||||||
PrototypeModel model = cspec.getCallingConvention("__stdcall");
|
PrototypeModel model = cspec.getCallingConvention("__stdcall");
|
||||||
|
|
||||||
test(model, "void func(int,long long,int,long long,int,int)",
|
test(model, "void func(int,long long,int,long long,int,int)",
|
||||||
"void,o0,join o1 o2,o3,join o4 o5,stack5c:4,stack60:4");
|
"void,o0,join o1 o2,o3,o4_5,stack5c:4,stack60:4");
|
||||||
|
|
||||||
test(model, "void func(float,double,float,double,float,float)",
|
test(model, "void func(float,double,float,double,float,float)",
|
||||||
"void,o0,join o1 o2,o3,join o4 o5,stack5c:4,stack60:4");
|
"void,o0,join o1 o2,o3,o4_5,stack5c:4,stack60:4");
|
||||||
|
|
||||||
test(model, "void func(int,double,long long,float,float)",
|
test(model, "void func(int,double,long long,float,float)",
|
||||||
"void,o0,join o1 o2,join o3 o4,o5,stack5c:4");
|
"void,o0,join o1 o2,join o3 o4,o5,stack5c:4");
|
||||||
|
@ -40,14 +40,14 @@ public class Sparc32ProtoModelTest extends AbstractProtoModelTest {
|
||||||
test(model, "void func(int,long double,float)", "void,o0,o1,o2");
|
test(model, "void func(int,long double,float)", "void,o0,o1,o2");
|
||||||
|
|
||||||
parseStructure("intpair", "int,int");
|
parseStructure("intpair", "int,int");
|
||||||
test(model, "void func(int,intpair,double)", "void,o0,o1,join o2 o3");
|
test(model, "void func(int,intpair,double)", "void,o0,o1,o2_3");
|
||||||
|
|
||||||
test(model, "int func()", "o0");
|
test(model, "int func()", "o0");
|
||||||
test(model, "long long func()", "join o0 o1");
|
test(model, "long long func()", "o0_1");
|
||||||
test(model, "float func()", "fs0");
|
test(model, "float func()", "fs0");
|
||||||
test(model, "double func()", "join fs0 fs1");
|
test(model, "double func()", "fd0");
|
||||||
test(model, "long double func(int,int)", "o0,stack40:4,o0,o1");
|
test(model, "long double func(int,int)", "o0,stack40:4,o0,o1");
|
||||||
test(model, "intpair func(long long)", "o0,stack40:4,join o0 o1");
|
test(model, "intpair func(long long)", "o0,stack40:4,o0_1");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@ public class Sparc64ProtoModelTest extends AbstractProtoModelTest {
|
||||||
public void testStdCall() throws Exception {
|
public void testStdCall() throws Exception {
|
||||||
PrototypeModel model = cspec.getCallingConvention("__stdcall");
|
PrototypeModel model = cspec.getCallingConvention("__stdcall");
|
||||||
|
|
||||||
|
|
||||||
test(model, "void func(int,long long,int,long long,int,int,int)",
|
test(model, "void func(int,long long,int,long long,int,int,int)",
|
||||||
"void,o0:4,o1,o2:4,o3,o4:4,o5:4,stack8b3:4");
|
"void,o0:4,o1,o2:4,o3,o4:4,o5:4,stack8b3:4");
|
||||||
|
|
||||||
|
@ -39,7 +38,7 @@ public class Sparc64ProtoModelTest extends AbstractProtoModelTest {
|
||||||
|
|
||||||
test(model, "void func(double,double)", "void,fd0,fd2");
|
test(model, "void func(double,double)", "void,fd0,fd2");
|
||||||
|
|
||||||
test(model, "void func(long double,int)", "void,join fd0 fd2,o4:4");
|
test(model, "void func(long double,int)", "void,fq0,o4:4");
|
||||||
|
|
||||||
test(model, "void func(int,double,float,long long)", "void,o0:4,fd2,fs5,o3");
|
test(model, "void func(int,double,float,long long)", "void,o0:4,fd2,fs5,o3");
|
||||||
|
|
||||||
|
@ -50,7 +49,7 @@ public class Sparc64ProtoModelTest extends AbstractProtoModelTest {
|
||||||
"void,o0:4,fd2,o2,fd6:4,fs9");
|
"void,o0:4,fd2,o2,fd6:4,fs9");
|
||||||
|
|
||||||
test(model, "void func(int,double,long long,float,float)",
|
test(model, "void func(int,double,long long,float,float)",
|
||||||
"void,o0:4,fd2,o2,fs7,fs9");
|
"void,o0:4,fd2,o2,fs7,fs9");
|
||||||
|
|
||||||
test(model, "char func()", "o0:1");
|
test(model, "char func()", "o0:1");
|
||||||
test(model, "int func()", "o0:4");
|
test(model, "int func()", "o0:4");
|
||||||
|
@ -65,7 +64,7 @@ public class Sparc64ProtoModelTest extends AbstractProtoModelTest {
|
||||||
// hidden return of structure
|
// hidden return of structure
|
||||||
test(model, "intpair func(long long)", "o0,stack7ef:8,o0");
|
test(model, "intpair func(long long)", "o0,stack7ef:8,o0");
|
||||||
|
|
||||||
test(model, "long double func(int,int)", "join fd0 fd2,o0:4,o1:4");
|
test(model, "long double func(int,int)", "fq0,o0:4,o1:4");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue