Attach handling of "this" to ProtoParameter

This commit is contained in:
caheckman 2020-07-24 15:31:08 -04:00
parent bcc0f7fe38
commit 004a99bb87
29 changed files with 338 additions and 149 deletions

View file

@ -984,6 +984,20 @@ void Architecture::parseDeadcodeDelay(const Element *el)
throw LowlevelError("Bad <deadcodedelay> tag"); throw LowlevelError("Bad <deadcodedelay> tag");
} }
/// Alter the range of addresses for which a pointer is allowed to be inferred.
void Architecture::parseInferPtrBounds(const Element *el)
{
const List &list(el->getChildren());
List::const_iterator iter;
for(iter=list.begin();iter!=list.end();++iter) {
const Element *subel = *iter;
Range range;
range.restoreXml(subel,this);
setInferPtrBounds(range);
}
}
/// Pull information from a \<funcptr> tag. Turn on alignment analysis of /// Pull information from a \<funcptr> tag. Turn on alignment analysis of
/// function pointers, some architectures have aligned function pointers /// function pointers, some architectures have aligned function pointers
/// and encode extra information in the unused bits. /// and encode extra information in the unused bits.
@ -1109,6 +1123,9 @@ void Architecture::parseProcessorConfig(DocumentStorage &store)
throw LowlevelError("Undefined space: "+spaceName); throw LowlevelError("Undefined space: "+spaceName);
setDefaultDataSpace(spc->getIndex()); setDefaultDataSpace(spc->getIndex());
} }
else if (elname == "inferptrbounds") {
parseInferPtrBounds(*iter);
}
else if (elname == "segmented_address") { else if (elname == "segmented_address") {
} }
else if (elname == "default_symbols") { else if (elname == "default_symbols") {
@ -1183,6 +1200,8 @@ void Architecture::parseCompilerConfig(DocumentStorage &store)
parseFuncPtrAlign(*iter); parseFuncPtrAlign(*iter);
else if (elname == "deadcodedelay") else if (elname == "deadcodedelay")
parseDeadcodeDelay(*iter); parseDeadcodeDelay(*iter);
else if (elname == "inferptrbounds")
parseInferPtrBounds(*iter);
} }
// <global> tags instantiate the base symbol table // <global> tags instantiate the base symbol table
// They need to know about all spaces, so it must come // They need to know about all spaces, so it must come

View file

@ -274,6 +274,7 @@ protected:
void parseLaneSizes(const Element *el); ///< Apply lane size configuration void parseLaneSizes(const Element *el); ///< Apply lane size configuration
void parseStackPointer(const Element *el); ///< Apply stack pointer configuration void parseStackPointer(const Element *el); ///< Apply stack pointer configuration
void parseDeadcodeDelay(const Element *el); ///< Apply dead-code delay configuration void parseDeadcodeDelay(const Element *el); ///< Apply dead-code delay configuration
void parseInferPtrBounds(const Element *el); ///< Apply pointer inference bounds
void parseFuncPtrAlign(const Element *el); ///< Apply function pointer alignment configuration void parseFuncPtrAlign(const Element *el); ///< Apply function pointer alignment configuration
void parseSpacebase(const Element *el); ///< Create an additional indexed space void parseSpacebase(const Element *el); ///< Create an additional indexed space
void parseNoHighPtr(const Element *el); ///< Apply memory alias configuration void parseNoHighPtr(const Element *el); ///< Apply memory alias configuration

View file

@ -1077,6 +1077,8 @@ SymbolEntry *ActionConstantPtr::isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op
// Make sure the constant is in the expected range for a pointer // Make sure the constant is in the expected range for a pointer
if (spc->getPointerLowerBound() > vn->getOffset()) if (spc->getPointerLowerBound() > vn->getOffset())
return (SymbolEntry *)0; return (SymbolEntry *)0;
if (spc->getPointerUpperBound() < vn->getOffset())
return (SymbolEntry *)0;
// Check if the constant looks like a single bit or mask // Check if the constant looks like a single bit or mask
if (bit_transitions(vn->getOffset(),vn->getSize()) < 3) if (bit_transitions(vn->getOffset(),vn->getSize()) < 3)
return (SymbolEntry *)0; return (SymbolEntry *)0;
@ -1205,7 +1207,6 @@ int4 ActionDeindirect::apply(Funcdata &data)
// We use isInputLocked as a test of whether the // We use isInputLocked as a test of whether the
// function pointer prototype has been applied before // function pointer prototype has been applied before
fc->forceSet(data,*fp); fc->forceSet(data,*fp);
data.updateOpFromSpec(fc);
count += 1; count += 1;
} }
} }
@ -2158,7 +2159,6 @@ int4 ActionDefaultParams::apply(Funcdata &data)
fc->setInternal(evalfp,data.getArch()->types->getTypeVoid()); fc->setInternal(evalfp,data.getArch()->types->getTypeVoid());
} }
fc->insertPcode(data); // Insert any necessary pcode fc->insertPcode(data); // Insert any necessary pcode
data.updateOpFromSpec(fc);
} }
return 0; // Indicate success return 0; // Indicate success
} }

View file

@ -37,8 +37,6 @@ void CPoolRecord::saveXml(ostream &s) const
a_v(s,"tag","classref"); a_v(s,"tag","classref");
else else
a_v(s,"tag","primitive"); a_v(s,"tag","primitive");
if (hasThisPointer())
a_v_b(s,"hasthis",true);
if (isConstructor()) if (isConstructor())
a_v_b(s,"constructor",true); a_v_b(s,"constructor",true);
if (isDestructor()) if (isDestructor())
@ -100,10 +98,6 @@ void CPoolRecord::restoreXml(const Element *el,TypeFactory &typegrp)
else if (tagstring == "classref") else if (tagstring == "classref")
tag = class_reference; tag = class_reference;
} }
else if (attr == "hasthis") {
if (xml_readbool(el->getAttributeValue(i)))
flags |= CPoolRecord::has_thisptr;
}
else if (attr == "constructor") { else if (attr == "constructor") {
if (xml_readbool(el->getAttributeValue(i))) if (xml_readbool(el->getAttributeValue(i)))
flags |= CPoolRecord::is_constructor; flags |= CPoolRecord::is_constructor;
@ -145,10 +139,9 @@ void CPoolRecord::restoreXml(const Element *el,TypeFactory &typegrp)
throw LowlevelError("Bad constant pool record: missing <data>"); throw LowlevelError("Bad constant pool record: missing <data>");
subel = *iter; subel = *iter;
if (flags != 0) { if (flags != 0) {
bool hasThisPtr = ((flags & has_thisptr)!=0);
bool isConstructor = ((flags & is_constructor)!=0); bool isConstructor = ((flags & is_constructor)!=0);
bool isDestructor = ((flags & is_destructor)!=0); bool isDestructor = ((flags & is_destructor)!=0);
type = typegrp.restoreXmlTypeWithCodeFlags(subel,hasThisPtr,isConstructor,isDestructor); type = typegrp.restoreXmlTypeWithCodeFlags(subel,isConstructor,isDestructor);
} }
else else
type = typegrp.restoreXmlType(subel); type = typegrp.restoreXmlType(subel);

View file

@ -55,9 +55,8 @@ public:
check_cast=7 ///< Pointer to object, new name in \b token, new data-type in \b type check_cast=7 ///< Pointer to object, new name in \b token, new data-type in \b type
}; };
enum { enum {
has_thisptr = 0x1, ///< Referenced method has a \b this pointer is_constructor = 0x1, ///< Referenced method is a constructor
is_constructor = 0x2, ///< Referenced method is a constructor is_destructor = 0x2 ///< Referenced method is a destructor
is_destructor = 0x4 ///< Referenced method is a destructor
}; };
private: private:
friend class ConstantPool; friend class ConstantPool;
@ -77,7 +76,6 @@ public:
int4 getByteDataLength(void) const { return byteDataLen; } ///< Number of bytes of string literal data int4 getByteDataLength(void) const { return byteDataLen; } ///< Number of bytes of string literal data
Datatype *getType(void) const { return type; } ///< Get the data-type associated with \b this Datatype *getType(void) const { return type; } ///< Get the data-type associated with \b this
uintb getValue(void) const { return value; } ///< Get the constant value associated with \b this uintb getValue(void) const { return value; } ///< Get the constant value associated with \b this
bool hasThisPointer(void) const { return ((flags & has_thisptr)!=0); } ///< Is object a method with a \b this pointer
bool isConstructor(void) const { return ((flags & is_constructor)!=0); } ///< Is object a constructor method bool isConstructor(void) const { return ((flags & is_constructor)!=0); } ///< Is object a constructor method
bool isDestructor(void) const { return ((flags & is_destructor)!=0); } ///< Is object a destructor method bool isDestructor(void) const { return ((flags & is_destructor)!=0); } ///< Is object a destructor method
void saveXml(ostream &s) const; ///< Save object to an XML stream void saveXml(ostream &s) const; ///< Save object to an XML stream

View file

@ -224,6 +224,16 @@ void Symbol::checkSizeTypeLock(void)
dispflags |= size_typelock; dispflags |= size_typelock;
} }
/// \param val is \b true if we are the "this" pointer
void Symbol::setThisPointer(bool val)
{
if (val)
dispflags |= is_this_ptr;
else
dispflags &= ~((uint4)is_this_ptr);
}
/// The name for a Symbol can be unspecified. See ScopeInternal::buildUndefinedName /// The name for a Symbol can be unspecified. See ScopeInternal::buildUndefinedName
/// \return \b true if the name of \b this is undefined /// \return \b true if the name of \b this is undefined
bool Symbol::isNameUndefined(void) const bool Symbol::isNameUndefined(void) const

View file

@ -173,6 +173,7 @@ protected:
virtual ~Symbol(void) {} ///< Destructor virtual ~Symbol(void) {} ///< Destructor
void setDisplayFormat(uint4 val); ///< Set the display format for \b this Symbol void setDisplayFormat(uint4 val); ///< Set the display format for \b this Symbol
void checkSizeTypeLock(void); ///< Calculate if \b size_typelock property is on void checkSizeTypeLock(void); ///< Calculate if \b size_typelock property is on
void setThisPointer(bool val); ///< Toggle whether \b this is the "this" pointer for a class method
public: public:
/// \brief Possible display (dispflag) properties for a Symbol /// \brief Possible display (dispflag) properties for a Symbol
enum { enum {
@ -701,6 +702,7 @@ public:
void saveXmlRecursive(ostream &s,bool onlyGlobal) const; ///< Save all contained scopes as an XML stream void saveXmlRecursive(ostream &s,bool onlyGlobal) const; ///< Save all contained scopes as an XML stream
void overrideSizeLockType(Symbol *sym,Datatype *ct); ///< Change the data-type of a Symbol that is \e sizelocked void overrideSizeLockType(Symbol *sym,Datatype *ct); ///< Change the data-type of a Symbol that is \e sizelocked
void resetSizeLockType(Symbol *sym); ///< Clear a Symbol's \e size-locked data-type void resetSizeLockType(Symbol *sym); ///< Clear a Symbol's \e size-locked data-type
void setThisPointer(Symbol *sym,bool val) { sym->setThisPointer(val); } ///< Toggle the given Symbol as the "this" pointer
bool isSubScope(const Scope *scp) const; ///< Is this a sub-scope of the given Scope bool isSubScope(const Scope *scp) const; ///< Is this a sub-scope of the given Scope
string getFullName(void) const; ///< Get the full name of \b this Scope string getFullName(void) const; ///< Get the full name of \b this Scope
void getNameSegments(vector<string> &vec) const; ///< Get the fullname of \b this in segments void getNameSegments(vector<string> &vec) const; ///< Get the fullname of \b this in segments

View file

@ -540,7 +540,7 @@ void ParamListStandard::assignMap(const vector<Datatype *> &proto,bool isinput,T
if (isinput) { if (isinput) {
if (res.size()==2) { // Check for hidden parameters defined by the output list 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().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()) if (res.back().addr.isInvalid())
throw ParamUnassignedError("Cannot assign parameter address for " + res.back().type->getName()); 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); Datatype *pointertp = typefactory.getTypePointer(pointersize,proto[i],wordsize);
res.back().addr = assignAddress(pointertp,status); res.back().addr = assignAddress(pointertp,status);
res.back().type = pointertp; res.back().type = pointertp;
res.back().flags = Varnode::indirectstorage; res.back().flags = ParameterPieces::indirectstorage;
} }
else else
res.back().addr = assignAddress(proto[i],status); 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()) if (res.back().addr.isInvalid())
throw ParamUnassignedError("Cannot assign return value as a pointer"); throw ParamUnassignedError("Cannot assign return value as a pointer");
res.back().type = pointertp; 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.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 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 // 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; glb = g;
input = (ParamList *)0; input = (ParamList *)0;
output = (ParamList *)0; output = (ParamList *)0;
compatModel = (const ProtoModel *)0;
extrapop=0; extrapop=0;
injectUponEntry = -1; injectUponEntry = -1;
injectUponReturn = -1; injectUponReturn = -1;
@ -1797,6 +1798,9 @@ ProtoModel::ProtoModel(const string &nm,const ProtoModel &op2)
stackgrowsnegative = op2.stackgrowsnegative; stackgrowsnegative = op2.stackgrowsnegative;
hasThis = op2.hasThis; hasThis = op2.hasThis;
isConstruct = op2.isConstruct; isConstruct = op2.isConstruct;
if (name == "__thiscall")
hasThis = true;
compatModel = &op2;
} }
ProtoModel::~ProtoModel(void) ProtoModel::~ProtoModel(void)
@ -1808,6 +1812,19 @@ ProtoModel::~ProtoModel(void)
delete output; 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 /// \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 /// 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) { if (val) {
flags |= Varnode::typelock; flags |= ParameterPieces::typelock;
if (type->getMetatype() == TYPE_UNKNOWN) // Check if we are locking TYPE_UNKNOWN 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 else
flags &= ~((uint4)(Varnode::typelock|Varnode::mark)); flags &= ~((uint4)(ParameterPieces::typelock|ParameterPieces::sizelock));
} }
void ParameterBasic::setNameLock(bool val) void ParameterBasic::setNameLock(bool val)
{ {
if (val) if (val)
flags |= Varnode::namelock; flags |= ParameterPieces::namelock;
else 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) void ParameterBasic::overrideSizeLockType(Datatype *ct)
@ -2352,6 +2378,12 @@ bool ParameterSymbol::isSizeTypeLocked(void) const
return sym->isSizeTypeLocked(); return sym->isSizeTypeLocked();
} }
bool ParameterSymbol::isThisPointer(void) const
{
return sym->isThisPointer();
}
bool ParameterSymbol::isIndirectStorage(void) const bool ParameterSymbol::isIndirectStorage(void) const
{ {
@ -2393,6 +2425,13 @@ void ParameterSymbol::setNameLock(bool val)
scope->clearAttribute(sym,Varnode::namelock); scope->clearAttribute(sym,Varnode::namelock);
} }
void ParameterSymbol::setThisPointer(bool val)
{
Scope *scope = sym->getScope();
scope->setThisPointer(sym, val);
}
void ParameterSymbol::overrideSizeLockType(Datatype *ct) void ParameterSymbol::overrideSizeLockType(Datatype *ct)
{ {
@ -2471,6 +2510,8 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame
SymbolEntry *entry; SymbolEntry *entry;
Address usepoint; Address usepoint;
bool isindirect = (pieces.flags & ParameterPieces::indirectstorage) != 0;
bool ishidden = (pieces.flags & ParameterPieces::hiddenretparm) != 0;
if (res->sym != (Symbol *)0) { if (res->sym != (Symbol *)0) {
entry = res->sym->getFirstWholeMap(); entry = res->sym->getFirstWholeMap();
if ((entry->getAddr() != pieces.addr)||(entry->getSize() != pieces.type->getSize())) { 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; usepoint = restricted_usepoint;
res->sym = scope->addSymbol(nm,pieces.type,pieces.addr,usepoint)->getSymbol(); res->sym = scope->addSymbol(nm,pieces.type,pieces.addr,usepoint)->getSymbol();
scope->setCategory(res->sym,0,i); scope->setCategory(res->sym,0,i);
if ((pieces.flags & (Varnode::indirectstorage|Varnode::hiddenretparm)) != 0) if (isindirect || ishidden) {
scope->setAttribute(res->sym,pieces.flags & (Varnode::indirectstorage|Varnode::hiddenretparm)); uint4 mirror = 0;
if (isindirect)
mirror |= Varnode::indirectstorage;
if (ishidden)
mirror |= Varnode::hiddenretparm;
scope->setAttribute(res->sym,mirror);
}
return res; return res;
} }
if ((res->sym->getFlags() & Varnode::indirectstorage) != (pieces.flags & Varnode::indirectstorage)) { if (res->sym->isIndirectStorage() != isindirect) {
if ((pieces.flags & Varnode::indirectstorage)!=0) if (isindirect)
scope->setAttribute(res->sym,Varnode::indirectstorage); scope->setAttribute(res->sym,Varnode::indirectstorage);
else else
scope->clearAttribute(res->sym,Varnode::indirectstorage); scope->clearAttribute(res->sym,Varnode::indirectstorage);
} }
if ((res->sym->getFlags() & Varnode::hiddenretparm) != (pieces.flags & Varnode::hiddenretparm)) { if (res->sym->isHiddenReturn() != ishidden) {
if ((pieces.flags & Varnode::hiddenretparm)!=0) if (ishidden)
scope->setAttribute(res->sym,Varnode::hiddenretparm); scope->setAttribute(res->sym,Varnode::hiddenretparm);
else else
scope->clearAttribute(res->sym,Varnode::hiddenretparm); scope->clearAttribute(res->sym,Varnode::hiddenretparm);
@ -2737,6 +2784,8 @@ void ProtoStoreInternal::saveXml(ostream &s) const
a_v_b(s,"typelock",true); a_v_b(s,"typelock",true);
if (param->isNameLocked()) if (param->isNameLocked())
a_v_b(s,"namelock",true); a_v_b(s,"namelock",true);
if (param->isThisPointer())
a_v_b(s,"thisptr",true);
if (param->isIndirectStorage()) if (param->isIndirectStorage())
a_v_b(s,"indirectstorage",true); a_v_b(s,"indirectstorage",true);
if (param->isHiddenReturn()) if (param->isHiddenReturn())
@ -2759,47 +2808,50 @@ void ProtoStoreInternal::restoreXml(const Element *el,ProtoModel *model)
List::const_iterator iter; List::const_iterator iter;
vector<ParameterPieces> pieces; vector<ParameterPieces> pieces;
vector<string> namelist; vector<string> namelist;
vector<bool> typelocklist;
vector<bool> namelocklist;
bool addressesdetermined = true; bool addressesdetermined = true;
pieces.push_back( ParameterPieces() ); // Push on placeholder for output pieces pieces.push_back( ParameterPieces() ); // Push on placeholder for output pieces
namelist.push_back("ret"); namelist.push_back("ret");
typelocklist.push_back(outparam->isTypeLocked());
namelocklist.push_back(false);
pieces.back().type = outparam->getType(); pieces.back().type = outparam->getType();
pieces.back().flags = 0; pieces.back().flags = 0;
if (outparam->isTypeLocked())
pieces.back().flags |= ParameterPieces::typelock;
if (outparam->isIndirectStorage()) if (outparam->isIndirectStorage())
pieces.back().flags |= Varnode::indirectstorage; pieces.back().flags |= ParameterPieces::indirectstorage;
if (outparam->getAddress().isInvalid()) if (outparam->getAddress().isInvalid())
addressesdetermined = false; addressesdetermined = false;
for(iter=list.begin();iter!=list.end();++iter) { // This is only the input params for(iter=list.begin();iter!=list.end();++iter) { // This is only the input params
const Element *subel = *iter; const Element *subel = *iter;
string name; string name;
bool typelock = false;
bool namelock = false;
uint4 flags = 0; uint4 flags = 0;
for(int4 i=0;i<subel->getNumAttributes();++i) { for(int4 i=0;i<subel->getNumAttributes();++i) {
const string &attr( subel->getAttributeName(i) ); const string &attr( subel->getAttributeName(i) );
if (attr == "name") if (attr == "name")
name = subel->getAttributeValue(i); name = subel->getAttributeValue(i);
else if (attr == "typelock") else if (attr == "typelock") {
typelock = xml_readbool(subel->getAttributeValue(i)); if (xml_readbool(subel->getAttributeValue(i)))
else if (attr == "namelock") flags |= ParameterPieces::typelock;
namelock = xml_readbool(subel->getAttributeValue(i)); }
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") { else if (attr == "indirectstorage") {
if (xml_readbool(subel->getAttributeValue(i))) if (xml_readbool(subel->getAttributeValue(i)))
flags |= Varnode::indirectstorage; flags |= ParameterPieces::indirectstorage;
} }
else if (attr == "hiddenretparm") { else if (attr == "hiddenretparm") {
if (xml_readbool(subel->getAttributeValue(i))) if (xml_readbool(subel->getAttributeValue(i)))
flags |= Varnode::hiddenretparm; flags |= ParameterPieces::hiddenretparm;
} }
} }
namelist.push_back(name); if ((flags & ParameterPieces::hiddenretparm) == 0)
typelocklist.push_back(typelock); namelist.push_back(name);
namelocklist.push_back(namelock);
pieces.push_back(ParameterPieces()); pieces.push_back(ParameterPieces());
ParameterPieces &curparam( pieces.back() ); ParameterPieces &curparam( pieces.back() );
const List &sublist(subel->getChildren()); const List &sublist(subel->getChildren());
@ -2811,8 +2863,6 @@ void ProtoStoreInternal::restoreXml(const Element *el,ProtoModel *model)
curparam.flags = flags; curparam.flags = flags;
if (curparam.addr.isInvalid()) if (curparam.addr.isInvalid())
addressesdetermined = false; addressesdetermined = false;
typelocklist.push_back(typelock);
namelocklist.push_back(namelock);
} }
ProtoParameter *curparam; ProtoParameter *curparam;
if (!addressesdetermined) { if (!addressesdetermined) {
@ -2821,28 +2871,53 @@ void ProtoStoreInternal::restoreXml(const Element *el,ProtoModel *model)
vector<Datatype *> typelist; vector<Datatype *> typelist;
for(int4 i=0;i<pieces.size();++i) // Save off the restored types for(int4 i=0;i<pieces.size();++i) // Save off the restored types
typelist.push_back( pieces[i].type ); typelist.push_back( pieces[i].type );
pieces.clear(); // throw out any other piece information vector<ParameterPieces> addrPieces;
model->assignParameterStorage(typelist,pieces,true); 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 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 = setOutput(pieces[0]);
curparam->setTypeLock(typelocklist[0]); curparam->setTypeLock((pieces[0].flags & ParameterPieces::typelock)!=0);
} }
uint4 j=1; uint4 j=1;
for(uint4 i=1;i<pieces.size();++i) { 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 = 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 continue; // increment i but not j
} }
curparam = setInput(i-1,namelist[j],pieces[i]); curparam = setInput(i-1,namelist[j],pieces[i]);
curparam->setTypeLock(typelocklist[j]); curparam->setTypeLock((pieces[i].flags & ParameterPieces::typelock)!=0);
curparam->setNameLock(namelocklist[j]); curparam->setNameLock((pieces[i].flags & ParameterPieces::namelock)!=0);
j = j + 1; 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. /// Prepend the indicated number of input parameters to \b this.
/// The new parameters have a data-type of xunknown4. If they were /// The new parameters have a data-type of xunknown4. If they were
/// originally locked, the existing parameters are preserved. /// originally locked, the existing parameters are preserved.
@ -2893,7 +2968,7 @@ void FuncProto::paramShift(int4 paramshift)
store->setOutput(pieces[0]); store->setOutput(pieces[0]);
uint4 j=1; uint4 j=1;
for(uint4 i=1;i<pieces.size();++i) { 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]); store->setInput(i-1,"rethidden",pieces[i]);
continue; // increment i but not j 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) for(int4 i=0;i<triallist.size();++i)
triallist[i]->clearMark(); triallist[i]->clearMark();
updateThisPointer();
} }
/// \brief Update input parameters based on Varnode trials, but do not store the data-type /// \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]); store->setOutput(pieces[0]);
uint4 j=1; uint4 j=1;
for(uint4 i=1;i<pieces.size();++i) { 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]); store->setInput(i-1,"rethidden",pieces[i]);
continue; // increment i but not j continue; // increment i but not j
} }
@ -3357,6 +3433,7 @@ void FuncProto::updateAllTypes(const vector<string> &namelist,const vector<Datat
catch(ParamUnassignedError &err) { catch(ParamUnassignedError &err) {
flags |= error_inputparam; flags |= error_inputparam;
} }
updateThisPointer();
} }
/// \brief Calculate the effect \b this has an a given storage location /// \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 bool FuncProto::isCompatible(const FuncProto &op2) const
{ {
if (model != op2.model) return false; if (!model->isCompatible(op2.model)) return false;
if (op2.isOutputLocked()) { if (op2.isOutputLocked()) {
if (isOutputLocked()) { if (isOutputLocked()) {
ProtoParameter *out1 = store->getOutput(); 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()) { if ((outparam->getType()->getMetatype()!=TYPE_VOID)&&outparam->getAddress().isInvalid()) {
throw LowlevelError("<returnsym> tag must include a valid storage address"); throw LowlevelError("<returnsym> tag must include a valid storage address");
} }
updateThisPointer();
} }
/// \brief Calculate the stack offset of \b this call site /// \brief Calculate the stack offset of \b this call site

View file

@ -292,6 +292,14 @@ public:
/// \brief Basic elements of a parameter: address, data-type, properties /// \brief Basic elements of a parameter: address, data-type, properties
struct ParameterPieces { struct ParameterPieces {
enum {
isthis = 1, ///< Parameter is "this" pointer
hiddenretparm = 2, ///< Parameter is hidden pointer to return value, mirrors Varnode::hiddenretparm
indirectstorage = 4, ///< Parameter is indirect pointer to true parameter, mirrors Varnode::indirectstorage
namelock = 8, ///< Parameter's name is locked, mirrors Varnode::namelock
typelock = 16, ///< Parameter's data-type is locked, mirrors Varnode::typelock
sizelock = 32 ///< Size of the parameter is locked (but not the data-type)
};
Address addr; ///< Storage address of the parameter Address addr; ///< Storage address of the parameter
Datatype *type; ///< The datatype of the parameter Datatype *type; ///< The datatype of the parameter
uint4 flags; ///< additional attributes of the parameter uint4 flags; ///< additional attributes of the parameter
@ -619,6 +627,7 @@ class ProtoModel {
int4 extrapop; ///< Extra bytes popped from stack int4 extrapop; ///< Extra bytes popped from stack
ParamList *input; ///< Resource model for input parameters ParamList *input; ///< Resource model for input parameters
ParamList *output; ///< Resource model for output parameters ParamList *output; ///< Resource model for output parameters
const ProtoModel *compatModel; ///< The model \b this is a copy of
vector<EffectRecord> effectlist; ///< List of side-effects vector<EffectRecord> effectlist; ///< List of side-effects
vector<VarnodeData> likelytrash; ///< Storage locations potentially carrying \e trash values vector<VarnodeData> likelytrash; ///< Storage locations potentially carrying \e trash values
int4 injectUponEntry; ///< Id of injection to perform at beginning of function (-1 means not used) int4 injectUponEntry; ///< Id of injection to perform at beginning of function (-1 means not used)
@ -645,6 +654,7 @@ public:
void setExtraPop(int4 ep) { extrapop = ep; } ///< Set the stack-pointer \e extrapop void setExtraPop(int4 ep) { extrapop = ep; } ///< Set the stack-pointer \e extrapop
int4 getInjectUponEntry(void) const { return injectUponEntry; } ///< Get the inject \e uponentry id int4 getInjectUponEntry(void) const { return injectUponEntry; } ///< Get the inject \e uponentry id
int4 getInjectUponReturn(void) const { return injectUponReturn; } ///< Get the inject \e uponreturn id int4 getInjectUponReturn(void) const { return injectUponReturn; } ///< Get the inject \e uponreturn id
bool isCompatible(const ProtoModel *op2) const; ///< Return \b true if other given model can be substituted for \b this
/// \brief Given a list of input \e trials, derive the most likely input prototype /// \brief Given a list of input \e trials, derive the most likely input prototype
/// ///
@ -911,11 +921,13 @@ public:
virtual bool isTypeLocked(void) const=0; ///< Is the parameter data-type locked virtual bool isTypeLocked(void) const=0; ///< Is the parameter data-type locked
virtual bool isNameLocked(void) const=0; ///< Is the parameter name locked virtual bool isNameLocked(void) const=0; ///< Is the parameter name locked
virtual bool isSizeTypeLocked(void) const=0; ///< Is the size of the parameter locked virtual bool isSizeTypeLocked(void) const=0; ///< Is the size of the parameter locked
virtual bool isThisPointer(void) const=0; ///< Is \b this the "this" pointer for a class method
virtual bool isIndirectStorage(void) const=0; ///< Is \b this really a pointer to the true parameter virtual bool isIndirectStorage(void) const=0; ///< Is \b this really a pointer to the true parameter
virtual bool isHiddenReturn(void) const=0; ///< Is \b this a pointer to storage for a return value virtual bool isHiddenReturn(void) const=0; ///< Is \b this a pointer to storage for a return value
virtual bool isNameUndefined(void) const=0; ///< Is the name of \b this parameter undefined virtual bool isNameUndefined(void) const=0; ///< Is the name of \b this parameter undefined
virtual void setTypeLock(bool val)=0; ///< Toggle the lock on the data-type virtual void setTypeLock(bool val)=0; ///< Toggle the lock on the data-type
virtual void setNameLock(bool val)=0; ///< Toggle the lock on the name virtual void setNameLock(bool val)=0; ///< Toggle the lock on the name
virtual void setThisPointer(bool val)=0; ///< Toggle whether \b this is the "this" pointer for a class method
/// \brief Change (override) the data-type of a \e size-locked parameter. /// \brief Change (override) the data-type of a \e size-locked parameter.
/// ///
@ -965,7 +977,7 @@ class ParameterBasic : public ProtoParameter {
string name; ///< The name of the parameter, "" for undefined or return value parameters string name; ///< The name of the parameter, "" for undefined or return value parameters
Address addr; ///< Storage address of the parameter Address addr; ///< Storage address of the parameter
Datatype *type; ///< Data-type of the parameter Datatype *type; ///< Data-type of the parameter
uint4 flags; ///< Lock properties. Varnode::mark is co-opted to hold the \e size-lock flag uint4 flags; ///< Lock and other properties from ParameterPieces flags
public: public:
ParameterBasic(const string &nm,const Address &ad,Datatype *tp,uint4 fl) { ParameterBasic(const string &nm,const Address &ad,Datatype *tp,uint4 fl) {
name = nm; addr = ad; type = tp; flags=fl; } ///< Construct from components name = nm; addr = ad; type = tp; flags=fl; } ///< Construct from components
@ -973,14 +985,16 @@ public:
virtual Datatype *getType(void) const { return type; } virtual Datatype *getType(void) const { return type; }
virtual Address getAddress(void) const { return addr; } virtual Address getAddress(void) const { return addr; }
virtual int4 getSize(void) const { return type->getSize(); } virtual int4 getSize(void) const { return type->getSize(); }
virtual bool isTypeLocked(void) const { return ((flags&Varnode::typelock)!=0); } virtual bool isTypeLocked(void) const { return ((flags&ParameterPieces::typelock)!=0); }
virtual bool isNameLocked(void) const { return ((flags&Varnode::namelock)!=0); } virtual bool isNameLocked(void) const { return ((flags&ParameterPieces::namelock)!=0); }
virtual bool isSizeTypeLocked(void) const { return ((flags&Varnode::mark)!=0); } virtual bool isSizeTypeLocked(void) const { return ((flags&ParameterPieces::sizelock)!=0); }
virtual bool isIndirectStorage(void) const { return ((flags&Varnode::indirectstorage)!=0); } virtual bool isThisPointer(void) const { return ((flags&ParameterPieces::isthis)!=0); }
virtual bool isHiddenReturn(void) const { return ((flags&Varnode::hiddenretparm)!=0); } virtual bool isIndirectStorage(void) const { return ((flags&ParameterPieces::indirectstorage)!=0); }
virtual bool isHiddenReturn(void) const { return ((flags&ParameterPieces::hiddenretparm)!=0); }
virtual bool isNameUndefined(void) const { return (name.size()==0); } virtual bool isNameUndefined(void) const { return (name.size()==0); }
virtual void setTypeLock(bool val); virtual void setTypeLock(bool val);
virtual void setNameLock(bool val); virtual void setNameLock(bool val);
virtual void setThisPointer(bool val);
virtual void overrideSizeLockType(Datatype *ct); virtual void overrideSizeLockType(Datatype *ct);
virtual void resetSizeLockType(TypeFactory *factory); virtual void resetSizeLockType(TypeFactory *factory);
virtual ProtoParameter *clone(void) const; virtual ProtoParameter *clone(void) const;
@ -1061,11 +1075,13 @@ public:
virtual bool isTypeLocked(void) const; virtual bool isTypeLocked(void) const;
virtual bool isNameLocked(void) const; virtual bool isNameLocked(void) const;
virtual bool isSizeTypeLocked(void) const; virtual bool isSizeTypeLocked(void) const;
virtual bool isThisPointer(void) const;
virtual bool isIndirectStorage(void) const; virtual bool isIndirectStorage(void) const;
virtual bool isHiddenReturn(void) const; virtual bool isHiddenReturn(void) const;
virtual bool isNameUndefined(void) const; virtual bool isNameUndefined(void) const;
virtual void setTypeLock(bool val); virtual void setTypeLock(bool val);
virtual void setNameLock(bool val); virtual void setNameLock(bool val);
virtual void setThisPointer(bool val);
virtual void overrideSizeLockType(Datatype *ct); virtual void overrideSizeLockType(Datatype *ct);
virtual void resetSizeLockType(TypeFactory *factory); virtual void resetSizeLockType(TypeFactory *factory);
virtual ProtoParameter *clone(void) const; virtual ProtoParameter *clone(void) const;
@ -1169,6 +1185,7 @@ class FuncProto {
vector<VarnodeData> likelytrash; ///< Locations that may contain \e trash values vector<VarnodeData> likelytrash; ///< Locations that may contain \e trash values
int4 injectid; ///< (If non-negative) id of p-code snippet that should replace this function int4 injectid; ///< (If non-negative) id of p-code snippet that should replace this function
int4 returnBytesConsumed; ///< Number of bytes of return value that are consumed by callers (0 = all bytes) int4 returnBytesConsumed; ///< Number of bytes of return value that are consumed by callers (0 = all bytes)
void updateThisPointer(void); ///< Make sure any "this" parameter is properly marked
protected: protected:
void paramShift(int4 paramshift); ///< Add parameters to the front of the input parameter list void paramShift(int4 paramshift); ///< Add parameters to the front of the input parameter list
bool isParamshiftApplied(void) const { return ((flags&paramshift_applied)!=0); } ///< Has a parameter shift been applied bool isParamshiftApplied(void) const { return ((flags&paramshift_applied)!=0); } ///< Has a parameter shift been applied
@ -1240,11 +1257,6 @@ public:
/// \brief Is \b this a prototype for a class method, taking a \e this pointer. /// \brief Is \b this a prototype for a class method, taking a \e this pointer.
bool hasThisPointer(void) const { return ((flags & has_thisptr)!=0); } bool hasThisPointer(void) const { return ((flags & has_thisptr)!=0); }
/// \brief Toggle the \e this-call setting for \b this prototype
///
/// \param val is \b true if \b this prototype uses a \e this pointer
void setThisPointer(bool val) { flags = val ? (flags|has_thisptr) : (flags & ~((uint4)has_thisptr)); }
/// \brief Is \b this prototype for a class constructor method /// \brief Is \b this prototype for a class constructor method
bool isConstructor(void) const { return ((flags & is_constructor)!=0); } bool isConstructor(void) const { return ((flags & is_constructor)!=0); }

View file

@ -421,29 +421,6 @@ FuncCallSpecs *Funcdata::getCallSpecs(const PcodeOp *op) const
return (FuncCallSpecs *)0; return (FuncCallSpecs *)0;
} }
/// \brief Update CALL PcodeOp properties based on its corresponding call specification
///
/// As call specifications for a particular call site are updated, this routine pushes
/// back properties to the particular CALL op that are relevant for analysis.
/// \param fc is the call specification
void Funcdata::updateOpFromSpec(FuncCallSpecs *fc)
{
PcodeOp *op = fc->getOp();
if (fc->isConstructor())
op->setAdditionalFlag(PcodeOp::is_constructor);
else
op->clearAdditionalFlag(PcodeOp::is_constructor);
if (fc->isDestructor())
op->setAdditionalFlag(PcodeOp::is_destructor);
else
op->clearAdditionalFlag(PcodeOp::is_destructor);
if (fc->hasThisPointer())
op->setAdditionalFlag(PcodeOp::has_thisptr);
else
op->clearAdditionalFlag(PcodeOp::has_thisptr);
}
/// \brief Compare call specification objects by call site address /// \brief Compare call specification objects by call site address
/// ///
/// \param a is the first call specification to compare /// \param a is the first call specification to compare

View file

@ -100,15 +100,12 @@ public:
indirect_store = 0x80000000 ///< CPUI_INDIRECT is caused by CPUI_STORE indirect_store = 0x80000000 ///< CPUI_INDIRECT is caused by CPUI_STORE
}; };
enum { enum {
has_thisptr = 0x1, ///< First parameter ( getIn(1) ) is a this pointer special_prop = 1, ///< Does some special form of datatype propagation
is_constructor = 0x2, ///< Op is call to a constructor special_print = 2, ///< Op is marked for special printing
is_destructor = 0x4, ///< Op is call to a destructor modified = 4, ///< This op has been modified by the current action
special_prop = 0x8, ///< Does some special form of datatype propagation warning = 8, ///< Warning has been generated for this op
special_print = 0x10, ///< Op is marked for special printing incidental_copy = 0x10, ///< Treat this as \e incidental for parameter recovery algorithms
modified = 0x20, ///< This op has been modified by the current action is_cpool_transformed = 0x20 ///< Have we checked for cpool transforms
warning = 0x40, ///< Warning has been generated for this op
incidental_copy = 0x80, ///< Treat this as \e incidental for parameter recovery algorithms
is_cpool_transformed = 0x100 ///< Have we checked for cpool transforms
}; };
private: private:
TypeOp *opcode; ///< Pointer to class providing behavioral details of the operation TypeOp *opcode; ///< Pointer to class providing behavioral details of the operation
@ -199,9 +196,6 @@ public:
bool isSplitting(void) const { return ((flags&PcodeOp::splittingbranch)!=0); } ///< Return \b true if this branch splits bool isSplitting(void) const { return ((flags&PcodeOp::splittingbranch)!=0); } ///< Return \b true if this branch splits
bool doesSpecialPropagation(void) const { return ((addlflags&PcodeOp::special_prop)!=0); } ///< Return \b true if this does datatype propagation bool doesSpecialPropagation(void) const { return ((addlflags&PcodeOp::special_prop)!=0); } ///< Return \b true if this does datatype propagation
bool doesSpecialPrinting(void) const { return ((addlflags&PcodeOp::special_print)!=0); } ///< Return \b true if this needs to special printing bool doesSpecialPrinting(void) const { return ((addlflags&PcodeOp::special_print)!=0); } ///< Return \b true if this needs to special printing
bool hasThisPointer(void) const { return ((addlflags&PcodeOp::has_thisptr)!=0); } ///< Return \b true if this is a call taking 'this' parameter
bool isConstructor(void) const { return ((addlflags&PcodeOp::is_constructor)!=0); } ///< Return \b true if this is call to a constructor
bool isDestructor(void) const { return ((addlflags&PcodeOp::is_destructor)!=0); } ///< Return \b true if this is call to a destructor
bool isIncidentalCopy(void) const { return ((addlflags&PcodeOp::incidental_copy)!=0); } ///< Return \b true if \b this COPY is \e incidental bool isIncidentalCopy(void) const { return ((addlflags&PcodeOp::incidental_copy)!=0); } ///< Return \b true if \b this COPY is \e incidental
/// \brief Return \b true if output is 1-bit boolean /// \brief Return \b true if output is 1-bit boolean
bool isCalculatedBool(void) const { return ((flags&(PcodeOp::calculated_bool|PcodeOp::booloutput))!=0); } bool isCalculatedBool(void) const { return ((flags&(PcodeOp::calculated_bool|PcodeOp::booloutput))!=0); }

View file

@ -510,8 +510,9 @@ void PrintC::opCall(const PcodeOp *op)
{ {
pushOp(&function_call,op); pushOp(&function_call,op);
const Varnode *callpoint = op->getIn(0); const Varnode *callpoint = op->getIn(0);
FuncCallSpecs *fc;
if (callpoint->getSpace()->getType()==IPTR_FSPEC) { if (callpoint->getSpace()->getType()==IPTR_FSPEC) {
FuncCallSpecs *fc = FuncCallSpecs::getFspecFromConst(callpoint->getAddr()); fc = FuncCallSpecs::getFspecFromConst(callpoint->getAddr());
if (fc->getName().size()==0) { if (fc->getName().size()==0) {
string name = genericFunctionName(fc->getEntryAddress()); string name = genericFunctionName(fc->getEntryAddress());
pushAtom(Atom(name,functoken,EmitXml::funcname_color,op,(const Funcdata *)0)); pushAtom(Atom(name,functoken,EmitXml::funcname_color,op,(const Funcdata *)0));
@ -527,14 +528,22 @@ void PrintC::opCall(const PcodeOp *op)
clear(); clear();
throw LowlevelError("Missing function callspec"); throw LowlevelError("Missing function callspec");
} }
int4 startparam = isSet(hide_thisparam) && op->hasThisPointer() ? 2 : 1; // TODO: Cannot hide "this" on a direct call until we print the whole
if (op->numInput() > startparam) { // thing with the proper C++ method invocation format. Otherwise the output
for(int4 i=startparam;i<op->numInput()-1;++i) // gives no indication of what object has a method being called.
// int4 skip = getHiddenThisSlot(op, fc);
int4 skip = -1;
int4 count = op->numInput() - 1; // Number of parameter expressions printed
count -= (skip < 0) ? 0 : 1; // Subtract one if "this" is hidden
if (count > 0) {
for(int4 i=0;i<count-1;++i)
pushOp(&comma,op); pushOp(&comma,op);
// implied vn's pushed on in reverse order for efficiency // implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied // see PrintLanguage::pushVnImplied
for(int4 i=op->numInput()-1;i>=startparam;--i) for(int4 i=op->numInput()-1;i>=1;--i) {
if (i == skip) continue;
pushVnImplied(op->getIn(i),op,mods); pushVnImplied(op->getIn(i),op,mods);
}
} }
else // Push empty token for void else // Push empty token for void
pushAtom(Atom("",blanktoken,EmitXml::no_color)); pushAtom(Atom("",blanktoken,EmitXml::no_color));
@ -545,18 +554,29 @@ void PrintC::opCallind(const PcodeOp *op)
{ {
pushOp(&function_call,op); pushOp(&function_call,op);
pushOp(&dereference,op); pushOp(&dereference,op);
// implied vn's pushed on in reverse order for efficiency const Funcdata *fd = op->getParent()->getFuncdata();
// see PrintLanguage::pushVnImplied FuncCallSpecs *fc = fd->getCallSpecs(op);
int4 startparam = isSet(hide_thisparam) && op->hasThisPointer() ? 2 : 1; if (fc == (FuncCallSpecs *)0)
if (op->numInput()>startparam + 1) { // Multiple parameters throw LowlevelError("Missing indirect function callspec");
int4 skip = getHiddenThisSlot(op, fc);
int4 count = op->numInput() - 1;
count -= (skip < 0) ? 0 : 1;
if (count > 1) { // Multiple parameters
pushVnImplied(op->getIn(0),op,mods); pushVnImplied(op->getIn(0),op,mods);
for(int4 i=startparam;i<op->numInput()-1;++i) for(int4 i=0;i<count-1;++i)
pushOp(&comma,op); pushOp(&comma,op);
for(int4 i=op->numInput()-1;i>=startparam;--i) // implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied
for(int4 i=op->numInput()-1;i>=1;--i) {
if (i == skip) continue;
pushVnImplied(op->getIn(i),op,mods); pushVnImplied(op->getIn(i),op,mods);
}
} }
else if (op->numInput()==startparam + 1) { // One parameter else if (count == 1) { // One parameter
pushVnImplied(op->getIn(startparam),op,mods); if (skip == 1)
pushVnImplied(op->getIn(2),op,mods);
else
pushVnImplied(op->getIn(1),op,mods);
pushVnImplied(op->getIn(0),op,mods); pushVnImplied(op->getIn(0),op,mods);
} }
else { // A void function else { // A void function
@ -1332,6 +1352,31 @@ bool PrintC::printCharacterConstant(ostream &s,const Address &addr,Datatype *cha
return true; return true;
} }
/// For the given CALL op, if a "this" pointer exists and needs to be hidden because
/// of the print configuration, return the Varnode slot corresponding to the "this".
/// Otherwise return -1.
/// \param op is the given CALL PcodeOp
/// \param fc is the function prototype corresponding to the CALL
/// \return the "this" Varnode slot or -1
int4 PrintC::getHiddenThisSlot(const PcodeOp *op,FuncProto *fc)
{
int4 numInput = op->numInput();
if (isSet(hide_thisparam) && fc->hasThisPointer()) {
for(int4 i=1;i<numInput-1;++i) {
ProtoParameter *param = fc->getParam(i-1);
if (param != (ProtoParameter *)0 && param->isThisPointer())
return i;
}
if (numInput >= 2) {
ProtoParameter *param = fc->getParam(numInput-2);
if (param != (ProtoParameter *)0 && param->isThisPointer())
return numInput - 1;
}
}
return -1;
}
void PrintC::resetDefaultsPrintC(void) void PrintC::resetDefaultsPrintC(void)
{ {
@ -1902,11 +1947,15 @@ void PrintC::emitPrototypeInputs(const FuncProto *proto)
if (sz == 0) if (sz == 0)
emit->print("void",EmitXml::keyword_color); emit->print("void",EmitXml::keyword_color);
else { else {
bool printComma = false;
for(int4 i=0;i<sz;++i) { for(int4 i=0;i<sz;++i) {
if (i!=0) if (printComma)
emit->print(","); emit->print(",");
ProtoParameter *param = proto->getParam(i); ProtoParameter *param = proto->getParam(i);
if (isSet(hide_thisparam) && param->isThisPointer())
continue;
Symbol *sym = param->getSymbol(); Symbol *sym = param->getSymbol();
printComma = true;
if (sym != (Symbol *)0) if (sym != (Symbol *)0)
emitVarDecl(sym); emitVarDecl(sym);
else { else {

View file

@ -161,6 +161,7 @@ protected:
void opTypeCast(const PcodeOp *op); ///< Push the given p-code op using type-cast syntax to the RPN stack void opTypeCast(const PcodeOp *op); ///< Push the given p-code op using type-cast syntax to the RPN stack
void opHiddenFunc(const PcodeOp *op); ///< Push the given p-code op as a hidden token void opHiddenFunc(const PcodeOp *op); ///< Push the given p-code op as a hidden token
bool printCharacterConstant(ostream &s,const Address &addr,Datatype *charType) const; bool printCharacterConstant(ostream &s,const Address &addr,Datatype *charType) const;
int4 getHiddenThisSlot(const PcodeOp *op,FuncProto *fc); ///< Get position of "this" pointer needing to be hidden
void resetDefaultsPrintC(void); ///< Set default values for options specific to PrintC void resetDefaultsPrintC(void); ///< Set default values for options specific to PrintC
virtual void pushConstant(uintb val,const Datatype *ct, virtual void pushConstant(uintb val,const Datatype *ct,
const Varnode *vn,const PcodeOp *op); const Varnode *vn,const PcodeOp *op);

View file

@ -39,7 +39,6 @@ PrintJava::PrintJava(Architecture *glb,const string &nm) : PrintC(glb,nm)
{ {
resetDefaultsPrintJava(); resetDefaultsPrintJava();
nullToken = "null"; // Java standard lower-case 'null' nullToken = "null"; // Java standard lower-case 'null'
mods |= hide_thisparam; // turn on hiding of 'this' parameter
if (castStrategy != (CastStrategy *)0) if (castStrategy != (CastStrategy *)0)
delete castStrategy; delete castStrategy;
@ -160,6 +159,7 @@ void PrintJava::resetDefaultsPrintJava(void)
{ {
option_NULL = true; // Automatically use 'null' token option_NULL = true; // Automatically use 'null' token
option_convention = false; // Automatically hide convention name option_convention = false; // Automatically hide convention name
mods |= hide_thisparam; // turn on hiding of 'this' parameter
} }
/// Assuming the given Varnode is a dereferenced pointer, determine whether /// Assuming the given Varnode is a dereferenced pointer, determine whether
@ -258,18 +258,29 @@ void PrintJava::opCallind(const PcodeOp *op)
{ {
pushOp(&function_call,op); pushOp(&function_call,op);
// implied vn's pushed on in reverse order for efficiency const Funcdata *fd = op->getParent()->getFuncdata();
// see PrintLanguage::pushVnImplied FuncCallSpecs *fc = fd->getCallSpecs(op);
int4 startparam = isSet(hide_thisparam) && op->hasThisPointer() ? 2 : 1; if (fc == (FuncCallSpecs *)0)
if (op->numInput()>startparam + 1) { // Multiple parameters throw LowlevelError("Missing indirect function callspec");
int4 skip = getHiddenThisSlot(op, fc);
int4 count = op->numInput() - 1;
count -= (skip < 0) ? 0 : 1;
if (count > 1) { // Multiple parameters
pushVnImplied(op->getIn(0),op,mods); pushVnImplied(op->getIn(0),op,mods);
for(int4 i=startparam;i<op->numInput()-1;++i) for(int4 i=0;i<count-1;++i)
pushOp(&comma,op); pushOp(&comma,op);
for(int4 i=op->numInput()-1;i>=startparam;--i) // implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied
for(int4 i=op->numInput()-1;i>=1;--i) {
if (i == skip) continue;
pushVnImplied(op->getIn(i),op,mods); pushVnImplied(op->getIn(i),op,mods);
}
} }
else if (op->numInput()==startparam + 1) { // One parameter else if (count == 1) { // One parameter
pushVnImplied(op->getIn(startparam),op,mods); if (skip == 1)
pushVnImplied(op->getIn(2),op,mods);
else
pushVnImplied(op->getIn(1),op,mods);
pushVnImplied(op->getIn(0),op,mods); pushVnImplied(op->getIn(0),op,mods);
} }
else { // A void function else { // A void function

View file

@ -24,6 +24,7 @@ void AddrSpace::calcScaleMask(void)
pointerLowerBound = (addressSize < 3) ? 0x100: 0x1000; pointerLowerBound = (addressSize < 3) ? 0x100: 0x1000;
highest = calc_mask(addressSize); // Maximum address highest = calc_mask(addressSize); // Maximum address
highest = highest * wordsize + (wordsize-1); // Maximum byte address highest = highest * wordsize + (wordsize-1); // Maximum byte address
pointerUpperBound = highest;
} }
/// Initialize an address space with its basic attributes /// Initialize an address space with its basic attributes

View file

@ -98,6 +98,7 @@ private:
uint4 flags; ///< Attributes of the space uint4 flags; ///< Attributes of the space
uintb highest; ///< Highest (byte) offset into this space uintb highest; ///< Highest (byte) offset into this space
uintb pointerLowerBound; ///< Offset below which we don't search for pointers uintb pointerLowerBound; ///< Offset below which we don't search for pointers
uintb pointerUpperBound; ///< Offset above which we don't search for pointers
char shortcut; ///< Shortcut character for printing char shortcut; ///< Shortcut character for printing
protected: protected:
string name; ///< Name of this space string name; ///< Name of this space
@ -127,6 +128,7 @@ public:
uint4 getAddrSize(void) const; ///< Get the size of the space uint4 getAddrSize(void) const; ///< Get the size of the space
uintb getHighest(void) const; ///< Get the highest byte-scaled address uintb getHighest(void) const; ///< Get the highest byte-scaled address
uintb getPointerLowerBound(void) const; ///< Get lower bound for assuming an offset is a pointer uintb getPointerLowerBound(void) const; ///< Get lower bound for assuming an offset is a pointer
uintb getPointerUpperBound(void) const; ///< Get upper bound for assuming an offset is a pointer
int4 getMinimumPtrSize(void) const; ///< Get the minimum pointer size for \b this space int4 getMinimumPtrSize(void) const; ///< Get the minimum pointer size for \b this space
uintb wrapOffset(uintb off) const; ///< Wrap -off- to the offset that fits into this space uintb wrapOffset(uintb off) const; ///< Wrap -off- to the offset that fits into this space
char getShortcut(void) const; ///< Get the shortcut character char getShortcut(void) const; ///< Get the shortcut character
@ -340,13 +342,20 @@ inline uintb AddrSpace::getHighest(void) const {
return highest; return highest;
} }
/// Constant offsets are tested against \b this bound as a quick filter before /// Constant offsets are tested against \b this lower bound as a quick filter before
/// attempting to lookup symbols. /// attempting to lookup symbols.
/// \return the minimum offset that will be inferred as a pointer /// \return the minimum offset that will be inferred as a pointer
inline uintb AddrSpace::getPointerLowerBound(void) const { inline uintb AddrSpace::getPointerLowerBound(void) const {
return pointerLowerBound; return pointerLowerBound;
} }
/// Constant offsets are tested against \b this upper bound as a quick filter before
/// attempting to lookup symbols.
/// \return the maximum offset that will be inferred as a pointer
inline uintb AddrSpace::getPointerUpperBound(void) const {
return pointerUpperBound;
}
/// A value of 0 means the size must match exactly. If the space is truncated, or /// A value of 0 means the size must match exactly. If the space is truncated, or
/// if there exists near pointers, this value may be non-zero. /// if there exists near pointers, this value may be non-zero.
inline int4 AddrSpace::getMinimumPtrSize(void) const { inline int4 AddrSpace::getMinimumPtrSize(void) const {

View file

@ -421,6 +421,16 @@ void AddrSpaceManager::insertResolver(AddrSpace *spc,AddressResolver *rsolv)
resolvelist[ind] = rsolv; resolvelist[ind] = rsolv;
} }
/// This method establishes for a single address space, what range of constants are checked
/// as possible symbol starts, when it is not known apriori that a constant is a pointer.
/// \param range is the range of values for a single address space
void AddrSpaceManager::setInferPtrBounds(const Range &range)
{
range.getSpace()->pointerLowerBound = range.getFirst();
range.getSpace()->pointerUpperBound = range.getLast();
}
/// Base destructor class, cleans up AddrSpace pointers which /// Base destructor class, cleans up AddrSpace pointers which
/// must be explicited created via \e new /// must be explicited created via \e new
AddrSpaceManager::~AddrSpaceManager(void) AddrSpaceManager::~AddrSpaceManager(void)

View file

@ -243,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
void setInferPtrBounds(const Range &range); ///< Set the range of addresses that can be inferred as pointers
JoinRecord *findJoinInternal(uintb offset) const; ///< Find JoinRecord for \e offset in the join 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

View file

@ -1153,13 +1153,11 @@ void TypeCode::printRaw(ostream &s) const
} }
/// Assuming \b this has an underlying function prototype, set some of its boolean properties /// Assuming \b this has an underlying function prototype, set some of its boolean properties
/// \param hasThisPtr toggles whether prototype has takes a "this" pointer
/// \param isConstructor toggles whether the function is a constructor /// \param isConstructor toggles whether the function is a constructor
/// \param isDestructor toggles whether the function is a destructor /// \param isDestructor toggles whether the function is a destructor
void TypeCode::setProperties(bool hasThisPtr,bool isConstructor,bool isDestructor) void TypeCode::setProperties(bool isConstructor,bool isDestructor)
{ {
proto->setThisPointer(hasThisPtr);
proto->setConstructor(isConstructor); proto->setConstructor(isConstructor);
proto->setDestructor(isDestructor); proto->setDestructor(isDestructor);
} }
@ -2201,11 +2199,10 @@ Datatype *TypeFactory::restoreXmlType(const Element *el)
/// ///
/// Kludge to get flags into code pointer types, when they can't come through XML /// Kludge to get flags into code pointer types, when they can't come through XML
/// \param el is the XML element describing the Datatype /// \param el is the XML element describing the Datatype
/// \param hasThisPtr toggles "this" pointer property on "function" datatypes
/// \param isConstructor toggles "constructor" property on "function" datatypes /// \param isConstructor toggles "constructor" property on "function" datatypes
/// \param isDestructor toggles "destructor" property on "function" datatypes /// \param isDestructor toggles "destructor" property on "function" datatypes
/// \return the restored Datatype object /// \return the restored Datatype object
Datatype *TypeFactory::restoreXmlTypeWithCodeFlags(const Element *el,bool hasThisPtr,bool isConstructor,bool isDestructor) Datatype *TypeFactory::restoreXmlTypeWithCodeFlags(const Element *el,bool isConstructor,bool isDestructor)
{ {
TypePointer tp; TypePointer tp;
@ -2226,8 +2223,8 @@ Datatype *TypeFactory::restoreXmlTypeWithCodeFlags(const Element *el,bool hasThi
throw LowlevelError("Special type restoreXml does not see code"); throw LowlevelError("Special type restoreXml does not see code");
TypeCode tc(""); TypeCode tc("");
tc.restoreXml(subel,*this); tc.restoreXml(subel,*this);
tc.setProperties(hasThisPtr,isConstructor,isDestructor); // Add in flags tc.setProperties(isConstructor,isDestructor); // Add in flags
tp.ptrto = findAdd(tc); // THEN add to container tp.ptrto = findAdd(tc); // THEN add to container
return findAdd(tp); return findAdd(tp);
} }

View file

@ -351,7 +351,7 @@ public:
TypeCode(const string &nm); ///< Construct from a name TypeCode(const string &nm); ///< Construct from a name
int4 compareBasic(const TypeCode *op) const; ///< Compare surface characteristics of two TypeCodes int4 compareBasic(const TypeCode *op) const; ///< Compare surface characteristics of two TypeCodes
const FuncProto *getPrototype(void) const { return proto; } ///< Get the function prototype const FuncProto *getPrototype(void) const { return proto; } ///< Get the function prototype
void setProperties(bool hasThisPtr,bool isConstructor,bool isDestructor); ///< Set additional function properties void setProperties(bool isConstructor,bool isDestructor); ///< Set additional function properties
virtual ~TypeCode(void); virtual ~TypeCode(void);
virtual void printRaw(ostream &s) const; virtual void printRaw(ostream &s) const;
virtual int4 compare(const Datatype &op,int4 level) const; virtual int4 compare(const Datatype &op,int4 level) const;
@ -432,7 +432,7 @@ public:
const vector<bool> &assignlist, const vector<bool> &assignlist,
TypeEnum *te); ///< Set named values for an enumeration TypeEnum *te); ///< Set named values for an enumeration
Datatype *restoreXmlType(const Element *el); ///< Restore Datatype from XML Datatype *restoreXmlType(const Element *el); ///< Restore Datatype from XML
Datatype *restoreXmlTypeWithCodeFlags(const Element *el,bool hasThisPtr,bool isConstructor,bool isDestructor); Datatype *restoreXmlTypeWithCodeFlags(const Element *el,bool isConstructor,bool isDestructor);
TypeVoid *getTypeVoid(void); ///< Get the "void" data-type TypeVoid *getTypeVoid(void); ///< Get the "void" data-type
Datatype *getBaseNoChar(int4 s,type_metatype m); ///< Get atomic type excluding "char" Datatype *getBaseNoChar(int4 s,type_metatype m); ///< Get atomic type excluding "char"
Datatype *getBase(int4 s,type_metatype m); ///< Get atomic type Datatype *getBase(int4 s,type_metatype m); ///< Get atomic type

View file

@ -29,7 +29,6 @@ src/main/java/ghidra/program/database/package.html||GHIDRA||||END|
src/main/java/ghidra/program/model/address/package.html||GHIDRA||||END| src/main/java/ghidra/program/model/address/package.html||GHIDRA||||END|
src/main/java/ghidra/program/model/block/package.html||GHIDRA||||END| src/main/java/ghidra/program/model/block/package.html||GHIDRA||||END|
src/main/java/ghidra/program/model/data/package.html||GHIDRA||||END| src/main/java/ghidra/program/model/data/package.html||GHIDRA||||END|
src/main/java/ghidra/program/model/graph/package.html||GHIDRA||||END|
src/main/java/ghidra/program/model/lang/package.html||GHIDRA||||END| src/main/java/ghidra/program/model/lang/package.html||GHIDRA||||END|
src/main/java/ghidra/program/model/listing/package.html||GHIDRA||||END| src/main/java/ghidra/program/model/listing/package.html||GHIDRA||||END|
src/main/java/ghidra/program/model/mem/package.html||GHIDRA||||END| src/main/java/ghidra/program/model/mem/package.html||GHIDRA||||END|

View file

@ -228,6 +228,14 @@
</element> </element>
</zeroOrMore> </zeroOrMore>
<zeroOrMore>
<element name="inferptrbounds">
<oneOrMore>
<ref name="range_type"/>
</oneOrMore>
</element>
</zeroOrMore>
<zeroOrMore> <zeroOrMore>
<ref name="segmentop_type"/> <ref name="segmentop_type"/>
</zeroOrMore> </zeroOrMore>

View file

@ -40,6 +40,14 @@
</element> </element>
</optional> </optional>
<zeroOrMore>
<element name="inferptrbounds">
<oneOrMore>
<ref name="range_type"/>
</oneOrMore>
</element>
</zeroOrMore>
<optional> <optional>
<element name="segmented_address"> <element name="segmented_address">
<attribute name="space"/> <attribute name="space"/>

View file

@ -653,7 +653,8 @@ public class SleighLanguage implements Language {
XmlElement element = parser.start("processor_spec"); XmlElement element = parser.start("processor_spec");
while (!parser.peek().isEnd()) { while (!parser.peek().isEnd()) {
element = parser.start("properties", "segmented_address", "segmentop", "programcounter", element = parser.start("properties", "segmented_address", "segmentop", "programcounter",
"data_space", "context_data", "volatile", "jumpassist", "incidentalcopy", "data_space", "inferptrbounds", "context_data", "volatile", "jumpassist",
"incidentalcopy",
"register_data", "default_symbols", "default_memory_blocks"); "register_data", "default_symbols", "default_memory_blocks");
if (element.getName().equals("properties")) { if (element.getName().equals("properties")) {
while (!parser.peek().isEnd()) { while (!parser.peek().isEnd()) {
@ -822,6 +823,11 @@ public class SleighLanguage implements Language {
parser.discardSubTree(); parser.discardSubTree();
} }
} }
else if (element.getName().equals("inferptrbounds")) {
while (parser.peek().isStart()) {
parser.discardSubTree();
}
}
else if (element.getName().equals("segmentop")) { else if (element.getName().equals("segmentop")) {
InjectPayloadSleigh payload = parseSegmentOp(element, parser); InjectPayloadSleigh payload = parseSegmentOp(element, parser);
addAdditionInject(payload); addAdditionInject(payload);

View file

@ -41,7 +41,6 @@ public abstract class ConstantPool {
public long value; // Primitive value of the object (if tag == PRIMITIVE) public long value; // Primitive value of the object (if tag == PRIMITIVE)
public byte[] byteData; public byte[] byteData;
public DataType type; public DataType type;
public boolean hasThisPtr = false;
public boolean isConstructor = false; public boolean isConstructor = false;
public StringBuilder build(long ref, PcodeDataTypeManager dtmanage) { public StringBuilder build(long ref, PcodeDataTypeManager dtmanage) {
@ -72,9 +71,6 @@ public abstract class ConstantPool {
else { else {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "primitive"); SpecXmlUtils.encodeStringAttribute(buf, "tag", "primitive");
} }
if (hasThisPtr) {
SpecXmlUtils.encodeBooleanAttribute(buf, "hasthis", true);
}
if (isConstructor) { if (isConstructor) {
SpecXmlUtils.encodeBooleanAttribute(buf, "constructor", true); SpecXmlUtils.encodeBooleanAttribute(buf, "constructor", true);
} }

View file

@ -13,6 +13,10 @@
<property key="pcodeInjectLibraryClass" value="ghidra.dalvik.dex.inject.PcodeInjectLibraryDex"/> <property key="pcodeInjectLibraryClass" value="ghidra.dalvik.dex.inject.PcodeInjectLibraryDex"/>
</properties> </properties>
<inferptrbounds>
<range space="ram" first="0" last="0"/> <!-- Don't try to infer pointers from constants in the body of a function -->
</inferptrbounds>
<jumpassist name="switchAssist"> <jumpassist name="switchAssist">
<case_pcode> <case_pcode>
<input name="index" size="4"/> <input name="index" size="4"/>

View file

@ -121,7 +121,8 @@ public class ConstantPoolDex extends ConstantPool {
String defName = res.token + '_' + Integer.toHexString(methodID); String defName = res.token + '_' + Integer.toHexString(methodID);
FunctionDefinitionDataType funcDef = new FunctionDefinitionDataType(defName, dtManager); FunctionDefinitionDataType funcDef = new FunctionDefinitionDataType(defName, dtManager);
res.type = new PointerDataType(funcDef); res.type = new PointerDataType(funcDef);
res.hasThisPtr = !isStatic; funcDef.setGenericCallingConvention(
isStatic ? GenericCallingConvention.stdcall : GenericCallingConvention.thiscall);
int prototypeIndex = methodIDItem.getProtoIndex() & 0xffff; int prototypeIndex = methodIDItem.getProtoIndex() & 0xffff;
PrototypesIDItem prototype = dexHeader.getPrototypes().get(prototypeIndex); PrototypesIDItem prototype = dexHeader.getPrototypes().get(prototypeIndex);

View file

@ -11,6 +11,11 @@
<register_data> <register_data>
<register name="SP" group="Alt"/> <register name="SP" group="Alt"/>
</register_data> </register_data>
<inferptrbounds>
<range space="ram" first="0" last="0"/> <!-- Don't try to infer pointers from constants in the body of a function -->
</inferptrbounds>
<jumpassist name="switchAssist"> <jumpassist name="switchAssist">
<!-- pcode to describe how to get case values from an index 0...size-1 --> <!-- pcode to describe how to get case values from an index 0...size-1 -->
<case_pcode> <case_pcode>

View file

@ -103,7 +103,7 @@ public class ConstantPoolJava extends ConstantPool {
new ParameterDefinitionImpl("", params.get(i), null); new ParameterDefinitionImpl("", params.get(i), null);
paramDefs[i] = currentParam; paramDefs[i] = currentParam;
} }
res.hasThisPtr = false; funcDef.setGenericCallingConvention(GenericCallingConvention.stdcall);
} }
//invokeinterface, invokespecial, and invokevirtual do have a this pointer //invokeinterface, invokespecial, and invokevirtual do have a this pointer
else { else {
@ -116,7 +116,7 @@ public class ConstantPoolJava extends ConstantPool {
new ParameterDefinitionImpl("", params.get(i - 1), null); new ParameterDefinitionImpl("", params.get(i - 1), null);
paramDefs[i] = currentParam; paramDefs[i] = currentParam;
} }
res.hasThisPtr = true; funcDef.setGenericCallingConvention(GenericCallingConvention.thiscall);
} }
funcDef.setArguments(paramDefs); funcDef.setArguments(paramDefs);
res.type = new PointerDataType(funcDef); res.type = new PointerDataType(funcDef);