mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Merge remote-tracking branch 'origin/caheckman_RenameRegParam'
This commit is contained in:
commit
513467b150
45 changed files with 641 additions and 318 deletions
|
@ -984,6 +984,20 @@ void Architecture::parseDeadcodeDelay(const Element *el)
|
|||
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
|
||||
/// function pointers, some architectures have aligned function pointers
|
||||
/// and encode extra information in the unused bits.
|
||||
|
@ -1109,6 +1123,9 @@ void Architecture::parseProcessorConfig(DocumentStorage &store)
|
|||
throw LowlevelError("Undefined space: "+spaceName);
|
||||
setDefaultDataSpace(spc->getIndex());
|
||||
}
|
||||
else if (elname == "inferptrbounds") {
|
||||
parseInferPtrBounds(*iter);
|
||||
}
|
||||
else if (elname == "segmented_address") {
|
||||
}
|
||||
else if (elname == "default_symbols") {
|
||||
|
@ -1183,6 +1200,8 @@ void Architecture::parseCompilerConfig(DocumentStorage &store)
|
|||
parseFuncPtrAlign(*iter);
|
||||
else if (elname == "deadcodedelay")
|
||||
parseDeadcodeDelay(*iter);
|
||||
else if (elname == "inferptrbounds")
|
||||
parseInferPtrBounds(*iter);
|
||||
}
|
||||
// <global> tags instantiate the base symbol table
|
||||
// They need to know about all spaces, so it must come
|
||||
|
|
|
@ -274,6 +274,7 @@ protected:
|
|||
void parseLaneSizes(const Element *el); ///< Apply lane size configuration
|
||||
void parseStackPointer(const Element *el); ///< Apply stack pointer 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 parseSpacebase(const Element *el); ///< Create an additional indexed space
|
||||
void parseNoHighPtr(const Element *el); ///< Apply memory alias configuration
|
||||
|
|
|
@ -1254,12 +1254,13 @@ FlowBlock *BlockGraph::nextFlowAfter(const FlowBlock *bl) const
|
|||
return nextbl;
|
||||
}
|
||||
|
||||
void BlockGraph::orderSwitchCases(void) const
|
||||
void BlockGraph::finalizePrinting(const Funcdata &data) const
|
||||
|
||||
{
|
||||
// Recurse into all the substructures
|
||||
vector<FlowBlock *>::const_iterator iter;
|
||||
for(iter=list.begin();iter!=list.end();++iter)
|
||||
(*iter)->orderSwitchCases();
|
||||
(*iter)->finalizePrinting(data);
|
||||
}
|
||||
|
||||
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
|
||||
CaseOrder &curcase( caseblocks[i] );
|
||||
int4 j = curcase.chain;
|
||||
|
@ -3113,7 +3117,7 @@ void BlockSwitch::orderSwitchCases(void) const
|
|||
else
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -170,7 +170,7 @@ public:
|
|||
virtual void flipInPlaceExecute(void);
|
||||
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 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 restoreXmlHeader(const Element *el); ///< Restore basic information for XML attributes
|
||||
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 emit(PrintLanguage *lng) const { lng->emitBlockGraph(this); }
|
||||
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 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
|
||||
|
@ -674,7 +674,7 @@ public:
|
|||
virtual void printHeader(ostream &s) const;
|
||||
virtual void emit(PrintLanguage *lng) const { lng->emitBlockSwitch(this); }
|
||||
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
|
||||
|
|
|
@ -2170,7 +2170,7 @@ int4 ActionFinalStructure::apply(Funcdata &data)
|
|||
BlockGraph &graph(data.getStructure());
|
||||
|
||||
graph.orderBlocks();
|
||||
graph.orderSwitchCases();
|
||||
graph.finalizePrinting(data);
|
||||
graph.scopeBreak(-1,-1); // Put in \e break statements
|
||||
graph.markUnstructured(); // Put in \e gotos
|
||||
graph.markLabelBumpUp(false); // Fix up labeling
|
||||
|
|
|
@ -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
|
||||
if (spc->getPointerLowerBound() > vn->getOffset())
|
||||
return (SymbolEntry *)0;
|
||||
if (spc->getPointerUpperBound() < vn->getOffset())
|
||||
return (SymbolEntry *)0;
|
||||
// Check if the constant looks like a single bit or mask
|
||||
if (bit_transitions(vn->getOffset(),vn->getSize()) < 3)
|
||||
return (SymbolEntry *)0;
|
||||
|
@ -1205,7 +1207,6 @@ int4 ActionDeindirect::apply(Funcdata &data)
|
|||
// We use isInputLocked as a test of whether the
|
||||
// function pointer prototype has been applied before
|
||||
fc->forceSet(data,*fp);
|
||||
data.updateOpFromSpec(fc);
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
@ -2158,7 +2159,6 @@ int4 ActionDefaultParams::apply(Funcdata &data)
|
|||
fc->setInternal(evalfp,data.getArch()->types->getTypeVoid());
|
||||
}
|
||||
fc->insertPcode(data); // Insert any necessary pcode
|
||||
data.updateOpFromSpec(fc);
|
||||
}
|
||||
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())))
|
||||
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
|
||||
count += castInput(op,i,data,castStrategy);
|
||||
if (opc == CPUI_LOAD) {
|
||||
|
@ -4738,6 +4748,7 @@ int4 ActionInferTypes::apply(Funcdata &data)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
data.getScopeLocal()->applyTypeRecommendations();
|
||||
buildLocaltypes(data); // Set up initial types (based on local info)
|
||||
for(iter=data.beginLoc();iter!=data.endLoc();++iter) {
|
||||
vn = *iter;
|
||||
|
|
|
@ -37,8 +37,6 @@ void CPoolRecord::saveXml(ostream &s) const
|
|||
a_v(s,"tag","classref");
|
||||
else
|
||||
a_v(s,"tag","primitive");
|
||||
if (hasThisPointer())
|
||||
a_v_b(s,"hasthis",true);
|
||||
if (isConstructor())
|
||||
a_v_b(s,"constructor",true);
|
||||
if (isDestructor())
|
||||
|
@ -100,10 +98,6 @@ void CPoolRecord::restoreXml(const Element *el,TypeFactory &typegrp)
|
|||
else if (tagstring == "classref")
|
||||
tag = class_reference;
|
||||
}
|
||||
else if (attr == "hasthis") {
|
||||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
flags |= CPoolRecord::has_thisptr;
|
||||
}
|
||||
else if (attr == "constructor") {
|
||||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
flags |= CPoolRecord::is_constructor;
|
||||
|
@ -145,10 +139,9 @@ void CPoolRecord::restoreXml(const Element *el,TypeFactory &typegrp)
|
|||
throw LowlevelError("Bad constant pool record: missing <data>");
|
||||
subel = *iter;
|
||||
if (flags != 0) {
|
||||
bool hasThisPtr = ((flags & has_thisptr)!=0);
|
||||
bool isConstructor = ((flags & is_constructor)!=0);
|
||||
bool isDestructor = ((flags & is_destructor)!=0);
|
||||
type = typegrp.restoreXmlTypeWithCodeFlags(subel,hasThisPtr,isConstructor,isDestructor);
|
||||
type = typegrp.restoreXmlTypeWithCodeFlags(subel,isConstructor,isDestructor);
|
||||
}
|
||||
else
|
||||
type = typegrp.restoreXmlType(subel);
|
||||
|
|
|
@ -55,9 +55,8 @@ public:
|
|||
check_cast=7 ///< Pointer to object, new name in \b token, new data-type in \b type
|
||||
};
|
||||
enum {
|
||||
has_thisptr = 0x1, ///< Referenced method has a \b this pointer
|
||||
is_constructor = 0x2, ///< Referenced method is a constructor
|
||||
is_destructor = 0x4 ///< Referenced method is a destructor
|
||||
is_constructor = 0x1, ///< Referenced method is a constructor
|
||||
is_destructor = 0x2 ///< Referenced method is a destructor
|
||||
};
|
||||
private:
|
||||
friend class ConstantPool;
|
||||
|
@ -77,7 +76,6 @@ public:
|
|||
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
|
||||
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 isDestructor(void) const { return ((flags & is_destructor)!=0); } ///< Is object a destructor method
|
||||
void saveXml(ostream &s) const; ///< Save object to an XML stream
|
||||
|
|
|
@ -224,6 +224,16 @@ void Symbol::checkSizeTypeLock(void)
|
|||
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
|
||||
/// \return \b true if the name of \b this is undefined
|
||||
bool Symbol::isNameUndefined(void) const
|
||||
|
@ -362,6 +372,8 @@ void Symbol::saveXmlHeader(ostream &s) const
|
|||
a_v_b(s,"hiddenretparm",true);
|
||||
if ((dispflags&isolate)!=0)
|
||||
a_v_b(s,"merge",false);
|
||||
if ((dispflags&is_this_ptr)!=0)
|
||||
a_v_b(s,"thisptr",true);
|
||||
int4 format = getDisplayFormat();
|
||||
if (format != 0) {
|
||||
s << " format=\"";
|
||||
|
@ -461,6 +473,10 @@ void Symbol::restoreXmlHeader(const Element *el)
|
|||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
flags |= Varnode::typelock;
|
||||
}
|
||||
else if (attName == "thisptr") {
|
||||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
dispflags |= is_this_ptr;
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
if (attName == "volatile") {
|
||||
|
|
|
@ -173,6 +173,7 @@ protected:
|
|||
virtual ~Symbol(void) {} ///< Destructor
|
||||
void setDisplayFormat(uint4 val); ///< Set the display format for \b this Symbol
|
||||
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:
|
||||
/// \brief Possible display (dispflag) properties for a Symbol
|
||||
enum {
|
||||
|
@ -183,7 +184,8 @@ public:
|
|||
force_char = 5, ///< Force integer to be printed as a character constant
|
||||
size_typelock = 8, ///< Only the size of the symbol is typelocked
|
||||
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
|
||||
|
@ -198,6 +200,7 @@ public:
|
|||
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 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 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
|
||||
|
@ -699,6 +702,7 @@ public:
|
|||
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 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
|
||||
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
|
||||
|
|
|
@ -540,7 +540,7 @@ void ParamListStandard::assignMap(const vector<Datatype *> &proto,bool isinput,T
|
|||
if (isinput) {
|
||||
if (res.size()==2) { // Check for hidden parameters defined by the output list
|
||||
res.back().addr = assignAddress(res.back().type,status); // Reserve first param for hidden ret value
|
||||
res.back().flags |= Varnode::hiddenretparm;
|
||||
res.back().flags |= ParameterPieces::hiddenretparm;
|
||||
if (res.back().addr.isInvalid())
|
||||
throw ParamUnassignedError("Cannot assign parameter address for " + res.back().type->getName());
|
||||
}
|
||||
|
@ -556,7 +556,7 @@ void ParamListStandard::assignMap(const vector<Datatype *> &proto,bool isinput,T
|
|||
Datatype *pointertp = typefactory.getTypePointer(pointersize,proto[i],wordsize);
|
||||
res.back().addr = assignAddress(pointertp,status);
|
||||
res.back().type = pointertp;
|
||||
res.back().flags = Varnode::indirectstorage;
|
||||
res.back().flags = ParameterPieces::indirectstorage;
|
||||
}
|
||||
else
|
||||
res.back().addr = assignAddress(proto[i],status);
|
||||
|
@ -1107,12 +1107,12 @@ void ParamListStandardOut::assignMap(const vector<Datatype *> &proto,bool isinpu
|
|||
if (res.back().addr.isInvalid())
|
||||
throw ParamUnassignedError("Cannot assign return value as a pointer");
|
||||
res.back().type = pointertp;
|
||||
res.back().flags = Varnode::indirectstorage;
|
||||
res.back().flags = ParameterPieces::indirectstorage;
|
||||
|
||||
res.push_back(ParameterPieces()); // Add extra storage location in the input params
|
||||
res.back().type = pointertp; // that holds a pointer to where the return value should be stored
|
||||
// leave its address invalid, to be filled in by the input list assignMap
|
||||
res.back().flags = Varnode::hiddenretparm; // Mark it as special
|
||||
res.back().flags = ParameterPieces::hiddenretparm; // Mark it as special
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1759,6 +1759,7 @@ ProtoModel::ProtoModel(Architecture *g)
|
|||
glb = g;
|
||||
input = (ParamList *)0;
|
||||
output = (ParamList *)0;
|
||||
compatModel = (const ProtoModel *)0;
|
||||
extrapop=0;
|
||||
injectUponEntry = -1;
|
||||
injectUponReturn = -1;
|
||||
|
@ -1797,6 +1798,9 @@ ProtoModel::ProtoModel(const string &nm,const ProtoModel &op2)
|
|||
stackgrowsnegative = op2.stackgrowsnegative;
|
||||
hasThis = op2.hasThis;
|
||||
isConstruct = op2.isConstruct;
|
||||
if (name == "__thiscall")
|
||||
hasThis = true;
|
||||
compatModel = &op2;
|
||||
}
|
||||
|
||||
ProtoModel::~ProtoModel(void)
|
||||
|
@ -1808,6 +1812,19 @@ ProtoModel::~ProtoModel(void)
|
|||
delete output;
|
||||
}
|
||||
|
||||
/// Test whether one ProtoModel can substituted for another during FuncCallSpecs::deindirect
|
||||
/// Currently this can only happen if one model is a copy of the other except for the
|
||||
/// hasThis boolean property.
|
||||
/// \param op2 is the other ProtoModel to compare with \b this
|
||||
/// \return \b true if the two models are compatible
|
||||
bool ProtoModel::isCompatible(const ProtoModel *op2) const
|
||||
|
||||
{
|
||||
if (this == op2 || compatModel == op2 || op2->compatModel == this)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Calculate input and output storage locations given a function prototype
|
||||
///
|
||||
/// The data-types of the function prototype are passed in as an ordered list, with the
|
||||
|
@ -2266,21 +2283,30 @@ void ParameterBasic::setTypeLock(bool val)
|
|||
|
||||
{
|
||||
if (val) {
|
||||
flags |= Varnode::typelock;
|
||||
flags |= ParameterPieces::typelock;
|
||||
if (type->getMetatype() == TYPE_UNKNOWN) // Check if we are locking TYPE_UNKNOWN
|
||||
flags |= Varnode::mark; // If so, set Varnode::mark to indicate the sizelock
|
||||
flags |= ParameterPieces::sizelock;
|
||||
}
|
||||
else
|
||||
flags &= ~((uint4)(Varnode::typelock|Varnode::mark));
|
||||
flags &= ~((uint4)(ParameterPieces::typelock|ParameterPieces::sizelock));
|
||||
}
|
||||
|
||||
void ParameterBasic::setNameLock(bool val)
|
||||
|
||||
{
|
||||
if (val)
|
||||
flags |= Varnode::namelock;
|
||||
flags |= ParameterPieces::namelock;
|
||||
else
|
||||
flags &= ~((uint4)Varnode::namelock);
|
||||
flags &= ~((uint4)ParameterPieces::namelock);
|
||||
}
|
||||
|
||||
void ParameterBasic::setThisPointer(bool val)
|
||||
|
||||
{
|
||||
if (val)
|
||||
flags |= ParameterPieces::isthis;
|
||||
else
|
||||
flags &= ~((uint4)ParameterPieces::isthis);
|
||||
}
|
||||
|
||||
void ParameterBasic::overrideSizeLockType(Datatype *ct)
|
||||
|
@ -2352,6 +2378,12 @@ bool ParameterSymbol::isSizeTypeLocked(void) const
|
|||
return sym->isSizeTypeLocked();
|
||||
}
|
||||
|
||||
bool ParameterSymbol::isThisPointer(void) const
|
||||
|
||||
{
|
||||
return sym->isThisPointer();
|
||||
}
|
||||
|
||||
bool ParameterSymbol::isIndirectStorage(void) const
|
||||
|
||||
{
|
||||
|
@ -2393,6 +2425,13 @@ void ParameterSymbol::setNameLock(bool val)
|
|||
scope->clearAttribute(sym,Varnode::namelock);
|
||||
}
|
||||
|
||||
void ParameterSymbol::setThisPointer(bool val)
|
||||
|
||||
{
|
||||
Scope *scope = sym->getScope();
|
||||
scope->setThisPointer(sym, val);
|
||||
}
|
||||
|
||||
void ParameterSymbol::overrideSizeLockType(Datatype *ct)
|
||||
|
||||
{
|
||||
|
@ -2471,6 +2510,8 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame
|
|||
SymbolEntry *entry;
|
||||
Address usepoint;
|
||||
|
||||
bool isindirect = (pieces.flags & ParameterPieces::indirectstorage) != 0;
|
||||
bool ishidden = (pieces.flags & ParameterPieces::hiddenretparm) != 0;
|
||||
if (res->sym != (Symbol *)0) {
|
||||
entry = res->sym->getFirstWholeMap();
|
||||
if ((entry->getAddr() != pieces.addr)||(entry->getSize() != pieces.type->getSize())) {
|
||||
|
@ -2483,18 +2524,24 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame
|
|||
usepoint = restricted_usepoint;
|
||||
res->sym = scope->addSymbol(nm,pieces.type,pieces.addr,usepoint)->getSymbol();
|
||||
scope->setCategory(res->sym,0,i);
|
||||
if ((pieces.flags & (Varnode::indirectstorage|Varnode::hiddenretparm)) != 0)
|
||||
scope->setAttribute(res->sym,pieces.flags & (Varnode::indirectstorage|Varnode::hiddenretparm));
|
||||
if (isindirect || ishidden) {
|
||||
uint4 mirror = 0;
|
||||
if (isindirect)
|
||||
mirror |= Varnode::indirectstorage;
|
||||
if (ishidden)
|
||||
mirror |= Varnode::hiddenretparm;
|
||||
scope->setAttribute(res->sym,mirror);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
if ((res->sym->getFlags() & Varnode::indirectstorage) != (pieces.flags & Varnode::indirectstorage)) {
|
||||
if ((pieces.flags & Varnode::indirectstorage)!=0)
|
||||
if (res->sym->isIndirectStorage() != isindirect) {
|
||||
if (isindirect)
|
||||
scope->setAttribute(res->sym,Varnode::indirectstorage);
|
||||
else
|
||||
scope->clearAttribute(res->sym,Varnode::indirectstorage);
|
||||
}
|
||||
if ((res->sym->getFlags() & Varnode::hiddenretparm) != (pieces.flags & Varnode::hiddenretparm)) {
|
||||
if ((pieces.flags & Varnode::hiddenretparm)!=0)
|
||||
if (res->sym->isHiddenReturn() != ishidden) {
|
||||
if (ishidden)
|
||||
scope->setAttribute(res->sym,Varnode::hiddenretparm);
|
||||
else
|
||||
scope->clearAttribute(res->sym,Varnode::hiddenretparm);
|
||||
|
@ -2737,6 +2784,8 @@ void ProtoStoreInternal::saveXml(ostream &s) const
|
|||
a_v_b(s,"typelock",true);
|
||||
if (param->isNameLocked())
|
||||
a_v_b(s,"namelock",true);
|
||||
if (param->isThisPointer())
|
||||
a_v_b(s,"thisptr",true);
|
||||
if (param->isIndirectStorage())
|
||||
a_v_b(s,"indirectstorage",true);
|
||||
if (param->isHiddenReturn())
|
||||
|
@ -2759,47 +2808,50 @@ void ProtoStoreInternal::restoreXml(const Element *el,ProtoModel *model)
|
|||
List::const_iterator iter;
|
||||
vector<ParameterPieces> pieces;
|
||||
vector<string> namelist;
|
||||
vector<bool> typelocklist;
|
||||
vector<bool> namelocklist;
|
||||
bool addressesdetermined = true;
|
||||
|
||||
pieces.push_back( ParameterPieces() ); // Push on placeholder for output pieces
|
||||
namelist.push_back("ret");
|
||||
typelocklist.push_back(outparam->isTypeLocked());
|
||||
namelocklist.push_back(false);
|
||||
pieces.back().type = outparam->getType();
|
||||
pieces.back().flags = 0;
|
||||
if (outparam->isTypeLocked())
|
||||
pieces.back().flags |= ParameterPieces::typelock;
|
||||
if (outparam->isIndirectStorage())
|
||||
pieces.back().flags |= Varnode::indirectstorage;
|
||||
pieces.back().flags |= ParameterPieces::indirectstorage;
|
||||
if (outparam->getAddress().isInvalid())
|
||||
addressesdetermined = false;
|
||||
|
||||
for(iter=list.begin();iter!=list.end();++iter) { // This is only the input params
|
||||
const Element *subel = *iter;
|
||||
string name;
|
||||
bool typelock = false;
|
||||
bool namelock = false;
|
||||
uint4 flags = 0;
|
||||
for(int4 i=0;i<subel->getNumAttributes();++i) {
|
||||
const string &attr( subel->getAttributeName(i) );
|
||||
if (attr == "name")
|
||||
name = subel->getAttributeValue(i);
|
||||
else if (attr == "typelock")
|
||||
typelock = xml_readbool(subel->getAttributeValue(i));
|
||||
else if (attr == "namelock")
|
||||
namelock = xml_readbool(subel->getAttributeValue(i));
|
||||
else if (attr == "typelock") {
|
||||
if (xml_readbool(subel->getAttributeValue(i)))
|
||||
flags |= ParameterPieces::typelock;
|
||||
}
|
||||
else if (attr == "namelock") {
|
||||
if (xml_readbool(subel->getAttributeValue(i)))
|
||||
flags |= ParameterPieces::namelock;
|
||||
}
|
||||
else if (attr == "thisptr") {
|
||||
if (xml_readbool(subel->getAttributeValue(i)))
|
||||
flags |= ParameterPieces::isthis;
|
||||
}
|
||||
else if (attr == "indirectstorage") {
|
||||
if (xml_readbool(subel->getAttributeValue(i)))
|
||||
flags |= Varnode::indirectstorage;
|
||||
flags |= ParameterPieces::indirectstorage;
|
||||
}
|
||||
else if (attr == "hiddenretparm") {
|
||||
if (xml_readbool(subel->getAttributeValue(i)))
|
||||
flags |= Varnode::hiddenretparm;
|
||||
flags |= ParameterPieces::hiddenretparm;
|
||||
}
|
||||
}
|
||||
if ((flags & ParameterPieces::hiddenretparm) == 0)
|
||||
namelist.push_back(name);
|
||||
typelocklist.push_back(typelock);
|
||||
namelocklist.push_back(namelock);
|
||||
pieces.push_back(ParameterPieces());
|
||||
ParameterPieces &curparam( pieces.back() );
|
||||
const List &sublist(subel->getChildren());
|
||||
|
@ -2811,8 +2863,6 @@ void ProtoStoreInternal::restoreXml(const Element *el,ProtoModel *model)
|
|||
curparam.flags = flags;
|
||||
if (curparam.addr.isInvalid())
|
||||
addressesdetermined = false;
|
||||
typelocklist.push_back(typelock);
|
||||
namelocklist.push_back(namelock);
|
||||
}
|
||||
ProtoParameter *curparam;
|
||||
if (!addressesdetermined) {
|
||||
|
@ -2821,28 +2871,53 @@ void ProtoStoreInternal::restoreXml(const Element *el,ProtoModel *model)
|
|||
vector<Datatype *> typelist;
|
||||
for(int4 i=0;i<pieces.size();++i) // Save off the restored types
|
||||
typelist.push_back( pieces[i].type );
|
||||
pieces.clear(); // throw out any other piece information
|
||||
model->assignParameterStorage(typelist,pieces,true);
|
||||
vector<ParameterPieces> addrPieces;
|
||||
model->assignParameterStorage(typelist,addrPieces,true);
|
||||
addrPieces.swap(pieces);
|
||||
uint4 k = 0;
|
||||
for(uint4 i=0;i<pieces.size();++i) {
|
||||
if ((pieces[i].flags & ParameterPieces::hiddenretparm)!=0)
|
||||
continue; // Increment i but not k
|
||||
pieces[i].flags = addrPieces[k].flags; // Use the original flags
|
||||
k = k + 1;
|
||||
}
|
||||
if (pieces[0].addr.isInvalid()) { // If could not get valid storage for output
|
||||
typelocklist[0] = false; // Treat as unlocked void
|
||||
pieces[0].flags &= ~((uint4)ParameterPieces::typelock); // Treat as unlocked void
|
||||
}
|
||||
curparam = setOutput(pieces[0]);
|
||||
curparam->setTypeLock(typelocklist[0]);
|
||||
curparam->setTypeLock((pieces[0].flags & ParameterPieces::typelock)!=0);
|
||||
}
|
||||
uint4 j=1;
|
||||
for(uint4 i=1;i<pieces.size();++i) {
|
||||
if ((pieces[i].flags&Varnode::hiddenretparm)!=0) {
|
||||
if ((pieces[i].flags&ParameterPieces::hiddenretparm)!=0) {
|
||||
curparam = setInput(i-1,"rethidden",pieces[i]);
|
||||
curparam->setTypeLock(typelocklist[0]); // Has output's typelock
|
||||
curparam->setTypeLock((pieces[0].flags & ParameterPieces::typelock)!=0); // Has output's typelock
|
||||
continue; // increment i but not j
|
||||
}
|
||||
curparam = setInput(i-1,namelist[j],pieces[i]);
|
||||
curparam->setTypeLock(typelocklist[j]);
|
||||
curparam->setNameLock(namelocklist[j]);
|
||||
curparam->setTypeLock((pieces[i].flags & ParameterPieces::typelock)!=0);
|
||||
curparam->setNameLock((pieces[i].flags & ParameterPieces::namelock)!=0);
|
||||
j = j + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// This is called after a new prototype is established (via restoreXml or updateAllTypes)
|
||||
/// It makes sure that if the ProtoModel calls for a "this" parameter, then the appropriate parameter
|
||||
/// is explicitly marked as the "this".
|
||||
void FuncProto::updateThisPointer(void)
|
||||
|
||||
{
|
||||
if (!model->hasThisPointer()) return;
|
||||
int4 numInputs = store->getNumInputs();
|
||||
if (numInputs == 0) return;
|
||||
ProtoParameter *param = store->getInput(0);
|
||||
if (param->isHiddenReturn()) {
|
||||
if (numInputs < 2) return;
|
||||
param = store->getInput(1);
|
||||
}
|
||||
param->setThisPointer(true);
|
||||
}
|
||||
|
||||
/// Prepend the indicated number of input parameters to \b this.
|
||||
/// The new parameters have a data-type of xunknown4. If they were
|
||||
/// originally locked, the existing parameters are preserved.
|
||||
|
@ -2893,7 +2968,7 @@ void FuncProto::paramShift(int4 paramshift)
|
|||
store->setOutput(pieces[0]);
|
||||
uint4 j=1;
|
||||
for(uint4 i=1;i<pieces.size();++i) {
|
||||
if ((pieces[i].flags & Varnode::hiddenretparm) != 0) {
|
||||
if ((pieces[i].flags & ParameterPieces::hiddenretparm) != 0) {
|
||||
store->setInput(i-1,"rethidden",pieces[i]);
|
||||
continue; // increment i but not j
|
||||
}
|
||||
|
@ -3219,6 +3294,7 @@ void FuncProto::updateInputTypes(Funcdata &data,const vector<Varnode *> &trialli
|
|||
}
|
||||
for(int4 i=0;i<triallist.size();++i)
|
||||
triallist[i]->clearMark();
|
||||
updateThisPointer();
|
||||
}
|
||||
|
||||
/// \brief Update input parameters based on Varnode trials, but do not store the data-type
|
||||
|
@ -3346,7 +3422,7 @@ void FuncProto::updateAllTypes(const vector<string> &namelist,const vector<Datat
|
|||
store->setOutput(pieces[0]);
|
||||
uint4 j=1;
|
||||
for(uint4 i=1;i<pieces.size();++i) {
|
||||
if ((pieces[i].flags & Varnode::hiddenretparm) != 0) {
|
||||
if ((pieces[i].flags & ParameterPieces::hiddenretparm) != 0) {
|
||||
store->setInput(i-1,"rethidden",pieces[i]);
|
||||
continue; // increment i but not j
|
||||
}
|
||||
|
@ -3357,6 +3433,7 @@ void FuncProto::updateAllTypes(const vector<string> &namelist,const vector<Datat
|
|||
catch(ParamUnassignedError &err) {
|
||||
flags |= error_inputparam;
|
||||
}
|
||||
updateThisPointer();
|
||||
}
|
||||
|
||||
/// \brief Calculate the effect \b this has an a given storage location
|
||||
|
@ -3591,7 +3668,7 @@ bool FuncProto::getBiggestContainedInputParam(const Address &loc,int4 size,Varno
|
|||
bool FuncProto::isCompatible(const FuncProto &op2) const
|
||||
|
||||
{
|
||||
if (model != op2.model) return false;
|
||||
if (!model->isCompatible(op2.model)) return false;
|
||||
if (op2.isOutputLocked()) {
|
||||
if (isOutputLocked()) {
|
||||
ProtoParameter *out1 = store->getOutput();
|
||||
|
@ -3683,8 +3760,6 @@ void FuncProto::saveXml(ostream &s) const
|
|||
a_v_b(s,"constructor",true);
|
||||
if (isDestructor())
|
||||
a_v_b(s,"destructor",true);
|
||||
if (hasThisPointer())
|
||||
a_v_b(s,"hasthis",true);
|
||||
s << ">\n";
|
||||
ProtoParameter *outparam = store->getOutput();
|
||||
s << " <returnsym";
|
||||
|
@ -3828,10 +3903,6 @@ void FuncProto::restoreXml(const Element *el,Architecture *glb)
|
|||
if (xml_readbool(el->getAttributeValue(i)))
|
||||
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
|
||||
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()) {
|
||||
throw LowlevelError("<returnsym> tag must include a valid storage address");
|
||||
}
|
||||
|
||||
updateThisPointer();
|
||||
}
|
||||
|
||||
/// \brief Calculate the stack offset of \b this call site
|
||||
|
|
|
@ -292,6 +292,14 @@ public:
|
|||
|
||||
/// \brief Basic elements of a parameter: address, data-type, properties
|
||||
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
|
||||
Datatype *type; ///< The datatype of the parameter
|
||||
uint4 flags; ///< additional attributes of the parameter
|
||||
|
@ -619,6 +627,7 @@ class ProtoModel {
|
|||
int4 extrapop; ///< Extra bytes popped from stack
|
||||
ParamList *input; ///< Resource model for input 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<VarnodeData> likelytrash; ///< Storage locations potentially carrying \e trash values
|
||||
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
|
||||
int4 getInjectUponEntry(void) const { return injectUponEntry; } ///< Get the inject \e uponentry 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
|
||||
///
|
||||
|
@ -911,11 +921,13 @@ public:
|
|||
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 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 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 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 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.
|
||||
///
|
||||
|
@ -965,7 +977,7 @@ class ParameterBasic : public ProtoParameter {
|
|||
string name; ///< The name of the parameter, "" for undefined or return value parameters
|
||||
Address addr; ///< Storage address 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:
|
||||
ParameterBasic(const string &nm,const Address &ad,Datatype *tp,uint4 fl) {
|
||||
name = nm; addr = ad; type = tp; flags=fl; } ///< Construct from components
|
||||
|
@ -973,14 +985,16 @@ public:
|
|||
virtual Datatype *getType(void) const { return type; }
|
||||
virtual Address getAddress(void) const { return addr; }
|
||||
virtual int4 getSize(void) const { return type->getSize(); }
|
||||
virtual bool isTypeLocked(void) const { return ((flags&Varnode::typelock)!=0); }
|
||||
virtual bool isNameLocked(void) const { return ((flags&Varnode::namelock)!=0); }
|
||||
virtual bool isSizeTypeLocked(void) const { return ((flags&Varnode::mark)!=0); }
|
||||
virtual bool isIndirectStorage(void) const { return ((flags&Varnode::indirectstorage)!=0); }
|
||||
virtual bool isHiddenReturn(void) const { return ((flags&Varnode::hiddenretparm)!=0); }
|
||||
virtual bool isTypeLocked(void) const { return ((flags&ParameterPieces::typelock)!=0); }
|
||||
virtual bool isNameLocked(void) const { return ((flags&ParameterPieces::namelock)!=0); }
|
||||
virtual bool isSizeTypeLocked(void) const { return ((flags&ParameterPieces::sizelock)!=0); }
|
||||
virtual bool isThisPointer(void) const { return ((flags&ParameterPieces::isthis)!=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 void setTypeLock(bool val);
|
||||
virtual void setNameLock(bool val);
|
||||
virtual void setThisPointer(bool val);
|
||||
virtual void overrideSizeLockType(Datatype *ct);
|
||||
virtual void resetSizeLockType(TypeFactory *factory);
|
||||
virtual ProtoParameter *clone(void) const;
|
||||
|
@ -1061,11 +1075,13 @@ public:
|
|||
virtual bool isTypeLocked(void) const;
|
||||
virtual bool isNameLocked(void) const;
|
||||
virtual bool isSizeTypeLocked(void) const;
|
||||
virtual bool isThisPointer(void) const;
|
||||
virtual bool isIndirectStorage(void) const;
|
||||
virtual bool isHiddenReturn(void) const;
|
||||
virtual bool isNameUndefined(void) const;
|
||||
virtual void setTypeLock(bool val);
|
||||
virtual void setNameLock(bool val);
|
||||
virtual void setThisPointer(bool val);
|
||||
virtual void overrideSizeLockType(Datatype *ct);
|
||||
virtual void resetSizeLockType(TypeFactory *factory);
|
||||
virtual ProtoParameter *clone(void) const;
|
||||
|
@ -1169,6 +1185,7 @@ class FuncProto {
|
|||
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 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:
|
||||
void paramShift(int4 paramshift); ///< Add parameters to the front of the input parameter list
|
||||
bool isParamshiftApplied(void) const { return ((flags¶mshift_applied)!=0); } ///< Has a parameter shift been applied
|
||||
|
@ -1240,11 +1257,6 @@ public:
|
|||
/// \brief Is \b this a prototype for a class method, taking a \e this pointer.
|
||||
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
|
||||
bool isConstructor(void) const { return ((flags & is_constructor)!=0); }
|
||||
|
||||
|
|
|
@ -421,29 +421,6 @@ FuncCallSpecs *Funcdata::getCallSpecs(const PcodeOp *op) const
|
|||
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
|
||||
///
|
||||
/// \param a is the first call specification to compare
|
||||
|
|
|
@ -87,6 +87,7 @@ class Funcdata {
|
|||
// Low level Varnode functions
|
||||
void setVarnodeProperties(Varnode *vn) const; ///< Look-up boolean properties and data-type information
|
||||
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 descend2Undef(Varnode *vn); ///< Transform all reads of the given Varnode to a special \b undefined constant
|
||||
|
||||
|
|
|
@ -866,6 +866,46 @@ bool Funcdata::syncVarnodesWithSymbols(const ScopeLocal *lm,bool typesyes)
|
|||
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
|
||||
///
|
||||
/// 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
|
||||
entry = localmap->queryProperties(vn->getAddr(), 1, usepoint, flags);
|
||||
if (entry != (SymbolEntry *) 0) {
|
||||
sym = entry->getSymbol();
|
||||
vn->setSymbolEntry(entry);
|
||||
sym = handleSymbolConflict(entry, vn);
|
||||
}
|
||||
else { // Must create a symbol entry
|
||||
if (!vn->isPersist()) { // Only create local symbol
|
||||
|
|
|
@ -84,7 +84,7 @@ public:
|
|||
unary = 0x8000, ///< Evaluate as unary expression
|
||||
binary = 0x10000, ///< Evaluate as binary expression
|
||||
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
|
||||
nonprinting = 0x100000, ///< Op should not be directly printed as source
|
||||
halt = 0x200000, ///< instruction causes processor or process to halt
|
||||
|
@ -100,15 +100,12 @@ public:
|
|||
indirect_store = 0x80000000 ///< CPUI_INDIRECT is caused by CPUI_STORE
|
||||
};
|
||||
enum {
|
||||
has_thisptr = 0x1, ///< First parameter ( getIn(1) ) is a this pointer
|
||||
is_constructor = 0x2, ///< Op is call to a constructor
|
||||
is_destructor = 0x4, ///< Op is call to a destructor
|
||||
special_prop = 0x8, ///< Does some special form of datatype propagation
|
||||
special_print = 0x10, ///< Op is marked for special printing
|
||||
modified = 0x20, ///< This op has been modified by the current action
|
||||
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
|
||||
special_prop = 1, ///< Does some special form of datatype propagation
|
||||
special_print = 2, ///< Op is marked for special printing
|
||||
modified = 4, ///< This op has been modified by the current action
|
||||
warning = 8, ///< Warning has been generated for this op
|
||||
incidental_copy = 0x10, ///< Treat this as \e incidental for parameter recovery algorithms
|
||||
is_cpool_transformed = 0x20 ///< Have we checked for cpool transforms
|
||||
};
|
||||
private:
|
||||
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 getRepeatSlot(const Varnode *vn,int4 firstSlot,list<PcodeOp *>::const_iterator iter) const;
|
||||
/// \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
|
||||
uint4 getHaltType(void) const { return (flags&(PcodeOp::halt|PcodeOp::badinstruction|PcodeOp::unimplemented|
|
||||
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 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 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
|
||||
/// \brief Return \b true if output is 1-bit boolean
|
||||
bool isCalculatedBool(void) const { return ((flags&(PcodeOp::calculated_bool|PcodeOp::booloutput))!=0); }
|
||||
|
|
|
@ -73,8 +73,8 @@ void OpBehavior::registerInstructions(vector<OpBehavior *> &inst,const Translate
|
|||
inst[CPUI_BOOL_OR] = new OpBehaviorBoolOr();
|
||||
|
||||
inst[CPUI_CAST] = new OpBehavior(CPUI_CAST,false,true);
|
||||
inst[CPUI_PTRADD] = new OpBehavior(CPUI_PTRADD,false,true);
|
||||
inst[CPUI_PTRSUB] = new OpBehavior(CPUI_PTRSUB,false,true);
|
||||
inst[CPUI_PTRADD] = new OpBehavior(CPUI_PTRADD,false);
|
||||
inst[CPUI_PTRSUB] = new OpBehavior(CPUI_PTRSUB,false);
|
||||
|
||||
inst[CPUI_FLOAT_EQUAL] = new OpBehaviorFloatEqual(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_CPOOLREF] = new OpBehavior(CPUI_CPOOLREF,false,true);
|
||||
inst[CPUI_NEW] = new OpBehavior(CPUI_NEW,false,true);
|
||||
inst[CPUI_INSERT] = new OpBehavior(CPUI_INSERT,false,true);
|
||||
inst[CPUI_EXTRACT] = new OpBehavior(CPUI_EXTRACT,false,true);
|
||||
inst[CPUI_INSERT] = new OpBehavior(CPUI_INSERT,false);
|
||||
inst[CPUI_EXTRACT] = new OpBehavior(CPUI_EXTRACT,false);
|
||||
inst[CPUI_POPCOUNT] = new OpBehaviorPopcount();
|
||||
}
|
||||
|
||||
|
|
|
@ -510,8 +510,9 @@ void PrintC::opCall(const PcodeOp *op)
|
|||
{
|
||||
pushOp(&function_call,op);
|
||||
const Varnode *callpoint = op->getIn(0);
|
||||
FuncCallSpecs *fc;
|
||||
if (callpoint->getSpace()->getType()==IPTR_FSPEC) {
|
||||
FuncCallSpecs *fc = FuncCallSpecs::getFspecFromConst(callpoint->getAddr());
|
||||
fc = FuncCallSpecs::getFspecFromConst(callpoint->getAddr());
|
||||
if (fc->getName().size()==0) {
|
||||
string name = genericFunctionName(fc->getEntryAddress());
|
||||
pushAtom(Atom(name,functoken,EmitXml::funcname_color,op,(const Funcdata *)0));
|
||||
|
@ -527,15 +528,23 @@ void PrintC::opCall(const PcodeOp *op)
|
|||
clear();
|
||||
throw LowlevelError("Missing function callspec");
|
||||
}
|
||||
int4 startparam = isSet(hide_thisparam) && op->hasThisPointer() ? 2 : 1;
|
||||
if (op->numInput() > startparam) {
|
||||
for(int4 i=startparam;i<op->numInput()-1;++i)
|
||||
// TODO: Cannot hide "this" on a direct call until we print the whole
|
||||
// thing with the proper C++ method invocation format. Otherwise the output
|
||||
// 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);
|
||||
// implied vn's pushed on in reverse order for efficiency
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
else // Push empty token for void
|
||||
pushAtom(Atom("",blanktoken,EmitXml::no_color));
|
||||
}
|
||||
|
@ -545,18 +554,29 @@ void PrintC::opCallind(const PcodeOp *op)
|
|||
{
|
||||
pushOp(&function_call,op);
|
||||
pushOp(&dereference,op);
|
||||
const Funcdata *fd = op->getParent()->getFuncdata();
|
||||
FuncCallSpecs *fc = fd->getCallSpecs(op);
|
||||
if (fc == (FuncCallSpecs *)0)
|
||||
throw LowlevelError("Missing indirect function callspec");
|
||||
int4 skip = getHiddenThisSlot(op, fc);
|
||||
int4 count = op->numInput() - 1;
|
||||
count -= (skip < 0) ? 0 : 1;
|
||||
if (count > 1) { // Multiple parameters
|
||||
pushVnImplied(op->getIn(0),op,mods);
|
||||
for(int4 i=0;i<count-1;++i)
|
||||
pushOp(&comma,op);
|
||||
// implied vn's pushed on in reverse order for efficiency
|
||||
// see PrintLanguage::pushVnImplied
|
||||
int4 startparam = isSet(hide_thisparam) && op->hasThisPointer() ? 2 : 1;
|
||||
if (op->numInput()>startparam + 1) { // Multiple parameters
|
||||
pushVnImplied(op->getIn(0),op,mods);
|
||||
for(int4 i=startparam;i<op->numInput()-1;++i)
|
||||
pushOp(&comma,op);
|
||||
for(int4 i=op->numInput()-1;i>=startparam;--i)
|
||||
for(int4 i=op->numInput()-1;i>=1;--i) {
|
||||
if (i == skip) continue;
|
||||
pushVnImplied(op->getIn(i),op,mods);
|
||||
}
|
||||
else if (op->numInput()==startparam + 1) { // One parameter
|
||||
pushVnImplied(op->getIn(startparam),op,mods);
|
||||
}
|
||||
else if (count == 1) { // One parameter
|
||||
if (skip == 1)
|
||||
pushVnImplied(op->getIn(2),op,mods);
|
||||
else
|
||||
pushVnImplied(op->getIn(1),op,mods);
|
||||
pushVnImplied(op->getIn(0),op,mods);
|
||||
}
|
||||
else { // A void function
|
||||
|
@ -1332,6 +1352,31 @@ bool PrintC::printCharacterConstant(ostream &s,const Address &addr,Datatype *cha
|
|||
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)
|
||||
|
||||
{
|
||||
|
@ -1902,11 +1947,15 @@ void PrintC::emitPrototypeInputs(const FuncProto *proto)
|
|||
if (sz == 0)
|
||||
emit->print("void",EmitXml::keyword_color);
|
||||
else {
|
||||
bool printComma = false;
|
||||
for(int4 i=0;i<sz;++i) {
|
||||
if (i!=0)
|
||||
if (printComma)
|
||||
emit->print(",");
|
||||
ProtoParameter *param = proto->getParam(i);
|
||||
if (isSet(hide_thisparam) && param->isThisPointer())
|
||||
continue;
|
||||
Symbol *sym = param->getSymbol();
|
||||
printComma = true;
|
||||
if (sym != (Symbol *)0)
|
||||
emitVarDecl(sym);
|
||||
else {
|
||||
|
|
|
@ -161,6 +161,7 @@ protected:
|
|||
void opTypeCast(const PcodeOp *op); ///< Push the given p-code op using type-cast syntax to the RPN stack
|
||||
void opHiddenFunc(const PcodeOp *op); ///< Push the given p-code op as a hidden token
|
||||
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
|
||||
virtual void pushConstant(uintb val,const Datatype *ct,
|
||||
const Varnode *vn,const PcodeOp *op);
|
||||
|
|
|
@ -37,15 +37,21 @@ PrintLanguage *PrintJavaCapability::buildLanguage(Architecture *glb)
|
|||
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'
|
||||
mods |= hide_thisparam; // turn on hiding of 'this' parameter
|
||||
if (castStrategy != (CastStrategy *)0)
|
||||
delete castStrategy;
|
||||
|
||||
castStrategy = new CastStrategyJava();
|
||||
}
|
||||
|
||||
void PrintJava::resetDefaults(void)
|
||||
|
||||
{
|
||||
PrintC::resetDefaults();
|
||||
resetDefaultsPrintJava();
|
||||
}
|
||||
|
||||
void PrintJava::docFunction(const Funcdata *fd)
|
||||
|
||||
{
|
||||
|
@ -148,6 +154,14 @@ bool PrintJava::isArrayType(const Datatype *ct)
|
|||
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
|
||||
/// it needs to be represented using '[0]' syntax.
|
||||
/// \param vn is the given Varnode
|
||||
|
@ -244,18 +258,29 @@ void PrintJava::opCallind(const PcodeOp *op)
|
|||
|
||||
{
|
||||
pushOp(&function_call,op);
|
||||
const Funcdata *fd = op->getParent()->getFuncdata();
|
||||
FuncCallSpecs *fc = fd->getCallSpecs(op);
|
||||
if (fc == (FuncCallSpecs *)0)
|
||||
throw LowlevelError("Missing indirect function callspec");
|
||||
int4 skip = getHiddenThisSlot(op, fc);
|
||||
int4 count = op->numInput() - 1;
|
||||
count -= (skip < 0) ? 0 : 1;
|
||||
if (count > 1) { // Multiple parameters
|
||||
pushVnImplied(op->getIn(0),op,mods);
|
||||
for(int4 i=0;i<count-1;++i)
|
||||
pushOp(&comma,op);
|
||||
// implied vn's pushed on in reverse order for efficiency
|
||||
// see PrintLanguage::pushVnImplied
|
||||
int4 startparam = isSet(hide_thisparam) && op->hasThisPointer() ? 2 : 1;
|
||||
if (op->numInput()>startparam + 1) { // Multiple parameters
|
||||
pushVnImplied(op->getIn(0),op,mods);
|
||||
for(int4 i=startparam;i<op->numInput()-1;++i)
|
||||
pushOp(&comma,op);
|
||||
for(int4 i=op->numInput()-1;i>=startparam;--i)
|
||||
for(int4 i=op->numInput()-1;i>=1;--i) {
|
||||
if (i == skip) continue;
|
||||
pushVnImplied(op->getIn(i),op,mods);
|
||||
}
|
||||
else if (op->numInput()==startparam + 1) { // One parameter
|
||||
pushVnImplied(op->getIn(startparam),op,mods);
|
||||
}
|
||||
else if (count == 1) { // One parameter
|
||||
if (skip == 1)
|
||||
pushVnImplied(op->getIn(2),op,mods);
|
||||
else
|
||||
pushVnImplied(op->getIn(1),op,mods);
|
||||
pushVnImplied(op->getIn(0),op,mods);
|
||||
}
|
||||
else { // A void function
|
||||
|
|
|
@ -56,9 +56,11 @@ class PrintJava : public PrintC {
|
|||
static OpToken instanceof; ///< The \b instanceof keyword
|
||||
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.
|
||||
void resetDefaultsPrintJava(void); ///< Set options that are specific to Java
|
||||
virtual void printUnicode(ostream &s,int4 onechar) const;
|
||||
public:
|
||||
PrintJava(Architecture *g,const string &nm="java-language"); ///< Constructor
|
||||
virtual void resetDefaults(void);
|
||||
virtual void docFunction(const Funcdata *fd);
|
||||
virtual void pushTypeStart(const Datatype *ct,bool noident);
|
||||
virtual void pushTypeEnd(const Datatype *ct);
|
||||
|
|
|
@ -6363,30 +6363,8 @@ int4 RulePtrsubUndo::applyOp(PcodeOp *op,Funcdata &data)
|
|||
if (!data.isTypeRecoveryOn()) return 0;
|
||||
|
||||
Varnode *basevn = op->getIn(0);
|
||||
TypePointer *ct = (TypePointer *)basevn->getType();
|
||||
bool undo = false;
|
||||
|
||||
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;
|
||||
if (basevn->getType()->isPtrsubMatching(op->getIn(1)->getOffset()))
|
||||
return 0;
|
||||
|
||||
data.opSetOpcode(op,CPUI_INT_ADD);
|
||||
return 1;
|
||||
|
|
|
@ -24,6 +24,7 @@ void AddrSpace::calcScaleMask(void)
|
|||
pointerLowerBound = (addressSize < 3) ? 0x100: 0x1000;
|
||||
highest = calc_mask(addressSize); // Maximum address
|
||||
highest = highest * wordsize + (wordsize-1); // Maximum byte address
|
||||
pointerUpperBound = highest;
|
||||
}
|
||||
|
||||
/// Initialize an address space with its basic attributes
|
||||
|
|
|
@ -98,6 +98,7 @@ private:
|
|||
uint4 flags; ///< Attributes of the space
|
||||
uintb highest; ///< Highest (byte) offset into this space
|
||||
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
|
||||
protected:
|
||||
string name; ///< Name of this space
|
||||
|
@ -127,6 +128,7 @@ public:
|
|||
uint4 getAddrSize(void) const; ///< Get the size of the space
|
||||
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 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
|
||||
uintb wrapOffset(uintb off) const; ///< Wrap -off- to the offset that fits into this space
|
||||
char getShortcut(void) const; ///< Get the shortcut character
|
||||
|
@ -340,13 +342,20 @@ inline uintb AddrSpace::getHighest(void) const {
|
|||
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.
|
||||
/// \return the minimum offset that will be inferred as a pointer
|
||||
inline uintb AddrSpace::getPointerLowerBound(void) const {
|
||||
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
|
||||
/// if there exists near pointers, this value may be non-zero.
|
||||
inline int4 AddrSpace::getMinimumPtrSize(void) const {
|
||||
|
|
|
@ -421,6 +421,16 @@ void AddrSpaceManager::insertResolver(AddrSpace *spc,AddressResolver *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
|
||||
/// must be explicited created via \e new
|
||||
AddrSpaceManager::~AddrSpaceManager(void)
|
||||
|
|
|
@ -243,6 +243,7 @@ protected:
|
|||
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 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
|
||||
public:
|
||||
AddrSpaceManager(void); ///< Construct an empty address space manager
|
||||
|
|
|
@ -316,6 +316,35 @@ void Datatype::saveXmlRef(ostream &s) const
|
|||
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
|
||||
/// Properties are read from the attributes of the 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
|
||||
/// \param hasThisPtr toggles whether prototype has takes a "this" pointer
|
||||
/// \param isConstructor toggles whether the function is a constructor
|
||||
/// \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->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
|
||||
/// \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 isDestructor toggles "destructor" property on "function" datatypes
|
||||
/// \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;
|
||||
|
@ -2197,7 +2223,7 @@ Datatype *TypeFactory::restoreXmlTypeWithCodeFlags(const Element *el,bool hasThi
|
|||
throw LowlevelError("Special type restoreXml does not see code");
|
||||
TypeCode tc("");
|
||||
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
|
||||
return findAdd(tp);
|
||||
}
|
||||
|
|
|
@ -126,6 +126,7 @@ public:
|
|||
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 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
|
||||
|
@ -350,7 +351,7 @@ public:
|
|||
TypeCode(const string &nm); ///< Construct from a name
|
||||
int4 compareBasic(const TypeCode *op) const; ///< Compare surface characteristics of two TypeCodes
|
||||
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 void printRaw(ostream &s) const;
|
||||
virtual int4 compare(const Datatype &op,int4 level) const;
|
||||
|
@ -431,7 +432,7 @@ public:
|
|||
const vector<bool> &assignlist,
|
||||
TypeEnum *te); ///< Set named values for an enumeration
|
||||
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
|
||||
Datatype *getBaseNoChar(int4 s,type_metatype m); ///< Get atomic type excluding "char"
|
||||
Datatype *getBase(int4 s,type_metatype m); ///< Get atomic type
|
||||
|
|
|
@ -1356,126 +1356,126 @@ TypeOpBoolOr::TypeOpBoolOr(TypeFactory *t)
|
|||
TypeOpFloatEqual::TypeOpFloatEqual(TypeFactory *t,const Translate *trans)
|
||||
: 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);
|
||||
}
|
||||
|
||||
TypeOpFloatNotEqual::TypeOpFloatNotEqual(TypeFactory *t,const Translate *trans)
|
||||
: 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);
|
||||
}
|
||||
|
||||
TypeOpFloatLess::TypeOpFloatLess(TypeFactory *t,const Translate *trans)
|
||||
: 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);
|
||||
}
|
||||
|
||||
TypeOpFloatLessEqual::TypeOpFloatLessEqual(TypeFactory *t,const Translate *trans)
|
||||
: 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);
|
||||
}
|
||||
|
||||
TypeOpFloatNan::TypeOpFloatNan(TypeFactory *t,const Translate *trans)
|
||||
: 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);
|
||||
}
|
||||
|
||||
TypeOpFloatAdd::TypeOpFloatAdd(TypeFactory *t,const Translate *trans)
|
||||
: 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);
|
||||
}
|
||||
|
||||
TypeOpFloatDiv::TypeOpFloatDiv(TypeFactory *t,const Translate *trans)
|
||||
: TypeOpBinary(t,CPUI_FLOAT_DIV,"/",TYPE_FLOAT,TYPE_FLOAT)
|
||||
{
|
||||
opflags = PcodeOp::binary | PcodeOp::floatingpoint;
|
||||
opflags = PcodeOp::binary;
|
||||
behave = new OpBehaviorFloatDiv(trans);
|
||||
}
|
||||
|
||||
TypeOpFloatMult::TypeOpFloatMult(TypeFactory *t,const Translate *trans)
|
||||
: 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);
|
||||
}
|
||||
|
||||
TypeOpFloatSub::TypeOpFloatSub(TypeFactory *t,const Translate *trans)
|
||||
: TypeOpBinary(t,CPUI_FLOAT_SUB,"-",TYPE_FLOAT,TYPE_FLOAT)
|
||||
{
|
||||
opflags = PcodeOp::binary | PcodeOp::floatingpoint;
|
||||
opflags = PcodeOp::binary;
|
||||
behave = new OpBehaviorFloatSub(trans);
|
||||
}
|
||||
|
||||
TypeOpFloatNeg::TypeOpFloatNeg(TypeFactory *t,const Translate *trans)
|
||||
: TypeOpUnary(t,CPUI_FLOAT_NEG,"-",TYPE_FLOAT,TYPE_FLOAT)
|
||||
{
|
||||
opflags = PcodeOp::unary | PcodeOp::floatingpoint;
|
||||
opflags = PcodeOp::unary;
|
||||
behave = new OpBehaviorFloatNeg(trans);
|
||||
}
|
||||
|
||||
TypeOpFloatAbs::TypeOpFloatAbs(TypeFactory *t,const Translate *trans)
|
||||
: TypeOpFunc(t,CPUI_FLOAT_ABS,"ABS",TYPE_FLOAT,TYPE_FLOAT)
|
||||
{
|
||||
opflags = PcodeOp::unary | PcodeOp::floatingpoint;
|
||||
opflags = PcodeOp::unary;
|
||||
behave = new OpBehaviorFloatAbs(trans);
|
||||
}
|
||||
|
||||
TypeOpFloatSqrt::TypeOpFloatSqrt(TypeFactory *t,const Translate *trans)
|
||||
: TypeOpFunc(t,CPUI_FLOAT_SQRT,"SQRT",TYPE_FLOAT,TYPE_FLOAT)
|
||||
{
|
||||
opflags = PcodeOp::unary | PcodeOp::floatingpoint;
|
||||
opflags = PcodeOp::unary;
|
||||
behave = new OpBehaviorFloatSqrt(trans);
|
||||
}
|
||||
|
||||
TypeOpFloatInt2Float::TypeOpFloatInt2Float(TypeFactory *t,const Translate *trans)
|
||||
: TypeOpFunc(t,CPUI_FLOAT_INT2FLOAT,"INT2FLOAT",TYPE_FLOAT,TYPE_INT)
|
||||
{
|
||||
opflags = PcodeOp::unary | PcodeOp::floatingpoint;
|
||||
opflags = PcodeOp::unary;
|
||||
behave = new OpBehaviorFloatInt2Float(trans);
|
||||
}
|
||||
|
||||
TypeOpFloatFloat2Float::TypeOpFloatFloat2Float(TypeFactory *t,const Translate *trans)
|
||||
: TypeOpFunc(t,CPUI_FLOAT_FLOAT2FLOAT,"FLOAT2FLOAT",TYPE_FLOAT,TYPE_FLOAT)
|
||||
{
|
||||
opflags = PcodeOp::unary | PcodeOp::floatingpoint;
|
||||
opflags = PcodeOp::unary;
|
||||
behave = new OpBehaviorFloatFloat2Float(trans);
|
||||
}
|
||||
|
||||
TypeOpFloatTrunc::TypeOpFloatTrunc(TypeFactory *t,const Translate *trans)
|
||||
: TypeOpFunc(t,CPUI_FLOAT_TRUNC,"TRUNC",TYPE_INT,TYPE_FLOAT)
|
||||
{
|
||||
opflags = PcodeOp::unary | PcodeOp::floatingpoint;
|
||||
opflags = PcodeOp::unary;
|
||||
behave = new OpBehaviorFloatTrunc(trans);
|
||||
}
|
||||
|
||||
TypeOpFloatCeil::TypeOpFloatCeil(TypeFactory *t,const Translate *trans)
|
||||
: TypeOpFunc(t,CPUI_FLOAT_CEIL,"CEIL",TYPE_FLOAT,TYPE_FLOAT)
|
||||
{
|
||||
opflags = PcodeOp::unary | PcodeOp::floatingpoint;
|
||||
opflags = PcodeOp::unary;
|
||||
behave = new OpBehaviorFloatCeil(trans);
|
||||
}
|
||||
|
||||
TypeOpFloatFloor::TypeOpFloatFloor(TypeFactory *t,const Translate *trans)
|
||||
: TypeOpFunc(t,CPUI_FLOAT_FLOOR,"FLOOR",TYPE_FLOAT,TYPE_FLOAT)
|
||||
{
|
||||
opflags = PcodeOp::unary | PcodeOp::floatingpoint;
|
||||
opflags = PcodeOp::unary;
|
||||
behave = new OpBehaviorFloatFloor(trans);
|
||||
}
|
||||
|
||||
TypeOpFloatRound::TypeOpFloatRound(TypeFactory *t,const Translate *trans)
|
||||
: TypeOpFunc(t,CPUI_FLOAT_ROUND,"ROUND",TYPE_FLOAT,TYPE_FLOAT)
|
||||
{
|
||||
opflags = PcodeOp::unary | PcodeOp::floatingpoint;
|
||||
opflags = PcodeOp::unary;
|
||||
behave = new OpBehaviorFloatRound(trans);
|
||||
}
|
||||
|
||||
|
@ -1610,8 +1610,8 @@ void TypeOpCast::printRaw(ostream &s,const PcodeOp *op)
|
|||
TypeOpPtradd::TypeOpPtradd(TypeFactory *t) : TypeOp(t,CPUI_PTRADD,"+")
|
||||
|
||||
{
|
||||
opflags = PcodeOp::special | PcodeOp::nocollapse;
|
||||
behave = new OpBehavior(CPUI_PTRADD,false,true); // Dummy behavior
|
||||
opflags = PcodeOp::ternary | PcodeOp::nocollapse;
|
||||
behave = new OpBehavior(CPUI_PTRADD,false); // Dummy behavior
|
||||
}
|
||||
|
||||
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
|
||||
// But the typing information doesn't really
|
||||
// allow this to be commutative.
|
||||
opflags = PcodeOp::special|PcodeOp::nocollapse;
|
||||
behave = new OpBehavior(CPUI_PTRSUB,false,true); // Dummy behavior
|
||||
opflags = PcodeOp::binary|PcodeOp::nocollapse;
|
||||
behave = new OpBehavior(CPUI_PTRSUB,false); // Dummy behavior
|
||||
}
|
||||
|
||||
Datatype *TypeOpPtrsub::getOutputLocal(const PcodeOp *op) const
|
||||
|
@ -1834,8 +1834,8 @@ void TypeOpNew::printRaw(ostream &s,const PcodeOp *op)
|
|||
TypeOpInsert::TypeOpInsert(TypeFactory *t)
|
||||
: TypeOpFunc(t,CPUI_INSERT,"INSERT",TYPE_UNKNOWN,TYPE_INT)
|
||||
{
|
||||
opflags = PcodeOp::special;
|
||||
behave = new OpBehavior(CPUI_INSERT,false,true); // Dummy behavior
|
||||
opflags = PcodeOp::ternary;
|
||||
behave = new OpBehavior(CPUI_INSERT,false); // Dummy behavior
|
||||
}
|
||||
|
||||
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)
|
||||
: TypeOpFunc(t,CPUI_EXTRACT,"EXTRACT",TYPE_INT,TYPE_INT)
|
||||
{
|
||||
opflags = PcodeOp::special;
|
||||
behave = new OpBehavior(CPUI_EXTRACT,false,true); // Dummy behavior
|
||||
opflags = PcodeOp::ternary;
|
||||
behave = new OpBehavior(CPUI_EXTRACT,false); // Dummy behavior
|
||||
}
|
||||
|
||||
Datatype *TypeOpExtract::getInputLocal(const PcodeOp *op,int4 slot) const
|
||||
|
|
|
@ -289,6 +289,17 @@ void ScopeLocal::collectNameRecs(void)
|
|||
Symbol *sym = *iter++;
|
||||
if (sym->isNameLocked()&&(!sym->isTypeLocked())) {
|
||||
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)
|
||||
|
||||
{
|
||||
Address param_usepoint = fd->getAddress() - 1;
|
||||
list<NameRecommend>::const_iterator iter;
|
||||
for(iter=nameRecommend.begin();iter!=nameRecommend.end();++iter) {
|
||||
const Address &addr((*iter).getAddr());
|
||||
|
@ -1258,6 +1270,9 @@ void ScopeLocal::recoverNameRecommendationsForSymbols(void)
|
|||
vn = fd->findLinkedVarnode(entry);
|
||||
}
|
||||
else {
|
||||
if (usepoint == param_usepoint)
|
||||
vn = fd->findVarnodeInput(size, addr);
|
||||
else
|
||||
vn = fd->findVarnodeWritten(size,addr,usepoint);
|
||||
if (vn == (Varnode *)0) continue;
|
||||
sym = vn->getHigh()->getSymbol();
|
||||
|
@ -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.
|
||||
/// 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.
|
||||
|
|
|
@ -60,6 +60,20 @@ public:
|
|||
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
|
||||
///
|
||||
/// 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)
|
||||
list<NameRecommend> nameRecommend; ///< Symbol name recommendations for specific addresses
|
||||
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 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
|
||||
|
@ -220,6 +235,7 @@ public:
|
|||
SymbolEntry *remapSymbol(Symbol *sym,const Address &addr,const Address &usepoint);
|
||||
SymbolEntry *remapSymbolDynamic(Symbol *sym,uint8 hash,const Address &usepoint);
|
||||
void recoverNameRecommendationsForSymbols(void);
|
||||
void applyTypeRecommendations(void); ///< Try to apply recommended data-type information
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -22,11 +22,14 @@ import docking.action.MenuData;
|
|||
import ghidra.app.decompiler.ClangFieldToken;
|
||||
import ghidra.app.decompiler.ClangToken;
|
||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||
import ghidra.app.util.AddEditDialog;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.pcode.HighCodeSymbol;
|
||||
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.UndefinedFunction;
|
||||
|
||||
|
@ -69,18 +72,22 @@ public class RenameGlobalAction extends AbstractDecompilerAction {
|
|||
PluginTool tool = context.getTool();
|
||||
final ClangToken tokenAtCursor = context.getTokenAtCursor();
|
||||
HighSymbol highSymbol = findHighSymbolFromToken(tokenAtCursor, context.getHighFunction());
|
||||
Address addr = null;
|
||||
Symbol symbol = null;
|
||||
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",
|
||||
"Memory storage not found for global variable");
|
||||
return;
|
||||
}
|
||||
RenameGlobalVariableTask nameTask =
|
||||
new RenameGlobalVariableTask(tool, context.getProgram(), context.getDecompilerPanel(),
|
||||
tokenAtCursor, addr);
|
||||
nameTask.runTask(true);
|
||||
AddEditDialog dialog = new AddEditDialog("Rename Global", context.getTool());
|
||||
dialog.editLabel(symbol, context.getProgram());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -243,6 +243,9 @@ public class CppExporter extends Exporter {
|
|||
options.grabFromToolAndProgram(null, opt, program);
|
||||
}
|
||||
}
|
||||
else {
|
||||
options.grabFromProgram(program); // Let headless pull program specific options
|
||||
}
|
||||
|
||||
if (isUseCppStyleComments) {
|
||||
options.setCommentStyle(CommentStyleEnum.CPPStyle);
|
||||
|
|
|
@ -25,11 +25,13 @@ import docking.widgets.fieldpanel.field.Field;
|
|||
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||
import ghidra.app.cmd.function.CreateFunctionCmd;
|
||||
import ghidra.app.cmd.function.DeleteFunctionCmd;
|
||||
import ghidra.app.cmd.label.RenameLabelCmd;
|
||||
import ghidra.app.decompiler.ClangToken;
|
||||
import ghidra.app.decompiler.ClangVariableToken;
|
||||
import ghidra.app.decompiler.component.ClangTextField;
|
||||
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.program.database.symbol.CodeSymbol;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
@ -79,12 +81,11 @@ public class HighSymbolTest extends AbstractDecompilerTest {
|
|||
private void renameGlobalVariable(HighSymbol highSymbol, ClangToken tokenAtCursor,
|
||||
String newName) {
|
||||
Address addr = highSymbol.getStorage().getMinAddress();
|
||||
RenameGlobalVariableTask rename = new RenameGlobalVariableTask(provider.getTool(),
|
||||
highSymbol.getProgram(), provider.getDecompilerPanel(), tokenAtCursor, addr);
|
||||
RenameLabelCmd cmd =
|
||||
new RenameLabelCmd(addr, highSymbol.getName(), newName, SourceType.USER_DEFINED);
|
||||
|
||||
assertTrue(rename.isValid(newName));
|
||||
modifyProgram(p -> {
|
||||
rename.commit();
|
||||
cmd.applyTo(highSymbol.getProgram());
|
||||
});
|
||||
waitForDecompiler();
|
||||
}
|
||||
|
|
|
@ -228,6 +228,14 @@
|
|||
</element>
|
||||
</zeroOrMore>
|
||||
|
||||
<zeroOrMore>
|
||||
<element name="inferptrbounds">
|
||||
<oneOrMore>
|
||||
<ref name="range_type"/>
|
||||
</oneOrMore>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
|
||||
<zeroOrMore>
|
||||
<ref name="segmentop_type"/>
|
||||
</zeroOrMore>
|
||||
|
|
|
@ -40,6 +40,14 @@
|
|||
</element>
|
||||
</optional>
|
||||
|
||||
<zeroOrMore>
|
||||
<element name="inferptrbounds">
|
||||
<oneOrMore>
|
||||
<ref name="range_type"/>
|
||||
</oneOrMore>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
|
||||
<optional>
|
||||
<element name="segmented_address">
|
||||
<attribute name="space"/>
|
||||
|
|
|
@ -662,7 +662,8 @@ public class SleighLanguage implements Language {
|
|||
XmlElement element = parser.start("processor_spec");
|
||||
while (!parser.peek().isEnd()) {
|
||||
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");
|
||||
if (element.getName().equals("properties")) {
|
||||
while (!parser.peek().isEnd()) {
|
||||
|
@ -827,6 +828,11 @@ public class SleighLanguage implements Language {
|
|||
parser.discardSubTree();
|
||||
}
|
||||
}
|
||||
else if (element.getName().equals("inferptrbounds")) {
|
||||
while (parser.peek().isStart()) {
|
||||
parser.discardSubTree();
|
||||
}
|
||||
}
|
||||
else if (element.getName().equals("segmentop")) {
|
||||
InjectPayloadSleigh payload = parseSegmentOp(element, parser);
|
||||
addAdditionInject(payload);
|
||||
|
|
|
@ -41,7 +41,6 @@ public abstract class ConstantPool {
|
|||
public long value; // Primitive value of the object (if tag == PRIMITIVE)
|
||||
public byte[] byteData;
|
||||
public DataType type;
|
||||
public boolean hasThisPtr = false;
|
||||
public boolean isConstructor = false;
|
||||
|
||||
public StringBuilder build(long ref, PcodeDataTypeManager dtmanage) {
|
||||
|
@ -72,9 +71,6 @@ public abstract class ConstantPool {
|
|||
else {
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "tag", "primitive");
|
||||
}
|
||||
if (hasThisPtr) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(buf, "hasthis", true);
|
||||
}
|
||||
if (isConstructor) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(buf, "constructor", true);
|
||||
}
|
||||
|
|
|
@ -52,7 +52,9 @@ public class FunctionPrototype {
|
|||
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 func is the function using the symbolmap
|
||||
|
@ -102,7 +104,7 @@ public class FunctionPrototype {
|
|||
noreturn = false;
|
||||
custom = false;
|
||||
extrapop = model.getExtrapop();
|
||||
hasThis = false;
|
||||
hasThis = model.hasThisPointer();
|
||||
isConstruct = false;
|
||||
isDestruct = false;
|
||||
// FIXME: If the FunctionDefinition has no parameters
|
||||
|
@ -126,6 +128,11 @@ public class FunctionPrototype {
|
|||
*/
|
||||
void grabFromFunction(Function f, int overrideExtrapop, boolean doOverride) {
|
||||
modelname = f.getCallingConventionName();
|
||||
PrototypeModel protoModel = f.getCallingConvention();
|
||||
if (protoModel == null) {
|
||||
protoModel = f.getProgram().getCompilerSpec().getDefaultCallingConvention();
|
||||
}
|
||||
hasThis = protoModel.hasThisPointer();
|
||||
modellock =
|
||||
((modelname != null) && (modelname != Function.UNKNOWN_CALLING_CONVENTION_STRING));
|
||||
injectname = f.getCallFixup();
|
||||
|
@ -164,10 +171,6 @@ public class FunctionPrototype {
|
|||
extrapop = overrideExtrapop;
|
||||
}
|
||||
else {
|
||||
PrototypeModel protoModel = f.getCallingConvention();
|
||||
if (protoModel == null) {
|
||||
protoModel = f.getProgram().getCompilerSpec().getDefaultCallingConvention();
|
||||
}
|
||||
if (purge == Function.INVALID_STACK_DEPTH_CHANGE ||
|
||||
purge == Function.UNKNOWN_STACK_DEPTH_CHANGE) {
|
||||
extrapop = protoModel.getExtrapop();
|
||||
|
@ -343,9 +346,6 @@ public class FunctionPrototype {
|
|||
if (custom) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "custom", custom);
|
||||
}
|
||||
if (hasThis) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "hasthis", hasThis);
|
||||
}
|
||||
if (isConstruct) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(res, "constructor", isConstruct);
|
||||
}
|
||||
|
@ -421,6 +421,12 @@ public class FunctionPrototype {
|
|||
throws PcodeXMLException {
|
||||
XmlElement node = parser.start("prototype");
|
||||
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");
|
||||
if (val.equals("unknown")) {
|
||||
extrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
|
||||
|
@ -452,10 +458,6 @@ public class FunctionPrototype {
|
|||
if (node.hasAttribute("custom")) {
|
||||
custom = SpecXmlUtils.decodeBoolean(node.getAttribute("custom"));
|
||||
}
|
||||
hasThis = false;
|
||||
if (node.hasAttribute("hasthis")) {
|
||||
hasThis = SpecXmlUtils.decodeBoolean(node.getAttribute("hasthis"));
|
||||
}
|
||||
isConstruct = false;
|
||||
if (node.hasAttribute("constructor")) {
|
||||
isConstruct = SpecXmlUtils.decodeBoolean(node.getAttribute("constructor"));
|
||||
|
|
|
@ -17,10 +17,11 @@ package ghidra.program.model.pcode;
|
|||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.listing.VariableStorage;
|
||||
import ghidra.program.model.lang.DynamicVariableStorage;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
import ghidra.xml.XmlElement;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
@ -40,6 +41,8 @@ public class HighSymbol {
|
|||
protected int categoryIndex; // Numbering within the sub-class
|
||||
private boolean namelock; // Is this variable's name 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
|
||||
protected SymbolEntry[] entryList; // List of mappings for this symbol
|
||||
|
||||
|
@ -53,6 +56,8 @@ public class HighSymbol {
|
|||
protected HighSymbol(HighFunction func) {
|
||||
function = func;
|
||||
dtmanage = function.getDataTypeManager();
|
||||
isThis = false;
|
||||
isHidden = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,6 +74,8 @@ public class HighSymbol {
|
|||
type = tp;
|
||||
namelock = false;
|
||||
typelock = false;
|
||||
isThis = false;
|
||||
isHidden = false;
|
||||
id = uniqueId;
|
||||
category = -1;
|
||||
categoryIndex = -1;
|
||||
|
@ -92,6 +99,8 @@ public class HighSymbol {
|
|||
type = tp;
|
||||
namelock = nlock;
|
||||
typelock = tlock;
|
||||
isThis = false;
|
||||
isHidden = false;
|
||||
id = uniqueId;
|
||||
category = -1;
|
||||
categoryIndex = -1;
|
||||
|
@ -101,6 +110,15 @@ public class HighSymbol {
|
|||
if (entryList == null) {
|
||||
entryList = new SymbolEntry[1];
|
||||
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 {
|
||||
SymbolEntry[] newList = new SymbolEntry[entryList.length + 1];
|
||||
|
@ -316,6 +334,20 @@ public class HighSymbol {
|
|||
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
|
||||
*/
|
||||
|
@ -349,6 +381,12 @@ public class HighSymbol {
|
|||
if (isIsolated()) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(buf, "merge", false);
|
||||
}
|
||||
if (isThis) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(buf, "thisptr", true);
|
||||
}
|
||||
if (isHidden) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(buf, "hiddenretparm", true);
|
||||
}
|
||||
SpecXmlUtils.encodeSignedIntegerAttribute(buf, "cat", category);
|
||||
if (categoryIndex >= 0) {
|
||||
SpecXmlUtils.encodeSignedIntegerAttribute(buf, "index", categoryIndex);
|
||||
|
@ -382,6 +420,16 @@ public class HighSymbol {
|
|||
if ((namelockstr != null) && (SpecXmlUtils.decodeBoolean(namelockstr))) {
|
||||
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;
|
||||
// String isolatestr = symel.getAttribute("merge");
|
||||
// if ((isolatestr != null) && !SpecXmlUtils.decodeBoolean(isolatestr)) {
|
||||
|
@ -431,6 +479,20 @@ public class HighSymbol {
|
|||
entry.restoreXML(parser);
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
<property key="pcodeInjectLibraryClass" value="ghidra.dalvik.dex.inject.PcodeInjectLibraryDex"/>
|
||||
</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">
|
||||
<case_pcode>
|
||||
<input name="index" size="4"/>
|
||||
|
|
|
@ -121,7 +121,8 @@ public class ConstantPoolDex extends ConstantPool {
|
|||
String defName = res.token + '_' + Integer.toHexString(methodID);
|
||||
FunctionDefinitionDataType funcDef = new FunctionDefinitionDataType(defName, dtManager);
|
||||
res.type = new PointerDataType(funcDef);
|
||||
res.hasThisPtr = !isStatic;
|
||||
funcDef.setGenericCallingConvention(
|
||||
isStatic ? GenericCallingConvention.stdcall : GenericCallingConvention.thiscall);
|
||||
|
||||
int prototypeIndex = methodIDItem.getProtoIndex() & 0xffff;
|
||||
PrototypesIDItem prototype = dexHeader.getPrototypes().get(prototypeIndex);
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
<register_data>
|
||||
<register name="SP" group="Alt"/>
|
||||
</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">
|
||||
<!-- pcode to describe how to get case values from an index 0...size-1 -->
|
||||
<case_pcode>
|
||||
|
|
|
@ -103,7 +103,7 @@ public class ConstantPoolJava extends ConstantPool {
|
|||
new ParameterDefinitionImpl("", params.get(i), null);
|
||||
paramDefs[i] = currentParam;
|
||||
}
|
||||
res.hasThisPtr = false;
|
||||
funcDef.setGenericCallingConvention(GenericCallingConvention.stdcall);
|
||||
}
|
||||
//invokeinterface, invokespecial, and invokevirtual do have a this pointer
|
||||
else {
|
||||
|
@ -116,7 +116,7 @@ public class ConstantPoolJava extends ConstantPool {
|
|||
new ParameterDefinitionImpl("", params.get(i - 1), null);
|
||||
paramDefs[i] = currentParam;
|
||||
}
|
||||
res.hasThisPtr = true;
|
||||
funcDef.setGenericCallingConvention(GenericCallingConvention.thiscall);
|
||||
}
|
||||
funcDef.setArguments(paramDefs);
|
||||
res.type = new PointerDataType(funcDef);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue