mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +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
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ((flags & ParameterPieces::hiddenretparm) == 0)
|
||||||
namelist.push_back(name);
|
namelist.push_back(name);
|
||||||
typelocklist.push_back(typelock);
|
|
||||||
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
|
||||||
|
|
|
@ -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¶mshift_applied)!=0); } ///< Has a parameter shift been applied
|
bool isParamshiftApplied(void) const { return ((flags¶mshift_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); }
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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); }
|
||||||
|
|
|
@ -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,15 +528,23 @@ 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);
|
||||||
|
const Funcdata *fd = op->getParent()->getFuncdata();
|
||||||
|
FuncCallSpecs *fc = fd->getCallSpecs(op);
|
||||||
|
if (fc == (FuncCallSpecs *)0)
|
||||||
|
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);
|
||||||
|
for(int4 i=0;i<count-1;++i)
|
||||||
|
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
|
||||||
int4 startparam = isSet(hide_thisparam) && op->hasThisPointer() ? 2 : 1;
|
for(int4 i=op->numInput()-1;i>=1;--i) {
|
||||||
if (op->numInput()>startparam + 1) { // Multiple parameters
|
if (i == skip) continue;
|
||||||
pushVnImplied(op->getIn(0),op,mods);
|
|
||||||
for(int4 i=startparam;i<op->numInput()-1;++i)
|
|
||||||
pushOp(&comma,op);
|
|
||||||
for(int4 i=op->numInput()-1;i>=startparam;--i)
|
|
||||||
pushVnImplied(op->getIn(i),op,mods);
|
pushVnImplied(op->getIn(i),op,mods);
|
||||||
}
|
}
|
||||||
else if (op->numInput()==startparam + 1) { // One parameter
|
}
|
||||||
pushVnImplied(op->getIn(startparam),op,mods);
|
else if (count == 1) { // One parameter
|
||||||
|
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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
const Funcdata *fd = op->getParent()->getFuncdata();
|
||||||
|
FuncCallSpecs *fc = fd->getCallSpecs(op);
|
||||||
|
if (fc == (FuncCallSpecs *)0)
|
||||||
|
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);
|
||||||
|
for(int4 i=0;i<count-1;++i)
|
||||||
|
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
|
||||||
int4 startparam = isSet(hide_thisparam) && op->hasThisPointer() ? 2 : 1;
|
for(int4 i=op->numInput()-1;i>=1;--i) {
|
||||||
if (op->numInput()>startparam + 1) { // Multiple parameters
|
if (i == skip) continue;
|
||||||
pushVnImplied(op->getIn(0),op,mods);
|
|
||||||
for(int4 i=startparam;i<op->numInput()-1;++i)
|
|
||||||
pushOp(&comma,op);
|
|
||||||
for(int4 i=op->numInput()-1;i>=startparam;--i)
|
|
||||||
pushVnImplied(op->getIn(i),op,mods);
|
pushVnImplied(op->getIn(i),op,mods);
|
||||||
}
|
}
|
||||||
else if (op->numInput()==startparam + 1) { // One parameter
|
}
|
||||||
pushVnImplied(op->getIn(startparam),op,mods);
|
else if (count == 1) { // One parameter
|
||||||
|
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,7 +2223,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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"/>
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"/>
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue