mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
renormalize join addresses
This commit is contained in:
parent
f71dc17292
commit
1c95e274ff
8 changed files with 125 additions and 3 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue