mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -09:00
GP-6946 Refactor JumpTable thunk check
This commit is contained in:
@@ -2302,6 +2302,26 @@ void JumpTable::recoverModel(Funcdata *fd)
|
|||||||
jmodel = (JumpModel *)0;
|
jmodel = (JumpModel *)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If the function is just a sequence of absolute jumps ending in an indirect jump that recovers
|
||||||
|
/// to a single address, return \b true.
|
||||||
|
/// \param fd is the function to test
|
||||||
|
/// \return \b true if the function looks like a thunk
|
||||||
|
bool JumpTable::isThunk(Funcdata *fd) const
|
||||||
|
|
||||||
|
{
|
||||||
|
if (addresstable.size() != 1) return false;
|
||||||
|
Address addr = addresstable[0];
|
||||||
|
if (addr.getOffset()==0)
|
||||||
|
return true;
|
||||||
|
list<PcodeOp *>::const_iterator iter;
|
||||||
|
for(iter = fd->beginOpAlive(); iter != fd->endOpAlive(); ++iter) {
|
||||||
|
OpCode opc = (*iter)->code();
|
||||||
|
if (opc != CPUI_BRANCHIND && opc != CPUI_BRANCH)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Check that the BRANCHIND is still reachable, if not throw JumptableNotReachableError.
|
/// Check that the BRANCHIND is still reachable, if not throw JumptableNotReachableError.
|
||||||
/// Check pathological cases when there is only one address in the table, if we find
|
/// Check pathological cases when there is only one address in the table, if we find
|
||||||
/// this, throw the JumptableThunkError. Let the model run its sanity check.
|
/// this, throw the JumptableThunkError. Let the model run its sanity check.
|
||||||
@@ -2319,24 +2339,8 @@ void JumpTable::sanityCheck(Funcdata *fd,vector<int4> *loadcounts)
|
|||||||
|
|
||||||
if (!isReachable(indirect))
|
if (!isReachable(indirect))
|
||||||
partialTable = true; // If the jumptable is not reachable, mark as incomplete
|
partialTable = true; // If the jumptable is not reachable, mark as incomplete
|
||||||
if (addresstable.size() == 1) { // One entry is likely some kind of thunk
|
if (isThunk(fd))
|
||||||
bool isthunk = false;
|
throw JumptableThunkError("Likely thunk");
|
||||||
uintb diff;
|
|
||||||
Address addr = addresstable[0];
|
|
||||||
if (addr.getOffset()==0)
|
|
||||||
isthunk = true;
|
|
||||||
else {
|
|
||||||
Address addr2 = indirect->getAddr();
|
|
||||||
diff = (addr.getOffset() < addr2.getOffset()) ?
|
|
||||||
(addr2.getOffset() - addr.getOffset()) :
|
|
||||||
(addr.getOffset() - addr2.getOffset());
|
|
||||||
if (diff > 0xffff)
|
|
||||||
isthunk = true;
|
|
||||||
}
|
|
||||||
if (isthunk) {
|
|
||||||
throw JumptableThunkError("Likely thunk");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!jmodel->sanityCheck(fd,indirect,addresstable,loadpoints,loadcounts)) {
|
if (!jmodel->sanityCheck(fd,indirect,addresstable,loadpoints,loadcounts)) {
|
||||||
ostringstream err;
|
ostringstream err;
|
||||||
err << "Jumptable at " << opaddress << " did not pass sanity check.";
|
err << "Jumptable at " << opaddress << " did not pass sanity check.";
|
||||||
|
|||||||
@@ -581,6 +581,7 @@ private:
|
|||||||
void clearSavedModel(void); ///< Clear any saved model
|
void clearSavedModel(void); ///< Clear any saved model
|
||||||
void recoverModel(Funcdata *fd); ///< Attempt recovery of the jump-table model
|
void recoverModel(Funcdata *fd); ///< Attempt recovery of the jump-table model
|
||||||
void trivialSwitchOver(void); ///< Switch \b this table over to a trivial model
|
void trivialSwitchOver(void); ///< Switch \b this table over to a trivial model
|
||||||
|
bool isThunk(Funcdata *fd) const; ///< Return \b true if the function looks like a thunk
|
||||||
void sanityCheck(Funcdata *fd,vector<int4> *loadpoints); ///< Perform sanity check on recovered address targets
|
void sanityCheck(Funcdata *fd,vector<int4> *loadpoints); ///< Perform sanity check on recovered address targets
|
||||||
int4 block2Position(const FlowBlock *bl) const; ///< Convert a basic-block to an out-edge index from the switch.
|
int4 block2Position(const FlowBlock *bl) const; ///< Convert a basic-block to an out-edge index from the switch.
|
||||||
static bool isReachable(PcodeOp *op); ///< Check if the given PcodeOp still seems reachable in its function
|
static bool isReachable(PcodeOp *op); ///< Check if the given PcodeOp still seems reachable in its function
|
||||||
|
|||||||
Reference in New Issue
Block a user