Merge remote-tracking branch 'origin/caheckman_RenameRegParam'

This commit is contained in:
ghidravore 2020-08-03 13:53:52 -04:00
commit 513467b150
45 changed files with 641 additions and 318 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

@ -1254,12 +1254,13 @@ FlowBlock *BlockGraph::nextFlowAfter(const FlowBlock *bl) const
return nextbl; return nextbl;
} }
void BlockGraph::orderSwitchCases(void) const void BlockGraph::finalizePrinting(const Funcdata &data) const
{ {
// Recurse into all the substructures
vector<FlowBlock *>::const_iterator iter; vector<FlowBlock *>::const_iterator iter;
for(iter=list.begin();iter!=list.end();++iter) for(iter=list.begin();iter!=list.end();++iter)
(*iter)->orderSwitchCases(); (*iter)->finalizePrinting(data);
} }
void BlockGraph::saveXmlBody(ostream &s) const void BlockGraph::saveXmlBody(ostream &s) const
@ -3082,9 +3083,12 @@ void BlockSwitch::grabCaseBasic(FlowBlock *switchbl,const vector<FlowBlock *> &c
} }
} }
void BlockSwitch::orderSwitchCases(void) const void BlockSwitch::finalizePrinting(const Funcdata &data) const
{ {
BlockGraph::finalizePrinting(data); // Make sure to still recurse
// We need to order the cases based on the label
// First populate the label and depth fields of the CaseOrder objects
for(int4 i=0;i<caseblocks.size();++i) { // Construct the depth parameter, to sort fall-thru cases for(int4 i=0;i<caseblocks.size();++i) { // Construct the depth parameter, to sort fall-thru cases
CaseOrder &curcase( caseblocks[i] ); CaseOrder &curcase( caseblocks[i] );
int4 j = curcase.chain; int4 j = curcase.chain;
@ -3113,7 +3117,7 @@ void BlockSwitch::orderSwitchCases(void) const
else else
curcase.label = 0; // Should never happen curcase.label = 0; // Should never happen
} }
// Order case statements based on case labels // Do actual sort of the cases based on label
stable_sort(caseblocks.begin(),caseblocks.end(),CaseOrder::compare); stable_sort(caseblocks.begin(),caseblocks.end(),CaseOrder::compare);
} }

View file

@ -170,7 +170,7 @@ public:
virtual void flipInPlaceExecute(void); virtual void flipInPlaceExecute(void);
virtual bool isComplex(void) const { return true; } ///< Is \b this too complex to be a condition (BlockCondition) virtual bool isComplex(void) const { return true; } ///< Is \b this too complex to be a condition (BlockCondition)
virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const; virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const;
virtual void orderSwitchCases(void) const {} ///< Order \e case components of any contained BlockSwitch virtual void finalizePrinting(const Funcdata &data) const {} ///< Make any final configurations necessary to print the block
virtual void saveXmlHeader(ostream &s) const; ///< Save basic information as XML attributes virtual void saveXmlHeader(ostream &s) const; ///< Save basic information as XML attributes
virtual void restoreXmlHeader(const Element *el); ///< Restore basic information for XML attributes virtual void restoreXmlHeader(const Element *el); ///< Restore basic information for XML attributes
virtual void saveXmlBody(ostream &s) const {} ///< Save detail about components to an XML stream virtual void saveXmlBody(ostream &s) const {} ///< Save detail about components to an XML stream
@ -296,7 +296,7 @@ public:
virtual void printRaw(ostream &s) const; virtual void printRaw(ostream &s) const;
virtual void emit(PrintLanguage *lng) const { lng->emitBlockGraph(this); } virtual void emit(PrintLanguage *lng) const { lng->emitBlockGraph(this); }
virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const; virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const;
virtual void orderSwitchCases(void) const; virtual void finalizePrinting(const Funcdata &data) const;
virtual void saveXmlBody(ostream &s) const; virtual void saveXmlBody(ostream &s) const;
virtual void restoreXmlBody(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver); virtual void restoreXmlBody(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver);
void restoreXml(const Element *el,const AddrSpaceManager *m); ///< Restore \b this BlockGraph from an XML stream void restoreXml(const Element *el,const AddrSpaceManager *m); ///< Restore \b this BlockGraph from an XML stream
@ -674,7 +674,7 @@ public:
virtual void printHeader(ostream &s) const; virtual void printHeader(ostream &s) const;
virtual void emit(PrintLanguage *lng) const { lng->emitBlockSwitch(this); } virtual void emit(PrintLanguage *lng) const { lng->emitBlockSwitch(this); }
virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const; virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const;
virtual void orderSwitchCases(void) const; virtual void finalizePrinting(const Funcdata &data) const;
}; };
/// \brief Helper class for resolving cross-references while deserializing BlockGraph objects /// \brief Helper class for resolving cross-references while deserializing BlockGraph objects

View file

@ -2170,7 +2170,7 @@ int4 ActionFinalStructure::apply(Funcdata &data)
BlockGraph &graph(data.getStructure()); BlockGraph &graph(data.getStructure());
graph.orderBlocks(); graph.orderBlocks();
graph.orderSwitchCases(); graph.finalizePrinting(data);
graph.scopeBreak(-1,-1); // Put in \e break statements graph.scopeBreak(-1,-1); // Put in \e break statements
graph.markUnstructured(); // Put in \e gotos graph.markUnstructured(); // Put in \e gotos
graph.markLabelBumpUp(false); // Fix up labeling graph.markLabelBumpUp(false); // Fix up labeling

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
} }
@ -2289,6 +2289,16 @@ int4 ActionSetCasts::apply(Funcdata &data)
if ((ct->getMetatype() != TYPE_PTR)||(ct->getPtrTo()->getSize() != AddrSpace::addressToByteInt(sz, ct->getWordSize()))) if ((ct->getMetatype() != TYPE_PTR)||(ct->getPtrTo()->getSize() != AddrSpace::addressToByteInt(sz, ct->getWordSize())))
data.opUndoPtradd(op,true); data.opUndoPtradd(op,true);
} }
else if (opc == CPUI_PTRSUB) { // Check for PTRSUB that no longer fits pointer
if (!op->getIn(0)->getHigh()->getType()->isPtrsubMatching(op->getIn(1)->getOffset())) {
if (op->getIn(1)->getOffset() == 0) {
data.opRemoveInput(op, 1);
data.opSetOpcode(op, CPUI_COPY);
}
else
data.opSetOpcode(op, CPUI_INT_ADD);
}
}
for(int4 i=0;i<op->numInput();++i) // Do input casts first, as output may depend on input for(int4 i=0;i<op->numInput();++i) // Do input casts first, as output may depend on input
count += castInput(op,i,data,castStrategy); count += castInput(op,i,data,castStrategy);
if (opc == CPUI_LOAD) { if (opc == CPUI_LOAD) {
@ -4738,6 +4748,7 @@ int4 ActionInferTypes::apply(Funcdata &data)
} }
return 0; return 0;
} }
data.getScopeLocal()->applyTypeRecommendations();
buildLocaltypes(data); // Set up initial types (based on local info) buildLocaltypes(data); // Set up initial types (based on local info)
for(iter=data.beginLoc();iter!=data.endLoc();++iter) { for(iter=data.beginLoc();iter!=data.endLoc();++iter) {
vn = *iter; vn = *iter;

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
@ -362,6 +372,8 @@ void Symbol::saveXmlHeader(ostream &s) const
a_v_b(s,"hiddenretparm",true); a_v_b(s,"hiddenretparm",true);
if ((dispflags&isolate)!=0) if ((dispflags&isolate)!=0)
a_v_b(s,"merge",false); a_v_b(s,"merge",false);
if ((dispflags&is_this_ptr)!=0)
a_v_b(s,"thisptr",true);
int4 format = getDisplayFormat(); int4 format = getDisplayFormat();
if (format != 0) { if (format != 0) {
s << " format=\""; s << " format=\"";
@ -461,6 +473,10 @@ void Symbol::restoreXmlHeader(const Element *el)
if (xml_readbool(el->getAttributeValue(i))) if (xml_readbool(el->getAttributeValue(i)))
flags |= Varnode::typelock; flags |= Varnode::typelock;
} }
else if (attName == "thisptr") {
if (xml_readbool(el->getAttributeValue(i)))
dispflags |= is_this_ptr;
}
break; break;
case 'v': case 'v':
if (attName == "volatile") { if (attName == "volatile") {

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 {
@ -183,7 +184,8 @@ public:
force_char = 5, ///< Force integer to be printed as a character constant force_char = 5, ///< Force integer to be printed as a character constant
size_typelock = 8, ///< Only the size of the symbol is typelocked size_typelock = 8, ///< Only the size of the symbol is typelocked
isolate = 16, ///< Symbol should not speculatively merge automatically isolate = 16, ///< Symbol should not speculatively merge automatically
merge_problems = 32 ///< Set if some SymbolEntrys did not get merged merge_problems = 32, ///< Set if some SymbolEntrys did not get merged
is_this_ptr = 64 ///< We are the "this" symbol for a class method
}; };
Symbol(Scope *sc,const string &nm,Datatype *ct); ///< Construct given a name and data-type Symbol(Scope *sc,const string &nm,Datatype *ct); ///< Construct given a name and data-type
@ -198,6 +200,7 @@ public:
bool isTypeLocked(void) const { return ((flags&Varnode::typelock)!=0); } ///< Is the Symbol type-locked bool isTypeLocked(void) const { return ((flags&Varnode::typelock)!=0); } ///< Is the Symbol type-locked
bool isNameLocked(void) const { return ((flags&Varnode::namelock)!=0); } ///< Is the Symbol name-locked bool isNameLocked(void) const { return ((flags&Varnode::namelock)!=0); } ///< Is the Symbol name-locked
bool isSizeTypeLocked(void) const { return ((dispflags & size_typelock)!=0); } ///< Is the Symbol size type-locked bool isSizeTypeLocked(void) const { return ((dispflags & size_typelock)!=0); } ///< Is the Symbol size type-locked
bool isThisPointer(void) const { return ((dispflags & is_this_ptr)!=0); } ///< Is \b this the "this" pointer
bool isIndirectStorage(void) const { return ((flags&Varnode::indirectstorage)!=0); } ///< Is storage really a pointer to the true Symbol bool isIndirectStorage(void) const { return ((flags&Varnode::indirectstorage)!=0); } ///< Is storage really a pointer to the true Symbol
bool isHiddenReturn(void) const { return ((flags&Varnode::hiddenretparm)!=0); } ///< Is this a reference to the function return value bool isHiddenReturn(void) const { return ((flags&Varnode::hiddenretparm)!=0); } ///< Is this a reference to the function return value
bool isNameUndefined(void) const; ///< Does \b this have an undefined name bool isNameUndefined(void) const; ///< Does \b this have an undefined name
@ -699,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();
@ -3683,8 +3760,6 @@ void FuncProto::saveXml(ostream &s) const
a_v_b(s,"constructor",true); a_v_b(s,"constructor",true);
if (isDestructor()) if (isDestructor())
a_v_b(s,"destructor",true); a_v_b(s,"destructor",true);
if (hasThisPointer())
a_v_b(s,"hasthis",true);
s << ">\n"; s << ">\n";
ProtoParameter *outparam = store->getOutput(); ProtoParameter *outparam = store->getOutput();
s << " <returnsym"; s << " <returnsym";
@ -3828,10 +3903,6 @@ void FuncProto::restoreXml(const Element *el,Architecture *glb)
if (xml_readbool(el->getAttributeValue(i))) if (xml_readbool(el->getAttributeValue(i)))
flags |= is_destructor; flags |= is_destructor;
} }
else if (attrname == "hasthis") {
if (xml_readbool(el->getAttributeValue(i)))
flags |= has_thisptr;
}
} }
if (mod != (ProtoModel *)0) // If a model was specified if (mod != (ProtoModel *)0) // If a model was specified
setModel(mod); // This sets extrapop to model default setModel(mod); // This sets extrapop to model default
@ -3945,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

