Merge remote-tracking branch 'origin/GP-1405_ThisPointerPrep'

This commit is contained in:
Ryan Kurtz 2022-07-07 00:58:42 -04:00
commit 7e4df39fe5
7 changed files with 64 additions and 1 deletions

View file

@ -4059,6 +4059,8 @@ int4 ActionPrototypeTypes::apply(Funcdata &data)
evalfp = data.getArch()->defaultfp; evalfp = data.getArch()->defaultfp;
if ((!data.getFuncProto().isModelLocked())&&(!data.getFuncProto().hasMatchingModel(evalfp))) if ((!data.getFuncProto().isModelLocked())&&(!data.getFuncProto().hasMatchingModel(evalfp)))
data.getFuncProto().setModel(evalfp); data.getFuncProto().setModel(evalfp);
if (data.getFuncProto().hasThisPointer())
data.prepareThisPointer();
iterend = data.endOp(CPUI_RETURN); iterend = data.endOp(CPUI_RETURN);

View file

@ -4198,6 +4198,28 @@ bool FuncProto::getBiggestContainedOutput(const Address &loc,int4 size,VarnodeDa
return model->getBiggestContainedOutput(loc,size,res); return model->getBiggestContainedOutput(loc,size,res);
} }
/// A likely pointer data-type for "this" pointer is passed in, which can be pointer to void. As the
/// storage of "this" may depend on the full prototype, if the prototype is not already locked in, we
/// assume the prototype returns void and takes the given data-type as the single input parameter.
/// \param dt is the given input data-type
/// \return the starting address of storage for the "this" pointer
Address FuncProto::getThisPointerStorage(Datatype *dt)
{
if (!model->hasThisPointer())
return Address();
vector<Datatype *> typelist;
typelist.push_back(getOutputType());
typelist.push_back(dt);
vector<ParameterPieces> res;
model->assignParameterStorage(typelist, res, true);
for(int4 i=1;i<res.size();++i) {
if ((res[i].flags & ParameterPieces::hiddenretparm) != 0) continue;
return res[i].addr;
}
return Address();
}
/// \brief Decide if \b this can be safely restricted to match another prototype /// \brief Decide if \b this can be safely restricted to match another prototype
/// ///
/// Do \b this and another given function prototype share enough of /// Do \b this and another given function prototype share enough of

View file

@ -1524,6 +1524,8 @@ public:
/// \brief Pass-back the biggest potential output storage location contained within the given range /// \brief Pass-back the biggest potential output storage location contained within the given range
bool getBiggestContainedOutput(const Address &loc,int4 size,VarnodeData &res) const; bool getBiggestContainedOutput(const Address &loc,int4 size,VarnodeData &res) const;
Address getThisPointerStorage(Datatype *dt); ///< Get the storage location associated with the "this" pointer
bool isCompatible(const FuncProto &op2) const; bool isCompatible(const FuncProto &op2) const;
AddrSpace *getSpacebase(void) const { return model->getSpacebase(); } ///< Get the \e stack address space AddrSpace *getSpacebase(void) const { return model->getSpacebase(); } ///< Get the \e stack address space
void printRaw(const string &funcname,ostream &s) const; void printRaw(const string &funcname,ostream &s) const;

View file

@ -374,6 +374,7 @@ public:
HighVariable *findHigh(const string &nm) const; ///< Find a high-level variable by name HighVariable *findHigh(const string &nm) const; ///< Find a high-level variable by name
void mapGlobals(void); ///< Make sure there is a Symbol entry for all global Varnodes void mapGlobals(void); ///< Make sure there is a Symbol entry for all global Varnodes
void prepareThisPointer(void); ///< Prepare for recovery of the "this" pointer
bool checkCallDoubleUse(const PcodeOp *opmatch,const PcodeOp *op,const Varnode *vn,uint4 fl,const ParamTrial &trial) const; bool checkCallDoubleUse(const PcodeOp *opmatch,const PcodeOp *op,const Varnode *vn,uint4 fl,const ParamTrial &trial) const;
bool onlyOpUse(const Varnode *invn,const PcodeOp *opmatch,const ParamTrial &trial,uint4 mainFlags) const; bool onlyOpUse(const Varnode *invn,const PcodeOp *opmatch,const ParamTrial &trial,uint4 mainFlags) const;
bool ancestorOpUse(int4 maxlevel,const Varnode *invn,const PcodeOp *op,ParamTrial &trial,int4 offset,uint4 mainFlags) const; bool ancestorOpUse(int4 maxlevel,const Varnode *invn,const PcodeOp *op,ParamTrial &trial,int4 offset,uint4 mainFlags) const;

