Merge remote-tracking branch 'origin/caheckman_transform'

This commit is contained in:
Ryan Kurtz 2019-12-17 11:30:30 -05:00
commit d575779e5b
19 changed files with 2215 additions and 890 deletions

View file

@ -295,6 +295,7 @@ model {
include "rangeutil.cc"
include "ruleaction.cc"
include "subflow.cc"
include "transform.cc"
include "blockaction.cc"
include "merge.cc"
include "double.cc"

View file

@ -79,7 +79,7 @@ DECCORE=capability architecture options graph cover block cast typeop database c
type variable varmap jumptable emulate emulateutil flow userop \
funcdata funcdata_block funcdata_op funcdata_varnode pcodeinject \
heritage prefersplit rangeutil ruleaction subflow blockaction merge double \
coreaction condexe override dynamic crc32 prettyprint \
transform coreaction condexe override dynamic crc32 prettyprint \
printlanguage printc printjava memstate opbehavior paramid $(COREEXT_NAMES)
# Files used for any project that use the sleigh decoder
SLEIGH= sleigh pcodeparse pcodecompile sleighbase slghsymbol \

View file

@ -220,6 +220,42 @@ AddrSpace *Architecture::getSpaceBySpacebase(const Address &loc,int4 size) const
return (AddrSpace *)0;
}
/// Look-up the laned register record associated with a specific storage location. Currently, the
/// record is only associated with the \e size of the storage, not its address. If there is no
/// associated record, null is returned.
/// \param loc is the starting address of the storage location
/// \param size is the size of the storage in bytes
/// \return the matching LanedRegister record or null
const LanedRegister *Architecture::getLanedRegister(const Address &loc,int4 size) const
{
int4 min = 0;
int4 max = lanerecords.size() - 1;
while(min <= max) {
int4 mid = (min + max) / 2;
int4 sz = lanerecords[mid].getWholeSize();
if (sz < size)
min = mid + 1;
else if (size < sz)
max = mid - 1;
else
return &lanerecords[mid];
}
return (const LanedRegister *)0;
}
/// Return a size intended for comparison with a Varnode size to immediately determine if
/// the Varnode is a potential laned register. If there are no laned registers for the architecture,
/// -1 is returned.
/// \return the size in bytes of the smallest laned register or -1.
int4 Architecture::getMinimumLanedRegisterSize(void) const
{
if (lanerecords.empty())
return -1;
return lanerecords[0].getWholeSize();
}
/// The default model is used whenever an explicit model is not known
/// or can't be determined.
/// \param nm is the name of the model to set
@ -811,6 +847,32 @@ void Architecture::parseIncidentalCopy(const Element *el)
}
}
/// Look for \<register> tags that have a \e vector_lane_size attribute.
/// Record these so that the decompiler can split large registers into appropriate lane size pieces.
/// \param el is the XML element
void Architecture::parseLaneSizes(const Element *el)
{
vector<uint4> maskList;
const List &childList(el->getChildren());
List::const_iterator iter;
LanedRegister lanedRegister; // Only allocate once
for(iter=childList.begin();iter!=childList.end();++iter) {
if (lanedRegister.restoreXml(*iter, this)) {
int4 sizeIndex = lanedRegister.getWholeSize();
while (maskList.size() <= sizeIndex)
maskList.push_back(0);
maskList[sizeIndex] |= lanedRegister.getSizeBitMask();
}
}
lanerecords.clear();
for(int4 i=0;i<maskList.size();++i) {
if (maskList[i] == 0) continue;
lanerecords.push_back(LanedRegister(i,maskList[i]));
}
}
/// Create a stack space and a stack-pointer register from this \<stackpointer> element
/// \param el is the XML element
void Architecture::parseStackPointer(const Element *el)
@ -976,6 +1038,7 @@ void Architecture::parseProcessorConfig(DocumentStorage &store)
else if (elname == "segmentop")
userops.parseSegmentOp(*iter,this);
else if (elname == "register_data") {
parseLaneSizes(*iter);
}
else if (elname == "segmented_address") {
}

View file

@ -30,6 +30,7 @@
#include "comment.hh"
#include "userop.hh"
#include "options.hh"
#include "transform.hh"
#include "prefersplit.hh"
#ifdef CPUI_STATISTICS
@ -151,6 +152,7 @@ public:
vector<TypeOp *> inst; ///< Registered p-code instructions
UserOpManage userops; ///< Specifically registered user-defined p-code ops
vector<PreferSplitRecord> splitrecords; ///< registers that we would prefer to see split for this processor
vector<LanedRegister> lanerecords; ///< Vector registers that have preferred lane sizes
ActionDatabase allacts; ///< Actions that can be applied in this architecture
bool loadersymbols_parsed; ///< True if loader symbols have been read
#ifdef CPUI_STATISTICS
@ -165,6 +167,8 @@ public:
bool hasModel(const string &nm) const; ///< Does this Architecture have a specific PrototypeModel
bool highPtrPossible(const Address &loc,int4 size) const; ///< Are pointers possible to the given location?
AddrSpace *getSpaceBySpacebase(const Address &loc,int4 size) const; ///< Get space associated with a \e spacebase register
const LanedRegister *getLanedRegister(const Address &loc,int4 size) const; ///< Get LanedRegister associated with storage
int4 getMinimumLanedRegisterSize(void) const; ///< Get the minimum size of a laned register in bytes
void setDefaultModel(const string &nm); ///< Set the default PrototypeModel
void clearAnalysis(Funcdata *fd); ///< Clear analysis specific to a function
void readLoaderSymbols(void); ///< Read any symbols from loader into database
@ -255,11 +259,12 @@ protected:
void parseProtoEval(const Element *el); ///< Apply prototype evaluation configuration
void parseDefaultProto(const Element *el); ///< Apply default prototype model configuration
void parseGlobal(const Element *el); ///< Apply global space configuration
void addOtherSpace(void); ////add OTHER space and all of its overlays to the symboltab
void addOtherSpace(void); ///< Add OTHER space and all of its overlays to the symboltab
void parseReadOnly(const Element *el); ///< Apply read-only region configuration
void parseVolatile(const Element *el); ///< Apply volatile region configuration
void parseReturnAddress(const Element *el); ///< Apply return address configuration
void parseIncidentalCopy(const Element *el); ///< Apply incidental copy configuration
void parseLaneSizes(const Element *el); ///< Apply lane size configuration
void parseStackPointer(const Element *el); ///< Apply stack pointer configuration
void parseDeadcodeDelay(const Element *el); ///< Apply dead-code delay configuration
void parseFuncPtrAlign(const Element *el); ///< Apply function pointer alignment configuration

View file