@ -87,6 +87,7 @@ class Funcdata {
// Low level Varnode functions // Low level Varnode functions
void setVarnodeProperties(Varnode *vn) const; ///< Look-up boolean properties and data-type information void setVarnodeProperties(Varnode *vn) const; ///< Look-up boolean properties and data-type information
HighVariable *assignHigh(Varnode *vn); ///< Assign a new HighVariable to a Varnode HighVariable *assignHigh(Varnode *vn); ///< Assign a new HighVariable to a Varnode
Symbol *handleSymbolConflict(SymbolEntry *entry,Varnode *vn); ///< Handle two variables with matching storage
bool syncVarnodesWithSymbol(VarnodeLocSet::const_iterator &iter,uint4 flags,Datatype *ct); bool syncVarnodesWithSymbol(VarnodeLocSet::const_iterator &iter,uint4 flags,Datatype *ct);
bool descend2Undef(Varnode *vn); ///< Transform all reads of the given Varnode to a special \b undefined constant bool descend2Undef(Varnode *vn); ///< Transform all reads of the given Varnode to a special \b undefined constant

View file

@ -866,6 +866,46 @@ bool Funcdata::syncVarnodesWithSymbols(const ScopeLocal *lm,bool typesyes)
return updateoccurred; return updateoccurred;
} }
/// A Varnode overlaps the given SymbolEntry. Make sure the Varnode is part of the variable
/// underlying the Symbol. If not, remap things so that the Varnode maps to a distinct Symbol.
/// In either case, attach the appropriate Symbol to the Varnode
/// \param entry is the given SymbolEntry
/// \param vn is the overlapping Varnode
/// \return the Symbol attached to the Varnode
Symbol *Funcdata::handleSymbolConflict(SymbolEntry *entry,Varnode *vn)
{
if (vn->isInput() || vn->isAddrTied() ||
vn->isPersist() || vn->isConstant() || entry->isDynamic()) {
vn->setSymbolEntry(entry);
return entry->getSymbol();
}
HighVariable *high = vn->getHigh();
Varnode *otherVn;
HighVariable *otherHigh = (HighVariable *)0;
// Look for a conflicting HighVariable
VarnodeLocSet::const_iterator iter = beginLoc(entry->getSize(),entry->getAddr());
while(iter != endLoc()) {
otherVn = *iter;
if (otherVn->getSize() != entry->getSize()) break;
if (otherVn->getAddr() != entry->getAddr()) break;
HighVariable *tmpHigh = otherVn->getHigh();
if (tmpHigh != high) {
otherHigh = tmpHigh;
break;
}
++iter;
}
if (otherHigh == (HighVariable *)0) {
vn->setSymbolEntry(entry);
return entry->getSymbol();
}
// If we reach here, we have a conflicting variable
buildDynamicSymbol(vn);
return vn->getSymbolEntry()->getSymbol();
}
/// \brief Update properties (and the data-type) for a set of Varnodes associated with one Symbol /// \brief Update properties (and the data-type) for a set of Varnodes associated with one Symbol
/// ///
/// The set of Varnodes with the same size and address all have their boolean properties /// The set of Varnodes with the same size and address all have their boolean properties
@ -994,8 +1034,7 @@ Symbol *Funcdata::linkSymbol(Varnode *vn)
// Find any entry overlapping base address // Find any entry overlapping base address
entry = localmap->queryProperties(vn->getAddr(), 1, usepoint, flags); entry = localmap->queryProperties(vn->getAddr(), 1, usepoint, flags);
if (entry != (SymbolEntry *) 0) { if (entry != (SymbolEntry *) 0) {
sym = entry->getSymbol(); sym = handleSymbolConflict(entry, vn);
vn->setSymbolEntry(entry);
} }
else { // Must create a symbol entry else { // Must create a symbol entry
if (!vn->isPersist()) { // Only create local symbol if (!vn->isPersist()) { // Only create local symbol

View file

@ -84,7 +84,7 @@ public:
unary = 0x8000, ///< Evaluate as unary expression unary = 0x8000, ///< Evaluate as unary expression
binary = 0x10000, ///< Evaluate as binary expression binary = 0x10000, ///< Evaluate as binary expression
special = 0x20000, ///< Cannot be evaluated (without special processing) special = 0x20000, ///< Cannot be evaluated (without special processing)
floatingpoint = 0x40000, ///< A floating point operation ternary = 0x40000, ///< Evaluate as ternary operator (or higher)
splittingbranch = 0x80000, ///< Dead edge cannot be removed as it splits splittingbranch = 0x80000, ///< Dead edge cannot be removed as it splits
nonprinting = 0x100000, ///< Op should not be directly printed as source nonprinting = 0x100000, ///< Op should not be directly printed as source
halt = 0x200000, ///< instruction causes processor or process to halt halt = 0x200000, ///< instruction causes processor or process to halt
@ -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
@ -158,7 +155,7 @@ public:
int4 getSlot(const Varnode *vn) const { int4 i,n; n=inrefs.size(); for(i=0;i<n;++i) if (inrefs[i]==vn) break; return i; } int4 getSlot(const Varnode *vn) const { int4 i,n; n=inrefs.size(); for(i=0;i<n;++i) if (inrefs[i]==vn) break; return i; }
int4 getRepeatSlot(const Varnode *vn,int4 firstSlot,list<PcodeOp *>::const_iterator iter) const; int4 getRepeatSlot(const Varnode *vn,int4 firstSlot,list<PcodeOp *>::const_iterator iter) const;
/// \brief Get the evaluation type of this op /// \brief Get the evaluation type of this op
uint4 getEvalType(void) const { return (flags&(PcodeOp::unary|PcodeOp::binary|PcodeOp::special)); } uint4 getEvalType(void) const { return (flags&(PcodeOp::unary|PcodeOp::binary|PcodeOp::special|PcodeOp::ternary)); }
/// \brief Get type which indicates unusual halt in control-flow /// \brief Get type which indicates unusual halt in control-flow
uint4 getHaltType(void) const { return (flags&(PcodeOp::halt|PcodeOp::badinstruction|PcodeOp::unimplemented| uint4 getHaltType(void) const { return (flags&(PcodeOp::halt|PcodeOp::badinstruction|PcodeOp::unimplemented|
PcodeOp::noreturn|PcodeOp::missing)); } PcodeOp::noreturn|PcodeOp::missing)); }
@ -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

@ -73,8 +73,8 @@ void OpBehavior::registerInstructions(vector<OpBehavior *> &inst,const Translate
inst[CPUI_BOOL_OR] = new OpBehaviorBoolOr(); inst[CPUI_BOOL_OR] = new OpBehaviorBoolOr();
inst[CPUI_CAST] = new OpBehavior(CPUI_CAST,false,true); inst[CPUI_CAST] = new OpBehavior(CPUI_CAST,false,true);
inst[CPUI_PTRADD] = new OpBehavior(CPUI_PTRADD,false,true); inst[CPUI_PTRADD] = new OpBehavior(CPUI_PTRADD,false);
inst[CPUI_PTRSUB] = new OpBehavior(CPUI_PTRSUB,false,true); inst[CPUI_PTRSUB] = new OpBehavior(CPUI_PTRSUB,false);
inst[CPUI_FLOAT_EQUAL] = new OpBehaviorFloatEqual(trans); inst[CPUI_FLOAT_EQUAL] = new OpBehaviorFloatEqual(trans);
inst[CPUI_FLOAT_NOTEQUAL] = new OpBehaviorFloatNotEqual(trans); inst[CPUI_FLOAT_NOTEQUAL] = new OpBehaviorFloatNotEqual(trans);
@ -99,8 +99,8 @@ void OpBehavior::registerInstructions(vector<OpBehavior *> &inst,const Translate
inst[CPUI_SEGMENTOP] = new OpBehavior(CPUI_SEGMENTOP,false,true); inst[CPUI_SEGMENTOP] = new OpBehavior(CPUI_SEGMENTOP,false,true);
inst[CPUI_CPOOLREF] = new OpBehavior(CPUI_CPOOLREF,false,true); inst[CPUI_CPOOLREF] = new OpBehavior(CPUI_CPOOLREF,false,true);
inst[CPUI_NEW] = new OpBehavior(CPUI_NEW,false,true); inst[CPUI_NEW] = new OpBehavior(CPUI_NEW,false,true);
inst[CPUI_INSERT] = new OpBehavior(CPUI_INSERT,false,true); inst[CPUI_INSERT] = new OpBehavior(CPUI_INSERT,false);
inst[CPUI_EXTRACT] = new OpBehavior(CPUI_EXTRACT,false,true); inst[CPUI_EXTRACT] = new OpBehavior(CPUI_EXTRACT,false);
inst[CPUI_POPCOUNT] = new OpBehaviorPopcount(); inst[CPUI_POPCOUNT] = new OpBehaviorPopcount();
} }

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

@ -37,15 +37,21 @@ PrintLanguage *PrintJavaCapability::buildLanguage(Architecture *glb)
PrintJava::PrintJava(Architecture *glb,const string &nm) : PrintC(glb,nm) PrintJava::PrintJava(Architecture *glb,const string &nm) : PrintC(glb,nm)
{ {
option_NULL = true; // Automatically use 'null' token 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;
castStrategy = new CastStrategyJava(); castStrategy = new CastStrategyJava();
} }
void PrintJava::resetDefaults(void)
{
PrintC::resetDefaults();
resetDefaultsPrintJava();
}
void PrintJava::docFunction(const Funcdata *fd) void PrintJava::docFunction(const Funcdata *fd)
{ {
@ -148,6 +154,14 @@ bool PrintJava::isArrayType(const Datatype *ct)
return false; return false;
} }
void PrintJava::resetDefaultsPrintJava(void)
{
option_NULL = true; // Automatically use 'null' token
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
/// it needs to be represented using '[0]' syntax. /// it needs to be represented using '[0]' syntax.
/// \param vn is the given Varnode /// \param vn is the given Varnode
@ -244,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

@ -56,9 +56,11 @@ class PrintJava : public PrintC {
static OpToken instanceof; ///< The \b instanceof keyword static OpToken instanceof; ///< The \b instanceof keyword
static bool isArrayType(const Datatype *ct); ///< Does the given data-type reference a java array static bool isArrayType(const Datatype *ct); ///< Does the given data-type reference a java array
static bool needZeroArray(const Varnode *vn); ///< Do we need '[0]' syntax. static bool needZeroArray(const Varnode *vn); ///< Do we need '[0]' syntax.
void resetDefaultsPrintJava(void); ///< Set options that are specific to Java
virtual void printUnicode(ostream &s,int4 onechar) const; virtual void printUnicode(ostream &s,int4 onechar) const;
public: public:
PrintJava(Architecture *g,const string &nm="java-language"); ///< Constructor PrintJava(Architecture *g,const string &nm="java-language"); ///< Constructor
virtual void resetDefaults(void);
virtual void docFunction(const Funcdata *fd); virtual void docFunction(const Funcdata *fd);
virtual void pushTypeStart(const Datatype *ct,bool noident); virtual void pushTypeStart(const Datatype *ct,bool noident);
virtual void pushTypeEnd(const Datatype *ct); virtual void pushTypeEnd(const Datatype *ct);

View file

@ -6363,30 +6363,8 @@ int4 RulePtrsubUndo::applyOp(PcodeOp *op,Funcdata &data)
if (!data.isTypeRecoveryOn()) return 0; if (!data.isTypeRecoveryOn()) return 0;
Varnode *basevn = op->getIn(0); Varnode *basevn = op->getIn(0);
TypePointer *ct = (TypePointer *)basevn->getType(); if (basevn->getType()->isPtrsubMatching(op->getIn(1)->getOffset()))
bool undo = false; return 0;
if (ct->getMetatype()!=TYPE_PTR)
undo = true;
else {
Datatype *basetype = ct->getPtrTo();
if (basetype->getMetatype()==TYPE_SPACEBASE) {
uintb newoff = AddrSpace::addressToByte(op->getIn(1)->getOffset(),ct->getWordSize());
basetype->getSubType(newoff,&newoff);
if (newoff != 0)
undo = true;
}
else {
int4 size = op->getIn(1)->getOffset();
int4 typesize = basetype->getSize();
if ((basetype->getMetatype()!=TYPE_ARRAY)&&(basetype->getMetatype()!=TYPE_STRUCT))
undo = true; // Not a pointer to a structured type
else if ((typesize <= AddrSpace::addressToByteInt(size,ct->getWordSize()))&&(typesize!=0))
undo = true;
}
}
if (!undo) return 0;
data.opSetOpcode(op,CPUI_INT_ADD); data.opSetOpcode(op,CPUI_INT_ADD);
return 1; return 1;

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

@ -316,6 +316,35 @@ void Datatype::saveXmlRef(ostream &s) const
saveXml(s); saveXml(s);
} }
/// A CPUI_PTRSUB must act on a pointer data-type where the given offset addresses a component.
/// Perform this check.
/// \param is the given offset
/// \return \b true if \b this is a suitable PTRSUB data-type
bool Datatype::isPtrsubMatching(uintb offset) const
{
if (metatype != TYPE_PTR)
return false;
Datatype *basetype = ((TypePointer *)this)->getPtrTo();
uint4 wordsize = ((TypePointer *)this)->getWordSize();
if (basetype->metatype==TYPE_SPACEBASE) {
uintb newoff = AddrSpace::addressToByte(offset,wordsize);
basetype->getSubType(newoff,&newoff);
if (newoff != 0)
return false;
}
else {
int4 size = offset;
int4 typesize = basetype->getSize();
if ((basetype->metatype != TYPE_ARRAY)&&(basetype->metatype != TYPE_STRUCT))
return false; // Not a pointer to a structured type
else if ((typesize <= AddrSpace::addressToByteInt(size,wordsize))&&(typesize!=0))
return false;
}
return true;
}
/// Restore the basic properties (name,size,id) of a data-type from an XML element /// Restore the basic properties (name,size,id) of a data-type from an XML element
/// Properties are read from the attributes of the element /// Properties are read from the attributes of the element
/// \param el is the XML element /// \param el is the XML element
@ -1124,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);
} }
@ -2172,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;
@ -2197,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

@ -126,6 +126,7 @@ public:
int4 typeOrderBool(const Datatype &op) const; ///< Order \b this with -op-, treating \e bool data-type as special int4 typeOrderBool(const Datatype &op) const; ///< Order \b this with -op-, treating \e bool data-type as special
void saveXmlBasic(ostream &s) const; ///< Save basic data-type properties void saveXmlBasic(ostream &s) const; ///< Save basic data-type properties
void saveXmlRef(ostream &s) const; ///< Write an XML reference of \b this to stream void saveXmlRef(ostream &s) const; ///< Write an XML reference of \b this to stream
bool isPtrsubMatching(uintb offset) const; ///< Is this data-type suitable as input to a CPUI_PTRSUB op
}; };
/// \brief Specifies subfields of a structure or what a pointer points to /// \brief Specifies subfields of a structure or what a pointer points to
@ -350,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;
@ -431,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

@ -1356,126 +1356,126 @@ TypeOpBoolOr::TypeOpBoolOr(TypeFactory *t)
TypeOpFloatEqual::TypeOpFloatEqual(TypeFactory *t,const Translate *trans) TypeOpFloatEqual::TypeOpFloatEqual(TypeFactory *t,const Translate *trans)
: TypeOpBinary(t,CPUI_FLOAT_EQUAL,"==",TYPE_BOOL,TYPE_FLOAT) : TypeOpBinary(t,CPUI_FLOAT_EQUAL,"==",TYPE_BOOL,TYPE_FLOAT)
{ {
opflags = PcodeOp::binary | PcodeOp::booloutput | PcodeOp::commutative | PcodeOp::floatingpoint; opflags = PcodeOp::binary | PcodeOp::booloutput | PcodeOp::commutative;
behave = new OpBehaviorFloatEqual(trans); behave = new OpBehaviorFloatEqual(trans);
} }
TypeOpFloatNotEqual::TypeOpFloatNotEqual(TypeFactory *t,const Translate *trans) TypeOpFloatNotEqual::TypeOpFloatNotEqual(TypeFactory *t,const Translate *trans)
: TypeOpBinary(t,CPUI_FLOAT_NOTEQUAL,"!=",TYPE_BOOL,TYPE_FLOAT) : TypeOpBinary(t,CPUI_FLOAT_NOTEQUAL,"!=",TYPE_BOOL,TYPE_FLOAT)
{ {
opflags = PcodeOp::binary | PcodeOp::booloutput | PcodeOp::commutative | PcodeOp::floatingpoint; opflags = PcodeOp::binary | PcodeOp::booloutput | PcodeOp::commutative;
behave = new OpBehaviorFloatNotEqual(trans); behave = new OpBehaviorFloatNotEqual(trans);
} }
TypeOpFloatLess::TypeOpFloatLess(TypeFactory *t,const Translate *trans) TypeOpFloatLess::TypeOpFloatLess(TypeFactory *t,const Translate *trans)
: TypeOpBinary(t,CPUI_FLOAT_LESS,"<",TYPE_BOOL,TYPE_FLOAT) : TypeOpBinary(t,CPUI_FLOAT_LESS,"<",TYPE_BOOL,TYPE_FLOAT)
{ {
opflags = PcodeOp::binary | PcodeOp::booloutput | PcodeOp::floatingpoint; opflags = PcodeOp::binary | PcodeOp::booloutput;
behave = new OpBehaviorFloatLess(trans); behave = new OpBehaviorFloatLess(trans);
} }
TypeOpFloatLessEqual::TypeOpFloatLessEqual(TypeFactory *t,const Translate *trans) TypeOpFloatLessEqual::TypeOpFloatLessEqual(TypeFactory *t,const Translate *trans)
: TypeOpBinary(t,CPUI_FLOAT_LESSEQUAL,"<=",TYPE_BOOL,TYPE_FLOAT) : TypeOpBinary(t,CPUI_FLOAT_LESSEQUAL,"<=",TYPE_BOOL,TYPE_FLOAT)
{ {
opflags = PcodeOp::binary | PcodeOp::booloutput | PcodeOp::floatingpoint; opflags = PcodeOp::binary | PcodeOp::booloutput;
behave = new OpBehaviorFloatLessEqual(trans); behave = new OpBehaviorFloatLessEqual(trans);
} }
TypeOpFloatNan::TypeOpFloatNan(TypeFactory *t,const Translate *trans) TypeOpFloatNan::TypeOpFloatNan(TypeFactory *t,const Translate *trans)
: TypeOpFunc(t,CPUI_FLOAT_NAN,"NAN",TYPE_BOOL,TYPE_FLOAT) : TypeOpFunc(t,CPUI_FLOAT_NAN,"NAN",TYPE_BOOL,TYPE_FLOAT)
{ {
opflags = PcodeOp::unary | PcodeOp::booloutput | PcodeOp::floatingpoint; opflags = PcodeOp::unary | PcodeOp::booloutput;
behave = new OpBehaviorFloatNan(trans); behave = new OpBehaviorFloatNan(trans);
} }
TypeOpFloatAdd::TypeOpFloatAdd(TypeFactory *t,const Translate *trans) TypeOpFloatAdd::TypeOpFloatAdd(TypeFactory *t,const Translate *trans)
: TypeOpBinary(t,CPUI_FLOAT_ADD,"+",TYPE_FLOAT,TYPE_FLOAT) : TypeOpBinary(t,CPUI_FLOAT_ADD,"+",TYPE_FLOAT,TYPE_FLOAT)
{ {
opflags = PcodeOp::binary | PcodeOp::commutative | PcodeOp::floatingpoint; opflags = PcodeOp::binary | PcodeOp::commutative;
behave = new OpBehaviorFloatAdd(trans); behave = new OpBehaviorFloatAdd(trans);
} }
TypeOpFloatDiv::TypeOpFloatDiv(TypeFactory *t,const Translate *trans) TypeOpFloatDiv::TypeOpFloatDiv(TypeFactory *t,const Translate *trans)
: TypeOpBinary(t,CPUI_FLOAT_DIV,"/",TYPE_FLOAT,TYPE_FLOAT) : TypeOpBinary(t,CPUI_FLOAT_DIV,"/",TYPE_FLOAT,TYPE_FLOAT)
{ {
opflags = PcodeOp::binary | PcodeOp::floatingpoint; opflags = PcodeOp::binary;
behave = new OpBehaviorFloatDiv(trans); behave = new OpBehaviorFloatDiv(trans);
} }
TypeOpFloatMult::TypeOpFloatMult(TypeFactory *t,const Translate *trans) TypeOpFloatMult::TypeOpFloatMult(TypeFactory *t,const Translate *trans)
: TypeOpBinary(t,CPUI_FLOAT_MULT,"*",TYPE_FLOAT,TYPE_FLOAT) : TypeOpBinary(t,CPUI_FLOAT_MULT,"*",TYPE_FLOAT,TYPE_FLOAT)
{ {
opflags = PcodeOp::binary | PcodeOp::commutative | PcodeOp::floatingpoint; opflags = PcodeOp::binary | PcodeOp::commutative;
behave = new OpBehaviorFloatMult(trans); behave = new OpBehaviorFloatMult(trans);
} }
TypeOpFloatSub::TypeOpFloatSub(TypeFactory *t,const Translate *trans) TypeOpFloatSub::TypeOpFloatSub(TypeFactory *t,const Translate *trans)
: TypeOpBinary(t,CPUI_FLOAT_SUB,"-",TYPE_FLOAT,TYPE_FLOAT) : TypeOpBinary(t,CPUI_FLOAT_SUB,"-",TYPE_FLOAT,TYPE_FLOAT)
{ {
opflags = PcodeOp::binary | PcodeOp::floatingpoint; opflags = PcodeOp::binary;
behave = new OpBehaviorFloatSub(trans); behave = new OpBehaviorFloatSub(trans);
} }
TypeOpFloatNeg::TypeOpFloatNeg(TypeFactory *t,const Translate *trans) TypeOpFloatNeg::TypeOpFloatNeg(TypeFactory *t,const Translate *trans)
: TypeOpUnary(t,CPUI_FLOAT_NEG,"-",TYPE_FLOAT,TYPE_FLOAT) : TypeOpUnary(t,CPUI_FLOAT_NEG,"-",TYPE_FLOAT,TYPE_FLOAT)
{ {
opflags = PcodeOp::unary | PcodeOp::floatingpoint; opflags = PcodeOp::unary;
behave = new OpBehaviorFloatNeg(trans); behave = new OpBehaviorFloatNeg(trans);
} }
TypeOpFloatAbs::TypeOpFloatAbs(TypeFactory *t,const Translate *trans) TypeOpFloatAbs::TypeOpFloatAbs(TypeFactory *t,const Translate *trans)
: TypeOpFunc(t,CPUI_FLOAT_ABS,"ABS",TYPE_FLOAT,TYPE_FLOAT) : TypeOpFunc(t,CPUI_FLOAT_ABS,"ABS",TYPE_FLOAT,TYPE_FLOAT)
{ {
opflags = PcodeOp::unary | PcodeOp::floatingpoint; opflags = PcodeOp::unary;
behave = new OpBehaviorFloatAbs(trans); behave = new OpBehaviorFloatAbs(trans);
} }
TypeOpFloatSqrt::TypeOpFloatSqrt(TypeFactory *t,const Translate *trans) TypeOpFloatSqrt::TypeOpFloatSqrt(TypeFactory *t,const Translate *trans)
: TypeOpFunc(t,CPUI_FLOAT_SQRT,"SQRT",TYPE_FLOAT,TYPE_FLOAT) : TypeOpFunc(t,CPUI_FLOAT_SQRT,"SQRT",TYPE_FLOAT,TYPE_FLOAT)
{ {
opflags = PcodeOp::unary | PcodeOp::floatingpoint; opflags = PcodeOp::unary;
behave = new OpBehaviorFloatSqrt(trans); behave = new OpBehaviorFloatSqrt(trans);
} }
TypeOpFloatInt2Float::TypeOpFloatInt2Float(TypeFactory *t,const Translate *trans) TypeOpFloatInt2Float::TypeOpFloatInt2Float(TypeFactory *t,const Translate *trans)
: TypeOpFunc(t,CPUI_FLOAT_INT2FLOAT,"INT2FLOAT",TYPE_FLOAT,TYPE_INT) : TypeOpFunc(t,CPUI_FLOAT_INT2FLOAT,"INT2FLOAT",TYPE_FLOAT,TYPE_INT)
{ {
opflags = PcodeOp::unary | PcodeOp::floatingpoint; opflags = PcodeOp::unary;
behave = new OpBehaviorFloatInt2Float(trans); behave = new OpBehaviorFloatInt2Float(trans);
} }
TypeOpFloatFloat2Float::TypeOpFloatFloat2Float(TypeFactory *t,const Translate *trans) TypeOpFloatFloat2Float::TypeOpFloatFloat2Float(TypeFactory *t,const Translate *trans)
: TypeOpFunc(t,CPUI_FLOAT_FLOAT2FLOAT,"FLOAT2FLOAT",TYPE_FLOAT,TYPE_FLOAT) : TypeOpFunc(t,CPUI_FLOAT_FLOAT2FLOAT,"FLOAT2FLOAT",TYPE_FLOAT,TYPE_FLOAT)
{ {
opflags = PcodeOp::unary | PcodeOp::floatingpoint; opflags = PcodeOp::unary;
behave = new OpBehaviorFloatFloat2Float(trans); behave = new OpBehaviorFloatFloat2Float(trans);
} }
TypeOpFloatTrunc::TypeOpFloatTrunc(TypeFactory *t,const Translate *trans) TypeOpFloatTrunc::TypeOpFloatTrunc(TypeFactory *t,const Translate *trans)
: TypeOpFunc(t,CPUI_FLOAT_TRUNC,"TRUNC",TYPE_INT,TYPE_FLOAT) : TypeOpFunc(t,CPUI_FLOAT_TRUNC,"TRUNC",TYPE_INT,TYPE_FLOAT)
{ {
opflags = PcodeOp::unary | PcodeOp::floatingpoint; opflags = PcodeOp::unary;
behave = new OpBehaviorFloatTrunc(trans); behave = new OpBehaviorFloatTrunc(trans);
} }
TypeOpFloatCeil::TypeOpFloatCeil(TypeFactory *t,const Translate *trans) TypeOpFloatCeil::TypeOpFloatCeil(TypeFactory *t,const Translate *trans)
: TypeOpFunc(t,CPUI_FLOAT_CEIL,"CEIL",TYPE_FLOAT,TYPE_FLOAT) : TypeOpFunc(t,CPUI_FLOAT_CEIL,"CEIL",TYPE_FLOAT,TYPE_FLOAT)
{ {
opflags = PcodeOp::unary | PcodeOp::floatingpoint; opflags = PcodeOp::unary;
behave = new OpBehaviorFloatCeil(trans); behave = new OpBehaviorFloatCeil(trans);
} }
TypeOpFloatFloor::TypeOpFloatFloor(TypeFactory *t,const Translate *trans) TypeOpFloatFloor::TypeOpFloatFloor(TypeFactory *t,const Translate *trans)
: TypeOpFunc(t,CPUI_FLOAT_FLOOR,"FLOOR",TYPE_FLOAT,TYPE_FLOAT) : TypeOpFunc(t,CPUI_FLOAT_FLOOR,"FLOOR",TYPE_FLOAT,TYPE_FLOAT)
{ {
opflags = PcodeOp::unary | PcodeOp::floatingpoint; opflags = PcodeOp::unary;
behave = new OpBehaviorFloatFloor(trans); behave = new OpBehaviorFloatFloor(trans);
} }
TypeOpFloatRound::TypeOpFloatRound(TypeFactory *t,const Translate *trans) TypeOpFloatRound::TypeOpFloatRound(TypeFactory *t,const Translate *trans)
: TypeOpFunc(t,CPUI_FLOAT_ROUND,"ROUND",TYPE_FLOAT,TYPE_FLOAT) : TypeOpFunc(t,CPUI_FLOAT_ROUND,"ROUND",TYPE_FLOAT,TYPE_FLOAT)
{ {
opflags = PcodeOp::unary | PcodeOp::floatingpoint; opflags = PcodeOp::unary;
behave = new OpBehaviorFloatRound(trans); behave = new OpBehaviorFloatRound(trans);
} }
@ -1610,8 +1610,8 @@ void TypeOpCast::printRaw(ostream &s,const PcodeOp *op)
TypeOpPtradd::TypeOpPtradd(TypeFactory *t) : TypeOp(t,CPUI_PTRADD,"+") TypeOpPtradd::TypeOpPtradd(TypeFactory *t) : TypeOp(t,CPUI_PTRADD,"+")
{ {
opflags = PcodeOp::special | PcodeOp::nocollapse; opflags = PcodeOp::ternary | PcodeOp::nocollapse;
behave = new OpBehavior(CPUI_PTRADD,false,true); // Dummy behavior behave = new OpBehavior(CPUI_PTRADD,false); // Dummy behavior
} }
Datatype *TypeOpPtradd::getInputLocal(const PcodeOp *op,int4 slot) const Datatype *TypeOpPtradd::getInputLocal(const PcodeOp *op,int4 slot) const
@ -1664,8 +1664,8 @@ TypeOpPtrsub::TypeOpPtrsub(TypeFactory *t) : TypeOp(t,CPUI_PTRSUB,"->")
// So it should be commutative // So it should be commutative
// But the typing information doesn't really // But the typing information doesn't really
// allow this to be commutative. // allow this to be commutative.
opflags = PcodeOp::special|PcodeOp::nocollapse; opflags = PcodeOp::binary|PcodeOp::nocollapse;
behave = new OpBehavior(CPUI_PTRSUB,false,true); // Dummy behavior behave = new OpBehavior(CPUI_PTRSUB,false); // Dummy behavior
} }
Datatype *TypeOpPtrsub::getOutputLocal(const PcodeOp *op) const Datatype *TypeOpPtrsub::getOutputLocal(const PcodeOp *op) const
@ -1834,8 +1834,8 @@ void TypeOpNew::printRaw(ostream &s,const PcodeOp *op)
TypeOpInsert::TypeOpInsert(TypeFactory *t) TypeOpInsert::TypeOpInsert(TypeFactory *t)
: TypeOpFunc(t,CPUI_INSERT,"INSERT",TYPE_UNKNOWN,TYPE_INT) : TypeOpFunc(t,CPUI_INSERT,"INSERT",TYPE_UNKNOWN,TYPE_INT)
{ {
opflags = PcodeOp::special; opflags = PcodeOp::ternary;
behave = new OpBehavior(CPUI_INSERT,false,true); // Dummy behavior behave = new OpBehavior(CPUI_INSERT,false); // Dummy behavior
} }
Datatype *TypeOpInsert::getInputLocal(const PcodeOp *op,int4 slot) const Datatype *TypeOpInsert::getInputLocal(const PcodeOp *op,int4 slot) const
@ -1849,8 +1849,8 @@ Datatype *TypeOpInsert::getInputLocal(const PcodeOp *op,int4 slot) const
TypeOpExtract::TypeOpExtract(TypeFactory *t) TypeOpExtract::TypeOpExtract(TypeFactory *t)
: TypeOpFunc(t,CPUI_EXTRACT,"EXTRACT",TYPE_INT,TYPE_INT) : TypeOpFunc(t,CPUI_EXTRACT,"EXTRACT",TYPE_INT,TYPE_INT)
{ {
opflags = PcodeOp::special; opflags = PcodeOp::ternary;
behave = new OpBehavior(CPUI_EXTRACT,false,true); // Dummy behavior behave = new OpBehavior(CPUI_EXTRACT,false); // Dummy behavior
} }
Datatype *TypeOpExtract::getInputLocal(const PcodeOp *op,int4 slot) const Datatype *TypeOpExtract::getInputLocal(const PcodeOp *op,int4 slot) const