View file

@ -1549,6 +1549,30 @@ void Funcdata::mapGlobals(void)
warningHeader("Globals starting with '_' overlap smaller symbols at the same address"); warningHeader("Globals starting with '_' overlap smaller symbols at the same address");
} }
/// Make sure that if a Varnode exists representing the "this" pointer for the function, that it
/// is treated as pointer data-type.
void Funcdata::prepareThisPointer(void)
{
int4 numInputs = funcp.numParams();
for(int4 i=0;i<numInputs;++i) {
ProtoParameter *param = funcp.getParam(i);
if (param->isThisPointer() && param->isTypeLocked())
return; // Data-type will be obtained directly from symbol
}
// Its possible that a recommendation for the "this" pointer has already been been collected.
// Currently the only type recommendations are for the "this" pointer. If there any, it is for "this"
if (localmap->hasTypeRecommendations())
return;
Datatype *dt = glb->types->getTypeVoid();
AddrSpace *spc = glb->getDefaultDataSpace();
dt = glb->types->getTypePointer(spc->getAddrSize(),dt,spc->getWordSize());
Address addr = funcp.getThisPointerStorage(dt);
localmap->addTypeRecommendation(addr, dt);
}
/// \brief Test for legitimate double use of a parameter trial /// \brief Test for legitimate double use of a parameter trial
/// ///
/// The given trial is a \e putative input to first CALL, but can also trace its data-flow /// The given trial is a \e putative input to first CALL, but can also trace its data-flow

View file

@ -302,7 +302,7 @@ void ScopeLocal::collectNameRecs(void)
// If the "this" pointer points to a class, try to preserve the data-type // If the "this" pointer points to a class, try to preserve the data-type
// even though the symbol is not preserved. // even though the symbol is not preserved.
SymbolEntry *entry = sym->getFirstWholeMap(); SymbolEntry *entry = sym->getFirstWholeMap();
typeRecommend.push_back(TypeRecommend(entry->getAddr(),dt)); addTypeRecommendation(entry->getAddr(), dt);
} }
} }
} }
@ -1385,6 +1385,16 @@ void ScopeLocal::applyTypeRecommendations(void)
} }
} }
/// Associate a data-type with a particular storage address. If we see an input Varnode at this address,
/// if no other info is available, the given data-type is applied.
/// \param addr is the storage address
/// \param dt is the given data-type
void ScopeLocal::addTypeRecommendation(const Address &addr,Datatype *dt)
{
typeRecommend.push_back(TypeRecommend(addr,dt));
}
/// The symbol is stored as a name recommendation and then removed from the scope. /// The symbol is stored as a name recommendation and then removed from the scope.
/// Name recommendations are associated either with a storage address and usepoint, or a dynamic hash. /// Name recommendations are associated either with a storage address and usepoint, or a dynamic hash.
/// The name may be reattached to a Symbol after decompilation. /// The name may be reattached to a Symbol after decompilation.

View file

@ -243,6 +243,8 @@ public:
SymbolEntry *remapSymbolDynamic(Symbol *sym,uint8 hash,const Address &usepoint); SymbolEntry *remapSymbolDynamic(Symbol *sym,uint8 hash,const Address &usepoint);
void recoverNameRecommendationsForSymbols(void); void recoverNameRecommendationsForSymbols(void);
void applyTypeRecommendations(void); ///< Try to apply recommended data-type information void applyTypeRecommendations(void); ///< Try to apply recommended data-type information
bool hasTypeRecommendations(void) const { return !typeRecommend.empty(); } ///< Are there data-type recommendations
void addTypeRecommendation(const Address &addr,Datatype *dt); ///< Add a new data-type recommendation
}; };
#endif #endif