mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
Attach handling of "this" to ProtoParameter
This commit is contained in:
parent
bcc0f7fe38
commit
004a99bb87
29 changed files with 338 additions and 149 deletions
|
@ -540,7 +540,7 @@ void ParamListStandard::assignMap(const vector<Datatype *> &proto,bool isinput,T
|
|||
if (isinput) {
|
||||
if (res.size()==2) { // Check for hidden parameters defined by the output list
|
||||
res.back().addr = assignAddress(res.back().type,status); // Reserve first param for hidden ret value
|
||||
res.back().flags |= Varnode::hiddenretparm;
|
||||
res.back().flags |= ParameterPieces::hiddenretparm;
|
||||
if (res.back().addr.isInvalid())
|
||||
throw ParamUnassignedError("Cannot assign parameter address for " + res.back().type->getName());
|
||||
}
|
||||
|
@ -556,7 +556,7 @@ void ParamListStandard::assignMap(const vector<Datatype *> &proto,bool isinput,T
|
|||
Datatype *pointertp = typefactory.getTypePointer(pointersize,proto[i],wordsize);
|
||||
res.back().addr = assignAddress(pointertp,status);
|
||||
res.back().type = pointertp;
|
||||
res.back().flags = Varnode::indirectstorage;
|
||||
res.back().flags = ParameterPieces::indirectstorage;
|
||||
}
|
||||
else
|
||||
res.back().addr = assignAddress(proto[i],status);
|
||||
|
@ -1107,12 +1107,12 @@ void ParamListStandardOut::assignMap(const vector<Datatype *> &proto,bool isinpu
|
|||
if (res.back().addr.isInvalid())
|
||||
throw ParamUnassignedError("Cannot assign return value as a pointer");
|
||||
res.back().type = pointertp;
|
||||
res.back().flags = Varnode::indirectstorage;
|
||||
res.back().flags = ParameterPieces::indirectstorage;
|
||||
|
||||
res.push_back(ParameterPieces()); // Add extra storage location in the input params
|
||||
res.back().type = pointertp; // that holds a pointer to where the return value should be stored
|
||||
// leave its address invalid, to be filled in by the input list assignMap
|
||||
res.back().flags = Varnode::hiddenretparm; // Mark it as special
|
||||
res.back().flags = ParameterPieces::hiddenretparm; // Mark it as special
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1759,6 +1759,7 @@ ProtoModel::ProtoModel(Architecture *g)
|
|||
glb = g;
|
||||
input = (ParamList *)0;
|
||||
output = (ParamList *)0;
|
||||
compatModel = (const ProtoModel *)0;
|
||||
extrapop=0;
|
||||
injectUponEntry = -1;
|
||||
injectUponReturn = -1;
|
||||
|
@ -1797,6 +1798,9 @@ ProtoModel::ProtoModel(const string &nm,const ProtoModel &op2)
|
|||
stackgrowsnegative = op2.stackgrowsnegative;
|
||||
hasThis = op2.hasThis;
|
||||
isConstruct = op2.isConstruct;
|
||||
if (name == "__thiscall")
|
||||
hasThis = true;
|
||||
compatModel = &op2;
|
||||
}
|
||||
|
||||
ProtoModel::~ProtoModel(void)
|
||||
|
@ -1808,6 +1812,19 @@ ProtoModel::~ProtoModel(void)
|
|||
delete output;
|
||||
}
|
||||
|
||||
/// Test whether one ProtoModel can substituted for another during FuncCallSpecs::deindirect
|
||||
/// Currently this can only happen if one model is a copy of the other except for the
|
||||
/// hasThis boolean property.
|
||||
/// \param op2 is the other ProtoModel to compare with \b this
|
||||
/// \return \b true if the two models are compatible
|
||||
bool ProtoModel::isCompatible(const ProtoModel *op2) const
|
||||
|
||||
{
|
||||
if (this == op2 || compatModel == op2 || op2->compatModel == this)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Calculate input and output storage locations given a function prototype
|
||||
///
|
||||
/// The data-types of the function prototype are passed in as an ordered list, with the
|
||||
|
@ -2266,21 +2283,30 @@ void ParameterBasic::setTypeLock(bool val)
|
|||
|
||||
{
|
||||
if (val) {
|
||||
flags |= Varnode::typelock;
|
||||
flags |= ParameterPieces::typelock;
|
||||
if (type->getMetatype() == TYPE_UNKNOWN) // Check if we are locking TYPE_UNKNOWN
|
||||
flags |= Varnode::mark; // If so, set Varnode::mark to indicate the sizelock
|
||||
flags |= ParameterPieces::sizelock;
|
||||
}
|
||||
else
|
||||
flags &= ~((uint4)(Varnode::typelock|Varnode::mark));
|
||||
flags &= ~((uint4)(ParameterPieces::typelock|ParameterPieces::sizelock));
|
||||
}
|
||||
|
||||
void ParameterBasic::setNameLock(bool val)
|
||||
|
||||
{
|
||||
if (val)
|
||||
flags |= Varnode::namelock;
|
||||
flags |= ParameterPieces::namelock;
|
||||
else
|
||||
flags &= ~((uint4)Varnode::namelock);
|
||||
flags &= ~((uint4)ParameterPieces::namelock);
|
||||
}
|
||||
|
||||
void ParameterBasic::setThisPointer(bool val)
|
||||
|
||||
{
|
||||
if (val)
|
||||
flags |= ParameterPieces::isthis;
|
||||
else
|
||||
flags &= ~((uint4)ParameterPieces::isthis);
|
||||
}
|
||||
|
||||
void ParameterBasic::overrideSizeLockType(Datatype *ct)
|
||||
|
@ -2352,6 +2378,12 @@ bool ParameterSymbol::isSizeTypeLocked(void) const
|
|||
return sym->isSizeTypeLocked();
|
||||
}
|
||||
|
||||
bool ParameterSymbol::isThisPointer(void) const
|
||||
|
||||
{
|
||||
return sym->isThisPointer();
|
||||
}
|
||||
|
||||
bool ParameterSymbol::isIndirectStorage(void) const
|
||||
|
||||
{
|
||||
|
@ -2393,6 +2425,13 @@ void ParameterSymbol::setNameLock(bool val)
|
|||
scope->clearAttribute(sym,Varnode::namelock);
|
||||
}
|
||||
|
||||
void ParameterSymbol::setThisPointer(bool val)
|
||||
|
||||
{
|
||||
Scope *scope = sym->getScope();
|
||||
scope->setThisPointer(sym, val);
|
||||
}
|
||||
|
||||
void ParameterSymbol::overrideSizeLockType(Datatype *ct)
|
||||
|
||||
{
|
||||
|
@ -2471,6 +2510,8 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame
|
|||
SymbolEntry *entry;
|
||||
Address usepoint;
|
||||
|
||||
bool isindirect = (pieces.flags & ParameterPieces::indirectstorage) != 0;
|
||||
bool ishidden = (pieces.flags & ParameterPieces::hiddenretparm) != 0;
|
||||
if (res->sym != (Symbol *)0) {
|
||||
entry = res->sym->getFirstWholeMap();
|
||||
if ((entry->getAddr() != pieces.addr)||(entry->getSize() != pieces.type->getSize())) {
|
||||
|
@ -2483,18 +2524,24 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame
|
|||
usepoint = restricted_usepoint;
|
||||
res->sym = scope->addSymbol(nm,pieces.type,pieces.addr,usepoint)->getSymbol();
|
||||
scope->setCategory(res->sym,0,i);
|
||||
if ((pieces.flags & (Varnode::indirectstorage|Varnode::hiddenretparm)) != 0)
|
||||
scope->setAttribute(res->sym,pieces.flags & (Varnode::indirectstorage|Varnode::hiddenretparm));
|
||||
if (isindirect || ishidden) {
|
||||
uint4 mirror = 0;
|
||||
if (isindirect)
|
||||
mirror |= Varnode::indirectstorage;
|
||||
if (ishidden)
|
||||
mirror |= Varnode::hiddenretparm;
|
||||
scope->setAttribute(res->sym,mirror);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
if ((res->sym->getFlags() & Varnode::indirectstorage) != (pieces.flags & Varnode::indirectstorage)) {
|
||||
if ((pieces.flags & Varnode::indirectstorage)!=0)
|
||||
if (res->sym->isIndirectStorage() != isindirect) {
|
||||
if (isindirect)
|
||||
scope->setAttribute(res->sym,Varnode::indirectstorage);
|
||||
else
|
||||
scope->clearAttribute(res->sym,Varnode::indirectstorage);
|
||||
}
|
||||
if ((res->sym->getFlags() & Varnode::hiddenretparm) != (pieces.flags & Varnode::hiddenretparm)) {
|
||||
if ((pieces.flags & Varnode::hiddenretparm)!=0)
|
||||
if (res->sym->isHiddenReturn() != ishidden) {
|
||||
if (ishidden)
|
||||
scope->setAttribute(res->sym,Varnode::hiddenretparm);
|
||||
else
|
||||
scope->clearAttribute(res->sym,Varnode::hiddenretparm);
|
||||
|
@ -2737,6 +2784,8 @@ void ProtoStoreInternal::saveXml(ostream &s) const
|
|||
a_v_b(s,"typelock",true);
|
||||
if (param->isNameLocked())
|
||||
a_v_b(s,"namelock",true);
|
||||
if (param->isThisPointer())
|
||||
a_v_b(s,"thisptr",true);
|
||||
if (param->isIndirectStorage())
|
||||
a_v_b(s,"indirectstorage",true);
|
||||
if (param->isHiddenReturn())
|
||||
|
@ -2759,47 +2808,50 @@ void ProtoStoreInternal::restoreXml(const Element *el,ProtoModel *model)
|
|||
List::const_iterator iter;
|
||||
vector<ParameterPieces> pieces;
|
||||
vector<string> namelist;
|
||||
vector<bool> typelocklist;
|
||||
vector<bool> namelocklist;
|
||||
bool addressesdetermined = true;
|
||||
|
||||
pieces.push_back( ParameterPieces() ); // Push on placeholder for output pieces
|
||||
namelist.push_back("ret");
|
||||
typelocklist.push_back(outparam->isTypeLocked());
|
||||
namelocklist.push_back(false);
|
||||
pieces.back().type = outparam->getType();
|
||||
pieces.back().flags = 0;
|
||||
if (outparam->isTypeLocked())
|
||||
pieces.back().flags |= ParameterPieces::typelock;
|
||||
if (outparam->isIndirectStorage())
|
||||
pieces.back().flags |= Varnode::indirectstorage;
|
||||
pieces.back().flags |= ParameterPieces::indirectstorage;
|
||||
if (outparam->getAddress().isInvalid())
|
||||
addressesdetermined = false;
|
||||
|
||||
for(iter=list.begin();iter!=list.end();++iter) { // This is only the input params
|
||||
const Element *subel = *iter;
|
||||
string name;
|
||||
bool typelock = false;
|
||||
bool namelock = false;
|
||||
uint4 flags = 0;
|
||||
for(int4 i=0;i<subel->getNumAttributes();++i) {
|
||||
const string &attr( subel->getAttributeName(i) );
|
||||
if (attr == "name")
|
||||
name = subel->getAttributeValue(i);
|
||||
else if (attr == "typelock")
|
||||
typelock = xml_readbool(subel->getAttributeValue(i));
|
||||
else if (attr == "namelock")
|
||||
namelock = xml_readbool(subel->getAttributeValue(i));
|
||||
else if (attr == "typelock") {
|
||||
if (xml_readbool(subel->getAttributeValue(i)))
|
||||
flags |= ParameterPieces::typelock;
|
||||
}
|
||||
else if (attr == "namelock") {
|
||||
if (xml_readbool(subel->getAttributeValue(i)))
|
||||
flags |= ParameterPieces::namelock;
|
||||
}
|
||||
else if (attr == "thisptr") {
|
||||
if (xml_readbool(subel->getAttributeValue(i)))
|
||||
flags |= ParameterPieces::isthis;
|
||||
}
|
||||
else if (attr == "indirectstorage") {
|
||||
if (xml_readbool(subel->getAttributeValue(i)))
|
||||
flags |= Varnode::indirectstorage;
|
||||
flags |= ParameterPieces::indirectstorage;
|
||||
}
|
||||
else if (attr == "hiddenretparm") {
|
||||
if (xml_readbool(subel->getAttributeValue(i)))
|
||||
flags |= Varnode::hiddenretparm;
|
||||
flags |= ParameterPieces::hiddenretparm;
|
||||
}
|
||||
}
|
||||
namelist.push_back(name);
|
||||
typelocklist.push_back(typelock);
|
||||
namelocklist.push_back(namelock);
|
||||
if ((flags & ParameterPieces::hiddenretparm) == 0)
|
||||
namelist.push_back(name);
|
||||
pieces.push_back(ParameterPieces());
|
||||
ParameterPieces &curparam( pieces.back() );
|
||||
const List &sublist(subel->getChildren());
|
||||
|
@ -2811,8 +2863,6 @@ void ProtoStoreInternal::restoreXml(const Element *el,ProtoModel *model)
|
|||
curparam.flags = flags;
|
||||
if (curparam.addr.isInvalid())
|
||||
addressesdetermined = false;
|
||||
typelocklist.push_back(typelock);
|
||||
namelocklist.push_back(namelock);
|
||||
}
|
||||
ProtoParameter *curparam;
|
||||
if (!addressesdetermined) {
|
||||
|
@ -2821,28 +2871,53 @@ void ProtoStoreInternal::restoreXml(const Element *el,ProtoModel *model)
|
|||
vector<Datatype *> typelist;
|
||||
for(int4 i=0;i<pieces.size();++i) // Save off the restored types
|
||||
typelist.push_back( pieces[i].type );
|
||||
pieces.clear(); // throw out any other piece information
|
||||
model->assignParameterStorage(typelist,pieces,true);
|
||||
vector<ParameterPieces> addrPieces;
|
||||
model->assignParameterStorage(typelist,addrPieces,true);
|
||||
addrPieces.swap(pieces);
|
||||
uint4 k = 0;
|
||||
for(uint4 i=0;i<pieces.size();++i) {
|
||||
if ((pieces[i].flags & ParameterPieces::hiddenretparm)!=0)
|
||||
continue; // Increment i but not k
|
||||
pieces[i].flags = addrPieces[k].flags; // Use the original flags
|
||||
k = k + 1;
|
||||
}
|
||||
if (pieces[0].addr.isInvalid()) { // If could not get valid storage for output
|
||||
typelocklist[0] = false; // Treat as unlocked void
|
||||
pieces[0].flags &= ~((uint4)ParameterPieces::typelock); // Treat as unlocked void
|
||||
}
|
||||
curparam = setOutput(pieces[0]);
|
||||
curparam->setTypeLock(typelocklist[0]);
|
||||
curparam->setTypeLock((pieces[0].flags & ParameterPieces::typelock)!=0);
|
||||
}
|
||||
uint4 j=1;
|
||||
for(uint4 i=1;i<pieces.size();++i) {
|
||||
if ((pieces[i].flags&Varnode::hiddenretparm)!=0) {
|
||||
if ((pieces[i].flags&ParameterPieces::hiddenretparm)!=0) {
|
||||
curparam = setInput(i-1,"rethidden",pieces[i]);
|
||||
curparam->setTypeLock(typelocklist[0]); // Has output's typelock
|
||||
curparam->setTypeLock((pieces[0].flags & ParameterPieces::typelock)!=0); // Has output's typelock
|
||||
continue; // increment i but not j
|
||||
}
|
||||
curparam = setInput(i-1,namelist[j],pieces[i]);
|
||||
curparam->setTypeLock(typelocklist[j]);
|
||||
curparam->setNameLock(namelocklist[j]);
|
||||
curparam->setTypeLock((pieces[i].flags & ParameterPieces::typelock)!=0);
|
||||
curparam->setNameLock((pieces[i].flags & ParameterPieces::namelock)!=0);
|
||||
j = j + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// This is called after a new prototype is established (via restoreXml or updateAllTypes)
|
||||
/// It makes sure that if the ProtoModel calls for a "this" parameter, then the appropriate parameter
|
||||
/// is explicitly marked as the "this".
|
||||
void FuncProto::updateThisPointer(void)
|
||||
|
||||
{
|
||||
if (!model->hasThisPointer()) return;
|
||||
int4 numInputs = store->getNumInputs();
|
||||
if (numInputs == 0) return;
|
||||
ProtoParameter *param = store->getInput(0);
|
||||
if (param->isHiddenReturn()) {
|
||||
if (numInputs < 2) return;
|
||||
param = store->getInput(1);
|
||||
}
|
||||
param->setThisPointer(true);
|
||||
}
|
||||
|
||||
/// Prepend the indicated number of input parameters to \b this.
|
||||
/// The new parameters have a data-type of xunknown4. If they were
|
||||
/// originally locked, the existing parameters are preserved.
|
||||
|
@ -2893,7 +2968,7 @@ void FuncProto::paramShift(int4 paramshift)
|
|||
store->setOutput(pieces[0]);
|
||||
uint4 j=1;
|
||||
for(uint4 i=1;i<pieces.size();++i) {
|
||||
if ((pieces[i].flags & Varnode::hiddenretparm) != 0) {
|
||||
if ((pieces[i].flags & ParameterPieces::hiddenretparm) != 0) {
|
||||
store->setInput(i-1,"rethidden",pieces[i]);
|
||||
continue; // increment i but not j
|
||||
}
|
||||
|
@ -3219,6 +3294,7 @@ void FuncProto::updateInputTypes(Funcdata &data,const vector<Varnode *> &trialli
|
|||
}
|
||||
for(int4 i=0;i<triallist.size();++i)
|
||||
triallist[i]->clearMark();
|
||||
updateThisPointer();
|
||||
}
|
||||
|
||||
/// \brief Update input parameters based on Varnode trials, but do not store the data-type
|
||||
|
@ -3346,7 +3422,7 @@ void FuncProto::updateAllTypes(const vector<string> &namelist,const vector<Datat
|
|||
store->setOutput(pieces[0]);
|
||||
uint4 j=1;
|
||||
for(uint4 i=1;i<pieces.size();++i) {
|
||||
if ((pieces[i].flags & Varnode::hiddenretparm) != 0) {
|
||||
if ((pieces[i].flags & ParameterPieces::hiddenretparm) != 0) {
|
||||
store->setInput(i-1,"rethidden",pieces[i]);
|
||||
continue; // increment i but not j
|
||||
}
|
||||
|
@ -3357,6 +3433,7 @@ void FuncProto::updateAllTypes(const vector<string> &namelist,const vector<Datat
|
|||
catch(ParamUnassignedError &err) {
|
||||
flags |= error_inputparam;
|
||||
}
|
||||
updateThisPointer();
|
||||
}
|
||||
|
||||
/// \brief Calculate the effect \b this has an a given storage location
|
||||
|
@ -3591,7 +3668,7 @@ bool FuncProto::getBiggestContainedInputParam(const Address &loc,int4 size,Varno
|
|||
bool FuncProto::isCompatible(const FuncProto &op2) const
|
||||
|
||||
{
|
||||
if (model != op2.model) return false;
|
||||
if (!model->isCompatible(op2.model)) return false;
|
||||
if (op2.isOutputLocked()) {
|
||||
if (isOutputLocked()) {
|
||||
ProtoParameter *out1 = store->getOutput();
|
||||
|
@ -3939,7 +4016,7 @@ void FuncProto::restoreXml(const Element *el,Architecture *glb)
|
|||
if ((outparam->getType()->getMetatype()!=TYPE_VOID)&&outparam->getAddress().isInvalid()) {
|
||||
throw LowlevelError("<returnsym> tag must include a valid storage address");
|
||||
}
|
||||
|
||||
updateThisPointer();
|
||||
}
|
||||
|
||||
/// \brief Calculate the stack offset of \b this call site
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue