mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GP-3148 More join space overlaps
This commit is contained in:
parent
2a5816cd3b
commit
74e1bbdb57
12 changed files with 168 additions and 69 deletions
|
@ -162,32 +162,6 @@ int4 Address::overlap(int4 skip,const Address &op,int4 size) const
|
|||
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,
|
||||
/// where \e this forms the most significant piece of the logical whole
|
||||
/// \param sz is the size of \e this hi region
|
||||
|
|
|
@ -87,9 +87,9 @@ public:
|
|||
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
|
||||
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 overlapJoin(int4 skip,const Address &op,int4 size) const; ///< Determine how two ranges overlap, when one might be in the \e join space
|
||||
bool isContiguous(int4 sz,const Address &loaddr,int4 losz) const; ///< Does \e this form a contigous range with \e loaddr
|
||||
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 \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 contiguous range with \e loaddr
|
||||
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
|
||||
|
@ -432,6 +432,20 @@ inline Address Address::operator-(int4 off) const {
|
|||
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.
|
||||
/// All constant values are represented as an offset into
|
||||
/// the \e constant \e space.
|
||||
|
|
|
@ -2616,10 +2616,9 @@ bool BlockBasic::noInterveningStatement(PcodeOp *first,int4 path,PcodeOp *last)
|
|||
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.
|
||||
/// \param varArray is the exact list of Varnodes
|
||||
/// \param bl is the basic block
|
||||
/// \return the MULTIEQUAL or null
|
||||
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.
|
||||
/// \param varArray is the given array of Varnodes
|
||||
/// \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)
|
||||
|
||||
{
|
||||
|
|
|
@ -3946,6 +3946,9 @@ int4 ActionDeadCode::apply(Funcdata &data)
|
|||
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)
|
||||
|
||||
{
|
||||
|
|
|
@ -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 *> ¬reached)
|
||||
|
||||
{
|
||||
|
|
|
@ -623,13 +623,11 @@ bool Funcdata::earlyJumpTableFail(PcodeOp *op)
|
|||
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
|
||||
/// copy of the current state of data-flow is made, simplification transformations are applied
|
||||
/// to the copy, and the resulting data-flow tree is examined to enumerate possible values
|
||||
/// of the input Varnode to the given BRANCHIND PcodeOp. This information is stored in a
|
||||
/// JumpTable object.
|
||||
/// If an existing and complete JumpTable exists for the BRANCHIND, it is returned immediately.
|
||||
/// Otherwise an attempt is made to analyze the current partial function and recover the set of destination
|
||||
/// addresses, which if successful will be returned as a new JumpTable object.
|
||||
/// \param partial is the Funcdata copy to perform analysis on if necessary
|
||||
/// \param op is the given BRANCHIND PcodeOp
|
||||
/// \param flow is current flow information for \b this function
|
||||
|
|
|
@ -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 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 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)
|
||||
|
||||
{
|
||||
|
|
|
@ -126,6 +126,30 @@ void AddrSpace::truncateSpace(uint4 newsize)
|
|||
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.
|
||||
/// The caller provides only the \e offset, and this routine fills
|
||||
/// in other details pertaining to this particular space.
|
||||
|
@ -363,6 +387,12 @@ ConstantSpace::ConstantSpace(AddrSpaceManager *m,const Translate *t)
|
|||
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
|
||||
/// the debugger and console dumps
|
||||
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
|
||||
}
|
||||
|
||||
/// \brief Calculate where a given address falls inside a range in the \e join space
|
||||
///
|
||||
/// 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
|
||||
int4 JoinSpace::overlapJoin(uintb offset,int4 size,AddrSpace *pointSpace,uintb pointOffset,int4 pointSkip) 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);
|
||||
// Set up so we traverse pieces in data order
|
||||
int4 startPiece,endPiece,dir;
|
||||
|
@ -502,8 +533,8 @@ int4 JoinSpace::pieceOverlap(uintb offset,int4 size,AddrSpace *pieceSpace,uintb
|
|||
int4 bytesAccum = 0;
|
||||
for(int4 i=startPiece;i!=endPiece;i += dir) {
|
||||
const VarnodeData &vData(joinRecord->getPiece(i));
|
||||
if (vData.space == pieceSpace && pieceOffset >= vData.offset && pieceOffset <= vData.offset + (vData.size-1)) {
|
||||
int4 res = (int4)(pieceOffset - vData.offset) + bytesAccum;
|
||||
if (vData.space == pointSpace && pointOffset >= vData.offset && pointOffset <= vData.offset + (vData.size-1)) {
|
||||
int4 res = (int4)(pointOffset - vData.offset) + bytesAccum;
|
||||
if (res >= size)
|
||||
return -1;
|
||||
return res;
|
||||
|
|
|
@ -163,6 +163,7 @@ public:
|
|||
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 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,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
|
||||
|
@ -193,6 +194,7 @@ public:
|
|||
class ConstantSpace : public AddrSpace {
|
||||
public:
|
||||
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 saveXml(ostream &s) const;
|
||||
virtual void decode(Decoder &decoder);
|
||||
|
@ -240,7 +242,7 @@ public:
|
|||
class JoinSpace : public AddrSpace {
|
||||
public:
|
||||
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,int4 size) const;
|
||||
virtual uintb decodeAttributes(Decoder &decoder,uint4 &size) const;
|
||||
|
|
|
@ -849,18 +849,32 @@ void AddrSpaceManager::renormalizeJoinAddress(Address &addr,int4 size)
|
|||
return;
|
||||
}
|
||||
vector<VarnodeData> newPieces;
|
||||
newPieces.push_back(joinRecord->pieces[pos1]);
|
||||
int4 sizeTrunc1 = (int4)(addr1.getOffset() - joinRecord->pieces[pos1].offset);
|
||||
pos1 += 1;
|
||||
while(pos1 <= pos2) {
|
||||
int4 sizeTrunc2 = joinRecord->pieces[pos2].size - (int4)(addr2.getOffset() - joinRecord->pieces[pos2].offset) - 1;
|
||||
|
||||
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]);
|
||||
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;
|
||||
newPieces.front().offset = addr1.getOffset();
|
||||
newPieces.front().size -= sizeTrunc1;
|
||||
newPieces.back().size -= sizeTrunc2;
|
||||
JoinRecord *newJoinRecord = findAddJoin(newPieces, size);
|
||||
JoinRecord *newJoinRecord = findAddJoin(newPieces, 0);
|
||||
addr = Address(newJoinRecord->unified.space,newJoinRecord->unified.offset);
|
||||
}
|
||||
|
||||
|
|
|
@ -124,8 +124,62 @@ public class ParamEntry {
|
|||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -118,8 +118,13 @@ public class ParamListStandard implements ParamList {
|
|||
VariableStorage store;
|
||||
try {
|
||||
if (res.space.getType() == AddressSpace.TYPE_JOIN) {
|
||||
Varnode[] pieces = element.getJoinRecord();
|
||||
store = new DynamicVariableStorage(program, false, pieces);
|
||||
Varnode[] pieces = element.getJoinPieces(sz);
|
||||
if (pieces != null) {
|
||||
store = new DynamicVariableStorage(program, false, pieces);
|
||||
}
|
||||
else {
|
||||
store = DynamicVariableStorage.getUnassignedDynamicStorage(false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Address addr = res.space.getAddress(res.offset);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue