renormalize join addresses

This commit is contained in:
caheckman 2020-02-07 15:55:21 -05:00
parent f71dc17292
commit 1c95e274ff
8 changed files with 125 additions and 3 deletions

View file

@ -179,6 +179,14 @@ bool Address::isContiguous(int4 sz,const Address &loaddr,int4 losz) const
return false; return false;
} }
/// If \b this is (originally) a \e join address, reevaluate it in terms of its new
/// \e offset and \e siz, changing the space and offset if necessary.
/// \param size is the new size in bytes of the underlying object
void Address::renormalize(int4 size) {
if (base->getType() == IPTR_JOIN)
base->getManager()->renormalizeJoinAddress(*this,size);
}
/// This is usually used to build an address from an \b \<addr\> /// This is usually used to build an address from an \b \<addr\>
/// tag, but it can be used to create an address from any tag /// tag, but it can be used to create an address from any tag
/// with the appropriate attributes /// with the appropriate attributes

View file

@ -80,6 +80,7 @@ public:
int4 overlap(int4 skip,const Address &op,int4 size) const; ///< Determine how two address ranges overlap int4 overlap(int4 skip,const Address &op,int4 size) const; ///< Determine how two address ranges overlap
bool isContiguous(int4 sz,const Address &loaddr,int4 losz) const; ///< Does \e this form a contigous range with \e loaddr bool isContiguous(int4 sz,const Address &loaddr,int4 losz) const; ///< Does \e this form a contigous range with \e loaddr
bool isConstant(void) const; ///< Is this a \e constant \e value bool isConstant(void) const; ///< Is this a \e constant \e value
void renormalize(int4 size); ///< Make sure there is a backing JoinRecord if \b this is in the \e join space
bool isJoin(void) const; ///< Is this a \e join \e value bool isJoin(void) const; ///< Is this a \e join \e value
void saveXml(ostream &s) const; ///< Save this to a stream as an XML tag void saveXml(ostream &s) const; ///< Save this to a stream as an XML tag
void saveXml(ostream &s,int4 size) const; ///< Save this and a size to a stream as an XML tag void saveXml(ostream &s,int4 size) const; ///< Save this and a size to a stream as an XML tag

View file

@ -873,8 +873,10 @@ Varnode *RulePullsubMulti::buildSubpiece(Varnode *basevn,uint4 outsize,uint4 shi
data.opSetOpcode(new_op,CPUI_SUBPIECE); data.opSetOpcode(new_op,CPUI_SUBPIECE);
if (usetmp) if (usetmp)
outvn = data.newUniqueOut(outsize,new_op); outvn = data.newUniqueOut(outsize,new_op);
else else {
smalladdr1.renormalize(outsize);
outvn = data.newVarnodeOut(outsize,smalladdr1,new_op); outvn = data.newVarnodeOut(outsize,smalladdr1,new_op);
}
data.opSetInput(new_op,basevn,0); data.opSetInput(new_op,basevn,0);
data.opSetInput(new_op,data.newConstant(4,shift),1); data.opSetInput(new_op,data.newConstant(4,shift),1);
@ -964,6 +966,7 @@ int4 RulePullsubMulti::applyOp(PcodeOp *op,Funcdata &data)
} }
// Build new multiequal near original multiequal // Build new multiequal near original multiequal
PcodeOp *new_multi = data.newOp(params.size(),mult->getAddr()); PcodeOp *new_multi = data.newOp(params.size(),mult->getAddr());
smalladdr2.renormalize(newSize);
Varnode *new_vn = data.newVarnodeOut(newSize,smalladdr2,new_multi); Varnode *new_vn = data.newVarnodeOut(newSize,smalladdr2,new_multi);
data.opSetOpcode(new_multi,CPUI_MULTIEQUAL); data.opSetOpcode(new_multi,CPUI_MULTIEQUAL);
data.opSetAllInput(new_multi,params); data.opSetAllInput(new_multi,params);
@ -2005,6 +2008,7 @@ int4 RuleLeftRight::applyOp(PcodeOp *op,Funcdata &data)
addr = addr + isa; addr = addr + isa;
data.opUnsetInput(op,0); data.opUnsetInput(op,0);
data.opUnsetOutput(leftshift); data.opUnsetOutput(leftshift);
addr.renormalize(tsz);
Varnode *newvn = data.newVarnodeOut(tsz,addr,leftshift); Varnode *newvn = data.newVarnodeOut(tsz,addr,leftshift);
data.opSetOpcode(leftshift,CPUI_SUBPIECE); data.opSetOpcode(leftshift,CPUI_SUBPIECE);
data.opSetInput(leftshift, data.newConstant( leftshift->getIn(1)->getSize(), 0), 1); data.opSetInput(leftshift, data.newConstant( leftshift->getIn(1)->getSize(), 0), 1);
@ -7456,6 +7460,7 @@ Varnode *RulePtrFlow::truncatePointer(AddrSpace *spc,PcodeOp *op,Varnode *vn,int
Address addr = vn->getAddr(); Address addr = vn->getAddr();
if (addr.isBigEndian()) if (addr.isBigEndian())
addr = addr + (vn->getSize() - spc->getAddrSize()); addr = addr + (vn->getSize() - spc->getAddrSize());
addr.renormalize(spc->getAddrSize());
newvn = data.newVarnodeOut(spc->getAddrSize(),addr,truncop); newvn = data.newVarnodeOut(spc->getAddrSize(),addr,truncop);
} }
data.opSetInput(op,newvn,slot); data.opSetInput(op,newvn,slot);

View file

@ -1156,6 +1156,7 @@ Address SubvariableFlow::getReplacementAddress(ReplaceVarnode *rvn) const
addr = addr + (rvn->vn->getSize() - flowsize - sa); addr = addr + (rvn->vn->getSize() - flowsize - sa);
else else
addr = addr + sa; addr = addr + sa;
addr.renormalize(flowsize);
return addr; return addr;
} }

View file

@ -69,7 +69,7 @@ class SubvariableFlow {
int4 slot; ///< slot being affected or other parameter int4 slot; ///< slot being affected or other parameter
}; };
int4 flowsize; ///< Size of the lgoical data-flow in bytes int4 flowsize; ///< Size of the logical data-flow in bytes
int4 bitsize; ///< Number of bits in logical variable int4 bitsize; ///< Number of bits in logical variable
bool returnsTraversed; ///< Have we tried to flow logical value across CPUI_RETURNs bool returnsTraversed; ///< Have we tried to flow logical value across CPUI_RETURNs
bool aggressive; ///< Do we "know" initial seed point must be a sub variable bool aggressive; ///< Do we "know" initial seed point must be a sub variable

View file

@ -196,6 +196,7 @@ void TransformVar::createReplacement(Funcdata *fd)
if (vn->getSpace()->isBigEndian()) if (vn->getSpace()->isBigEndian())
bytePos = vn->getSize() - bytePos - byteSize; bytePos = vn->getSize() - bytePos - byteSize;
Address addr = vn->getAddr() + bytePos; Address addr = vn->getAddr() + bytePos;
addr.renormalize(byteSize);
if (def == (TransformOp *)0) if (def == (TransformOp *)0)
replacement = fd->newVarnode(byteSize,addr); replacement = fd->newVarnode(byteSize,addr);
else else

View file