View file

@ -289,6 +289,17 @@ void ScopeLocal::collectNameRecs(void)
Symbol *sym = *iter++; Symbol *sym = *iter++;
if (sym->isNameLocked()&&(!sym->isTypeLocked())) { if (sym->isNameLocked()&&(!sym->isTypeLocked())) {
addRecommendName(sym); addRecommendName(sym);
if (sym->isThisPointer()) { // If there is a "this" pointer
Datatype *dt = sym->getType();
if (dt->getMetatype() == TYPE_PTR) {
if (((TypePointer *)dt)->getPtrTo()->getMetatype() == TYPE_STRUCT) {
// If the "this" pointer points to a class, try to preserve the data-type
// even though the symbol is not preserved.
SymbolEntry *entry = sym->getFirstWholeMap();
typeRecommend.push_back(TypeRecommend(entry->getAddr(),dt));
}
}
}
} }
} }
} }
@ -1240,6 +1251,7 @@ SymbolEntry *ScopeLocal::remapSymbolDynamic(Symbol *sym,uint8 hash,const Address
void ScopeLocal::recoverNameRecommendationsForSymbols(void) void ScopeLocal::recoverNameRecommendationsForSymbols(void)
{ {
Address param_usepoint = fd->getAddress() - 1;
list<NameRecommend>::const_iterator iter; list<NameRecommend>::const_iterator iter;
for(iter=nameRecommend.begin();iter!=nameRecommend.end();++iter) { for(iter=nameRecommend.begin();iter!=nameRecommend.end();++iter) {
const Address &addr((*iter).getAddr()); const Address &addr((*iter).getAddr());
@ -1258,7 +1270,10 @@ void ScopeLocal::recoverNameRecommendationsForSymbols(void)
vn = fd->findLinkedVarnode(entry); vn = fd->findLinkedVarnode(entry);
} }
else { else {
vn = fd->findVarnodeWritten(size,addr,usepoint); if (usepoint == param_usepoint)
vn = fd->findVarnodeInput(size, addr);
else
vn = fd->findVarnodeWritten(size,addr,usepoint);
if (vn == (Varnode *)0) continue; if (vn == (Varnode *)0) continue;
sym = vn->getHigh()->getSymbol(); sym = vn->getHigh()->getSymbol();
if (sym == (Symbol *)0) continue; if (sym == (Symbol *)0) continue;
@ -1298,6 +1313,20 @@ void ScopeLocal::recoverNameRecommendationsForSymbols(void)
} }
} }
/// Run through the recommended list, search for an input Varnode matching the storage address
/// and try to apply the data-type to it. Do not override existing type lock.
void ScopeLocal::applyTypeRecommendations(void)
{
list<TypeRecommend>::const_iterator iter;
for(iter=typeRecommend.begin();iter!=typeRecommend.end();++iter) {
Datatype *dt = (*iter).getType();
Varnode *vn = fd->findVarnodeInput(dt->getSize(), (*iter).getAddress());
if (vn != (Varnode *)0)
vn->updateType(dt, true, false);
}
}
/// The symbol is stored as a name recommendation and then removed from the scope. /// The symbol is stored as a name recommendation and then removed from the scope.
/// Name recommendations are associated either with a storage address and usepoint, or a dynamic hash. /// Name recommendations are associated either with a storage address and usepoint, or a dynamic hash.
/// The name may be reattached to a Symbol after decompilation. /// The name may be reattached to a Symbol after decompilation.

View file

@ -60,6 +60,20 @@ public:
uint8 getSymbolId(void) const { return symbolId; } ///< Get the original Symbol id uint8 getSymbolId(void) const { return symbolId; } ///< Get the original Symbol id
}; };
/// \brief Data-type for a storage location when there is no Symbol (yet)
///
/// Allow a data-type to be fed into a specific storage location. Currently
/// this only applies to input Varnodes.
class TypeRecommend {
Address addr; ///< Storage address of the Varnode
Datatype *dataType; ///< Data-type to assign to the Varnode
public:
TypeRecommend(const Address &ad,Datatype *dt) :
addr(ad), dataType(dt) {} ///< Constructor
const Address &getAddress(void) const { return addr; } ///< Get the storage address
Datatype *getType(void) const { return dataType; } ///< Get the data-type
};
/// \brief Partial data-type information mapped to a specific range of bytes /// \brief Partial data-type information mapped to a specific range of bytes
/// ///
/// This object gives a hint about the data-type for a sequence of bytes /// This object gives a hint about the data-type for a sequence of bytes
@ -184,6 +198,7 @@ class ScopeLocal : public ScopeInternal {
RangeList localRange; ///< The set of addresses that might hold mapped locals (not parameters) RangeList localRange; ///< The set of addresses that might hold mapped locals (not parameters)
list<NameRecommend> nameRecommend; ///< Symbol name recommendations for specific addresses list<NameRecommend> nameRecommend; ///< Symbol name recommendations for specific addresses
list<DynamicRecommend> dynRecommend; ///< Symbol name recommendations for dynamic locations list<DynamicRecommend> dynRecommend; ///< Symbol name recommendations for dynamic locations
list<TypeRecommend> typeRecommend; ///< Data-types for specific storage locations
bool stackGrowsNegative; ///< Marked \b true if the stack is considered to \e grow towards smaller offsets bool stackGrowsNegative; ///< Marked \b true if the stack is considered to \e grow towards smaller offsets
bool rangeLocked; ///< True if the subset of addresses \e mapped to \b this scope has been locked bool rangeLocked; ///< True if the subset of addresses \e mapped to \b this scope has been locked
bool adjustFit(RangeHint &a) const; ///< Make the given RangeHint fit in the current Symbol map bool adjustFit(RangeHint &a) const; ///< Make the given RangeHint fit in the current Symbol map
@ -220,6 +235,7 @@ public:
SymbolEntry *remapSymbol(Symbol *sym,const Address &addr,const Address &usepoint); SymbolEntry *remapSymbol(Symbol *sym,const Address &addr,const Address &usepoint);
SymbolEntry *remapSymbolDynamic(Symbol *sym,uint8 hash,const Address &usepoint); SymbolEntry *remapSymbolDynamic(Symbol *sym,uint8 hash,const Address &usepoint);
void recoverNameRecommendationsForSymbols(void); void recoverNameRecommendationsForSymbols(void);
void applyTypeRecommendations(void); ///< Try to apply recommended data-type information
}; };
#endif #endif

View file

@ -22,11 +22,14 @@ import docking.action.MenuData;
import ghidra.app.decompiler.ClangFieldToken; import ghidra.app.decompiler.ClangFieldToken;
import ghidra.app.decompiler.ClangToken; import ghidra.app.decompiler.ClangToken;
import ghidra.app.plugin.core.decompile.DecompilerActionContext; import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.app.util.AddEditDialog;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Function;
import ghidra.program.model.pcode.HighCodeSymbol; import ghidra.program.model.pcode.HighCodeSymbol;
import ghidra.program.model.pcode.HighSymbol; import ghidra.program.model.pcode.HighSymbol;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.UndefinedFunction; import ghidra.util.UndefinedFunction;
@ -69,18 +72,22 @@ public class RenameGlobalAction extends AbstractDecompilerAction {
PluginTool tool = context.getTool(); PluginTool tool = context.getTool();
final ClangToken tokenAtCursor = context.getTokenAtCursor(); final ClangToken tokenAtCursor = context.getTokenAtCursor();
HighSymbol highSymbol = findHighSymbolFromToken(tokenAtCursor, context.getHighFunction()); HighSymbol highSymbol = findHighSymbolFromToken(tokenAtCursor, context.getHighFunction());
Address addr = null; Symbol symbol = null;
if (highSymbol instanceof HighCodeSymbol) { if (highSymbol instanceof HighCodeSymbol) {
addr = ((HighCodeSymbol) highSymbol).getStorage().getMinAddress(); symbol = ((HighCodeSymbol) highSymbol).getCodeSymbol();
if (symbol == null) {
// Try to get the dynamic symbol
Address addr = ((HighCodeSymbol) highSymbol).getStorage().getMinAddress();
SymbolTable symbolTable = context.getProgram().getSymbolTable();
symbol = symbolTable.getPrimarySymbol(addr);
}
} }
if (addr == null || !addr.isMemoryAddress()) { if (symbol == null) {
Msg.showError(this, tool.getToolFrame(), "Rename Failed", Msg.showError(this, tool.getToolFrame(), "Rename Failed",
"Memory storage not found for global variable"); "Memory storage not found for global variable");
return; return;
} }
RenameGlobalVariableTask nameTask = AddEditDialog dialog = new AddEditDialog("Rename Global", context.getTool());
new RenameGlobalVariableTask(tool, context.getProgram(), context.getDecompilerPanel(), dialog.editLabel(symbol, context.getProgram());
tokenAtCursor, addr);
nameTask.runTask(true);
} }
} }

