GP-3148 More join space overlaps

This commit is contained in:
caheckman 2023-02-28 12:40:24 -05:00
parent 2a5816cd3b
commit 74e1bbdb57
12 changed files with 168 additions and 69 deletions

View file

@ -162,32 +162,6 @@ int4 Address::overlap(int4 skip,const Address &op,int4 size) const
return (int4) dist; return (int4) dist;
} }
/// This method is equivalent to Address::overlap, but a range in the \e join space can be
/// considered overlapped with its constituent pieces.
/// If \e this + \e skip falls in the range, \e op to \e op + \e size, then a non-negative integer is
/// returned indicating where in the interval it falls. Otherwise -1 is returned.
/// \param skip is an adjust to \e this address
/// \param op is the start of the range to check
/// \param size is the size of the range
/// \return an integer indicating how overlap occurs
int4 Address::overlapJoin(int4 skip,const Address &op,int4 size) const
{
if (base != op.base) {
if (op.base->getType()==IPTR_JOIN) {
uintb dist = base->wrapOffset(offset + skip);
return ((JoinSpace *)op.base)->pieceOverlap(op.offset,size,base,dist);
}
return -1;
}
if (base->getType()==IPTR_CONSTANT) return -1; // Must not be constants
uintb dist = base->wrapOffset(offset+skip-op.offset);
if (dist >= size) return -1; // but must fall before op+size
return (int4) dist;
}
/// Does the location \e this, \e sz form a contiguous region to \e loaddr, \e losz, /// Does the location \e this, \e sz form a contiguous region to \e loaddr, \e losz,
/// where \e this forms the most significant piece of the logical whole /// where \e this forms the most significant piece of the logical whole
/// \param sz is the size of \e this hi region /// \param sz is the size of \e this hi region

View file

@ -87,9 +87,9 @@ public:
friend ostream &operator<<(ostream &s,const Address &addr); ///< Write out an address to stream friend ostream &operator<<(ostream &s,const Address &addr); ///< Write out an address to stream
bool containedBy(int4 sz,const Address &op2,int4 sz2) const; ///< Determine if \e op2 range contains \b this range bool containedBy(int4 sz,const Address &op2,int4 sz2) const; ///< Determine if \e op2 range contains \b this range
int4 justifiedContain(int4 sz,const Address &op2,int4 sz2,bool forceleft) const; ///< Determine if \e op2 is the least significant part of \e this. int4 justifiedContain(int4 sz,const Address &op2,int4 sz2,bool forceleft) const; ///< Determine if \e op2 is the least significant part of \e this.
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 \b this address falls in a given address range
int4 overlapJoin(int4 skip,const Address &op,int4 size) const; ///< Determine how two ranges overlap, when one might be in the \e join space int4 overlapJoin(int4 skip,const Address &op,int4 size) const; ///< Determine how \b this falls in a possible \e join space address range
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 contiguous 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 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
@ -432,6 +432,20 @@ inline Address Address::operator-(int4 off) const {
return Address(base,base->wrapOffset(offset-off)); return Address(base,base->wrapOffset(offset-off));
} }
/// This method is equivalent to Address::overlap, but a range in the \e join space can be
/// considered overlapped with its constituent pieces.
/// If \e this + \e skip falls in the range, \e op to \e op + \e size, then a non-negative integer is
/// returned indicating where in the interval it falls. Otherwise -1 is returned.
/// \param skip is an adjust to \e this address
/// \param op is the start of the range to check
/// \param size is the size of the range
/// \return an integer indicating how overlap occurs
inline int4 Address::overlapJoin(int4 skip,const Address &op,int4 size) const
{
return op.getSpace()->overlapJoin(op.getOffset(), size, base, offset, skip);
}
/// Determine if this address is from the \e constant \e space. /// Determine if this address is from the \e constant \e space.
/// All constant values are represented as an offset into /// All constant values are represented as an offset into
/// the \e constant \e space. /// the \e constant \e space.

View file

@ -2616,10 +2616,9 @@ bool BlockBasic::noInterveningStatement(PcodeOp *first,int4 path,PcodeOp *last)
return false; return false;
} }
/// If there exists a CPUI_MULTIEQUAL PcodeOp in the given basic block that takes this exact list of Varnodes /// If there exists a CPUI_MULTIEQUAL PcodeOp in \b this basic block that takes the given exact list of Varnodes
/// as its inputs, return that PcodeOp. Otherwise return null. /// as its inputs, return that PcodeOp. Otherwise return null.
/// \param varArray is the exact list of Varnodes /// \param varArray is the exact list of Varnodes
/// \param bl is the basic block
/// \return the MULTIEQUAL or null /// \return the MULTIEQUAL or null
PcodeOp *BlockBasic::findMultiequal(const vector<Varnode *> &varArray) PcodeOp *BlockBasic::findMultiequal(const vector<Varnode *> &varArray)
@ -2646,7 +2645,7 @@ PcodeOp *BlockBasic::findMultiequal(const vector<Varnode *> &varArray)
/// with the input Varnode in the indicated slot. /// with the input Varnode in the indicated slot.
/// \param varArray is the given array of Varnodes /// \param varArray is the given array of Varnodes
/// \param slot is the indicated slot /// \param slot is the indicated slot
/// \return \true if all the Varnodes are defined in the same way /// \return \b true if all the Varnodes are defined in the same way
bool BlockBasic::liftVerifyUnroll(vector<Varnode *> &varArray,int4 slot) bool BlockBasic::liftVerifyUnroll(vector<Varnode *> &varArray,int4 slot)
{ {

View file

@ -3946,6 +3946,9 @@ int4 ActionDeadCode::apply(Funcdata &data)
return 0; return 0;
} }
/// \brief Clear all marks on the given list of PcodeOps
///
/// \param opList is the given list
void ActionConditionalConst::clearMarks(const vector<PcodeOp *> &opList) void ActionConditionalConst::clearMarks(const vector<PcodeOp *> &opList)
{ {

View file

@ -1380,9 +1380,14 @@ void FlowInfo::checkMultistageJumptables(void)
} }
} }
/// \brief Recover jumptables for current set of BRANCHIND ops using existing flow /// \brief Recover jumptables for the current set of BRANCHIND ops using existing flow
/// ///
/// \param newTables will hold one JumpTable pointer for each BRANCHIND in \b tablelist /// This method passes back a list of JumpTable objects, one for each BRANCHIND in the current
/// \b tablelist where the jumptable can be recovered. If a particular BRANCHIND cannot be recovered
/// because the current partial control flow cannot legally reach it, the BRANCHIND is passed back
/// in a separate list.
/// \param newTables will hold the list of recovered JumpTables
/// \param notreached will hold the list of BRANCHIND ops that could not be reached
void FlowInfo::recoverJumpTables(vector<JumpTable *> &newTables,vector<PcodeOp *> &notreached) void FlowInfo::recoverJumpTables(vector<JumpTable *> &newTables,vector<PcodeOp *> &notreached)
{ {

View file

@ -623,13 +623,11 @@ bool Funcdata::earlyJumpTableFail(PcodeOp *op)
return false; return false;
} }
/// \brief Recover destinations for a BRANCHIND by analyzing nearby data and control-flow /// \brief Recover control-flow destinations for a BRANCHIND
/// ///
/// This is the high-level entry point for jump-table/switch recovery. In short, a /// If an existing and complete JumpTable exists for the BRANCHIND, it is returned immediately.
/// copy of the current state of data-flow is made, simplification transformations are applied /// Otherwise an attempt is made to analyze the current partial function and recover the set of destination
/// to the copy, and the resulting data-flow tree is examined to enumerate possible values /// addresses, which if successful will be returned as a new JumpTable object.
/// of the input Varnode to the given BRANCHIND PcodeOp. This information is stored in a
/// JumpTable object.
/// \param partial is the Funcdata copy to perform analysis on if necessary /// \param partial is the Funcdata copy to perform analysis on if necessary
/// \param op is the given BRANCHIND PcodeOp /// \param op is the given BRANCHIND PcodeOp
/// \param flow is current flow information for \b this function /// \param flow is current flow information for \b this function

View file

@ -606,7 +606,7 @@ static bool matching_constants(Varnode *vn1,Varnode *vn2)
/// \param path is the specific branch to take from the CBRANCH to reach the switch /// \param path is the specific branch to take from the CBRANCH to reach the switch
/// \param rng is the range of values causing the switch path to be taken /// \param rng is the range of values causing the switch path to be taken
/// \param v is the Varnode holding the value controlling the CBRANCH /// \param v is the Varnode holding the value controlling the CBRANCH
/// \param unroll is \b true if the guard is duplicated across multiple blocks /// \param unr is \b true if the guard is duplicated across multiple blocks
GuardRecord::GuardRecord(PcodeOp *bOp,PcodeOp *rOp,int4 path,const CircleRange &rng,Varnode *v,bool unr) GuardRecord::GuardRecord(PcodeOp *bOp,PcodeOp *rOp,int4 path,const CircleRange &rng,Varnode *v,bool unr)
{ {

View file

@ -126,6 +126,30 @@ void AddrSpace::truncateSpace(uint4 newsize)
calcScaleMask(); calcScaleMask();
} }
/// \brief Determine if a given point is contained in an address range in \b this address space
///
/// The point is specified as an address space and offset pair plus an additional number of bytes to "skip".
/// A non-negative value is returned if the point falls in the address range.
/// If the point falls on the first byte of the range, 0 is returned. For the second byte, 1 is returned, etc.
/// Otherwise -1 is returned.
/// \param offset is the starting offset of the address range within \b this space
/// \param size is the size of the address range in bytes
/// \param pointSpace is the address space of the given point
/// \param pointOff is the offset of the given point
/// \param pointSkip is the additional bytes to skip
/// \return a non-negative value indicating where the point falls in the range, or -1
int4 AddrSpace::overlapJoin(uintb offset,int4 size,AddrSpace *pointSpace,uintb pointOff,int4 pointSkip) const
{
if (this != pointSpace)
return -1;
uintb dist = wrapOffset(pointOff+pointSkip-offset);
if (dist >= size) return -1; // but must fall before op+size
return (int4) dist;
}
/// Write the main attributes for an address within \b this space. /// Write the main attributes for an address within \b this space.
/// The caller provides only the \e offset, and this routine fills /// The caller provides only the \e offset, and this routine fills
/// in other details pertaining to this particular space. /// in other details pertaining to this particular space.
@ -363,6 +387,12 @@ ConstantSpace::ConstantSpace(AddrSpaceManager *m,const Translate *t)
setFlags(big_endian); setFlags(big_endian);
} }
int4 ConstantSpace::overlapJoin(uintb offset,int4 size,AddrSpace *pointSpace,uintb pointOff,int4 pointSkip) const
{
return -1;
}
/// Constants are always printed as hexidecimal values in /// Constants are always printed as hexidecimal values in
/// the debugger and console dumps /// the debugger and console dumps
void ConstantSpace::printRaw(ostream &s,uintb offset) const void ConstantSpace::printRaw(ostream &s,uintb offset) const
@ -471,21 +501,22 @@ JoinSpace::JoinSpace(AddrSpaceManager *m,const Translate *t,int4 ind)
clearFlags(heritaged); // This space is never heritaged, but does dead-code analysis clearFlags(heritaged); // This space is never heritaged, but does dead-code analysis
} }
/// \brief Calculate where a given address falls inside a range in the \e join space int4 JoinSpace::overlapJoin(uintb offset,int4 size,AddrSpace *pointSpace,uintb pointOffset,int4 pointSkip) const
///
/// The given address, specified as an (AddrSpace, offset) pair is assumed to not be in the \e join space,
/// but is assumed to be in one of the pieces of the join. A final non-negative offset is returned if the
/// address falls in one of the pieces. The offset is in data order, i.e. the offset is 0 if the given Address
/// matches the address of the first element in an array overlaid on the \e join range.
/// -1 is returned if the given Address does not lie in any piece.
/// \param offset is the offset into the \e join space, specifying the range
/// \param size is the size of the range, which may be smaller than the size of the JoinRecord
/// \param pieceSpace is the AddrSpace of the given address
/// \param pieceOffset is the offset of the given address
/// \return a non-negative offset indicating where in the range the Address lies, or -1
int4 JoinSpace::pieceOverlap(uintb offset,int4 size,AddrSpace *pieceSpace,uintb pieceOffset) const
{ {
if (this == pointSpace) {
// If the point is in the join space, translate the point into the piece address space
JoinRecord *pieceRecord = getManager()->findJoin(pointOffset);
int4 pos;
Address addr = pieceRecord->getEquivalentAddress(pointOffset + pointSkip, pos);
pointSpace = addr.getSpace();
pointOffset = addr.getOffset();
}
else {
if (pointSpace->getType() == IPTR_CONSTANT)
return -1;
pointOffset = pointSpace->wrapOffset(pointOffset + pointSkip);
}
JoinRecord *joinRecord = getManager()->findJoin(offset); JoinRecord *joinRecord = getManager()->findJoin(offset);
// Set up so we traverse pieces in data order // Set up so we traverse pieces in data order
int4 startPiece,endPiece,dir; int4 startPiece,endPiece,dir;
@ -502,8 +533,8 @@ int4 JoinSpace::pieceOverlap(uintb offset,int4 size,AddrSpace *pieceSpace,uintb
int4 bytesAccum = 0; int4 bytesAccum = 0;
for(int4 i=startPiece;i!=endPiece;i += dir) { for(int4 i=startPiece;i!=endPiece;i += dir) {
const VarnodeData &vData(joinRecord->getPiece(i)); const VarnodeData &vData(joinRecord->getPiece(i));
if (vData.space == pieceSpace && pieceOffset >= vData.offset && pieceOffset <= vData.offset + (vData.size-1)) { if (vData.space == pointSpace && pointOffset >= vData.offset && pointOffset <= vData.offset + (vData.size-1)) {
int4 res = (int4)(pieceOffset - vData.offset) + bytesAccum; int4 res = (int4)(pointOffset - vData.offset) + bytesAccum;
if (res >= size) if (res >= size)
return -1; return -1;
return res; return res;

View file

@ -163,6 +163,7 @@ public:
virtual const VarnodeData &getSpacebaseFull(int4 i) const; ///< Return original spacebase register before truncation virtual const VarnodeData &getSpacebaseFull(int4 i) const; ///< Return original spacebase register before truncation
virtual bool stackGrowsNegative(void) const; ///< Return \b true if a stack in this space grows negative virtual bool stackGrowsNegative(void) const; ///< Return \b true if a stack in this space grows negative
virtual AddrSpace *getContain(void) const; ///< Return this space's containing space (if any) virtual AddrSpace *getContain(void) const; ///< Return this space's containing space (if any)
virtual int4 overlapJoin(uintb offset,int4 size,AddrSpace *pointSpace,uintb pointOff,int4 pointSkip) const;
virtual void encodeAttributes(Encoder &encoder,uintb offset) const; ///< Encode address attributes to a stream virtual void encodeAttributes(Encoder &encoder,uintb offset) const; ///< Encode address attributes to a stream
virtual void encodeAttributes(Encoder &encoder,uintb offset,int4 size) const; ///< Encode an address and size attributes to a stream virtual void encodeAttributes(Encoder &encoder,uintb offset,int4 size) const; ///< Encode an address and size attributes to a stream
virtual uintb decodeAttributes(Decoder &decoder,uint4 &size) const; ///< Recover an offset and size virtual uintb decodeAttributes(Decoder &decoder,uint4 &size) const; ///< Recover an offset and size
@ -193,6 +194,7 @@ public:
class ConstantSpace : public AddrSpace { class ConstantSpace : public AddrSpace {
public: public:
ConstantSpace(AddrSpaceManager *m,const Translate *t); ///< Only constructor ConstantSpace(AddrSpaceManager *m,const Translate *t); ///< Only constructor
virtual int4 overlapJoin(uintb offset,int4 size,AddrSpace *pointSpace,uintb pointOff,int4 pointSkip) const;
virtual void printRaw(ostream &s,uintb offset) const; virtual void printRaw(ostream &s,uintb offset) const;
virtual void saveXml(ostream &s) const; virtual void saveXml(ostream &s) const;
virtual void decode(Decoder &decoder); virtual void decode(Decoder &decoder);
@ -240,7 +242,7 @@ public:
class JoinSpace : public AddrSpace { class JoinSpace : public AddrSpace {
public: public:
JoinSpace(AddrSpaceManager *m,const Translate *t,int4 ind); JoinSpace(AddrSpaceManager *m,const Translate *t,int4 ind);
int4 pieceOverlap(uintb offset,int4 size,AddrSpace *pieceSpace,uintb pieceOffset) const; virtual int4 overlapJoin(uintb offset,int4 size,AddrSpace *pointSpace,uintb pointOff,int4 pointSkip) const;
virtual void encodeAttributes(Encoder &encoder,uintb offset) const; virtual void encodeAttributes(Encoder &encoder,uintb offset) const;
virtual void encodeAttributes(Encoder &encoder,uintb offset,int4 size) const; virtual void encodeAttributes(Encoder &encoder,uintb offset,int4 size) const;
virtual uintb decodeAttributes(Decoder &decoder,uint4 &size) const; virtual uintb decodeAttributes(Decoder &decoder,uint4 &size) const;

View file

@ -849,18 +849,32 @@ void AddrSpaceManager::renormalizeJoinAddress(Address &addr,int4 size)
return; return;
} }
vector<VarnodeData> newPieces; vector<VarnodeData> newPieces;
newPieces.push_back(joinRecord->pieces[pos1]);
int4 sizeTrunc1 = (int4)(addr1.getOffset() - joinRecord->pieces[pos1].offset); int4 sizeTrunc1 = (int4)(addr1.getOffset() - joinRecord->pieces[pos1].offset);
pos1 += 1; int4 sizeTrunc2 = joinRecord->pieces[pos2].size - (int4)(addr2.getOffset() - joinRecord->pieces[pos2].offset) - 1;
while(pos1 <= pos2) {
if (pos2 < pos1) { // Little endian
newPieces.push_back(joinRecord->pieces[pos2]);
pos2 += 1;
while(pos2 <= pos1) {
newPieces.push_back(joinRecord->pieces[pos2]);
pos2 += 1;
}
newPieces.back().offset = addr1.getOffset();
newPieces.back().size -= sizeTrunc1;
newPieces.front().size -= sizeTrunc2;
}
else {
newPieces.push_back(joinRecord->pieces[pos1]); newPieces.push_back(joinRecord->pieces[pos1]);
pos1 += 1; pos1 += 1;
while(pos1 <= pos2) {
newPieces.push_back(joinRecord->pieces[pos1]);
pos1 += 1;
}
newPieces.front().offset = addr1.getOffset();
newPieces.front().size -= sizeTrunc1;
newPieces.back().size -= sizeTrunc2;
} }
int4 sizeTrunc2 = joinRecord->pieces[pos2].size - (int4)(addr2.getOffset() - joinRecord->pieces[pos2].offset) - 1; JoinRecord *newJoinRecord = findAddJoin(newPieces, 0);
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); addr = Address(newJoinRecord->unified.space,newJoinRecord->unified.offset);
} }

View file

@ -124,8 +124,62 @@ public class ParamEntry {
return spaceid; return spaceid;
} }
public Varnode[] getJoinRecord() { /**
return joinrec; * Collect pieces from the join list, in endian order, until the given size is covered.
* The last piece is trimmed to match the size exactly. If the size is too big to be
* covered by this ParamEntry, null is returned.
* @param sz is the given size
* @return the collected array of Varnodes or null
*/
public Varnode[] getJoinPieces(int sz) {
int num = 0;
int first, replace;
Varnode vn = null;
Varnode[] res;
if (isBigEndian()) {
first = 0;
while (sz > 0) {
if (num >= joinrec.length) {
return null;
}
vn = joinrec[num];
if (vn.getSize() > sz) {
num += 1;
break;
}
sz -= vn.getSize();
num += 1;
}
replace = num - 1;
}
else {
while (sz > 0) {
if (num >= joinrec.length) {
return null;
}
vn = joinrec[joinrec.length - 1 - num];
if (vn.getSize() > sz) {
num += 1;
break;
}
sz -= vn.getSize();
num += 1;
}
first = joinrec.length - num;
replace = first;
}
if (sz == 0 && num == joinrec.length) {
return joinrec;
}
res = new Varnode[num];
for (int i = 0; i < num; ++i) {
res[i] = joinrec[first + i];
}
if (sz > 0) {
res[replace] = new Varnode(vn.getAddress(), sz);
}
return res;
} }
/** /**

View file

@ -118,8 +118,13 @@ public class ParamListStandard implements ParamList {
VariableStorage store; VariableStorage store;
try { try {
if (res.space.getType() == AddressSpace.TYPE_JOIN) { if (res.space.getType() == AddressSpace.TYPE_JOIN) {
Varnode[] pieces = element.getJoinRecord(); Varnode[] pieces = element.getJoinPieces(sz);
store = new DynamicVariableStorage(program, false, pieces); if (pieces != null) {
store = new DynamicVariableStorage(program, false, pieces);
}
else {
store = DynamicVariableStorage.getUnassignedDynamicStorage(false);
}
} }
else { else {
Address addr = res.space.getAddress(res.offset); Address addr = res.space.getAddress(res.offset);