@ -16,6 +16,7 @@
#include "coreaction.hh"
#include "condexe.hh"
#include "double.hh"
#include "subflow.hh"
/// \brief A stack equation
struct StackEqn {
@ -494,6 +495,121 @@ int4 ActionStackPtrFlow::apply(Funcdata &data)
return 0;
}
/// \brief Examine the PcodeOps using the given Varnode to determine possible lane sizes
///
/// Run through the defining op and any descendant ops of the given Varnode, looking for
/// CPUI_PIECE and CPUI_SUBPIECE. Use these to determine possible lane sizes and
/// register them with the given LanedRegister object.
/// \param vn is the given Varnode
/// \param allowedLanes is used to determine if a putative lane size is allowed
/// \param checkLanes collects the possible lane sizes
void ActionLaneDivide::collectLaneSizes(Varnode *vn,const LanedRegister &allowedLanes,LanedRegister &checkLanes)
{
list<PcodeOp *>::const_iterator iter = vn->beginDescend();
int4 step = 0; // 0 = descendants, 1 = def, 2 = done
if (iter == vn->endDescend()) {
step = 1;
}
while(step < 2) {
int4 curSize; // Putative lane size
if (step == 0) {
PcodeOp *op = *iter;
++iter;
if (iter == vn->endDescend())
step = 1;
if (op->code() != CPUI_SUBPIECE) continue; // Is the big register split into pieces
curSize = op->getOut()->getSize();
}
else {
step = 2;
if (!vn->isWritten()) continue;
PcodeOp *op = vn->getDef();
if (op->code() != CPUI_PIECE) continue; // Is the big register formed from smaller pieces
curSize = op->getIn(0)->getSize();
int4 tmpSize = op->getIn(1)->getSize();
if (tmpSize < curSize)
curSize = tmpSize;
}
if (allowedLanes.allowedLane(curSize))
checkLanes.addLaneSize(curSize); // Register this possible size
}
}
/// \brief Search for a likely lane size and try to divide a single Varnode into these lanes
///
/// There are different ways to search for a lane size:
///
/// Mode 0: Collect putative lane sizes based on the local ops using the Varnode. Attempt
/// to divide based on each of those lane sizes in turn.
///
/// Mode 1: Similar to mode 0, except we allow for SUBPIECE operations that truncate to
/// variables that are smaller than the lane size.
///
/// Mode 2: Attempt to divide based on a default lane size.
/// \param data is the function being transformed
/// \param vn is the given single Varnode
/// \param lanedRegister is acceptable set of lane sizes for the Varnode
/// \param mode is the lane size search mode (0, 1, or 2)
/// \return \b true if the Varnode (and its data-flow) was successfully split
bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,int4 mode)
{
LanedRegister checkLanes; // Lanes we are going to try, initialized to no lanes
bool allowDowncast = (mode > 0);
if (mode < 2)
collectLaneSizes(vn,lanedRegister,checkLanes);
else {
checkLanes.addLaneSize(4); // Default lane size
}
LanedRegister::const_iterator enditer = checkLanes.end();
for(LanedRegister::const_iterator iter=checkLanes.begin();iter!=enditer;++iter) {
int4 curSize = *iter;
LaneDescription description(lanedRegister.getWholeSize(),curSize); // Lane scheme dictated by curSize
LaneDivide laneDivide(&data,vn,description,allowDowncast);
if (laneDivide.doTrace()) {
laneDivide.apply();
count += 1; // Indicate a change was made
return true;
}
}
return false;
}
int4 ActionLaneDivide::apply(Funcdata &data)
{
map<VarnodeData,const LanedRegister *>::const_iterator iter;
for(int4 mode=0;mode<3;++mode) {
bool allStorageProcessed = true;
for(iter=data.beginLaneAccess();iter!=data.endLaneAccess();++iter) {
const LanedRegister *lanedReg = (*iter).second;
Address addr = (*iter).first.getAddr();
int4 sz = (*iter).first.size;
VarnodeLocSet::const_iterator viter = data.beginLoc(sz,addr);
VarnodeLocSet::const_iterator venditer = data.endLoc(sz,addr);
bool allVarnodesProcessed = true;
while(viter != venditer) {
Varnode *vn = *viter;
if (processVarnode(data, vn, *lanedReg, mode)) {
viter = data.beginLoc(sz,addr);
venditer = data.endLoc(sz, addr); // Recalculate bounds
allVarnodesProcessed = true;
}
else {
++viter;
allVarnodesProcessed = false;
}
}
if (!allVarnodesProcessed)
allStorageProcessed = false;
}
if (allStorageProcessed) break;
}
data.clearLanedAccessMap();
return 0;
}
int4 ActionSegmentize::apply(Funcdata &data)
{
@ -820,12 +936,16 @@ int4 ActionShadowVar::apply(Funcdata &data)
/// \brief Determine if given Varnode might be a pointer constant.
///
/// If it is a pointer, return the symbol it points to, or NULL otherwise.
/// If it is a pointer, return the symbol it points to, or NULL otherwise. If it is determined
/// that the Varnode is a pointer to a specific symbol, the encoding of the full pointer is passed back.
/// Usually this is just the constant value of the Varnode, but in this case of partial pointers
/// (like \e near pointers) the full pointer may contain additional information.
/// \param spc is the address space being pointed to
/// \param vn is the given Varnode
/// \param op is the lone descendant of the Varnode
/// \param slot is the slot index of the Varnode
/// \param rampoint will hold the Address of the resolved symbol
/// \param fullEncoding will hold the full pointer encoding being passed back
/// \param data is the function being analyzed
/// \return the recovered symbol or NULL
SymbolEntry *ActionConstantPtr::isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op,int4 slot,
@ -1025,14 +1145,30 @@ int4 ActionDeindirect::apply(Funcdata &data)
return 0;
}
/// Check if the given Varnode has a matching LanedRegister record. If so, add its
/// storage location to the given function's laned access list.
/// \param data is the given function
/// \param vn is the given Varnode
void ActionVarnodeProps::markLanedVarnode(Funcdata &data,Varnode *vn)
{
if (vn->isConstant()) return;
Architecture *glb = data.getArch();
const LanedRegister *lanedRegister = glb->getLanedRegister(vn->getAddr(),vn->getSize());
if (lanedRegister != (const LanedRegister *)0)
data.markLanedVarnode(vn,lanedRegister);
}
int4 ActionVarnodeProps::apply(Funcdata &data)
{
Architecture *glb = data.getArch();
bool cachereadonly = glb->readonlypropagate;
if (glb->userops.getVolatileRead() == (VolatileReadOp *)0) {
if (!cachereadonly)
return 0; // Nothing to do to special properties
int4 minLanedSize = 1000000; // Default size meant to filter no Varnodes
if (!data.isLanedRegComplete()) {
int4 sz = glb->getMinimumLanedRegisterSize();
if (sz > 0)
minLanedSize = sz;
}
VarnodeLocSet::const_iterator iter;
Varnode *vn;
@ -1041,6 +1177,9 @@ int4 ActionVarnodeProps::apply(Funcdata &data)
while(iter != data.endLoc()) {
vn = *iter++; // Advance iterator in case vn is deleted
if (vn->isAnnotation()) continue;
int4 vnSize = vn->getSize();
if (vnSize >= minLanedSize)
markLanedVarnode(data, vn);
if (vn->hasActionProperty()) {
if (cachereadonly&&vn->isReadOnly()) {
if (data.fillinReadOnly(vn)) // Try to replace vn with its lookup in LoadImage
@ -1050,7 +1189,7 @@ int4 ActionVarnodeProps::apply(Funcdata &data)
if (data.replaceVolatile(vn))
count += 1; // Try to replace vn with pcode op
}
else if (((vn->getNZMask() & vn->getConsume())==0)&&(vn->getSize()<=sizeof(uintb))) {
else if (((vn->getNZMask() & vn->getConsume())==0)&&(vnSize<=sizeof(uintb))) {
// FIXME: uintb should be arbitrary precision
if (vn->isConstant()) continue; // Don't replace a constant
if (vn->isWritten()) {
@ -1070,6 +1209,7 @@ int4 ActionVarnodeProps::apply(Funcdata &data)
}
}
}
data.setLanedRegGenerated();
return 0;
}
@ -1860,8 +2000,11 @@ int4 ActionLikelyTrash::apply(Funcdata &data)
for(uint4 i=0;i<indlist.size();++i) {
PcodeOp *op = indlist[i];
if (op->code() == CPUI_INDIRECT)
data.truncateIndirect(indlist[i]);
if (op->code() == CPUI_INDIRECT) {
// Trucate data-flow through INDIRECT, turning it into indirect creation
data.opSetInput(op,data.newConstant(op->getOut()->getSize(), 0),0);
data.markIndirectCreation(op,false);
}
else if (op->code() == CPUI_INT_AND) {
data.opSetInput(op,data.newConstant(op->getIn(1)->getSize(),0),1);
}
@ -4628,6 +4771,7 @@ void universal_action(Architecture *conf)
conf->extra_pool_rules.clear(); // Rules are now absorbed into universal
}
actstackstall->addAction( actprop );
actstackstall->addAction( new ActionLaneDivide("base") );
actstackstall->addAction( new ActionMultiCse("analysis") );
actstackstall->addAction( new ActionShadowVar("analysis") );
actstackstall->addAction( new ActionDeindirect("deindirect") );

View file

@ -97,6 +97,24 @@ public:
virtual int4 apply(Funcdata &data);
};
/// \brief Find Varnodes with a vectorized lane scheme and attempt to split the lanes
///
/// The Architecture lists (vector) registers that may be used to perform parallelized operations
/// on \b lanes within the register. This action looks for these registers as Varnodes, determines
/// if a particular lane scheme makes sense in terms of the function's data-flow, and then
/// rewrites the data-flow so that the lanes become explicit Varnodes.
class ActionLaneDivide : public Action {
void collectLaneSizes(Varnode *vn,const LanedRegister &allowedLanes,LanedRegister &checkLanes);
bool processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,int4 mode);
public:
ActionLaneDivide(const string &g) : Action(rule_onceperfunc,"lanedivide",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionLaneDivide(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Make sure pointers into segmented spaces have the correct form.
///
/// Convert user-defined ops defined as segment p-code ops by a cspec tag into the internal CPUI_SEGMENTOP
@ -185,8 +203,15 @@ public:
virtual int4 apply(Funcdata &data);
};
/// \brief Transform read-only variables to constants
/// \brief Transform based on Varnode properties, such as \e read-only and \e volatile
///
/// This performs various transforms that are based on Varnode properties.
/// - Read-only Varnodes are converted to the underlying constant
/// - Volatile Varnodes are converted read/write functions
/// - Varnodes whose values are not consumed are replaced with constant 0 Varnodes
/// - Large Varnodes are flagged for lane analysis
class ActionVarnodeProps : public Action {
void markLanedVarnode(Funcdata &data,Varnode *vn); ///< Mark possible laned register storage
public:
ActionVarnodeProps(const string &g) : Action(0,"varnodeprops",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {

View file

@ -56,7 +56,8 @@ class Funcdata {
restart_pending = 0x200, ///< Analysis must be restarted (because of new override info)
unimplemented_present = 0x400, ///< Set if function contains unimplemented instructions
baddata_present = 0x800, ///< Set if function flowed into bad data
double_precis_on = 0x1000 ///< Set if we are performing double precision recovery
double_precis_on = 0x1000, ///< Set if we are performing double precision recovery
big_varnodes_generated = 0x2000 ///< Set when search for laned registers is complete
};
uint4 flags; ///< Boolean properties associated with \b this function
uint4 clean_up_index; ///< Creation index of first Varnode created after start of cleanup
@ -80,6 +81,7 @@ class Funcdata {
Merge covermerge; ///< Variable range intersection algorithms
ParamActive *activeoutput; ///< Data for assessing which parameters are passed to \b this function
Override localoverride; ///< Overrides of data-flow, prototypes, etc. that are local to \b this function
map<VarnodeData,const LanedRegister *> lanedMap; ///< Current storage locations which may be laned registers
// Low level Varnode functions
void setVarnodeProperties(Varnode *vn) const; ///< Look-up boolean properties and data-type information
@ -130,6 +132,8 @@ public:
bool isTypeRecoveryOn(void) const { return ((flags&typerecovery_on)!=0); } ///< Has data-type recovery processes started
bool hasNoCode(void) const { return ((flags & no_code)!=0); } ///< Return \b true if \b this function has no code body
void setNoCode(bool val) { if (val) flags |= no_code; else flags &= ~no_code; } ///< Toggle whether \b this has a body
bool isLanedRegComplete(void) const { return ((flags&big_varnodes_generated)!=0); } ///< Have potential laned registers been generated
void setLanedRegGenerated(void) { flags |= big_varnodes_generated; } ///< Mark that laned registers have been collected
/// \brief Toggle whether \b this is being used for jump-table recovery
///
@ -346,13 +350,18 @@ public:
/// \brief End of (input or free) Varnodes at a given storage address
VarnodeDefSet::const_iterator endDef(uint4 fl,const Address &addr) const { return vbank.endDef(fl,addr); }
void markLanedVarnode(Varnode *vn,const LanedRegister *lanedReg); ///< Mark Varnode as potential laned register
map<VarnodeData,const LanedRegister *>::const_iterator beginLaneAccess(void) const { return lanedMap.begin(); } ///< Beginning iterator over laned accesses
map<VarnodeData,const LanedRegister *>::const_iterator endLaneAccess(void) const { return lanedMap.end(); } ///< Ending iterator over laned accesses
void clearLanedAccessMap(void) { lanedMap.clear(); } ///< Clear records from the laned access list
HighVariable *findHigh(const string &name) const; ///< Find a high-level variable by name
void mapGlobals(void); ///< Make sure there is a Symbol entry for all global Varnodes
bool checkCallDoubleUse(const PcodeOp *opmatch,const PcodeOp *op,const Varnode *vn,const ParamTrial &trial) const;
bool onlyOpUse(const Varnode *invn,const PcodeOp *opmatch,const ParamTrial &trial) const;
bool ancestorOpUse(int4 maxlevel,const Varnode *invn,const PcodeOp *op,ParamTrial &trial) const;
bool syncVarnodesWithSymbols(const ScopeLocal *lm,bool typesyes);
void splitVarnode(Varnode *vn,int4 lowsize,Varnode *&vnlo,Varnode *& vnhi);
void transferVarnodeProperties(Varnode *vn,Varnode *newVn,int4 lsbOffset);
bool fillinReadOnly(Varnode *vn); ///< Replace the given Varnode with its (constant) value in the load image
bool replaceVolatile(Varnode *vn); ///< Replace accesses of the given Varnode with \e volatile operations
void markIndirectOnly(void); ///< Mark \e illegal \e input Varnodes used only in INDIRECTs
@ -385,9 +394,8 @@ public:
PcodeOp *cloneOp(const PcodeOp *op,const SeqNum &seq); /// Clone a PcodeOp into \b this function
PcodeOp *canonicalReturnOp(void) const; /// Find a representative CPUI_RETURN op for \b this function
PcodeOp *newIndirectOp(PcodeOp *indeffect,const Address &addr,int4 size,uint4 extraFlags);
void setIndirectCreation(PcodeOp *op,PcodeOp *indeffect,Varnode *outvn,bool possibleout);
PcodeOp *newIndirectCreation(PcodeOp *indeffect,const Address &addr,int4 size,bool possibleout);
void truncateIndirect(PcodeOp *indop); ///< Convert CPUI_INDIRECT into an \e indirect \e creation
void markIndirectCreation(PcodeOp *indop,bool possibleOutput); ///< Convert CPUI_INDIRECT into an \e indirect \e creation
PcodeOp *findOp(const SeqNum &sq) { return obank.findOp(sq); } ///< Find PcodeOp with given sequence number
void opInsertBefore(PcodeOp *op,PcodeOp *follow); ///< Insert given PcodeOp before a specific op
void opInsertAfter(PcodeOp *op,PcodeOp *prev); ///< Insert given PcodeOp after a specific op

View file

@ -663,31 +663,6 @@ PcodeOp *Funcdata::newIndirectOp(PcodeOp *indeffect,const Address &addr,int4 siz
return newop;
}
/// \brief Turn given PcodeOp into a CPUI_INDIRECT that \e indirectly \e creates a Varnode
///
/// An \e indirectly \e created Varnode effectively has no data-flow before the INDIRECT op
/// that defines it, and the value contained by the Varnode is not explicitly calculable.
/// \param op is the given PcodeOp to convert to a CPUI_INDIRECT
/// \param indeffect is the p-code causing the indirect effect
/// \param outvn is the (preexisting) Varnode that will be marked as \e created by the INDIRECT
/// \param possibleout is \b true if the output should be treated as a \e directwrite.
void Funcdata::setIndirectCreation(PcodeOp *op,PcodeOp *indeffect,Varnode *outvn,bool possibleout)
{
Varnode *newin;
newin = newConstant(outvn->getSize(),0);
op->flags |= PcodeOp::indirect_creation;
opSetOutput(op,outvn);
if (!possibleout)
newin->flags |= Varnode::indirect_creation;
outvn->flags |= Varnode::indirect_creation;
opSetOpcode(op,CPUI_INDIRECT);
opSetInput(op,newin,0);
opSetInput(op,newVarnodeIop(indeffect),1);
opInsertBefore(op,indeffect);
}
/// \brief Build a CPUI_INDIRECT op that \e indirectly \e creates a Varnode
///
/// An \e indirectly \e created Varnode effectively has no data-flow before the INDIRECT op
@ -718,22 +693,24 @@ PcodeOp *Funcdata::newIndirectCreation(PcodeOp *indeffect,const Address &addr,in
return newop;
}
/// Data-flow through the given CPUI_INDIRECT op is truncated causing the output Varnode
/// to be \e indirectly \e created.
/// Data-flow through the given CPUI_INDIRECT op is marked so that the output Varnode
/// is considered \e indirectly \e created.
/// An \e indirectly \e created Varnode effectively has no data-flow before the INDIRECT op
/// that defines it, and the value contained by the Varnode is not explicitly calculable.
/// \param indop is the given CPUI_INDIRECT op
void Funcdata::truncateIndirect(PcodeOp *indop)
/// \param possibleOutput is \b true if INDIRECT should be marked as a possible call output
void Funcdata::markIndirectCreation(PcodeOp *indop,bool possibleOutput)
{
Varnode *outvn = indop->getOut();
Varnode *newin = newConstant(outvn->getSize(),0);
Varnode *in0 = indop->getIn(0);
indop->flags |= PcodeOp::indirect_creation;
newin->flags |= Varnode::indirect_creation;
if (!in0->isConstant())
throw LowlevelError("Indirect creation not properly formed");
if (!possibleOutput)
in0->flags |= Varnode::indirect_creation;
outvn->flags |= Varnode::indirect_creation;
opSetInput(indop,newin,0);
}
/// \brief Generate raw p-code for the function

View file

@ -286,6 +286,21 @@ void Funcdata::destroyVarnode(Varnode *vn)
vbank.destroy(vn);
}
/// Record the given Varnode as a potential laned register access.
/// The address and size of the Varnode is recorded, anticipating that new
/// Varnodes at the same storage location may be created
/// \param vn is the given Varnode to mark
/// \param lanedReg is the laned register record to associate with the Varnode
void Funcdata::markLanedVarnode(Varnode *vn,const LanedRegister *lanedReg)
{
VarnodeData storage;
storage.space = vn->getSpace();
storage.offset = vn->getOffset();
storage.size = vn->getSize();
lanedMap[storage] = lanedReg;
}
/// Look up the Symbol visible in \b this function's Scope and return the HighVariable
/// associated with it. If the Symbol doesn't exist or there is no Varnode holding at least
/// part of the value of the Symbol, NULL is returned.
@ -479,34 +494,22 @@ void Funcdata::setHighLevel(void)
assignHigh(*iter);
}
/// \brief Create two new Varnodes which split the given Varnode
/// \brief Copy properties from an existing Varnode to a new Varnode
///
/// Attributes are copied from the original into the split pieces if appropriate
/// \param vn is the given Varnode
/// \param lowsize is the desired size in bytes of the least significant portion
/// \param vnlo will hold the least significant portion
/// \param vnhi will hold the most significant portion
void Funcdata::splitVarnode(Varnode *vn,int4 lowsize,Varnode *& vnlo,Varnode *& vnhi)
/// The new Varnode is assumed to overlap the storage of the existing Varnode.
/// Properties like boolean flags and \e consume bits are copied as appropriate.
/// \param vn is the existing Varnode
/// \param newVn is the new Varnode that has its properties set
/// \param lsbOffset is the significance offset of the new Varnode within the exising
void Funcdata::transferVarnodeProperties(Varnode *vn,Varnode *newVn,int4 lsbOffset)
{
int4 highsize = vn->getSize() - lowsize;
Address addrhi = vn->getAddr();
Address addrlo = addrhi;
uintb consumehi = vn->getConsume() >> 8*lowsize;
uintb consumelo = vn->getConsume() & calc_mask(lowsize);
if (vn->getSpace()->isBigEndian())
addrlo = addrhi + highsize;
else
addrhi = addrhi + lowsize;
uintb newConsume = (vn->getConsume() >> 8*lsbOffset) & calc_mask(newVn->getSize());
uint4 vnflags = vn->getFlags() & (Varnode::directwrite|Varnode::addrforce|Varnode::auto_live);
vnhi = newVarnode(highsize,addrhi);
vnlo = newVarnode(lowsize,addrlo);
uint4 vnFlags = vn->getFlags() & (Varnode::directwrite|Varnode::addrforce|Varnode::auto_live);
vnhi->setFlags(vnflags); // Preserve addrforce setting
vnlo->setFlags(vnflags);
vnhi->setConsume(consumehi);
vnlo->setConsume(consumelo);
newVn->setFlags(vnFlags); // Preserve addrforce setting
newVn->setConsume(newConsume);
}
/// Treat the given Varnode as read-only, look up its value in LoadImage
@ -535,6 +538,9 @@ bool Funcdata::fillinReadOnly(Varnode *vn)
return false; // No change was made
}
if (vn->getSize() > sizeof(uintb))
return false; // Constant will exceed precision
uintb res;
uint1 bytes[32];
try {

View file

@ -92,7 +92,7 @@ class HeritageInfo {
bool warningissued; ///< \b true if warning issued previously
void set(AddrSpace *spc,int4 dl,int4 dcdl) {
space=spc; delay=dl; deadcodedelay=dcdl; deadremoved=0; warningissued=false; loadGuardSearch = false; } ///< Set all fields
bool isHeritaged(void) const { return (space != (AddrSpace *)0); }
bool isHeritaged(void) const { return (space != (AddrSpace *)0); } ///< Return \b true if heritage is performed on this space
void reset(void) {
deadremoved = 0; deadcodedelay = delay; warningissued = false; loadGuardSearch = false; } ///< Reset
};

View file

@ -42,3 +42,14 @@ void VarnodeData::restoreXml(const Element *el,const AddrSpaceManager *manage)
}
}
/// Return \b true, if \b this, as an address range, contains the other address range
/// \param op2 is the other VarnodeData to test for containment
/// \return \b true if \b this contains the other
bool VarnodeData::contains(const VarnodeData &op2) const
{
if (space != op2.space) return false;
if (op2.offset < offset) return false;
if ((offset + (size-1)) < (op2.offset + (op2.size-1))) return false;
return true;
}

View file

@ -43,6 +43,9 @@ struct VarnodeData {
/// Recover this object from an XML tag
void restoreXml(const Element *el,const AddrSpaceManager *manage);
/// Does \b this container another given VarnodeData
bool contains(const VarnodeData &op2) const;
};
/// VarnodeData can be sorted in terms of the space its in

View file

@ -263,7 +263,6 @@ void PrintLanguage::pushVnLHS(const Varnode *vn,const PcodeOp *op)
/// ending with the given operator token, needs to be surrounded by parentheses to convey
/// the proper meaning.
/// \param op2 is the input token to \b this operator
/// \param stage is the stage of \b this operator currently being printed
/// \return \b true if \b op2 (as input to \b this) should be parenthesized
bool PrintLanguage::parentheses(const OpToken *op2)

View file

@ -543,6 +543,7 @@ int4 RuleShiftBitops::applyOp(PcodeOp *op,Funcdata &data)
if (!constvn->isConstant()) return 0; // Must be a constant shift
Varnode *vn = op->getIn(0);
if (!vn->isWritten()) return 0;
if (vn->getSize() > sizeof(uintb)) return 0; // FIXME: Can't exceed uintb precision
int4 sa;
bool leftshift;
@ -3216,7 +3217,7 @@ int4 RuleSignShift::applyOp(PcodeOp *op,Funcdata &data)
return 1;
}
/// \class RuleSignShift
/// \class RuleTestSign
/// \brief Convert sign-bit test to signed comparison: `(V s>> 0x1f) != 0 => V s< 0`
void RuleTestSign::getOpList(vector<uint4> &oplist) const
@ -4972,6 +4973,7 @@ int4 RuleEmbed::applyOp(PcodeOp *op,Funcdata &data)
PcodeOp *subop;
int4 i;
if (op->getOut()->getSize() > sizeof(uintb)) return 0; // FIXME: Can't exceed uintb precision
for(i=0;i<2;++i) {
subout = op->getIn(i);
if (!subout->isWritten()) continue;
@ -5001,8 +5003,6 @@ int4 RuleEmbed::applyOp(PcodeOp *op,Funcdata &data)
}
}
// Be careful of precision limit when constructing mask
if (subout->getSize() + c > sizeof(uintb)) continue;
uintb mask = calc_mask(subout->getSize());
mask <<= 8*c;
@ -7334,7 +7334,7 @@ int4 RuleSplitFlow::applyOp(PcodeOp *op,Funcdata &data)
return 0;
SplitFlow splitFlow(&data,vn,loSize);
if (!splitFlow.doTrace()) return 0;
splitFlow.doReplacement();
splitFlow.apply();
return 1;
}
@ -7699,13 +7699,13 @@ int4 RuleSubfloatConvert::applyOp(PcodeOp *op,Funcdata &data)
if (outsize > insize) {
SubfloatFlow subflow(&data,outvn,insize);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
subflow.apply();
return 1;
}
else {
SubfloatFlow subflow(&data,invn,outsize);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
subflow.apply();
return 1;
}
return 0;

