mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-10 07:08:21 +08:00
GP-6610 Add count of jumptable recover stages
This commit is contained in:
@@ -768,25 +768,10 @@ void FlowInfo::truncateIndirectJump(PcodeOp *op,JumpTable::RecoveryMode mode)
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Test if the given p-code op is a member of an array
|
||||
///
|
||||
/// \param array is the array of p-code ops to search
|
||||
/// \param op is the given p-code op to search for
|
||||
/// \return \b true if the op is a member of the array
|
||||
bool FlowInfo::isInArray(vector<PcodeOp *> &array,PcodeOp *op)
|
||||
|
||||
{
|
||||
for(int4 i=0;i<array.size();++i) {
|
||||
if (array[i] == op) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FlowInfo::generateOps(void)
|
||||
|
||||
{
|
||||
vector<PcodeOp *> notreached; // indirect ops that are not reachable
|
||||
int4 notreachcnt = 0;
|
||||
clearProperties();
|
||||
addrlist.push_back(data.getAddress());
|
||||
while(!addrlist.empty()) // Recovering as much as possible except jumptables
|
||||
@@ -812,10 +797,9 @@ void FlowInfo::generateOps(void)
|
||||
|
||||
checkContainedCall(); // Check for PIC constructions
|
||||
checkMultistageJumptables();
|
||||
while(notreachcnt < notreached.size()) {
|
||||
tablelist.push_back(notreached[notreachcnt]);
|
||||
notreachcnt += 1;
|
||||
}
|
||||
for(int4 i=0;i<notreached.size();++i)
|
||||
tablelist.push_back(notreached[i]);
|
||||
notreached.clear();
|
||||
if (hasInject())
|
||||
injectPcode();
|
||||
} while(!tablelist.empty()); // Inlining or multistage may have added new indirect branches
|
||||
@@ -1445,7 +1429,7 @@ void FlowInfo::recoverJumpTables(vector<JumpTable *> &newTables,vector<PcodeOp *
|
||||
truncateIndirectJump(op,mode); // Treat the indirect jump as a call
|
||||
}
|
||||
else if (jt->isPartial()) {
|
||||
if (tablelist.size() > 1 && !isInArray(notreached,op)) {
|
||||
if (tablelist.size() > 1 && jt->getRecoverCount() <= 1) {
|
||||
// If the recovery is incomplete with current flow AND there is more flow to generate,
|
||||
// AND we haven't tried to recover this table before
|
||||
notreached.push_back(op); // Save this op so we can try to recover the table again later
|
||||
|
||||
@@ -138,7 +138,6 @@ private:
|
||||
void recoverJumpTables(vector<JumpTable *> &newTables,vector<PcodeOp *> ¬reached);
|
||||
void deleteCallSpec(FuncCallSpecs *fc); ///< Remove the given call site from the list for \b this function
|
||||
void truncateIndirectJump(PcodeOp *op,JumpTable::RecoveryMode mode); ///< Treat indirect jump as CALLIND/RETURN
|
||||
static bool isInArray(vector<PcodeOp *> &array,PcodeOp *op);
|
||||
public:
|
||||
FlowInfo(Funcdata &d,PcodeOpBank &o,BlockGraph &b,vector<FuncCallSpecs *> &q); ///< Constructor
|
||||
FlowInfo(Funcdata &d,PcodeOpBank &o,BlockGraph &b,vector<FuncCallSpecs *> &q,const FlowInfo *op2); ///< Cloning constructor
|
||||
|
||||
@@ -491,6 +491,7 @@ JumpTable *Funcdata::installJumpTable(const Address &addr)
|
||||
JumpTable::RecoveryMode Funcdata::stageJumpTable(Funcdata &partial,JumpTable *jt,PcodeOp *op,FlowInfo *flow)
|
||||
|
||||
{
|
||||
jt->incrementRecoveryCount();
|
||||
if (!partial.isJumptableRecoveryOn()) {
|
||||
// Do full analysis on the table if we haven't before
|
||||
partial.flags |= jumptablerecovery_on; // Mark that this Funcdata object is dedicated to jumptable recovery
|
||||
|
||||
@@ -2403,9 +2403,7 @@ JumpTable::JumpTable(Address ad)
|
||||
switchVarConsume = ~((uintb)0);
|
||||
defaultBlock = -1;
|
||||
lastBlock = -1;
|
||||
maxaddsub = 1;
|
||||
maxleftright = 1;
|
||||
maxext = 1;
|
||||
recoverCount = 0;
|
||||
displayFormat = 0;
|
||||
partialTable = false;
|
||||
collectloads = false;
|
||||
@@ -2424,9 +2422,7 @@ JumpTable::JumpTable(const JumpTable *op2)
|
||||
switchVarConsume = ~((uintb)0);
|
||||
defaultBlock = -1;
|
||||
lastBlock = op2->lastBlock;
|
||||
maxaddsub = op2->maxaddsub;
|
||||
maxleftright = op2->maxleftright;
|
||||
maxext = op2->maxext;
|
||||
recoverCount = op2->recoverCount;
|
||||
displayFormat = op2->displayFormat;
|
||||
partialTable = op2->partialTable;
|
||||
collectloads = op2->collectloads;
|
||||
@@ -2771,8 +2767,9 @@ void JumpTable::clear(void)
|
||||
indirect = (PcodeOp *)0;
|
||||
switchVarConsume = ~((uintb)0);
|
||||
defaultBlock = -1;
|
||||
recoverCount = 0;
|
||||
partialTable = false;
|
||||
// -opaddress- -maxtablesize- -maxaddsub- -maxleftright- -maxext- -collectloads- are permanent
|
||||
// -opaddress- -maxtablesize- -collectloads- are permanent
|
||||
}
|
||||
|
||||
/// The recovered addresses and case labels are encode to the stream.
|
||||
@@ -2871,6 +2868,7 @@ bool JumpTable::checkForMultistage(Funcdata *fd)
|
||||
if (addresstable.size()!=1) return false;
|
||||
if (partialTable) return false;
|
||||
if (indirect == (PcodeOp *)0) return false;
|
||||
if (recoverCount > 1) return false;
|
||||
|
||||
if (fd->getOverride().queryMultistageJumptable(indirect->getAddr())) {
|
||||
partialTable = true; // Mark that we need additional recovery
|
||||
|
||||
@@ -549,6 +549,9 @@ public:
|
||||
fail_callother = 4 ///< Address formed by CALLOTHER
|
||||
};
|
||||
private:
|
||||
static constexpr uint4 maxaddsub = 1; ///< Maximum ADDs or SUBs to normalize
|
||||
static constexpr uint4 maxleftright = 1; ///< Maximum shifts to normalize
|
||||
static constexpr uint4 maxext = 1; ///< Maximum extensions to normalize
|
||||
/// \brief An address table index and its corresponding out-edge
|
||||
struct IndexPair {
|
||||
int4 blockPosition; ///< Out-edge index for the basic-block
|
||||
@@ -568,9 +571,7 @@ private:
|
||||
uintb switchVarConsume; ///< Bits of the switch variable being consumed
|
||||
int4 defaultBlock; ///< The out-edge corresponding to the \e default switch destination (-1 = undefined)
|
||||
int4 lastBlock; ///< Block out-edge corresponding to last entry in the address table
|
||||
uint4 maxaddsub; ///< Maximum ADDs or SUBs to normalize
|
||||
uint4 maxleftright; ///< Maximum shifts to normalize
|
||||
uint4 maxext; ///< Maximum extensions to normalize
|
||||
int4 recoverCount; ///< Number of times recovery attempted on \b this table
|
||||
uint4 displayFormat; ///< Display format for integer \e case values
|
||||
bool partialTable; ///< Set to \b true if \b this table is incomplete and needs additional recovery steps
|
||||
bool collectloads; ///< Set to \b true if information about in-memory model data is/should be collected
|
||||
@@ -598,14 +599,14 @@ public:
|
||||
const Address &getOpAddress(void) const { return opaddress; } ///< Get the address of the BRANCHIND for the switch
|
||||
PcodeOp *getIndirectOp(void) const { return indirect; } ///< Get the BRANCHIND PcodeOp
|
||||
void setIndirectOp(PcodeOp *ind) { opaddress = ind->getAddr(); indirect = ind; } ///< Set the BRANCHIND PcodeOp
|
||||
void setNormMax(uint4 maddsub,uint4 mleftright,uint4 mext) {
|
||||
maxaddsub = maddsub; maxleftright = mleftright; maxext = mext; } ///< Set the switch variable normalization model restrictions
|
||||
uint4 getDisplayFormat(void) const { return displayFormat; } ///< Get the display format for integer cases
|
||||
void setDisplayFormat(uint4 format) { displayFormat = format; } ///< Set the display format to use for integer case values
|
||||
void setOverride(const vector<Address> &addrtable,const Address &naddr,uintb h,uintb sv);
|
||||
int4 numIndicesByBlock(const FlowBlock *bl) const;
|
||||
int4 getIndexByBlock(const FlowBlock *bl,int4 i) const;
|
||||
Address getAddressByIndex(int4 i) const { return addresstable[i]; } ///< Get the i-th address table entry
|
||||
int4 getRecoverCount(void) const { return recoverCount; } ///< Get number of times a recovery has been attempted
|
||||
void incrementRecoveryCount(void) { recoverCount += 1; } ///< Record that another round of recovery is being attempted
|
||||
void setLastAsDefault(void); ///< Set the \e default jump-table target to be the last address in the table
|
||||
void setDefaultBlock(int4 bl) { defaultBlock = bl; } ///< Set out-edge of the switch destination considered to be \e default
|
||||
void setLoadCollect(bool val) { collectloads = val; } ///< Set whether LOAD records should be collected
|
||||
|
||||
Reference in New Issue
Block a user