View file

@ -1,68 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.decompile.actions;
import ghidra.app.decompiler.ClangToken;
import ghidra.app.decompiler.component.DecompilerPanel;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.*;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException;
public class RenameGlobalVariableTask extends RenameTask {
private Address address; // Address of global variable
private SymbolTable symboltable;
private Symbol symbol;
public RenameGlobalVariableTask(PluginTool tool, Program program, DecompilerPanel panel,
ClangToken token, Address addr) {
super(tool, program, panel, token, token.getText());
address = addr;
symboltable = program.getSymbolTable();
symbol = null;
}
@Override
public void commit() throws DuplicateNameException, InvalidInputException {
if (symbol != null) {
symbol.setName(newName, SourceType.USER_DEFINED);
}
else {
symboltable.createLabel(address, newName, SourceType.USER_DEFINED);
}
}
@Override
public String getTransactionName() {
return "Rename Global Variable";
}
@Override
public boolean isValid(String newNm) {
newName = newNm;
Symbol dupsym = symboltable.getGlobalSymbol(newName, address);
if (dupsym != null) {
errorMsg = "Duplicate symbol name";
return false;
}
symbol = symboltable.getPrimarySymbol(address);
return true;
}
}

View file

@ -243,6 +243,9 @@ public class CppExporter extends Exporter {
options.grabFromToolAndProgram(null, opt, program); options.grabFromToolAndProgram(null, opt, program);
} }
} }
else {
options.grabFromProgram(program); // Let headless pull program specific options
}
if (isUseCppStyleComments) { if (isUseCppStyleComments) {
options.setCommentStyle(CommentStyleEnum.CPPStyle); options.setCommentStyle(CommentStyleEnum.CPPStyle);

View file

@ -25,11 +25,13 @@ import docking.widgets.fieldpanel.field.Field;
import docking.widgets.fieldpanel.support.FieldLocation; import docking.widgets.fieldpanel.support.FieldLocation;
import ghidra.app.cmd.function.CreateFunctionCmd; import ghidra.app.cmd.function.CreateFunctionCmd;
import ghidra.app.cmd.function.DeleteFunctionCmd; import ghidra.app.cmd.function.DeleteFunctionCmd;
import ghidra.app.cmd.label.RenameLabelCmd;
import ghidra.app.decompiler.ClangToken; import ghidra.app.decompiler.ClangToken;
import ghidra.app.decompiler.ClangVariableToken; import ghidra.app.decompiler.ClangVariableToken;
import ghidra.app.decompiler.component.ClangTextField; import ghidra.app.decompiler.component.ClangTextField;
import ghidra.app.decompiler.component.DecompilerPanel; import ghidra.app.decompiler.component.DecompilerPanel;
import ghidra.app.plugin.core.decompile.actions.*; import ghidra.app.plugin.core.decompile.actions.IsolateVariableTask;
import ghidra.app.plugin.core.decompile.actions.RenameVariableTask;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.program.database.symbol.CodeSymbol; import ghidra.program.database.symbol.CodeSymbol;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
@ -79,12 +81,11 @@ public class HighSymbolTest extends AbstractDecompilerTest {
private void renameGlobalVariable(HighSymbol highSymbol, ClangToken tokenAtCursor, private void renameGlobalVariable(HighSymbol highSymbol, ClangToken tokenAtCursor,
String newName) { String newName) {
Address addr = highSymbol.getStorage().getMinAddress(); Address addr = highSymbol.getStorage().getMinAddress();
RenameGlobalVariableTask rename = new RenameGlobalVariableTask(provider.getTool(), RenameLabelCmd cmd =
highSymbol.getProgram(), provider.getDecompilerPanel(), tokenAtCursor, addr); new RenameLabelCmd(addr, highSymbol.getName(), newName, SourceType.USER_DEFINED);
assertTrue(rename.isValid(newName));
modifyProgram(p -> { modifyProgram(p -> {
rename.commit(); cmd.applyTo(highSymbol.getProgram());
}); });
waitForDecompiler(); waitForDecompiler();
} }

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

@ -662,7 +662,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()) {
@ -827,6 +828,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

@ -52,7 +52,9 @@ public class FunctionPrototype {
private boolean isDestruct; // Function is an object destructor private boolean isDestruct; // Function is an object destructor
/** /**
* Construct a FunctionPrototype backed by a local symbolmap * Construct a FunctionPrototype backed by a local symbolmap.
* This is only a partial initialization. It is intended to be followed either by
* grabFromFunction() or readPrototypeXML()
* *
* @param ls is the LocalSymbolMap backing the prototype * @param ls is the LocalSymbolMap backing the prototype
* @param func is the function using the symbolmap * @param func is the function using the symbolmap
@ -102,7 +104,7 @@ public class FunctionPrototype {
noreturn = false; noreturn = false;
custom = false; custom = false;
extrapop = model.getExtrapop(); extrapop = model.getExtrapop();
hasThis = false; hasThis = model.hasThisPointer();
isConstruct = false; isConstruct = false;
isDestruct = false; isDestruct = false;
// FIXME: If the FunctionDefinition has no parameters // FIXME: If the FunctionDefinition has no parameters
@ -126,6 +128,11 @@ public class FunctionPrototype {
*/ */
void grabFromFunction(Function f, int overrideExtrapop, boolean doOverride) { void grabFromFunction(Function f, int overrideExtrapop, boolean doOverride) {
modelname = f.getCallingConventionName(); modelname = f.getCallingConventionName();
PrototypeModel protoModel = f.getCallingConvention();
if (protoModel == null) {
protoModel = f.getProgram().getCompilerSpec().getDefaultCallingConvention();
}
hasThis = protoModel.hasThisPointer();
modellock = modellock =
((modelname != null) && (modelname != Function.UNKNOWN_CALLING_CONVENTION_STRING)); ((modelname != null) && (modelname != Function.UNKNOWN_CALLING_CONVENTION_STRING));
injectname = f.getCallFixup(); injectname = f.getCallFixup();
@ -164,10 +171,6 @@ public class FunctionPrototype {
extrapop = overrideExtrapop; extrapop = overrideExtrapop;
} }
else { else {
PrototypeModel protoModel = f.getCallingConvention();
if (protoModel == null) {
protoModel = f.getProgram().getCompilerSpec().getDefaultCallingConvention();
}
if (purge == Function.INVALID_STACK_DEPTH_CHANGE || if (purge == Function.INVALID_STACK_DEPTH_CHANGE ||
purge == Function.UNKNOWN_STACK_DEPTH_CHANGE) { purge == Function.UNKNOWN_STACK_DEPTH_CHANGE) {
extrapop = protoModel.getExtrapop(); extrapop = protoModel.getExtrapop();
@ -343,9 +346,6 @@ public class FunctionPrototype {
if (custom) { if (custom) {
SpecXmlUtils.encodeBooleanAttribute(res, "custom", custom); SpecXmlUtils.encodeBooleanAttribute(res, "custom", custom);
} }
if (hasThis) {
SpecXmlUtils.encodeBooleanAttribute(res, "hasthis", hasThis);
}
if (isConstruct) { if (isConstruct) {
SpecXmlUtils.encodeBooleanAttribute(res, "constructor", isConstruct); SpecXmlUtils.encodeBooleanAttribute(res, "constructor", isConstruct);
} }
@ -421,6 +421,12 @@ public class FunctionPrototype {
throws PcodeXMLException { throws PcodeXMLException {
XmlElement node = parser.start("prototype"); XmlElement node = parser.start("prototype");
modelname = node.getAttribute("model"); modelname = node.getAttribute("model");
PrototypeModel protoModel =
dtmanage.getProgram().getCompilerSpec().getCallingConvention(modelname);
if (protoModel == null) {
throw new PcodeXMLException("Bad prototype model name: " + modelname);
}
hasThis = protoModel.hasThisPointer();
String val = node.getAttribute("extrapop"); String val = node.getAttribute("extrapop");
if (val.equals("unknown")) { if (val.equals("unknown")) {
extrapop = PrototypeModel.UNKNOWN_EXTRAPOP; extrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
@ -452,10 +458,6 @@ public class FunctionPrototype {
if (node.hasAttribute("custom")) { if (node.hasAttribute("custom")) {
custom = SpecXmlUtils.decodeBoolean(node.getAttribute("custom")); custom = SpecXmlUtils.decodeBoolean(node.getAttribute("custom"));
} }
hasThis = false;
if (node.hasAttribute("hasthis")) {
hasThis = SpecXmlUtils.decodeBoolean(node.getAttribute("hasthis"));
}
isConstruct = false; isConstruct = false;
if (node.hasAttribute("constructor")) { if (node.hasAttribute("constructor")) {
isConstruct = SpecXmlUtils.decodeBoolean(node.getAttribute("constructor")); isConstruct = SpecXmlUtils.decodeBoolean(node.getAttribute("constructor"));

View file

@ -17,10 +17,11 @@ package ghidra.program.model.pcode;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Program; import ghidra.program.model.lang.DynamicVariableStorage;
import ghidra.program.model.listing.VariableStorage; import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.Namespace; import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.Symbol; import ghidra.program.model.symbol.Symbol;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.xml.SpecXmlUtils; import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.XmlElement; import ghidra.xml.XmlElement;
import ghidra.xml.XmlPullParser; import ghidra.xml.XmlPullParser;
@ -40,6 +41,8 @@ public class HighSymbol {
protected int categoryIndex; // Numbering within the sub-class protected int categoryIndex; // Numbering within the sub-class
private boolean namelock; // Is this variable's name locked private boolean namelock; // Is this variable's name locked
private boolean typelock; // Is this variable's datatype locked private boolean typelock; // Is this variable's datatype locked
private boolean isThis; // True if we are "this" symbol for function method call
private boolean isHidden; // True if we are hidden symbol containing pointer to where return value is stored
private long id; // Unique id of this symbol private long id; // Unique id of this symbol
protected SymbolEntry[] entryList; // List of mappings for this symbol protected SymbolEntry[] entryList; // List of mappings for this symbol
@ -53,6 +56,8 @@ public class HighSymbol {
protected HighSymbol(HighFunction func) { protected HighSymbol(HighFunction func) {
function = func; function = func;
dtmanage = function.getDataTypeManager(); dtmanage = function.getDataTypeManager();
isThis = false;
isHidden = false;
} }
/** /**
@ -69,6 +74,8 @@ public class HighSymbol {
type = tp; type = tp;
namelock = false; namelock = false;
typelock = false; typelock = false;
isThis = false;
isHidden = false;
id = uniqueId; id = uniqueId;
category = -1; category = -1;
categoryIndex = -1; categoryIndex = -1;
@ -92,6 +99,8 @@ public class HighSymbol {
type = tp; type = tp;
namelock = nlock; namelock = nlock;
typelock = tlock; typelock = tlock;
isThis = false;
isHidden = false;
id = uniqueId; id = uniqueId;
category = -1; category = -1;
categoryIndex = -1; categoryIndex = -1;
@ -101,6 +110,15 @@ public class HighSymbol {
if (entryList == null) { if (entryList == null) {
entryList = new SymbolEntry[1]; entryList = new SymbolEntry[1];
entryList[0] = entry; entryList[0] = entry;
if (entry.getStorage().isAutoStorage()) {
AutoParameterType autoType = entry.getStorage().getAutoParameterType();
if (autoType == AutoParameterType.THIS) {
isThis = true;
}
else if (autoType == AutoParameterType.RETURN_STORAGE_PTR) {
isHidden = true;
}
}
} }
else { else {
SymbolEntry[] newList = new SymbolEntry[entryList.length + 1]; SymbolEntry[] newList = new SymbolEntry[entryList.length + 1];
@ -316,6 +334,20 @@ public class HighSymbol {
return false; return false;
} }
/**
* @return true if symbol is a "this" pointer for a class method
*/
public boolean isThisPointer() {
return isThis;
}
/**
* @return true is symbol holds a pointer to where a function's return value should be stored
*/
public boolean isHiddenReturn() {
return isHidden;
}
/** /**
* @return the first mapping object attached to this symbol * @return the first mapping object attached to this symbol
*/ */
@ -349,6 +381,12 @@ public class HighSymbol {
if (isIsolated()) { if (isIsolated()) {
SpecXmlUtils.encodeBooleanAttribute(buf, "merge", false); SpecXmlUtils.encodeBooleanAttribute(buf, "merge", false);
} }
if (isThis) {
SpecXmlUtils.encodeBooleanAttribute(buf, "thisptr", true);
}
if (isHidden) {
SpecXmlUtils.encodeBooleanAttribute(buf, "hiddenretparm", true);
}
SpecXmlUtils.encodeSignedIntegerAttribute(buf, "cat", category); SpecXmlUtils.encodeSignedIntegerAttribute(buf, "cat", category);
if (categoryIndex >= 0) { if (categoryIndex >= 0) {
SpecXmlUtils.encodeSignedIntegerAttribute(buf, "index", categoryIndex); SpecXmlUtils.encodeSignedIntegerAttribute(buf, "index", categoryIndex);
@ -382,6 +420,16 @@ public class HighSymbol {
if ((namelockstr != null) && (SpecXmlUtils.decodeBoolean(namelockstr))) { if ((namelockstr != null) && (SpecXmlUtils.decodeBoolean(namelockstr))) {
namelock = true; namelock = true;
} }
isThis = false;
String thisstring = symel.getAttribute("thisptr");
if ((thisstring != null) && (SpecXmlUtils.decodeBoolean(thisstring))) {
isThis = true;
}
isHidden = false;
String hiddenstring = symel.getAttribute("hiddenretparm");
if ((hiddenstring != null) && (SpecXmlUtils.decodeBoolean(hiddenstring))) {
isHidden = true;
}
// isolate = false; // isolate = false;
// String isolatestr = symel.getAttribute("merge"); // String isolatestr = symel.getAttribute("merge");
// if ((isolatestr != null) && !SpecXmlUtils.decodeBoolean(isolatestr)) { // if ((isolatestr != null) && !SpecXmlUtils.decodeBoolean(isolatestr)) {
@ -431,6 +479,20 @@ public class HighSymbol {
entry.restoreXML(parser); entry.restoreXML(parser);
addMapEntry(entry); addMapEntry(entry);
} }
if ((isThis || isHidden) && entryList != null) {
SymbolEntry entry = entryList[0];
VariableStorage storage = entry.getStorage();
AutoParameterType autoType =
isThis ? AutoParameterType.THIS : AutoParameterType.RETURN_STORAGE_PTR;
try {
VariableStorage newStorage = new DynamicVariableStorage(storage.getProgram(),
autoType, storage.getFirstVarnode());
entryList[0] = new MappedEntry(this, newStorage, entry.getPCAdress());
}
catch (InvalidInputException e) {
throw new PcodeXMLException("Unable to parse auto-parameter");
}
}
} }
/** /**

View file

@ -12,6 +12,10 @@
<property key="Analyzers.Android ODEX Header Format" value="true"/> <property key="Analyzers.Android ODEX Header Format" value="true"/>
<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>

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);