File diff suppressed because it is too large Load diff

View file

@ -109,130 +109,78 @@ class SubvariableFlow {
Varnode *getReplaceVarnode(ReplaceVarnode *rvn);
bool processNextWork(void); ///< Extend the subgraph from the next node in the worklist
public:
SubvariableFlow(Funcdata *f,Varnode *root,uintb mask,bool aggr,bool sext);
bool doTrace(void);
void doReplacement(void);
SubvariableFlow(Funcdata *f,Varnode *root,uintb mask,bool aggr,bool sext); ///< Constructor
bool doTrace(void); ///< Trace logical value through data-flow, constructing transform
void doReplacement(void); ///< Perform the discovered transform, making logical values explicit
};
// Class for splitting up varnodes that hold 2 logical variables
class SplitFlow {
class ReplaceVarnode {
friend class SplitFlow;
Varnode *vn; // Varnode being split
Varnode *replaceLo; // Replacement holding least significant part of original
Varnode *replaceHi; // Replacement holding most significant part
bool defTraversed; // Has the defining op been traversed
public:
ReplaceVarnode(void);
};
class ReplaceOp {
friend class SplitFlow;
PcodeOp *op; // Original op being split
OpCode opcode; // Replacement opcode
PcodeOp *loOp; // Replacement for least sig part
PcodeOp *hiOp; // Replacement for most sig part
int4 numParams;
bool doDelete; // Original operation should be deleted
bool isLogicalInput; // Op is putting a logical value into the whole, as opposed to pulling one out
ReplaceVarnode *output; // Output varnode(s) if needed
public:
ReplaceOp(bool isLogic,PcodeOp *o,OpCode opc,int4 num);
};
int4 concatSize; // Size of combined logicals
int4 loSize; // Size of logical piece in least sig part of combined
int4 hiSize; // Size of logical piece in most sig part of combined
Funcdata *fd;
map<Varnode *,ReplaceVarnode> varmap;
list<ReplaceOp> oplist;
vector<ReplaceVarnode *> worklist;
void assignReplaceOp(bool isLogicalInput,PcodeOp *op,OpCode opc,int4 numParam,ReplaceVarnode *outrvn);
void assignLogicalPieces(ReplaceVarnode *rvn);
void buildReplaceOutputs(ReplaceOp *rop);
void replacePiece(ReplaceOp *rop);
void replaceZext(ReplaceOp *rop);
void replaceLeftInput(ReplaceOp *rop);
void replaceLeftTerminal(ReplaceOp *rop);
void replaceOp(ReplaceOp *rop);
ReplaceVarnode *setReplacement(Varnode *vn,bool &inworklist);
bool addOpOutput(PcodeOp *op);
bool addOpInputs(PcodeOp *op,ReplaceVarnode *outrvn,int4 numParam);
bool traceForward(ReplaceVarnode *rvn);
bool traceBackward(ReplaceVarnode *rvn);
bool processNextWork(void);
/// \brief Class for splitting up Varnodes that hold 2 logical variables
///
/// Starting from a \e root Varnode provided to the constructor, \b this class looks for data-flow
/// that consistently holds 2 logical values in a single Varnode. If doTrace() returns \b true,
/// a consistent view has been created and invoking apply() will split all Varnodes and PcodeOps
/// involved in the data-flow into their logical pieces.
class SplitFlow : public TransformManager {
LaneDescription laneDescription; ///< Description of how to split Varnodes
vector<TransformVar *> worklist; ///< Pending work list of Varnodes to push the split through
TransformVar *setReplacement(Varnode *vn);
bool addOp(PcodeOp *op,TransformVar *rvn,int4 slot);
bool traceForward(TransformVar *rvn);
bool traceBackward(TransformVar *rvn);
bool processNextWork(void); ///< Process the next logical value on the worklist
public:
SplitFlow(Funcdata *f,Varnode *root,int4 lowSize);
void doReplacement(void);
bool doTrace(void);
SplitFlow(Funcdata *f,Varnode *root,int4 lowSize); ///< Constructor
bool doTrace(void); ///< Trace split through data-flow, constructing transform
};
// Structures for tracing floating point variables if they are
// stored at points in a higher precision encoding. This is nearly identical
// in spirit to the SubvariableFlow class, but it performs on floating point
// variables contained in higher precision storage, rather than integers stored
// as a subfield of a bigger integer
// This the floating point version of SubvariablFlow, it follows the flow of a logical lower
// precision value stored in higher precision locations
class SubfloatFlow {
class ReplaceOp;
class ReplaceVarnode {
friend class SubfloatFlow;
Varnode *vn; // Varnode being split
Varnode *replacement; // The new subvariable varnode
ReplaceOp *def; // Defining op for new varnode
};
class ReplaceOp {
friend class SubfloatFlow;
PcodeOp *op; // op getting paralleled
PcodeOp *replacement; // The new op
OpCode opc; // type of new op
int4 numparams;
ReplaceVarnode *output; // varnode output
vector<ReplaceVarnode *> input; // varnode inputs
};
class PulloutRecord { // Node where logical variable is getting pulled out into a real varnode
friend class SubfloatFlow;
OpCode opc; // (possibly) new opcode
PcodeOp *pullop; // Op producing the real output
ReplaceVarnode *input; // The logical variable input
};
class CompareRecord {
friend class SubfloatFlow;
ReplaceVarnode *in1;
ReplaceVarnode *in2;
PcodeOp *compop;
};
int4 precision; // Number of bytes of precision in the logical flow
Funcdata *fd;
const FloatFormat *format;
map<Varnode *,ReplaceVarnode> varmap;
list<ReplaceVarnode> newvarlist;
list<ReplaceOp> oplist;
list<PulloutRecord> pulllist;
list<CompareRecord> complist;
vector<ReplaceVarnode *> worklist;
ReplaceVarnode *setReplacement(Varnode *vn,bool &inworklist);
ReplaceVarnode *setReplacementNoFlow(Varnode *vn);
ReplaceOp *createOp(OpCode opc,int4 numparam,ReplaceVarnode *outrvn);
ReplaceOp *createOpDown(OpCode opc,int4 numparam,PcodeOp *op,ReplaceVarnode *inrvn,int4 slot);
bool traceForward(ReplaceVarnode *rvn);
bool traceBackward(ReplaceVarnode *rvn);
bool createLink(ReplaceOp *rop,int4 slot,Varnode *vn);
void addtopulllist(PcodeOp *pullop,ReplaceVarnode *rvn);
bool addtopushlist(PcodeOp *pushop,ReplaceVarnode *rvn);
void addtocomplist(ReplaceVarnode *in1,ReplaceVarnode *in2,PcodeOp *op);
ReplaceVarnode *addConstant(Varnode *vn);
void replaceInput(ReplaceVarnode *rvn);
Varnode *getReplaceVarnode(ReplaceVarnode *rvn);
/// \brief Class for tracing changes of precision in floating point variables
///
/// It follows the flow of a logical lower precision value stored in higher precision locations
/// and then rewrites the data-flow in terms of the lower precision, eliminating the
/// precision conversions.
class SubfloatFlow : public TransformManager {
int4 precision; ///< Number of bytes of precision in the logical flow
int4 terminatorCount; ///< Number of terminating nodes reachable via the root
const FloatFormat *format; ///< The floating-point format of the logical value
vector<TransformVar *> worklist; ///< Current list of placeholders that still need to be traced
TransformVar *setReplacement(Varnode *vn);
bool traceForward(TransformVar *rvn);
bool traceBackward(TransformVar *rvn);
bool processNextWork(void);
public:
SubfloatFlow(Funcdata *f,Varnode *root,int4 prec);
bool doTrace(void);
void doReplacement(void);
virtual bool preserveAddress(Varnode *vn,int4 bitSize,int4 lsbOffset) const;
bool doTrace(void); ///< Trace logical value as far as possible
};
class LaneDivide : public TransformManager {
/// \brief Description of a large Varnode that needs to be traced (in the worklist)
class WorkNode {
friend class LaneDivide;
Varnode *vn; ///< The underlying Varnode with lanes
TransformVar *lanes; ///< Lane placeholders for underyling Varnode
int4 numLanes; ///< Number of lanes in the particular Varnode
int4 skipLanes; ///< Number of lanes to skip in the global description
};
LaneDescription description; ///< Global description of lanes that need to be split
vector<WorkNode> workList; ///< List of Varnodes still left to trace
bool allowSubpieceTerminator; ///< \b true if we allow lanes to be cast (via SUBPIECE) to a smaller integer size
TransformVar *setReplacement(Varnode *vn,int4 numLanes,int4 skipLanes);
void buildUnaryOp(OpCode opc,PcodeOp *op,TransformVar *inVars,TransformVar *outVars,int4 numLanes);
void buildBinaryOp(OpCode opc,PcodeOp *op,TransformVar *in0Vars,TransformVar *in1Vars,TransformVar *outVars,int4 numLanes);
bool buildPiece(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes);
bool buildMultiequal(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes);
bool buildStore(PcodeOp *op,int4 numLanes,int4 skipLanes);
bool buildLoad(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes);
bool buildRightShift(PcodeOp *op,TransformVar *outVars,int4 numLanes,int4 skipLanes);
bool traceForward(TransformVar *rvn,int4 numLanes,int4 skipLanes);
bool traceBackward(TransformVar *rvn,int4 numLanes,int4 skipLanes);
bool processNextWork(void); ///< Process the next Varnode on the work list
public:
LaneDivide(Funcdata *f,Varnode *root,const LaneDescription &desc,bool allowDowncast); ///< Constructor
bool doTrace(void); ///< Trace lanes as far as possible from the root Varnode
};
#endif

View file

@ -0,0 +1,746 @@
/* ###
* 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.
*/
#include "transform.hh"
#include "funcdata.hh"
/// \param op2 is the lane description to copy from
LaneDescription::LaneDescription(const LaneDescription &op2)
{
wholeSize = op2.wholeSize;
laneSize = op2.laneSize;
lanePosition = op2.lanePosition;
}
/// Create lanes that are all the same size
/// \param origSize is the size of the whole in bytes
/// \param sz is the size of a lane in bytes
LaneDescription::LaneDescription(int4 origSize,int4 sz)
{
wholeSize = origSize;
int4 numLanes = origSize / sz;
laneSize.resize(numLanes);
lanePosition.resize(numLanes);
int4 pos = 0;
for(int4 i=0;i<numLanes;++i) {
laneSize[i] = sz;
lanePosition[i] = pos;
pos += sz;
}
}
/// \param origSize is the size of the whole in bytes
/// \param lo is the size of the least significant lane in bytes
/// \param hi is the size of the most significant lane in bytes
LaneDescription::LaneDescription(int4 origSize,int4 lo,int4 hi)
{
wholeSize = origSize;
laneSize.resize(2);
lanePosition.resize(2);
laneSize[0] = lo;
laneSize[1] = hi;
lanePosition[0] = 0;
lanePosition[1] = lo;
}
/// Given a subrange, specified as an offset into the whole and size,
/// throw out any lanes in \b this that aren't in the subrange, so that the
/// size of whole is the size of the subrange. If the subrange intersects partially
/// with any of the lanes, return \b false.
/// \param lsbOffset is the number of bytes to remove from the front of the description
/// \param size is the number of bytes in the subrange
/// \return \b true if \b this was successfully transformed to the subrange
bool LaneDescription::subset(int4 lsbOffset,int4 size)
{
if (lsbOffset == 0 && size == wholeSize)
return true; // subrange is the whole range
int4 firstLane = getBoundary(lsbOffset);
if (firstLane < 0) return false;
int4 lastLane = getBoundary(lsbOffset + size);
if (lastLane < 0) return false;
vector<int4> newLaneSize;
lanePosition.clear();
int4 newPosition = 0;
for(int4 i=firstLane;i<lastLane;++i) {
int4 sz = laneSize[i];
lanePosition.push_back(newPosition);
newLaneSize.push_back(sz);
newPosition += sz;
}
wholeSize = size;
laneSize = newLaneSize;
return true;
}
/// Position 0 will map to index 0 and a position equal to whole size will
/// map to the number of lanes. Positions that are out of bounds or that do
/// not fall on a lane boundary will return -1.
/// \param bytePos is the given byte position to test
/// \return the index of the lane that start at the given position
int4 LaneDescription::getBoundary(int4 bytePos) const
{
if (bytePos < 0 || bytePos > wholeSize)
return -1;
if (bytePos == wholeSize)
return lanePosition.size();
int4 min = 0;
int4 max = lanePosition.size() - 1;
while(min <= max) {
int4 index = (min + max) / 2;
int4 pos = lanePosition[index];
if (pos == bytePos) return index;
if (pos < bytePos)
min = index + 1;
else
max = index - 1;
}
return -1;
}
/// \brief Decide if a given truncation is natural for \b this description
///
/// A subset of lanes are specified and a truncation (given by a byte position and byte size).
/// If the truncation, relative to the subset, contains at least 1 lane and does not split any
/// lanes, then return \b true and pass back the number of lanes and starting lane of the truncation.
/// \param numLanes is the number of lanes in the original subset
/// \param skipLanes is the starting (least significant) lane index of the original subset
/// \param bytePos is the number of bytes to truncate from the front (least significant portion) of the subset
/// \param size is the number of bytes to include in the truncation
/// \param resNumLanes will hold the number of lanes in the truncation
/// \param resSkipLanes will hold the starting lane in the truncation
/// \return \b true if the truncation is natural
bool LaneDescription::restriction(int4 numLanes,int4 skipLanes,int4 bytePos,int4 size,
int4 &resNumLanes,int4 &resSkipLanes) const
{
resSkipLanes = getBoundary(lanePosition[skipLanes] + bytePos);
if (resSkipLanes < 0) return false;
int4 finalIndex = getBoundary(lanePosition[skipLanes] + bytePos + size);
if (finalIndex < 0) return false;
resNumLanes = finalIndex - resSkipLanes;
return (resNumLanes != 0);
}
/// \brief Decide if a given subset of lanes can be extended naturally for \b this description
///
/// A subset of lanes are specified and their position within an extension (given by a byte position).
/// The size in bytes of the extension is also given. If the extension is contained within \b this description,
/// and the boundaries of the extension don't split any lanes, then return \b true and pass back
/// the number of lanes and starting lane of the extension.
/// \param numLanes is the number of lanes in the original subset
/// \param skipLanes is the starting (least significant) lane index of the original subset
/// \param bytePos is the number of bytes to truncate from the front (least significant portion) of the extension
/// \param size is the number of bytes in the extension
/// \param resNumLanes will hold the number of lanes in the extension
/// \param resSkipLanes will hold the starting lane in the extension
/// \return \b true if the extension is natural
bool LaneDescription::extension(int4 numLanes,int4 skipLanes,int4 bytePos,int4 size,
int4 &resNumLanes,int4 &resSkipLanes) const
{
resSkipLanes = getBoundary(lanePosition[skipLanes] - bytePos);
if (resSkipLanes < 0) return false;
int4 finalIndex = getBoundary(lanePosition[skipLanes] - bytePos + size);
if (finalIndex < 0) return false;
resNumLanes = finalIndex - resSkipLanes;
return (resNumLanes != 0);
}
/// Create the Varnode object (constant, unique, vector piece) described by the
/// given placeholder. If the Varnode is an output, assume the op already exists
/// and create the Varnode as an output. Set the \b replacement field with the
/// new Varnode.
/// \param fd is the function in which to create the replacement
void TransformVar::createReplacement(Funcdata *fd)
{
if (replacement != (Varnode *)0)
return; // Replacement already created
switch(type) {
case TransformVar::preexisting:
replacement = vn;
break;
case TransformVar::constant:
replacement = fd->newConstant(byteSize,val);
break;
case TransformVar::normal_temp:
case TransformVar::piece_temp:
if (def == (TransformOp *)0)
replacement = fd->newUnique(byteSize);
else
replacement = fd->newUniqueOut(byteSize,def->replacement);
break;
case TransformVar::piece:
{
int4 bytePos = (int4)val;
if ((bytePos & 7) != 0)
throw LowlevelError("Varnode piece is not byte aligned");
bytePos >>= 3;
if (vn->getSpace()->isBigEndian())
bytePos = vn->getSize() - bytePos - byteSize;
Address addr = vn->getAddr() + bytePos;
if (def == (TransformOp *)0)
replacement = fd->newVarnode(byteSize,addr);
else
replacement = fd->newVarnodeOut(byteSize, addr, def->replacement);
fd->transferVarnodeProperties(vn,replacement,bytePos);
break;
}
case TransformVar::constant_iop:
{
PcodeOp *indeffect = PcodeOp::getOpFromConst(Address(fd->getArch()->getIopSpace(),val));
replacement = fd->newVarnodeIop(indeffect);
break;
}
default:
throw LowlevelError("Bad TransformVar type");
}
}
/// Create a new PcodeOp or modify an existing one so that it matches this placeholder description.
/// Go ahead an insert the new PcodeOp into the basic block if possible
/// \param fd is the function in which to make the modifications
void TransformOp::createReplacement(Funcdata *fd)
{
if ((special & TransformOp::op_preexisting)!=0) {
replacement = op;
fd->opSetOpcode(op, opc);
while(input.size() < op->numInput())
fd->opRemoveInput(op, op->numInput()-1);
while(op->numInput() < input.size())
fd->opInsertInput(op, (Varnode *)0, op->numInput()-1);
}
else {
replacement = fd->newOp(input.size(),op->getAddr());
fd->opSetOpcode(replacement, opc);
if (output != (TransformVar *)0)
output->createReplacement(fd);
if (follow == (TransformOp *)0) { // Can be inserted immediately
if (opc == CPUI_MULTIEQUAL)
fd->opInsertBegin(replacement, op->getParent());
else
fd->opInsertBefore(replacement, op);
}
}
}
/// \param fd is the function into which the PcodeOp will be inserted
/// \return \b true if the op is successfully inserted or already inserted
bool TransformOp::attemptInsertion(Funcdata *fd)
{
if (follow != (TransformOp *)0) {
if (follow->follow == (TransformOp *)0) { // Check if the follow is inserted
if (opc == CPUI_MULTIEQUAL)
fd->opInsertBegin(replacement, follow->replacement->getParent());
else
fd->opInsertBefore(replacement,follow->replacement);
follow = (TransformOp *)0; // Mark that this has been inserted
return true;
}
return false;
}
return true; // Already inserted
}
void LanedRegister::LanedIterator::normalize(void)
{
uint4 flag = 1;
flag <<= size;
while(flag <= mask) {
if ((flag & mask) != 0) return; // Found a valid lane size
size += 1;
flag <<= 1;
}
size = -1; // Indicate ending iterator
}
/// Read XML of the form \<register name=".." vector_lane_sizes=".."/>
/// \param el is the particular \e register tag
/// \param manage is used to map register names to storage info
/// \return \b true if the XML description provides lane sizes
bool LanedRegister::restoreXml(const Element *el,const AddrSpaceManager *manage)
{
string laneSizes;
for(int4 i=0;i<el->getNumAttributes();++i) {
if (el->getAttributeName(i) == "vector_lane_sizes") {
laneSizes = el->getAttributeValue(i);
break;
}
}
if (laneSizes.empty()) return false;
VarnodeData storage;
storage.space = (AddrSpace *)0;
storage.restoreXml(el, manage);
wholeSize = storage.size;
sizeBitMask = 0;
string::size_type pos = 0;
while(pos != string::npos) {
string::size_type nextPos = laneSizes.find(',',pos);
string value;
if (nextPos == string::npos) {
value = laneSizes.substr(pos); // To the end of the string
pos = nextPos;
}
else {
value = laneSizes.substr(pos,(nextPos - pos));
pos = nextPos + 1;
if (pos >= laneSizes.size())
pos = string::npos;
}
istringstream s(value);
s.unsetf(ios::dec | ios::hex | ios::oct);
int4 sz = -1;
s >> sz;
if (sz < 0 || sz > 16)
throw LowlevelError("Bad lane size: " + value);
addLaneSize(sz);
}
return true;
}
TransformManager::~TransformManager(void)
{
map<int4,TransformVar *>::iterator iter;
for(iter=pieceMap.begin();iter!=pieceMap.end();++iter) {
delete [] (*iter).second;
}
}
/// \brief Should the address of the given Varnode be preserved when constructing a piece
///
/// A new Varnode will be created that represents a logical piece of the given Varnode.
/// This routine determines whether the new Varnode should be constructed using
/// storage which overlaps the given Varnode. It returns \b true if overlapping storage
/// should be used, \b false if the new Varnode should be constructed as a unique temporary.
/// \param vn is the given Varnode
/// \param bitSize is the logical size of the Varnode piece being constructed
/// \param lsbOffset is the least significant bit position of the logical value within the given Varnode
/// \return \b true if overlapping storage should be used in construction
bool TransformManager::preserveAddress(Varnode *vn,int4 bitSize,int4 lsbOffset) const
{
if ((lsbOffset & 7) != 0) return false; // Logical value not aligned
if (vn->getSpace()->getType() == IPTR_INTERNAL) return false;
return true;
}
void TransformManager::clearVarnodeMarks(void)
{
map<int4,TransformVar *>::const_iterator iter;
for(iter=pieceMap.begin();iter!=pieceMap.end();++iter) {
Varnode *vn = (*iter).second->vn;
if (vn == (Varnode *)0)
continue;
vn->clearMark();
}
}
/// \param vn is the preexisting Varnode to create a placeholder for
/// \return the new placeholder node
TransformVar *TransformManager::newPreexistingVarnode(Varnode *vn)
{
TransformVar *res = new TransformVar[1];
pieceMap[vn->getCreateIndex()] = res; // Enter preexisting Varnode into map, so we don't make another placeholder
// value of 0 treats this as "piece" of itself at offset 0, allows getPiece() to find it
res->initialize(TransformVar::preexisting,vn,vn->getSize()*8,vn->getSize(),0);
res->flags = TransformVar::split_terminator;
return res;
}
/// \param size is the size in bytes of the new unique Varnode
/// \return the new placeholder node
TransformVar *TransformManager::newUnique(int4 size)
{
newVarnodes.push_back(TransformVar());
TransformVar *res = &newVarnodes.back();
res->initialize(TransformVar::normal_temp,(Varnode *)0,size*8,size,0);
return res;
}
/// Create a new constant in the transform view. A piece of an existing constant
/// can be created by giving the existing value and the least significant offset.
/// \param size is the size in bytes of the new constant
/// \param lsbOffset is the number of bits to strip off of the existing value
/// \param val is the value of the constant
/// \return the new placeholder node
TransformVar *TransformManager::newConstant(int4 size,int4 lsbOffset,uintb val)
{
newVarnodes.push_back(TransformVar());
TransformVar *res = &newVarnodes.back();
res->initialize(TransformVar::constant,(Varnode *)0,size*8,size,(val >> lsbOffset) & calc_mask(size));
return res;
}
/// Used for creating INDIRECT placeholders.
/// \param vn is the original iop parameter to the INDIRECT
/// \return the new placeholder node
TransformVar *TransformManager::newIop(Varnode *vn)
{
newVarnodes.push_back(TransformVar());
TransformVar *res = &newVarnodes.back();
res->initialize(TransformVar::constant_iop,(Varnode *)0,vn->getSize()*8,vn->getSize(),vn->getOffset());
return res;
}
/// Given a single logical value within a larger Varnode, create a placeholder for
/// that logical value.
/// \param vn is the large Varnode
/// \param bitSize is the size of the logical value in bits
/// \param lsbOffset is the number of least significant bits of the Varnode dropped from the value
/// \return the placeholder variable
TransformVar *TransformManager::newPiece(Varnode *vn,int4 bitSize,int4 lsbOffset)
{
TransformVar *res = new TransformVar[1];
pieceMap[vn->getCreateIndex()] = res;
int4 byteSize = (bitSize + 7) / 8;
uint4 type = preserveAddress(vn, bitSize, lsbOffset) ? TransformVar::piece : TransformVar::piece_temp;
res->initialize(type, vn, bitSize, byteSize, lsbOffset);
res->flags = TransformVar::split_terminator;
return res;
}
/// \brief Create placeholder nodes splitting a Varnode into its lanes
///
/// Given a big Varnode and a lane description, create placeholders for all the explicit pieces
/// that the big Varnode will be split into.
/// \param vn is the big Varnode to split
/// \param description shows how the big Varnode will be split
/// \return an array of the new TransformVar placeholders from least to most significant
TransformVar *TransformManager::newSplit(Varnode *vn,const LaneDescription &description)
{
int4 num = description.getNumLanes();
TransformVar *res = new TransformVar[num];
pieceMap[vn->getCreateIndex()] = res;
for(int4 i=0;i<num;++i) {
int4 bitpos = description.getPosition(i) * 8;
TransformVar *newVar = &res[i];
int4 byteSize = description.getSize(i);
if (vn->isConstant())
newVar->initialize(TransformVar::constant,vn,byteSize * 8,byteSize, (vn->getOffset() >> bitpos) & calc_mask(byteSize));
else {
uint4 type = preserveAddress(vn, byteSize * 8, bitpos) ? TransformVar::piece : TransformVar::piece_temp;
newVar->initialize(type,vn,byteSize * 8, byteSize, bitpos);
}
}
res[num-1].flags = TransformVar::split_terminator;
return res;
}
/// \brief Create placeholder nodes splitting a Varnode into a subset of lanes in the given description
///
/// Given a big Varnode and specific subset of a lane description, create placeholders for all
/// the explicit pieces that the big Varnode will be split into.
/// \param vn is the big Varnode to split
/// \param description gives a list of potentional lanes
/// \param numLanes is the number of lanes in the subset
/// \param startLane is the starting (least significant) lane in the subset
/// \return an array of the new TransformVar placeholders from least to most significant
TransformVar *TransformManager::newSplit(Varnode *vn,const LaneDescription &description,int4 numLanes,int4 startLane)
{
TransformVar *res = new TransformVar[numLanes];
pieceMap[vn->getCreateIndex()] = res;
int4 baseBitPos = description.getPosition(startLane) * 8;
for(int4 i=0;i<numLanes;++i) {
int4 bitpos = description.getPosition(startLane + i) * 8 - baseBitPos;
int4 byteSize = description.getSize(startLane + i);
TransformVar *newVar = &res[i];
if (vn->isConstant())
newVar->initialize(TransformVar::constant,vn,byteSize * 8, byteSize, (vn->getOffset() >> bitpos) & calc_mask(byteSize));
else {
uint4 type = preserveAddress(vn, byteSize * 8, bitpos) ? TransformVar::piece : TransformVar::piece_temp;
newVar->initialize(type,vn,byteSize * 8, byteSize, bitpos);
}
}
res[numLanes-1].flags = TransformVar::split_terminator;
return res;
}
/// \brief Create a new placeholder op intended to replace an existing op
///
/// An uninitialized placeholder for the new op is created.
/// \param numParams is the number of Varnode inputs intended for the new op
/// \param opc is the opcode of the new op
/// \param replace is the existing op the new op will replace
/// \return the new placeholder node
TransformOp *TransformManager::newOpReplace(int4 numParams,OpCode opc,PcodeOp *replace)
{
newOps.push_back(TransformOp());
TransformOp &rop(newOps.back());
rop.op = replace;
rop.replacement = (PcodeOp *)0;
rop.opc = opc;
rop.special = TransformOp::op_replacement;
rop.output = (TransformVar *)0;
rop.follow = (TransformOp *)0;
rop.input.resize(numParams,(TransformVar *)0);
return &rop;
}
/// \brief Create a new placeholder op that will not replace an existing op
///
/// An uninitialized placeholder for the new op is created. When (if) the new op is created
/// it will not replace an existing op. The op that follows it must be given.
/// \param numParams is the number of Varnode inputs intended for the new op
/// \param opc is the opcode of the new op
/// \param follow is the placeholder for the op that follow the new op when it is created
/// \return the new placeholder node
TransformOp *TransformManager::newOp(int4 numParams,OpCode opc,TransformOp *follow)
{
newOps.push_back(TransformOp());
TransformOp &rop(newOps.back());
rop.op = follow->op;
rop.replacement = (PcodeOp *)0;
rop.opc = opc;
rop.special = 0;
rop.output = (TransformVar *)0;
rop.follow = follow;
rop.input.resize(numParams,(TransformVar *)0);
return &rop;
}
/// \brief Create a new placeholder op for an existing PcodeOp
///
/// An uninitialized placeholder for the existing op is created. When applied, this causes
/// the op to be transformed as described by the placeholder, changing its opcode and
/// inputs. The output however is unaffected.
/// \param numParams is the number of Varnode inputs intended for the transformed op
/// \param opc is the opcode of the transformed op
/// \param originalOp is the preexisting PcodeOp
/// \return the new placeholder node
TransformOp *TransformManager::newPreexistingOp(int4 numParams,OpCode opc,PcodeOp *originalOp)
{
newOps.push_back(TransformOp());
TransformOp &rop(newOps.back());
rop.op = originalOp;
rop.replacement = (PcodeOp *)0;
rop.opc = opc;
rop.special = TransformOp::op_preexisting;
rop.output = (TransformVar *)0;
rop.follow = (TransformOp *)0;
rop.input.resize(numParams,(TransformVar *)0);
return &rop;
}
/// Check if a placeholder node was created for the preexisting Varnode for,
/// otherwise create a new one.
/// \param vn is the preexisting Varnode to find a placeholder for
/// \return the placeholder node
TransformVar *TransformManager::getPreexistingVarnode(Varnode *vn)
{
if (vn->isConstant())
return newConstant(vn->getSize(), 0, vn->getOffset());
map<int4,TransformVar *>::const_iterator iter;
iter = pieceMap.find(vn->getCreateIndex());
if (iter != pieceMap.end())
return (*iter).second;
return newPreexistingVarnode(vn);
}
/// Given a big Varnode, find the placeholder corresponding to the logical value
/// given by a size and significance offset. If it doesn't exist, create it.
/// \param vn is the big Varnode containing the logical value
/// \param bitSize is the size of the logical value in bytes
/// \param lsbOffset is the signficance offset of the logical value within the Varnode
/// \return the found/created placeholder
TransformVar *TransformManager::getPiece(Varnode *vn,int4 bitSize,int4 lsbOffset)
{
map<int4,TransformVar *>::const_iterator iter;
iter = pieceMap.find(vn->getCreateIndex());
if (iter != pieceMap.end()) {
TransformVar *res = (*iter).second;
if (res->bitSize != bitSize || res->val != lsbOffset)
throw LowlevelError("Cannot create multiple pieces for one Varnode through getPiece");
return res;
}
return newPiece(vn,bitSize,lsbOffset);
}
/// \brief Find (or create) placeholder nodes splitting a Varnode into its lanes
///
/// Given a big Varnode and a lane description, look up placeholders for all its
/// explicit pieces. If they don't exist, create them.
/// \param vn is the big Varnode to split
/// \param description shows how the big Varnode will be split
/// \return an array of the TransformVar placeholders from least to most significant
TransformVar *TransformManager::getSplit(Varnode *vn,const LaneDescription &description)
{
map<int4,TransformVar *>::const_iterator iter;
iter = pieceMap.find(vn->getCreateIndex());
if (iter != pieceMap.end()) {
return (*iter).second;
}
return newSplit(vn,description);
}
/// \brief Find (or create) placeholder nodes splitting a Varnode into a subset of lanes from a description
///
/// Given a big Varnode and a specific subset of a lane description, look up placeholders
/// for all the explicit pieces. If they don't exist, create them.
/// \param vn is the big Varnode to split
/// \param description describes all the possible lanes
/// \param numLanes is the number of lanes in the subset
/// \param startLane is the starting (least significant) lane in the subset
/// \return an array of the TransformVar placeholders from least to most significant
TransformVar *TransformManager::getSplit(Varnode *vn,const LaneDescription &description,int4 numLanes,int4 startLane)
{
map<int4,TransformVar *>::const_iterator iter;
iter = pieceMap.find(vn->getCreateIndex());
if (iter != pieceMap.end()) {
return (*iter).second;
}
return newSplit(vn,description,numLanes,startLane);
}
/// \brief Handle some special PcodeOp marking
/// If a PcodeOp is an INDIRECT creation, we need to do special marking of the op and Varnodes
/// \param rop is the placeholder op with the special requirement
void TransformManager::specialHandling(TransformOp &rop)
{
if ((rop.special & TransformOp::indirect_creation) != 0)
fd->markIndirectCreation(rop.replacement, false);
else if ((rop.special & TransformOp::indirect_creation_possible_out) != 0)
fd->markIndirectCreation(rop.replacement, true);
}
/// Run through the list of TransformOp placeholders and create the actual PcodeOp object.
/// If the op has an output Varnode, create it. Make sure all the new ops are inserted in
/// control flow.
void TransformManager::createOps(void)
{
list<TransformOp>::iterator iter;
for(iter=newOps.begin();iter!=newOps.end();++iter)
(*iter).createReplacement(fd);
int4 followCount;
do {
followCount = 0;
for(iter=newOps.begin();iter!=newOps.end();++iter) {
if (!(*iter).attemptInsertion(fd))
followCount += 1;
}
} while(followCount != 0);
}
/// Record any input vars in the given container
/// \param inputList will hold any inputs
void TransformManager::createVarnodes(vector<TransformVar *> &inputList)
{
map<int4,TransformVar *>::iterator piter;
for(piter=pieceMap.begin();piter!=pieceMap.end();++piter) {
TransformVar *vArray = (*piter).second;
for(int4 i=0;;++i) {
TransformVar *rvn = vArray + i;
if (rvn->type == TransformVar::piece) {
Varnode *vn = rvn->vn;
if (vn->isInput()) {
inputList.push_back(rvn);
if (vn->isMark())
rvn->flags |= TransformVar::input_duplicate;
else
vn->setMark();
}
}
rvn->createReplacement(fd);
if ((rvn->flags & TransformVar::split_terminator)!=0)
break;
}
}
list<TransformVar>::iterator iter;
for(iter=newVarnodes.begin();iter!=newVarnodes.end();++iter) {
(*iter).createReplacement(fd);
}
}
void TransformManager::removeOld(void)
{
list<TransformOp>::iterator iter;
for(iter=newOps.begin();iter!=newOps.end();++iter) {
TransformOp &rop(*iter);
if ((rop.special & TransformOp::op_replacement) != 0) {
if (!rop.op->isDead())
fd->opDestroy(rop.op); // Destroy old op (and its output Varnode)
}
}
}
/// Remove all input Varnodes from the given container.
/// Mark all the replacement Varnodes as inputs.
/// \param inputList is the given container of input placeholders
void TransformManager::transformInputVarnodes(vector<TransformVar *> &inputList)
{
for(int4 i=0;i<inputList.size();++i) {
TransformVar *rvn = inputList[i];
if ((rvn->flags & TransformVar::input_duplicate)==0)
fd->deleteVarnode(rvn->vn);
rvn->replacement = fd->setInputVarnode(rvn->replacement);
}
}
void TransformManager::placeInputs(void)
{
list<TransformOp>::iterator iter;
for(iter=newOps.begin();iter!=newOps.end();++iter) {
TransformOp &rop(*iter);
PcodeOp *op = rop.replacement;
for(int4 i=0;i<rop.input.size();++i) {
TransformVar *rvn = rop.input[i];
Varnode *vn = rvn->replacement;
fd->opSetInput(op, vn, i);
}
specialHandling(rop);
}
}
void TransformManager::apply(void)
{
vector<TransformVar *> inputList;
createOps();
createVarnodes(inputList);
removeOld();
transformInputVarnodes(inputList);
placeInputs();
}

View file

@ -0,0 +1,229 @@
/* ###
* 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.
*/
/// \file transform.hh
/// \brief Classes for building large scale transforms of function data-flow
#ifndef __TRANSFORM__
#define __TRANSFORM__
#include "varnode.hh"
class Funcdata; // Forward declaration
class TransformOp;
/// \brief Placeholder node for Varnode that will exist after a transform is applied to a function
class TransformVar {
friend class TransformManager;
friend class TransformOp;
public:
/// \brief Types of replacement Varnodes
enum {
piece = 1, ///< New Varnode is a piece of an original Varnode
preexisting = 2, ///< Varnode preexisted in the original data-flow
normal_temp = 3, ///< A new temporary (unique space) Varnode
piece_temp = 4, ///< A temporary representing a piece of an original Varnode
constant = 5, ///< A new constant Varnode
constant_iop = 6, ///< Special iop constant encoding a PcodeOp reference
};
/// \brief Flags for a TransformVar
enum {
split_terminator = 1, ///< The last (most significant piece) of a split array
input_duplicate = 2 ///< This is a piece of an input that has already been visited
};
private:
Varnode *vn; ///< Original \b big Varnode of which \b this is a component
Varnode *replacement; ///< The new explicit lane Varnode
uint4 type; ///< Type of new Varnode
uint4 flags; ///< Boolean properties of the placeholder
int4 byteSize; ///< Size of the lane Varnode in bytes
int4 bitSize; ///< Size of the logical value in bits
uintb val; ///< Value of constant or (bit) position within the original big Varnode
TransformOp *def; ///< Defining op for new Varnode
void createReplacement(Funcdata *fd); ///< Create the new/modified variable this placeholder represents
void initialize(uint4 tp,Varnode *v,int4 bits,int4 bytes,uintb value);
public:
Varnode *getOriginal(void) const { return vn; } ///< Get the original Varnode \b this placeholder models
TransformOp *getDef(void) const { return def; } ///< Get the operator that defines this placeholder variable
};
/// \brief Placeholder node for PcodeOp that will exist after a transform is applied to a function
class TransformOp {
friend class TransformManager;
friend class TransformVar;
public:
/// Special annotations on new pcode ops
enum {
op_replacement = 1, ///< Op replaces an existing op
op_preexisting = 2, ///< Op already exists (but will be transformed)
indirect_creation = 4, ///< Mark op as indirect creation
indirect_creation_possible_out = 8 ///< Mark op as indirect creation and possible call output
};
private:
PcodeOp *op; ///< Original op which \b this is splitting (or null)
PcodeOp *replacement; ///< The new replacement op
OpCode opc; ///< Opcode of the new op
uint4 special; ///< Special handling code when creating
TransformVar *output; ///< Varnode output
vector<TransformVar *> input; ///< Varnode inputs
TransformOp *follow; ///< The following op after \b this (if not null)
void createReplacement(Funcdata *fd); ///< Create the new/modified op this placeholder represents
bool attemptInsertion(Funcdata *fd); ///< Try to put the new PcodeOp into its basic block
public:
TransformVar *getOut(void) const { return output; } ///< Get the output placeholder variable for \b this operator
TransformVar *getIn(int4 i) const { return input[i]; } ///< Get the i-th input placeholder variable for \b this
};
/// \brief Describes a (register) storage location and the ways it might be split into lanes
class LanedRegister {
friend class LanedIterator;
public:
/// \brief Class for iterating over possible lane sizes
class LanedIterator {
int4 size; ///< Current lane size
uint4 mask; ///< Collection being iterated over
void normalize(void); ///< Normalize the iterator, after increment or initialization
public:
LanedIterator(const LanedRegister *lanedR) { size = 0; mask = lanedR->sizeBitMask; normalize(); } ///< Constructor
LanedIterator(void) { size = -1; mask = 0; } ///< Constructor for ending iterator
LanedIterator &operator++(void) { size += 1; normalize(); return *this; } ///< Preincrement operator
int4 operator*(void) const { return size; } /// Dereference operator
LanedIterator &operator=(const LanedIterator &op2) { size = op2.size; mask = op2.mask; return *this; } ///< Assignment
bool operator==(const LanedIterator &op2) const { return (size == op2.size); } ///< Equal operator
bool operator!=(const LanedIterator &op2) const { return (size != op2.size); } ///< Not-equal operator
};
typedef LanedIterator const_iterator;
private:
int4 wholeSize; ///< Size of the whole register
uint4 sizeBitMask; ///< A 1-bit for every permissible lane size
public:
LanedRegister(void) { wholeSize = 0; sizeBitMask = 0; } ///< Constructor for use with restoreXml
LanedRegister(int4 sz,uint4 mask) { wholeSize = sz; sizeBitMask = mask; } ///< Constructor
bool restoreXml(const Element *el,const AddrSpaceManager *manage); ///< Restore object from XML stream
int4 getWholeSize(void) const { return wholeSize; } ///< Get the size in bytes of the whole laned register
uint4 getSizeBitMask(void) const { return sizeBitMask; } ///< Get the bit mask of possible lane sizes
void addLaneSize(int4 size) { sizeBitMask |= ((uint4)1 << size); } ///< Add a new \e size to the allowed list
bool allowedLane(int4 size) const { return (((sizeBitMask >> size) & 1) != 0); } ///< Is \e size among the allowed lane sizes
const_iterator begin(void) const { return LanedIterator(this); } ///< Starting iterator over possible lane sizes
const_iterator end(void) const { return LanedIterator(); } ///< Ending iterator over possible lane sizes
};
/// \brief Description of logical lanes within a \b big Varnode
///
/// A \b lane is a byte offset and size within a Varnode. Lanes within a
/// Varnode are disjoint. In general, we expect a Varnode to be tiled with
/// lanes all of the same size, but the API allows for possibly non-uniform lanes.
class LaneDescription {
int4 wholeSize; ///< Size of the region being split in bytes
vector<int4> laneSize; ///< Size of lanes in bytes
vector<int4> lanePosition; ///< Significance positions of lanes in bytes
public:
LaneDescription(const LaneDescription &op2); ///< Copy constructor
LaneDescription(int4 origSize,int4 sz); ///< Construct uniform lanes
LaneDescription(int4 origSize,int4 lo,int4 hi); ///< Construct two lanes of arbitrary size
bool subset(int4 lsbOffset,int4 size); ///< Trim \b this to a subset of the original lanes
int4 getNumLanes(void) const { return laneSize.size(); } ///< Get the total number of lanes
int4 getWholeSize(void) const { return wholeSize; } ///< Get the size of the region being split
int4 getSize(int4 i) const { return laneSize[i]; } ///< Get the size of the i-th lane
int4 getPosition(int4 i) const { return lanePosition[i]; } ///< Get the significance offset of the i-th lane
int4 getBoundary(int4 bytePos) const; ///< Get index of lane that starts at the given byte position
bool restriction(int4 numLanes,int4 skipLanes,int4 bytePos,int4 size,int4 &resNumLanes,int4 &resSkipLanes) const;
bool extension(int4 numLanes,int4 skipLanes,int4 bytePos,int4 size,int4 &resNumLanes,int4 &resSkipLanes) const;
};
/// \brief Class for splitting larger registers holding smaller logical lanes
///
/// Given a starting Varnode in the data-flow, look for evidence of the Varnode
/// being interpreted as disjoint logical values concatenated together (lanes).
/// If the interpretation is consistent for data-flow involving the Varnode, split
/// Varnode and data-flow into explicit operations on the lanes.
class TransformManager {
Funcdata *fd; ///< Function being operated on
map<int4,TransformVar *> pieceMap; ///< Map from large Varnodes to their new pieces
list<TransformVar> newVarnodes; ///< Storage for Varnode placeholder nodes
list<TransformOp> newOps; ///< Storage for PcodeOp placeholder nodes
void specialHandling(TransformOp &rop);
void createOps(void); ///< Create a new op for each placeholder
void createVarnodes(vector<TransformVar *> &inputList); ///< Create a Varnode for each placeholder
void removeOld(void); ///< Remove old preexisting PcodeOps and Varnodes that are now obsolete
void transformInputVarnodes(vector<TransformVar *> &inputList); ///< Remove old input Varnodes, mark new input Varnodes
void placeInputs(void); ///< Set input Varnodes for all new ops
public:
TransformManager(Funcdata *f) { fd = f; } ///< Constructor
virtual ~TransformManager(void); ///< Destructor
virtual bool preserveAddress(Varnode *vn,int4 bitSize,int4 lsbOffset) const;
Funcdata *getFunction(void) const { return fd; } ///< Get function being transformed
void clearVarnodeMarks(void); ///< Clear mark for all Varnodes in the map
TransformVar *newPreexistingVarnode(Varnode *vn); ///< Make placeholder for preexisting Varnode
TransformVar *newUnique(int4 size); ///< Make placeholder for new unique space Varnode
TransformVar *newConstant(int4 size,int4 lsbOffset,uintb val); ///< Make placeholder for constant Varnode
TransformVar *newIop(Varnode *vn); ///< Make placeholder for special iop constant
TransformVar *newPiece(Varnode *vn,int4 bitSize,int4 lsbOffset); ///< Make placeholder for piece of a Varnode
TransformVar *newSplit(Varnode *vn,const LaneDescription &description);
TransformVar *newSplit(Varnode *vn,const LaneDescription &description,int4 numLanes,int4 startLane);
TransformOp *newOpReplace(int4 numParams,OpCode opc,PcodeOp *replace);
TransformOp *newOp(int4 numParams,OpCode opc,TransformOp *follow);
TransformOp *newPreexistingOp(int4 numParams,OpCode opc,PcodeOp *originalOp);
TransformVar *getPreexistingVarnode(Varnode *vn); ///< Get (or create) placeholder for preexisting Varnode
TransformVar *getPiece(Varnode *vn,int4 bitSize,int4 lsbOffset); ///< Get (or create) placeholder piece
TransformVar *getSplit(Varnode *vn,const LaneDescription &description);
TransformVar *getSplit(Varnode *vn,const LaneDescription &description,int4 numLanes,int4 startLane);
void opSetInput(TransformOp *rop,TransformVar *rvn,int4 slot); ///< Mark given variable as input to given op
void opSetOutput(TransformOp *rop,TransformVar *rvn); ///< Mark given variable as output of given op
void apply(void); ///< Apply the full transform to the function
};
/// \brief Initialize \b this variable from raw data
///
/// \param tp is the type of variable to create
/// \param v is the underlying Varnode of which this is a piece (may be null)
/// \param bits is the number of bits in the variable
/// \param bytes is the number of bytes in the variable
/// \param value is the associated value
inline void TransformVar::initialize(uint4 tp,Varnode *v,int4 bits,int4 bytes,uintb value)
{
type = tp;
vn = v;
val = value;
bitSize = bits;
byteSize = bytes;
flags = 0;
def = (TransformOp *)0;
replacement = (Varnode *)0;
}
/// \param rop is the given placeholder op whose input is set
/// \param rvn is the placeholder variable to set
/// \param slot is the input position to set
inline void TransformManager::opSetInput(TransformOp *rop,TransformVar *rvn,int4 slot)
{
rop->input[slot] = rvn;
}
/// Establish that the given op produces the given var as output.
/// Mark both the \e output field of the TransformOp and the \e def field of the TransformVar.
/// \param rop is the given op
/// \param rvn is the given variable
inline void TransformManager::opSetOutput(TransformOp *rop,TransformVar *rvn)
{
rop->output = rvn;
rvn->def = rop;
}
#endif

View file

@ -137,9 +137,9 @@ private:
list<PcodeOp *> descend; ///< List of every op using this varnode as input
mutable Cover *cover; ///< Addresses covered by the def->use of this Varnode
mutable union {
Datatype *dataType; ///< For type propagate algorithm
ValueSet *valueSet;
} temp;
Datatype *dataType; ///< Temporary data-type associated with \b this for use in type propagate algorithm
ValueSet *valueSet; ///< Value set associated with \b this when performing Value Set Analysis
} temp; ///< Temporary storage for analysis algorithms
uintb consumed; ///< What parts of this varnode are used
uintb nzm; ///< Which bits do we know are zero
friend class VarnodeBank;