@ -118,6 +118,41 @@ void SpacebaseSpace::restoreXml(const Element *el)
contain = getManager()->getSpaceByName(el->getAttributeValue("contain")); contain = getManager()->getSpaceByName(el->getAttributeValue("contain"));
} }
/// The \e join space range maps to the underlying pieces in a natural endian aware way.
/// Given an offset in the range, figure out what address it is mapping to.
/// The particular piece is passed back as an index, and the Address is returned.
/// \param offset is the offset within \b this range to map
/// \param pos will hold the passed back piece index
/// \return the Address mapped to
Address JoinRecord::getEquivalentAddress(uintb offset,int4 &pos) const
{
if (offset < unified.offset)
return Address(); // offset comes before this range
int4 smallOff = (int4)(offset - unified.offset);
if (pieces[0].space->isBigEndian()) {
for(pos=0;pos<pieces.size();++pos) {
int4 pieceSize = pieces[pos].size;
if (smallOff < pieceSize)
break;
smallOff -= pieceSize;
}
if (pos == pieces.size())
return Address(); // offset comes after this range
}
else {
for (pos = pieces.size() - 1; pos >= 0; --pos) {
int4 pieceSize = pieces[pos].size;
if (smallOff < pieceSize)
break;
smallOff -= pieceSize;
}
if (pos < 0)
return Address(); // offset comes after this range
}
return Address(pieces[pos].space,pieces[pos].offset + smallOff);
}
/// Allow sorting on JoinRecords so that a collection of pieces can be quickly mapped to /// Allow sorting on JoinRecords so that a collection of pieces can be quickly mapped to
/// its logical whole, specified with a join address /// its logical whole, specified with a join address
bool JoinRecord::operator<(const JoinRecord &op2) const bool JoinRecord::operator<(const JoinRecord &op2) const
@ -612,6 +647,30 @@ JoinRecord *AddrSpaceManager::findAddJoin(const vector<VarnodeData> &pieces,uint
return splitlist.back(); return splitlist.back();
} }
/// Given a specific \e offset into the \e join address space, recover the JoinRecord that
/// contains the offset, as a range in the \e join address space. If there is no existing
/// record, null is returned.
/// \param offset is an offset into the join space
/// \return the JoinRecord containing that offset or null
JoinRecord *AddrSpaceManager::findJoinInternal(uintb offset) const
{
int4 min=0;
int4 max=splitlist.size()-1;
while(min<=max) { // Binary search
int4 mid = (min+max)/2;
JoinRecord *rec = splitlist[mid];
uintb val = rec->unified.offset;
if (val + rec->unified.size <= offset)
min = mid + 1;
else if (val > offset)
max = mid - 1;
else
return rec;
}
return (JoinRecord *)0;
}
/// Given a specific \e offset into the \e join address space, recover the JoinRecord that /// Given a specific \e offset into the \e join address space, recover the JoinRecord that
/// lists the pieces corresponding to that offset. The offset must originally have come from /// lists the pieces corresponding to that offset. The offset must originally have come from
/// a JoinRecord returned by \b findAddJoin, otherwise this method throws an exception. /// a JoinRecord returned by \b findAddJoin, otherwise this method throws an exception.
@ -619,7 +678,7 @@ JoinRecord *AddrSpaceManager::findAddJoin(const vector<VarnodeData> &pieces,uint
/// \return the JoinRecord for that offset /// \return the JoinRecord for that offset
JoinRecord *AddrSpaceManager::findJoin(uintb offset) const JoinRecord *AddrSpaceManager::findJoin(uintb offset) const
{ // Find a split record given the unified (join space) offset {
int4 min=0; int4 min=0;
int4 max=splitlist.size()-1; int4 max=splitlist.size()-1;
while(min<=max) { // Binary search while(min<=max) { // Binary search
@ -733,6 +792,48 @@ Address AddrSpaceManager::constructJoinAddress(const Translate *translate,
return join->getUnified().getAddr(); return join->getUnified().getAddr();
} }
/// If an Address in the \e join AddressSpace is shifted from its original offset, it may no
/// longer have a valid JoinRecord. The shift or size change may even make the address of
/// one of the pieces a more natural representation. Given a new Address and size, this method
/// decides if there is a matching JoinRecord. If not it either constructs a new JoinRecord or
/// computes the address within the containing piece. The given Address is changed if necessary
/// either to the offset corresponding to the new JoinRecord or to a normal \e non-join Address.
/// \param addr is the given Address
/// \param size is the size of the range in bytes
void AddrSpaceManager::renormalizeJoinAddress(Address &addr,int4 size)
{
JoinRecord *joinRecord = findJoinInternal(addr.getOffset());
if (joinRecord == (JoinRecord *)0)
throw LowlevelError("Join address not covered by a JoinRecord");
if (addr.getOffset() == joinRecord->unified.offset && size == joinRecord->unified.size)
return; // JoinRecord matches perfectly, no change necessary
int4 pos1;
Address addr1 = joinRecord->getEquivalentAddress(addr.getOffset(), pos1);
int4 pos2;
Address addr2 = joinRecord->getEquivalentAddress(addr.getOffset() + (size-1), pos2);
if (addr2.isInvalid())
throw LowlevelError("Join address range not covered");
if (pos1 == pos2) {
addr = addr1;
return;
}
vector<VarnodeData> newPieces;
newPieces.push_back(joinRecord->pieces[pos1]);
int4 sizeTrunc1 = (int4)(addr1.getOffset() - joinRecord->pieces[pos1].offset);
pos1 += 1;
while(pos1 <= pos2) {
newPieces.push_back(joinRecord->pieces[pos1]);
pos1 += 1;
}
int4 sizeTrunc2 = joinRecord->pieces[pos2].size - (int4)(addr2.getOffset() - joinRecord->pieces[pos2].offset) - 1;
newPieces.front().offset = addr1.getOffset();
newPieces.front().size -= sizeTrunc1;
newPieces.back().size -= sizeTrunc2;
JoinRecord *newJoinRecord = findAddJoin(newPieces, size);
addr = Address(newJoinRecord->unified.space,newJoinRecord->unified.offset);
}
/// This constructs only a shell for the Translate object. It /// This constructs only a shell for the Translate object. It
/// won't be usable until it is initialized for a specific processor /// won't be usable until it is initialized for a specific processor
/// The main entry point for this is the Translate::initialize method, /// The main entry point for this is the Translate::initialize method,

View file

@ -201,6 +201,7 @@ public:
bool isFloatExtension(void) const { return (pieces.size() == 1); } ///< Does this record extend a float varnode bool isFloatExtension(void) const { return (pieces.size() == 1); } ///< Does this record extend a float varnode
const VarnodeData &getPiece(int4 i) const { return pieces[i]; } ///< Get the i-th piece const VarnodeData &getPiece(int4 i) const { return pieces[i]; } ///< Get the i-th piece
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 \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
}; };
@ -242,6 +243,7 @@ protected:
void copySpaces(const AddrSpaceManager *op2); ///< Copy spaces from another manager void copySpaces(const AddrSpaceManager *op2); ///< Copy spaces from another manager
void addSpacebasePointer(SpacebaseSpace *basespace,const VarnodeData &ptrdata,int4 truncSize,bool stackGrowth); ///< Set the base register of a spacebase space void addSpacebasePointer(SpacebaseSpace *basespace,const VarnodeData &ptrdata,int4 truncSize,bool stackGrowth); ///< Set the base register of a spacebase space
void insertResolver(AddrSpace *spc,AddressResolver *rsolv); ///< Override the base resolver for a space void insertResolver(AddrSpace *spc,AddressResolver *rsolv); ///< Override the base resolver for a space
JoinRecord *findJoinInternal(uintb offset) const; ///< Find JoinRecord for \e offset in the join space
public: public:
AddrSpaceManager(void); ///< Construct an empty address space manager AddrSpaceManager(void); ///< Construct an empty address space manager
virtual ~AddrSpaceManager(void); ///< Destroy the manager virtual ~AddrSpaceManager(void); ///< Destroy the manager
@ -272,6 +274,9 @@ public:
/// \brief Build a logical whole from register pairs /// \brief Build a logical whole from register pairs
Address constructJoinAddress(const Translate *translate,const Address &hiaddr,int4 hisz,const Address &loaddr,int4 losz); Address constructJoinAddress(const Translate *translate,const Address &hiaddr,int4 hisz,const Address &loaddr,int4 losz);
/// \brief Make sure a possibly offset \e join address has a proper JoinRecord
void renormalizeJoinAddress(Address &addr,int4 size);
}; };
/// \brief The interface to a translation engine for a processor. /// \brief The interface to a translation engine for a processor.