Decompiler support for offset/relative pointers

This commit is contained in:
caheckman 2021-10-05 16:46:19 -04:00
parent 513c9beb9d
commit cce187a4c5
18 changed files with 746 additions and 174 deletions

View file

@ -2231,10 +2231,12 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
Datatype *outct,*ct,*tokenct;
Varnode *vn,*outvn;
PcodeOp *newop;
HighVariable *outHigh;
bool force=false;
tokenct = op->getOpcode()->getOutputToken(op,castStrategy);
outvn = op->getOut();
outHigh = outvn->getHigh();
if (outvn->isImplied()) {
// implied varnode must have parse type
if (outvn->isTypeLock()) {
@ -2242,13 +2244,13 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
// The Varnode input to a CPUI_RETURN is marked as implied but
// casting should act as if it were explicit
if (outOp == (PcodeOp *)0 || outOp->code() != CPUI_RETURN) {
force = !isOpIdentical(outvn->getType(), tokenct);
force = !isOpIdentical(outHigh->getType(), tokenct);
}
}
else if (outvn->getType()->getMetatype() != TYPE_PTR) // If implied varnode has an atomic (non-pointer) type
else if (outHigh->getType()->getMetatype() != TYPE_PTR) // If implied varnode has an atomic (non-pointer) type
outvn->updateType(tokenct,false,false); // Ignore it in favor of the token type
else if (tokenct->getMetatype() == TYPE_PTR) { // If the token is a pointer AND implied varnode is pointer
outct = ((TypePointer *)outvn->getType())->getPtrTo();
outct = ((TypePointer *)outHigh->getType())->getPtrTo();
type_metatype meta = outct->getMetatype();
// Preserve implied pointer if it points to a composite
if ((meta!=TYPE_ARRAY)&&(meta!=TYPE_STRUCT))
@ -2256,7 +2258,7 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
}
}
if (!force) {
outct = outvn->getHigh()->getType(); // Type of result
outct = outHigh->getType(); // Type of result
ct = castStrategy->castStandard(outct,tokenct,false,true);
if (ct == (Datatype *)0) return 0;
}
@ -4237,7 +4239,10 @@ void ActionInferTypes::buildLocaltypes(Funcdata &data)
vn = *iter;
if (vn->isAnnotation()) continue;
if ((!vn->isWritten())&&(vn->hasNoDescend())) continue;
ct = vn->getLocalType();
bool needsBlock = false;
ct = vn->getLocalType(needsBlock);
if (needsBlock)
vn->setStopUpPropagation();
#ifdef TYPEPROP_DEBUG
propagationDebug(data.getArch(),vn,ct,(PcodeOp *)0,0,(Varnode *)0);
#endif
@ -4271,11 +4276,12 @@ bool ActionInferTypes::writeBack(Funcdata &data)
/// Determine if the given data-type edge looks like a pointer
/// propagating through an "add a constant" operation. We assume the input
/// to the edge has a pointer data-type. This routine returns one the commands:
/// - 0 indicates this is "add a constant" and the constant is passed back
/// - 1 indicating the pointer does not propagate through
/// - 2 the input data-type propagates through untransformed
/// - 0 indicates this is "add a constant" adding a zero (PTRSUB or PTRADD)
/// - 1 indicates this is "add a constant" and the constant is passed back
/// - 2 indicating the pointer does not propagate through
/// - 3 the input data-type propagates through untransformed
///
/// \param off passes back the constant offset if the command is '0'
/// \param off passes back the constant offset if the command is '0' or '1'
/// \param op is the PcodeOp propagating the data-type
/// \param slot is the input edge being propagated
/// \param sz is the size of the data-type being pointed to
@ -4284,21 +4290,21 @@ int4 ActionInferTypes::propagateAddPointer(uintb &off,PcodeOp *op,int4 slot,int4
{
if (op->code() == CPUI_PTRADD) {
if (slot != 0) return 1;
if (slot != 0) return 2;
Varnode *constvn = op->getIn(1);
uintb mult = op->getIn(2)->getOffset();
if (constvn->isConstant()) {
off = (constvn->getOffset() * mult) & calc_mask(constvn->getSize()) ;
return 0;
return (off == 0) ? 0 : 1;
}
if (sz != 0 && (mult % sz) != 0)
return 1;
return 2;
return 2;
return 3;
}
if (op->code() == CPUI_PTRSUB) {
if (slot != 0) return 1;
if (slot != 0) return 2;
off = op->getIn(1)->getOffset();
return 0;
return (off == 0) ? 0 : 1;
}
if (op->code() == CPUI_INT_ADD) {
Varnode *othervn = op->getIn(1-slot);
@ -4311,23 +4317,23 @@ int4 ActionInferTypes::propagateAddPointer(uintb &off,PcodeOp *op,int4 slot,int4
if (constvn->isConstant()) {
uintb mult = constvn->getOffset();
if (mult == calc_mask(constvn->getSize())) // If multiplying by -1
return 1; // Assume this is a pointer difference and don't propagate
return 2; // Assume this is a pointer difference and don't propagate
if (sz != 0 && (mult % sz) !=0)
return 1;
return 2;
}
return 2;
return 3;
}
}
if (sz == 1)
return 2;
return 1;
return 3;
return 2;
}
if (othervn->getTempType()->getMetatype() == TYPE_PTR) // Check if othervn marked as ptr
return 1;
return 2;
off = othervn->getOffset();
return 0;
return (off == 0) ? 0 : 1;
}
return 1;
return 2;
}
/// \brief Propagate a pointer data-type through an ADD operation.
@ -4347,27 +4353,38 @@ Datatype *ActionInferTypes::propagateAddIn2Out(TypeFactory *typegrp,PcodeOp *op,
TypePointer *pointer = (TypePointer *)op->getIn(inslot)->getTempType(); // We know this is a pointer type
uintb uoffset;
int4 command = propagateAddPointer(uoffset,op,inslot,pointer->getPtrTo()->getSize());
if (command == 1) return op->getOut()->getTempType(); // Doesn't look like a good pointer add
if (command != 2) {
if (command == 2) return op->getOut()->getTempType(); // Doesn't look like a good pointer add
TypePointer *parent = (TypePointer *)0;
uintb parentOff;
if (command != 3) {
uoffset = AddrSpace::addressToByte(uoffset,pointer->getWordSize());
bool allowWrap = (op->code() != CPUI_PTRSUB);
do {
pointer = pointer->downChain(uoffset,allowWrap,*typegrp);
pointer = pointer->downChain(uoffset,parent,parentOff,allowWrap,*typegrp);
if (pointer == (TypePointer *)0)
return op->getOut()->getTempType();
break;
} while(uoffset != 0);
}
Datatype *rettype = pointer;
if (rettype == (Datatype *)0)
rettype = op->getOut()->getTempType();
if (op->getIn(inslot)->isSpacebase()) {
if (rettype->getMetatype() == TYPE_PTR) {
TypePointer *ptype = (TypePointer *)rettype;
if (ptype->getPtrTo()->getMetatype() == TYPE_SPACEBASE)
rettype = typegrp->getTypePointer(ptype->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),ptype->getWordSize());
}
if (parent != (TypePointer *)0) {
// If the innermost containing object is a TYPE_STRUCT or TYPE_ARRAY
// preserve info about this container
Datatype *pt;
if (pointer == (TypePointer *)0)
pt = typegrp->getBase(1,TYPE_UNKNOWN); // Offset does not point at a proper sub-type
else
pt = pointer->getPtrTo(); // The sub-type being directly pointed at
pointer = typegrp->getTypePointerRel(parent, pt, parentOff);
}
return rettype;
if (pointer == (TypePointer *)0) {
if (command == 0)
return op->getIn(inslot)->getTempType();
return op->getOut()->getTempType();
}
if (op->getIn(inslot)->isSpacebase()) {
if (pointer->getPtrTo()->getMetatype() == TYPE_SPACEBASE)
pointer = typegrp->getTypePointer(pointer->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),pointer->getWordSize());
}
return pointer;
}
/// \brief Determine if propagation should happen along the given edge
@ -4468,7 +4485,13 @@ bool ActionInferTypes::propagateTypeEdge(TypeFactory *typegrp,PcodeOp *op,int4 i
Varnode *invn,*outvn;
Datatype *newtype;
outvn = (outslot==-1) ? op->getOut() : op->getIn(outslot);
if (outslot < 0)
outvn = op->getOut();
else {
outvn = op->getIn(outslot);
if (outvn->stopsUpPropagation())
return false;
}
if (outvn->isAnnotation()) return false;
if (outvn->isTypeLock()) return false; // Can't propagate through typelock
invn = (inslot==-1) ? op->getOut() : op->getIn(inslot);
@ -4481,13 +4504,31 @@ bool ActionInferTypes::propagateTypeEdge(TypeFactory *typegrp,PcodeOp *op,int4 i
return false;
}
switch(op->code()) {
case CPUI_INDIRECT:
case CPUI_COPY:
case CPUI_MULTIEQUAL:
case CPUI_INT_LESS:
case CPUI_INT_LESSEQUAL:
case CPUI_INT_EQUAL:
case CPUI_INT_NOTEQUAL:
if (invn->isSpacebase()) {
AddrSpace *spc = typegrp->getArch()->getDefaultDataSpace();
newtype = typegrp->getTypePointer(alttype->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),spc->getWordSize());
}
else if (alttype->isPointerRel() && !outvn->isConstant()) {
TypePointerRel *relPtr = (TypePointerRel *)alttype;
if (relPtr->getParent()->getMetatype() == TYPE_STRUCT && relPtr->getPointerOffset() >= 0) {
// If we know the pointer is in the middle of a structure, don't propagate across comparison operators
// as the two sides of the operator are likely to be different types , and the other side can also
// get data-type information from the structure pointer
newtype = typegrp->getTypePointer(relPtr->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),relPtr->getWordSize());
}
else
newtype = alttype;
}
else
newtype = alttype;
break;
case CPUI_INDIRECT:
case CPUI_COPY:
case CPUI_MULTIEQUAL:
case CPUI_INT_AND:
case CPUI_INT_OR:
case CPUI_INT_XOR:
@ -4805,6 +4846,7 @@ PcodeOp *ActionInferTypes::canonicalReturnOp(Funcdata &data)
void ActionInferTypes::propagateAcrossReturns(Funcdata &data)
{
if (data.getFuncProto().isOutputLocked()) return;
PcodeOp *op = canonicalReturnOp(data);
if (op == (PcodeOp *)0) return;
TypeFactory *typegrp = data.getArch()->types;
@ -4826,7 +4868,7 @@ void ActionInferTypes::propagateAcrossReturns(Funcdata &data)
if (vn->getTempType() == ct) continue; // Already propagated
vn->setTempType(ct);
#ifdef TYPEPROP_DEBUG
propagationDebug(typegrp->getArch(),vn,ct,retop,1,(Varnode *)0);
propagationDebug(typegrp->getArch(),vn,ct,op,1,(Varnode *)0);
#endif
propagateOneType(typegrp, vn);
}

View file

@ -2147,6 +2147,7 @@ void ScopeInternal::setAttribute(Symbol *sym,uint4 attr)
attr &= (Varnode::typelock | Varnode::namelock | Varnode::readonly | Varnode::incidental_copy |
Varnode::nolocalalias | Varnode::volatil | Varnode::indirectstorage | Varnode::hiddenretparm);
sym->flags |= attr;
sym->checkSizeTypeLock();
}
void ScopeInternal::clearAttribute(Symbol *sym,uint4 attr)
@ -2155,6 +2156,7 @@ void ScopeInternal::clearAttribute(Symbol *sym,uint4 attr)
attr &= (Varnode::typelock | Varnode::namelock | Varnode::readonly | Varnode::incidental_copy |
Varnode::nolocalalias | Varnode::volatil | Varnode::indirectstorage | Varnode::hiddenretparm);
sym->flags &= ~attr;
sym->checkSizeTypeLock();
}
void ScopeInternal::setDisplayFormat(Symbol *sym,uint4 attr)

View file

@ -127,6 +127,7 @@ void IfaceDecompCapability::registerCommands(IfaceStatus *status)
status->registerCom(new IfcCallOtherFixup(),"fixup","callother");
status->registerCom(new IfcVolatile(),"volatile");
status->registerCom(new IfcReadonly(),"readonly");
status->registerCom(new IfcPointerSetting(),"pointer","setting");
status->registerCom(new IfcPreferSplit(),"prefersplit");
status->registerCom(new IfcStructureBlocks(),"structure","blocks");
status->registerCom(new IfcAnalyzeRange(), "analyze","range");
@ -2889,6 +2890,48 @@ void IfcReadonly::execute(istream &s)
*status->optr << "Successfully marked range as readonly" << endl;
}
/// \class IfcPointerSetting
/// \brief Create a pointer with additional settings: `pointer setting <name> <basetype> offset <val>`
///
/// The new data-type is named and must be pointer. It must have a setting
/// - \b offset which creates a shifted pointer
void IfcPointerSetting::execute(istream &s)
{
if (dcp->conf == (Architecture *)0)
throw IfaceExecutionError("No load image present");
string typeName;
string baseType;
string setting;
s >> ws;
if (s.eof())
throw IfaceParseError("Missing name");
s >> typeName >> ws;
if (s.eof())
throw IfaceParseError("Missing base-type");
s >> baseType >> ws;
if (s.eof())
throw IfaceParseError("Missing setting");
s >> setting >> ws;
if (setting == "offset") {
int4 off = -1;
s.unsetf(ios::dec | ios::hex | ios::oct); // Let user specify base
s >> off;
if (off <= 0)
throw IfaceParseError("Missing offset");
Datatype *bt = dcp->conf->types->findByName(baseType);
if (bt == (Datatype *)0 || bt->getMetatype() != TYPE_STRUCT)
throw IfaceParseError("Base-type must be a structure");
Datatype *ptrto = TypePointerRel::getPtrTo(bt, off, *dcp->conf->types);
AddrSpace *spc = dcp->conf->getDefaultDataSpace();
dcp->conf->types->getTypePointerRel(spc->getAddrSize(), bt, ptrto, spc->getWordSize(), off,typeName);
}
else
throw IfaceParseError("Unknown pointer setting: "+setting);
*status->optr << "Successfully created pointer: " << typeName << endl;
}
/// \class IfcPreferSplit
/// \brief Mark a storage location to be split: `prefersplit <address+size> <splitsize>`
///

View file

@ -554,6 +554,11 @@ public:
virtual void execute(istream &s);
};
class IfcPointerSetting : public IfaceDecompCommand {
public:
virtual void execute(istream &s);
};
class IfcPreferSplit : public IfaceDecompCommand {
public:
virtual void execute(istream &s);

View file

@ -105,7 +105,8 @@ public:
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
is_cpool_transformed = 0x20, ///< Have we checked for cpool transforms
stop_propagation = 40 ///< Stop propagation into output from descendants
};
private:
TypeOp *opcode; ///< Pointer to class providing behavioral details of the operation
@ -202,6 +203,9 @@ public:
/// \brief Return \b true if we have already examined this cpool
bool isCpoolTransformed(void) const { return ((addlflags&PcodeOp::is_cpool_transformed)!=0); }
bool isCollapsible(void) const; ///< Return \b true if this can be collapsed to a COPY of a constant
bool stopsPropagation(void) const { return ((addlflags&stop_propagation)!=0); } ///< Is propagation from below stopped
void setStopPropagation(void) { addlflags |= stop_propagation; } ///< Stop propagation from below
void clearStopPropagation(void) { addlflags &= ~stop_propagation; } ///< Allow propagation from below
/// \brief Return \b true if this LOADs or STOREs from a dynamic \e spacebase pointer
bool usesSpacebasePtr(void) const { return ((flags&PcodeOp::spacebase_ptr)!=0); }
uintm getCseHash(void) const; ///< Return hash indicating possibility of common subexpression elimination

View file

@ -74,6 +74,8 @@ OpToken PrintC::ptr_expr = { "*", 1, 62, false, OpToken::unary_prefix, 0, 0, (Op
OpToken PrintC::array_expr = { "[]", 2, 66, false, OpToken::postsurround, 1, 0, (OpToken *)0 };
OpToken PrintC::enum_cat = { "|", 2, 26, true, OpToken::binary, 0, 0, (OpToken *)0 };
const string PrintC::typePointerRelToken = "ADJ";
// Constructing this registers the capability
PrintCCapability PrintCCapability::printCCapability;
@ -780,6 +782,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
{
TypePointer *ptype;
TypePointerRel *ptrel;
Datatype *ct;
const Varnode *in0;
bool valueon,flex,arrayvalue;
@ -791,13 +794,24 @@ void PrintC::opPtrsub(const PcodeOp *op)
clear();
throw LowlevelError("PTRSUB off of non-pointer type");
}
ct = ptype->getPtrTo();
if (ptype->isFormalPointerRel()) {
ptrel = (TypePointerRel *)ptype;
ct = ptrel->getParent();
}
else {
ptrel = (TypePointerRel *)0;
ct = ptype->getPtrTo();
}
m = mods & ~(print_load_value|print_store_value); // Current state of mods
valueon = (mods & (print_load_value|print_store_value)) != 0;
flex = isValueFlexible(in0);
if (ct->getMetatype() == TYPE_STRUCT) {
uintb suboff = op->getIn(1)->getOffset(); // How far into container
if (ptrel != (TypePointerRel *)0) {
suboff += ptrel->getPointerOffset();
suboff &= calc_mask(ptype->getSize());
}
suboff = AddrSpace::addressToByte(suboff,ptype->getWordSize());
string fieldname;
Datatype *fieldtype;
@ -832,12 +846,16 @@ void PrintC::opPtrsub(const PcodeOp *op)
if (flex) { // EMIT &( ).name
pushOp(&addressof,op);
pushOp(&object_member,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m | print_load_value);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
}
else { // EMIT &( )->name
pushOp(&addressof,op);
pushOp(&pointer_member,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
}
@ -847,11 +865,15 @@ void PrintC::opPtrsub(const PcodeOp *op)
pushOp(&subscript,op);
if (flex) { // EMIT ( ).name
pushOp(&object_member,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m | print_load_value);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
}
else { // EMIT ( )->name
pushOp(&pointer_member,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
}
@ -912,22 +934,30 @@ void PrintC::opPtrsub(const PcodeOp *op)
if (flex) { // EMIT ( )
// (*&struct->arrayfield)[i]
// becomes struct->arrayfield[i]
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
}
else { // EMIT *( )
pushOp(&dereference,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
}
}
else {
if (flex) { // EMIT ( )[0]
pushOp(&subscript,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
push_integer(0,4,false,(Varnode *)0,op);
}
else { // EMIT (* )[0]
pushOp(&subscript,op);
pushOp(&dereference,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
push_integer(0,4,false,(Varnode *)0,op);
}
@ -1561,6 +1591,7 @@ void PrintC::pushConstant(uintb val,const Datatype *ct,
clear();
throw LowlevelError("Cannot have a constant of type void");
case TYPE_PTR:
case TYPE_PTRSTRUCT:
if (option_NULL&&(val==0)) { // A null pointer
pushAtom(Atom(nullToken,vartoken,EmitXml::var_color,op,vn));
return;
@ -1582,6 +1613,7 @@ void PrintC::pushConstant(uintb val,const Datatype *ct,
case TYPE_CODE:
case TYPE_ARRAY:
case TYPE_STRUCT:
case TYPE_PARTIALSTRUCT:
break;
}
// Default printing

View file

@ -113,6 +113,7 @@ protected:
static OpToken ptr_expr; ///< Pointer adornment for a type declaration
static OpToken array_expr; ///< Array adornment for a type declaration
static OpToken enum_cat; ///< The \e concatenation operator for enumerated values
static const string typePointerRelToken; ///< The token to print indicating PTRSUB relative to a TypePointerRel
bool option_NULL; ///< Set to \b true if we should emit NULL keyword
bool option_inplace_ops; ///< Set to \b true if we should use '+=' '&=' etc.
bool option_convention; ///< Set to \b true if we should print calling convention
@ -196,6 +197,7 @@ protected:
virtual void emitFunctionDeclaration(const Funcdata *fd);
virtual void emitTypeDefinition(const Datatype *ct);
virtual bool checkPrintNegation(const Varnode *vn);
void pushTypePointerRel(const PcodeOp *op);
public:
PrintC(Architecture *g,const string &nm="c-language"); ///< Constructor
void setNULLPrinting(bool val) { option_NULL = val; } ///< Toggle the printing of a 'NULL' token
@ -313,4 +315,16 @@ public:
virtual void callback(EmitXml *emit);
};
/// \brief Push a token indicating a PTRSUB (a -> operator) is acting at an offset from the original pointer
///
/// When a variable has TypePointerRel as its data-type, PTRSUB acts relative to the \e parent
/// data-type. We print a specific token to indicate this relative shift is happening.
/// \param op is is the PTRSUB op
inline void PrintC::pushTypePointerRel(const PcodeOp *op)
{
pushOp(&function_call,op);
pushAtom(Atom(typePointerRelToken,optoken,EmitXml::funcname_color,op));
}
#endif

View file

@ -5619,6 +5619,10 @@ void AddTreeState::clear(void)
{
multsum = 0;
nonmultsum = 0;
if (pRelType != (const TypePointerRel *)0) {
nonmultsum = ((TypePointerRel *)ct)->getPointerOffset();
nonmultsum &= ptrmask;
}
multiple.clear();
coeff.clear();
nonmult.clear();
@ -5630,6 +5634,29 @@ void AddTreeState::clear(void)
distributeOp = (PcodeOp *)0;
}
/// For some forms of pointer (TypePointerRel), the pointer can be interpreted as having two versions
/// of the data-type being pointed to. This method initializes analysis for the second version, assuming
/// analysis of the first version has failed.
/// \return \b true if there is a second version that can still be analyzed
bool AddTreeState::initAlternateForm(void)
{
if (pRelType == (const TypePointerRel *)0)
return false;
pRelType = (const TypePointerRel *)0;
baseType = ct->getPtrTo();
if (baseType->isVariableLength())
size = 0; // Open-ended size being pointed to, there will be no "multiples" component
else
size = AddrSpace::byteToAddressInt(baseType->getSize(),ct->getWordSize());
int4 unitsize = AddrSpace::addressToByteInt(1,ct->getWordSize());
isDegenerate = (baseType->getSize() <= unitsize && baseType->getSize() > 0);
preventDistribution = false;
clear();
return true;
}
AddTreeState::AddTreeState(Funcdata &d,PcodeOp *op,int4 slot)
: data(d)
{
@ -5639,12 +5666,19 @@ AddTreeState::AddTreeState(Funcdata &d,PcodeOp *op,int4 slot)
ptrsize = ptr->getSize();
ptrmask = calc_mask(ptrsize);
baseType = ct->getPtrTo();
multsum = 0; // Sums start out as zero
nonmultsum = 0;
pRelType = (const TypePointerRel *)0;
if (ct->isFormalPointerRel()) {
pRelType = (const TypePointerRel *)ct;
baseType = pRelType->getParent();
nonmultsum = pRelType->getPointerOffset();
nonmultsum &= ptrmask;
}
if (baseType->isVariableLength())
size = 0; // Open-ended size being pointed to, there will be no "multiples" component
else
size = AddrSpace::byteToAddressInt(baseType->getSize(),ct->getWordSize());
multsum = 0; // Sums start out as zero
nonmultsum = 0;
correct = 0;
offset = 0;
valid = true; // Valid until proven otherwise
@ -5652,6 +5686,8 @@ AddTreeState::AddTreeState(Funcdata &d,PcodeOp *op,int4 slot)
isDistributeUsed = false;
isSubtype = false;
distributeOp = (PcodeOp *)0;
int4 unitsize = AddrSpace::addressToByteInt(1,ct->getWordSize());
isDegenerate = (baseType->getSize() <= unitsize && baseType->getSize() > 0);
}
/// Even if the current base data-type is not an array, the pointer expression may incorporate
@ -5815,11 +5851,13 @@ bool AddTreeState::checkTerm(Varnode *vn,uintb treeCoeff)
isDistributeUsed = true;
}
nonmultsum += val;
nonmultsum &= ptrmask;
return true;
}
if (treeCoeff != 1)
isDistributeUsed = true;
multsum += val; // Add multiples of size into multsum
multsum &= ptrmask;
return false;
}
if (vn->isWritten()) {
@ -5861,6 +5899,12 @@ bool AddTreeState::spanAddTree(PcodeOp *op,uintb treeCoeff)
two_is_non = checkTerm(op->getIn(1),treeCoeff);
if (!valid) return false;
if (pRelType != (const TypePointerRel *)0) {
if (multsum != 0 || nonmultsum >= size || !multiple.empty()) {
valid = false;
return false;
}
}
if (one_is_non&&two_is_non) return true;
if (one_is_non)
nonmult.push_back(op->getIn(0));
@ -5874,8 +5918,6 @@ bool AddTreeState::spanAddTree(PcodeOp *op,uintb treeCoeff)
void AddTreeState::calcSubtype(void)
{
nonmultsum &= ptrmask; // Make sure we are modulo ptr's space
multsum &= ptrmask;
if (size == 0 || nonmultsum < size)
offset = nonmultsum;
else {
@ -6018,10 +6060,34 @@ Varnode *AddTreeState::buildExtra(void)
return resNode;
}
/// The base data-type being pointed to is unit sized (or smaller). Everything is a multiple, so an ADD
/// is always converted into a PTRADD.
/// \return \b true if the degenerate transform was applied
bool AddTreeState::buildDegenerate(void)
{
if (baseType->getSize() < ct->getWordSize())
// If the size is really less than scale, there is
// probably some sort of padding going on
return false; // Don't transform at all
if (baseOp->getOut()->getType()->getMetatype() != TYPE_PTR) // Make sure pointer propagates thru INT_ADD
return false;
vector<Varnode *> newparams;
int4 slot = baseOp->getSlot(ptr);
newparams.push_back( ptr );
newparams.push_back( baseOp->getIn(1-slot) );
newparams.push_back( data.newConstant(ct->getSize(),1));
data.opSetAllInput(baseOp,newparams);
data.opSetOpcode(baseOp,CPUI_PTRADD);
return true;
}
/// \return \b true if a transform was applied
bool AddTreeState::apply(void)
{
if (isDegenerate)
return buildDegenerate();
spanAddTree(baseOp,1);
if (!valid) return false; // Were there any show stoppers
if (distributeOp != (PcodeOp *)0 && !isDistributeUsed) {
@ -6060,13 +6126,18 @@ bool AddTreeState::apply(void)
return true;
}
/// The original ADD tree has been successfully spit into \e multiple and
/// The original ADD tree has been successfully split into \e multiple and
/// \e non-multiple pieces. Rewrite the tree as a pointer expression, putting
/// any \e multiple pieces into a PTRADD operation, creating a PTRSUB if a sub
/// data-type offset has been calculated, and preserving and remaining terms.
void AddTreeState::buildTree(void)
{
if (pRelType != (const TypePointerRel *)0) {
int4 ptrOff = ((TypePointerRel *)ct)->getPointerOffset();
offset -= ptrOff;
offset &= ptrmask;
}
Varnode *multNode = buildMultiples();
Varnode *extraNode = buildExtra();
PcodeOp *newop = (PcodeOp *)0;
@ -6082,6 +6153,8 @@ void AddTreeState::buildTree(void)
// Create PTRSUB portion of operation
if (isSubtype) {
newop = data.newOpBefore(baseOp,CPUI_PTRSUB,multNode,data.newConstant(ptrsize,offset));
if (size != 0)
newop->setStopPropagation();
multNode = newop->getOut();
}
@ -6216,29 +6289,12 @@ int4 RulePtrArith::applyOp(PcodeOp *op,Funcdata &data)
if (evaluatePointerExpression(op, slot) != 2) return 0;
if (!verifyPreferredPointer(op, slot)) return 0;
const TypePointer *tp = (const TypePointer *) ct;
ct = tp->getPtrTo(); // Type being pointed to
int4 unitsize = AddrSpace::addressToByteInt(1,tp->getWordSize());
if (ct->getSize() == unitsize) { // Degenerate case
if (op->getOut()->getType()->getMetatype() != TYPE_PTR) // Make sure pointer propagates thru INT_ADD
return 0;
vector<Varnode *> newparams;
newparams.push_back( op->getIn(slot) );
newparams.push_back( op->getIn(1-slot) );
newparams.push_back( data.newConstant(tp->getSize(),1));
data.opSetAllInput(op,newparams);
data.opSetOpcode(op,CPUI_PTRADD);
return 1;
}
if ((ct->getSize() < unitsize)&&(ct->getSize()>0))
// If the size is really less than scale, there is
// probably some sort of padding going on
return 0;
AddTreeState state(data,op,slot);
if (!state.apply())
return 0;
return 1;
if (state.apply()) return 1;
if (state.initAlternateForm()) {
if (state.apply()) return 1;
}
return 0;
}
/// \class RuleStructOffset0
@ -6259,10 +6315,7 @@ void RuleStructOffset0::getOpList(vector<uint4> &oplist) const
int4 RuleStructOffset0::applyOp(PcodeOp *op,Funcdata &data)
{
Datatype *ct,*sub_ct;
PcodeOp *newop;
int4 movesize; // Number of bytes being moved by load or store
uintb offset;
if (!data.isTypeRecoveryOn()) return 0;
if (op->code()==CPUI_LOAD) {
@ -6274,25 +6327,37 @@ int4 RuleStructOffset0::applyOp(PcodeOp *op,Funcdata &data)
else
return 0;
ct = op->getIn(1)->getType();
Datatype *ct = op->getIn(1)->getType();
if (ct->getMetatype() != TYPE_PTR) return 0;
ct = ((TypePointer *)ct)->getPtrTo();
if (ct->getMetatype() == TYPE_STRUCT) {
if (ct->getSize() < movesize)
Datatype *baseType = ((TypePointer *)ct)->getPtrTo();
uintb offset = 0;
if (ct->isFormalPointerRel()) {
TypePointerRel *ptRel = (TypePointerRel *)ct;
baseType = ptRel->getParent();
if (baseType->getMetatype() != TYPE_STRUCT)
return 0;
int4 iOff = ptRel->getPointerOffset();
iOff = AddrSpace::addressToByteInt(iOff, ptRel->getWordSize());
if (iOff >= baseType->getSize())
return 0;
offset = iOff;
}
if (baseType->getMetatype() == TYPE_STRUCT) {
if (baseType->getSize() < movesize)
return 0; // Moving something bigger than entire structure
sub_ct = ct->getSubType(0,&offset); // Get field at offset 0
if (sub_ct==(Datatype *)0) return 0;
if (sub_ct->getSize() < movesize) return 0; // Subtype is too small to handle LOAD/STORE
// if (ct->getSize() == movesize) {
Datatype *subType = baseType->getSubType(offset,&offset); // Get field at pointer's offset
if (subType==(Datatype *)0) return 0;
if (subType->getSize() < movesize) return 0; // Subtype is too small to handle LOAD/STORE
// if (baseType->getSize() == movesize) {
// If we reach here, move is same size as the structure, which is the same size as
// the first element.
// }
}
else if (ct->getMetatype() == TYPE_ARRAY) {
if (ct->getSize() < movesize)
else if (baseType->getMetatype() == TYPE_ARRAY) {
if (baseType->getSize() < movesize)
return 0; // Moving something bigger than entire array
if (ct->getSize() == movesize) { // Moving something the size of entire array
if (((TypeArray *)ct)->numElements() != 1)
if (baseType->getSize() == movesize) { // Moving something the size of entire array
if (((TypeArray *)baseType)->numElements() != 1)
return 0;
// If we reach here, moving something size of single element. Assume this is normal access.
}
@ -6300,7 +6365,8 @@ int4 RuleStructOffset0::applyOp(PcodeOp *op,Funcdata &data)
else
return 0;
newop = data.newOpBefore(op,CPUI_PTRSUB,op->getIn(1),data.newConstant(op->getIn(1)->getSize(),0));
PcodeOp *newop = data.newOpBefore(op,CPUI_PTRSUB,op->getIn(1),data.newConstant(op->getIn(1)->getSize(),0));
newop->setStopPropagation();
data.opSetInput(op,newop->getOut(),1);
return 1;
}
@ -6499,6 +6565,7 @@ int4 RulePtrsubUndo::applyOp(PcodeOp *op,Funcdata &data)
return 0;
data.opSetOpcode(op,CPUI_INT_ADD);
op->clearStopPropagation();
return 1;
}

View file

@ -45,6 +45,7 @@ class AddTreeState {
Varnode *ptr; ///< The pointer varnode
const TypePointer *ct; ///< The pointer data-type
const Datatype *baseType; ///< The base data-type being pointed at
const TypePointerRel *pRelType; ///< A copy of \b ct, if it is a relative pointer
int4 ptrsize; ///< Size of the pointer
int4 size; ///< Size of data-type being pointed to (in address units) or 0 for open ended pointer
uintb ptrmask; ///< Mask for modulo calculations in ptr space
@ -60,6 +61,7 @@ class AddTreeState {
bool isDistributeUsed; ///< Are terms produced by distributing used
bool isSubtype; ///< Is there a sub-type (using CPUI_PTRSUB)
bool valid; ///< Set to \b true if the whole expression can be transformed
bool isDegenerate; ///< Set to \b true if pointer to unitsize or smaller
uint4 findArrayHint(void) const; ///< Look for evidence of an array in a sub-component
bool hasMatchingSubType(uintb off,uint4 arrayHint,uintb *newoff) const;
bool checkMultTerm(Varnode *vn,PcodeOp *op, uintb treeCoeff); ///< Accumulate details of INT_MULT term and continue traversal if appropriate
@ -68,11 +70,13 @@ class AddTreeState {
void calcSubtype(void); ///< Calculate final sub-type offset
Varnode *buildMultiples(void); ///< Build part of tree that is multiple of base size
Varnode *buildExtra(void); ///< Build part of tree not accounted for by multiples or \e offset
bool buildDegenerate(void); ///< Transform ADD into degenerate PTRADD
void buildTree(void); ///< Build the transformed ADD tree
void clear(void); ///< Reset for a new ADD tree traversal
public:
AddTreeState(Funcdata &d,PcodeOp *op,int4 slot); ///< Construct given root of ADD tree and pointer
bool apply(void); ///< Attempt to transform the pointer expression
bool initAlternateForm(void); ///< Prepare analysis if there is an alternate form of the base pointer
};
class RuleEarlyRemoval : public Rule {

View file

@ -16,8 +16,8 @@
#include "type.hh"
#include "funcdata.hh"
sub_metatype Datatype::base2sub[11] = {
SUB_STRUCT, SUB_ARRAY, SUB_PTR, SUB_FLOAT, SUB_CODE, SUB_BOOL,
sub_metatype Datatype::base2sub[13] = {
SUB_STRUCT, SUB_PARTIALSTRUCT, SUB_ARRAY, SUB_PTRREL, SUB_PTR, SUB_FLOAT, SUB_CODE, SUB_BOOL,
SUB_UINT_PLAIN, SUB_INT_PLAIN, SUB_UNKNOWN, SUB_SPACEBASE, SUB_VOID
};
@ -176,9 +176,15 @@ void metatype2string(type_metatype metatype,string &res)
case TYPE_PTR:
res = "ptr";
break;
case TYPE_PTRSTRUCT:
res = "ptrstruct";
break;
case TYPE_ARRAY:
res = "array";
break;
case TYPE_PARTIALSTRUCT:
res = "part";
break;
case TYPE_STRUCT:
res = "struct";
break;
@ -218,6 +224,10 @@ type_metatype string2metatype(const string &metastring)
case 'p':
if (metastring=="ptr")
return TYPE_PTR;
else if (metastring=="part")
return TYPE_PARTIALSTRUCT;
else if (metastring=="ptrstruct")
return TYPE_PTRSTRUCT;
break;
case 'a':
if (metastring=="array")
@ -269,14 +279,15 @@ void Datatype::saveXml(ostream &s) const
{
s << "<type";
saveXmlBasic(s);
saveXmlBasic(metatype,s);
s << "/>";
}
/// Write out basic data-type properties (name,size,id) as XML attributes.
/// This routine presumes the initial tag is already written to the stream.
/// \param meta is the metatype to put in the XML
/// \param s is the stream to write to
void Datatype::saveXmlBasic(ostream &s) const
void Datatype::saveXmlBasic(type_metatype meta,ostream &s) const
{
a_v(s,"name",name);
@ -290,7 +301,7 @@ void Datatype::saveXmlBasic(ostream &s) const
}
a_v_i(s,"size",size);
string metastring;
metatype2string(metatype,metastring);
metatype2string(meta,metastring);
a_v(s,"metatype",metastring);
if ((flags & coretype)!=0)
a_v_b(s,"core",true);
@ -339,31 +350,22 @@ void Datatype::saveXmlTypedef(ostream &s) const
/// A CPUI_PTRSUB must act on a pointer data-type where the given offset addresses a component.
/// Perform this check.
/// \param offset is the given offset
/// \param off is the given offset
/// \return \b true if \b this is a suitable PTRSUB data-type
bool Datatype::isPtrsubMatching(uintb offset) const
bool Datatype::isPtrsubMatching(uintb off) const
{
if (metatype != TYPE_PTR)
return false;
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 sz = 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(sz,wordsize))&&(typesize!=0))
return false;
}
return true;
/// Some data-types are ephemeral, and, in the final decompiler output, get replaced with a formal version
/// that is a stripped down version of the original. This method returns this stripped down version, if it
/// exists, or null otherwise. A non-null return should correspond with hasStripped returning \b true.
/// \return the stripped version or null
Datatype *Datatype::getStripped(void) const
{
return (Datatype *)0;
}
/// Restore the basic properties (name,size,id) of a data-type from an XML element
@ -469,7 +471,7 @@ void TypeChar::saveXml(ostream &s) const
return;
}
s << "<type";
saveXmlBasic(s);
saveXmlBasic(metatype,s);
a_v_b(s,"char",true);
s << "/>";
}
@ -511,7 +513,7 @@ void TypeUnicode::saveXml(ostream &s) const
return;
}
s << "<type";
saveXmlBasic(s);
saveXmlBasic(metatype,s);
a_v_b(s,"utf",true);
s << "/>";
}
@ -569,7 +571,7 @@ void TypePointer::saveXml(ostream &s) const
return;
}
s << "<type";
saveXmlBasic(s);
saveXmlBasic(metatype,s);
if (wordsize != 1)
a_v_i(s,"wordsize",wordsize);
s << '>';
@ -588,21 +590,37 @@ void TypePointer::restoreXml(const Element *el,TypeFactory &typegrp)
s >> wordsize;
}
ptrto = typegrp.restoreXmlType( *el->getChildren().begin() );
calcSubmeta();
if (name.size() == 0) // Inherit only coretype only if no name
flags = ptrto->getInheritable();
}
/// Pointers to structures may require a specific \b submeta
void TypePointer::calcSubmeta(void)
{
if (ptrto->getMetatype() == TYPE_STRUCT) {
if (ptrto->numDepend() > 1 || ptrto->isIncompleteStruct())
submeta = SUB_PTR_STRUCT;
}
}
/// \brief Find a sub-type pointer given an offset into \b this
///
/// Add a constant offset to \b this pointer.
/// If there is a valid component at that offset, return a pointer
/// to the data-type of the component or NULL otherwise.
/// This routine only goes down one level at most. Pass back the
/// renormalized offset relative to the new data-type
/// renormalized offset relative to the new data-type. If \b this is
/// a pointer to (into) a container, the data-type of the container is passed back,
/// with the offset into the container.
/// \param off is a reference to the offset to add
/// \param par is used to pass back the container
/// \param parOff is used to pass back the offset into the container
/// \param allowArrayWrap is \b true if the pointer should be treated as a pointer to an array
/// \param typegrp is the factory producing the (possibly new) data-type
/// \return a pointer datatype for the component or NULL
TypePointer *TypePointer::downChain(uintb &off,bool allowArrayWrap,TypeFactory &typegrp)
TypePointer *TypePointer::downChain(uintb &off,TypePointer *&par,uintb &parOff,bool allowArrayWrap,TypeFactory &typegrp)
{
int4 ptrtoSize = ptrto->getSize();
@ -621,16 +639,41 @@ TypePointer *TypePointer::downChain(uintb &off,bool allowArrayWrap,TypeFactory &
}
}
// If we know we have exactly one of an array, strip the array to get pointer to element
bool doStrip = (ptrto->getMetatype() != TYPE_ARRAY);
type_metatype meta = ptrto->getMetatype();
bool isArray = (meta == TYPE_ARRAY);
if (isArray || meta == TYPE_STRUCT) {
par = this;
parOff = off;
}
Datatype *pt = ptrto->getSubType(off,&off);
if (pt == (Datatype *)0)
return (TypePointer *)0;
if (doStrip)
if (!isArray)
return typegrp.getTypePointerStripArray(size, pt, wordsize);
return typegrp.getTypePointer(size,pt,wordsize);
}
bool TypePointer::isPtrsubMatching(uintb off) const
{
if (ptrto->getMetatype()==TYPE_SPACEBASE) {
uintb newoff = AddrSpace::addressToByte(off,wordsize);
ptrto->getSubType(newoff,&newoff);
if (newoff != 0)
return false;
}
else {
int4 sz = off;
int4 typesize = ptrto->getSize();
if ((ptrto->getMetatype() != TYPE_ARRAY)&&(ptrto->getMetatype() != TYPE_STRUCT))
return false; // Not a pointer to a structured type
else if ((typesize <= AddrSpace::addressToByteInt(sz,wordsize))&&(typesize!=0))
return false;
}
return true;
}
void TypeArray::printRaw(ostream &s) const
{
@ -696,7 +739,7 @@ void TypeArray::saveXml(ostream &s) const
return;
}
s << "<type";
saveXmlBasic(s);
saveXmlBasic(metatype,s);
a_v_i(s,"arraysize",arraysize);
s << '>';
arrayof->saveXmlRef(s);
@ -870,7 +913,7 @@ void TypeEnum::saveXml(ostream &s) const
return;
}
s << "<type";
saveXmlBasic(s);
saveXmlBasic(metatype,s);
a_v(s,"enum","true");
s << ">\n";
map<uintb,string>::const_iterator iter;
@ -1142,7 +1185,7 @@ void TypeStruct::saveXml(ostream &s) const
return;
}
s << "<type";
saveXmlBasic(s);
saveXmlBasic(metatype,s);
s << ">\n";
vector<TypeField>::const_iterator iter;
for(iter=field.begin();iter!=field.end();++iter) {
@ -1181,6 +1224,125 @@ void TypeStruct::restoreXml(const Element *el,TypeFactory &typegrp)
}
if (maxoffset > size)
throw LowlevelError("Size too small for fields of structure "+name);
if (size == 0) // We can restore an incomplete structure, indicated by 0 size
flags |= struct_incomplete;
else
flags &= ~(uint4)struct_incomplete; // Otherwise the structure is complete
}
void TypePointerRel::restoreXml(const Element *el,TypeFactory &typegrp)
{
flags = is_ptrrel;
restoreXmlBasic(el);
for(int4 i=0;i<el->getNumAttributes();++i)
if (el->getAttributeName(i) == "wordsize") {
istringstream s(el->getAttributeValue(i));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> wordsize;
}
const List &list(el->getChildren());
List::const_iterator iter;
iter = list.begin();
parent = typegrp.restoreXmlType( *iter );
++iter;
istringstream s1((*iter)->getContent());
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> offset;
if (offset == 0)
throw new LowlevelError("For metatype=\"ptrstruct\", <off> tag must not be zero");
ptrto = getPtrTo(parent, offset, typegrp);
submeta = (ptrto->getMetatype()==TYPE_UNKNOWN) ? SUB_PTRREL_UNK: SUB_PTRREL;
if (name.size() == 0) // If the data-type is not named
cacheStrippedType(typegrp); // it is considered ephemeral
}
void TypePointerRel::printRaw(ostream &s) const
{
ptrto->printRaw(s);
s << " *+";
s << dec << offset;
s << '[' ;
parent->printRaw(s);
s << ']';
}
int4 TypePointerRel::compareDependency(const Datatype &op) const
{
int4 res = Datatype::compareDependency(op); // Note: we go to Datatype, not TypePointer
if (res != 0) return res;
// Both must be pointers
const TypePointerRel *tp = (const TypePointerRel*)&op;
if (offset != tp->offset) return (offset < tp->offset) ? -1 : 1;
if (parent != tp->parent) return (parent < tp->parent) ? -1 : 1;
if (wordsize != tp->wordsize) return (wordsize < tp->wordsize) ? -1 : 1;
if (ptrto == tp->ptrto) return 0;
return (ptrto < tp->ptrto) ? -1 : 1; // Compare the absolute pointers
}
void TypePointerRel::saveXml(ostream &s) const
{
s << "<type";
saveXmlBasic(TYPE_PTRSTRUCT,s); // Override the metatype for XML
if (wordsize != 1)
a_v_i(s,"wordsize",wordsize);
s << ">\n";
parent->saveXmlRef(s);
s << "<off>" << dec << offset << "</off>\n";
s << "</type>";
}
TypePointer *TypePointerRel::downChain(uintb &off,TypePointer *&par,uintb &parOff,bool allowArrayWrap,
TypeFactory &typegrp)
{
if (off < ptrto->getSize() && stripped != (TypePointer *)0) {
return TypePointer::downChain(off,par,parOff,allowArrayWrap,typegrp);
}
uintb relOff = (off + offset) & calc_mask(size); // Convert off to be relative to the parent container
if (relOff >= parent->getSize())
return (TypePointer *)0; // Don't let pointer shift beyond original container
TypePointer *origPointer = typegrp.getTypePointer(size, parent, wordsize);
off = relOff;
return origPointer->downChain(off,par,parOff,allowArrayWrap,typegrp);
}
bool TypePointerRel::isPtrsubMatching(uintb off) const
{
if (stripped != (TypePointer *)0)
return TypePointer::isPtrsubMatching(off);
int4 iOff = AddrSpace::addressToByteInt((int4)off,wordsize);
iOff += offset;
return (iOff >= 0 && iOff <= parent->getSize());
}
/// \brief Given a containing data-type and offset, find the "pointed to" data-type suitable for a TypePointerRel
///
/// The biggest contained data-type that starts at the exact offset is returned. If the offset is negative
/// or the is no data-type starting exactly there, an \b xunknown1 data-type is returned.
/// \param base is the given container data-type
/// \param off is the offset relative to the start of the container
/// \param typegrp is the factory owning the data-types
/// \return the "pointed to" data-type
Datatype *TypePointerRel::getPtrTo(Datatype *base,int4 off,TypeFactory &typegrp)
{
if (off > 0) {
uintb curoff = off;
do {
base = base->getSubType(curoff,&curoff);
} while(curoff != 0 && base != (Datatype *)0);
if (base == (Datatype *)0)
base = typegrp.getBase(1, TYPE_UNKNOWN);
}
else
base = typegrp.getBase(1, TYPE_UNKNOWN);
return base;
}
/// Turn on the data-type's function prototype
@ -1374,7 +1536,7 @@ void TypeCode::saveXml(ostream &s) const
return;
}
s << "<type";
saveXmlBasic(s);
saveXmlBasic(metatype,s);
s << ">\n";
if (proto != (FuncProto *)0)
proto->saveXml(s);
@ -1552,7 +1714,7 @@ void TypeSpacebase::saveXml(ostream &s) const
return;
}
s << "<type";
saveXmlBasic(s);
saveXmlBasic(metatype,s);
a_v(s,"space",spaceid->getName());
s << '>';
localframe.saveXml(s);
@ -1865,7 +2027,8 @@ Datatype *TypeFactory::setName(Datatype *ct,const string &n)
}
/// Make sure all the offsets are fully established then set fields of the structure
/// If -fixedsize- is greater than 0, force the final structure to have that size
/// If \b fixedsize is greater than 0, force the final structure to have that size.
/// This method should only be used on an incomplete structure. It will mark the structure as complete.
/// \param fd is the list of fields to set
/// \param ot is the TypeStruct object to modify
/// \param fixedsize is 0 or the forced size of the structure
@ -1876,6 +2039,8 @@ bool TypeFactory::setFields(vector<TypeField> &fd,TypeStruct *ot,int4 fixedsize,
{
int4 offset,cursize,curalign;
if (!ot->isIncompleteStruct())
throw LowlevelError("Can only set fields on an incomplete structure");
offset = 0;
vector<TypeField>::iterator iter;
@ -1916,7 +2081,8 @@ bool TypeFactory::setFields(vector<TypeField> &fd,TypeStruct *ot,int4 fixedsize,
tree.erase(ot);
ot->setFields(fd);
ot->flags |= (flags & (Datatype::opaque_string | Datatype::variable_length));
ot->flags &= ~(uint4)Datatype::struct_incomplete;
ot->flags |= (flags & (Datatype::opaque_string | Datatype::variable_length | Datatype::struct_incomplete));
if (fixedsize > 0) { // If the caller is trying to force a size
if (fixedsize > ot->size) // If the forced size is bigger than the size required for fields
ot->size = fixedsize; // Force the bigger size
@ -2172,6 +2338,8 @@ Datatype *TypeFactory::getTypedef(Datatype *ct,const string &name,uint8 id)
TypePointer *TypeFactory::getTypePointerStripArray(int4 s,Datatype *pt,uint4 ws)
{
if (pt->hasStripped())
pt = pt->getStripped();
if (pt->getMetatype() == TYPE_ARRAY)
pt = ((TypeArray *)pt)->getBase(); // Strip the first ARRAY type
TypePointer tmp(s,pt,ws);
@ -2186,6 +2354,8 @@ TypePointer *TypeFactory::getTypePointerStripArray(int4 s,Datatype *pt,uint4 ws)
TypePointer *TypeFactory::getTypePointer(int4 s,Datatype *pt,uint4 ws)
{
if (pt->hasStripped())
pt = pt->getStripped();
TypePointer tmp(s,pt,ws);
return (TypePointer *) findAdd(tmp);
}
@ -2200,6 +2370,8 @@ TypePointer *TypeFactory::getTypePointer(int4 s,Datatype *pt,uint4 ws)
TypePointer *TypeFactory::getTypePointer(int4 s,Datatype *pt,uint4 ws,const string &n)
{
if (pt->hasStripped())
pt = pt->getStripped();
TypePointer tmp(s,pt,ws);
tmp.name = n;
tmp.id = Datatype::hashName(n);
@ -2219,7 +2391,7 @@ TypePointer *TypeFactory::getTypePointerNoDepth(int4 s,Datatype *pt,uint4 ws)
type_metatype meta = basetype->getMetatype();
// Make sure that at least we return a pointer to something the size of -pt-
if (meta == TYPE_PTR)
return (TypePointer *)pt;
pt = getBase(pt->getSize(),TYPE_UNKNOWN); // Pass back unknown *
else if (meta == TYPE_UNKNOWN) {
if (basetype->getSize() == pt->getSize()) // If -pt- is pointer to UNKNOWN of the size of a pointer
return (TypePointer *)pt; // Just return pt, don't add another pointer
@ -2239,7 +2411,7 @@ TypeArray *TypeFactory::getTypeArray(int4 as,Datatype *ao)
return (TypeArray *) findAdd(tmp);
}
/// The created structure will have no fields. They must be added later.
/// The created structure will be incomplete and have no fields. They must be added later.
/// \param n is the name of the structure
/// \return the TypeStruct object
TypeStruct *TypeFactory::getTypeStruct(const string &n)
@ -2290,6 +2462,35 @@ TypeCode *TypeFactory::getTypeCode(ProtoModel *model,Datatype *outtype,
return (TypeCode *) findAdd(tc);
}
/// Find/create a pointer data-type that points at a known offset relative to a containing data-type.
/// The resulting data-type is unnamed and ephemeral.
/// \param parentPtr is a model pointer data-type, pointing to the containing data-type
/// \param ptrTo is the data-type being pointed directly to
/// \param off is the offset of the pointed-to data-type relative to the \e container
/// \return the new/matching pointer
TypePointerRel *TypeFactory::getTypePointerRel(TypePointer *parentPtr,Datatype *ptrTo,int4 off)
{
TypePointerRel tp(parentPtr->size,ptrTo,parentPtr->wordsize,parentPtr->ptrto,off);
tp.cacheStrippedType(*this); // Mark as ephemeral
TypePointerRel *res = (TypePointerRel *) findAdd(tp);
return res;
}
/// \brief Build a named pointer offset into a larger container
///
/// The resulting data-type is named and not ephemeral and will display as a formal data-type
/// in decompiler output.
TypePointerRel *TypeFactory::getTypePointerRel(int4 sz,Datatype *parent,Datatype *ptrTo,int4 ws,int4 off,const string &nm)
{
TypePointerRel tp(sz,ptrTo,ws,parent,off);
tp.name = nm;
tp.id = Datatype::hashName(nm);
TypePointerRel *res = (TypePointerRel *)findAdd(tp);
return res;
}
/// The indicated Datatype object is removed from this container.
/// Indirect references (via TypeArray TypeStruct etc.) are not affected
/// \param ct is the data-type to destroy
@ -2542,19 +2743,17 @@ Datatype *TypeFactory::restoreXmlTypeNoRef(const Element *el,bool forcecore)
if (isVarLength)
newid = Datatype::hashSize(newid, structsize);
ct = findByIdLocal(structname,newid);
bool stubfirst = false;
if (ct == (Datatype *)0) {
ts.id = newid;
ts.size = structsize; // Include size if we have it, so arrays can be defined without knowing struct fields
ct = findAdd(ts); // Create stub to allow recursive definitions
stubfirst = true;
}
else if (ct->getMetatype() != TYPE_STRUCT)
throw LowlevelError("Trying to redefine type: "+structname);
ts.restoreXml(el,*this);
if (forcecore)
ts.flags |= Datatype::coretype;
if ((ct->getSize() != 0)&&(!stubfirst)) { // Structure of this name was already present
if (!ct->isIncompleteStruct()) { // Structure of this name was already present
if (0!=ct->compareDependency(ts))
throw LowlevelError("Redefinition of structure: "+structname);
}

View file

@ -31,38 +31,43 @@ extern void print_data(ostream &s,uint1 *buffer,int4 size,const Address &baseadd
/// the number, the more \b specific the type, in calculations involving the generality
/// of a type.
enum type_metatype {
TYPE_VOID = 10, ///< Standard "void" type, absence of type
TYPE_SPACEBASE = 9, ///< Placeholder for symbol/type look-up calculations
TYPE_UNKNOWN = 8, ///< An unknown low-level type. Treated as an unsigned integer.
TYPE_INT = 7, ///< Signed integer. Signed is considered less specific than unsigned in C
TYPE_UINT = 6, ///< Unsigned integer
TYPE_BOOL = 5, ///< Boolean
TYPE_CODE = 4, ///< Data is actual executable code
TYPE_FLOAT = 3, ///< Floating-point
TYPE_VOID = 12, ///< Standard "void" type, absence of type
TYPE_SPACEBASE = 11, ///< Placeholder for symbol/type look-up calculations
TYPE_UNKNOWN = 10, ///< An unknown low-level type. Treated as an unsigned integer.
TYPE_INT = 9, ///< Signed integer. Signed is considered less specific than unsigned in C
TYPE_UINT = 8, ///< Unsigned integer
TYPE_BOOL = 7, ///< Boolean
TYPE_CODE = 6, ///< Data is actual executable code
TYPE_FLOAT = 5, ///< Floating-point
TYPE_PTR = 2, ///< Pointer data-type
TYPE_ARRAY = 1, ///< Array data-type, made up of a sequence of "element" datatype
TYPE_PTR = 4, ///< Pointer data-type
TYPE_PTRSTRUCT = 3, ///< Pointer into a structure data-type (specialization of TYPE_PTR)
TYPE_ARRAY = 2, ///< Array data-type, made up of a sequence of "element" datatype
TYPE_PARTIALSTRUCT = 1, ///< Part of a structure, stored separately from the whole
TYPE_STRUCT = 0 ///< Structure data-type, made up of component datatypes
};
enum sub_metatype {
SUB_VOID = 16, ///< Compare as a TYPE_VOID
SUB_SPACEBASE = 15, ///< Compare as a TYPE_SPACEBASE
SUB_UNKNOWN = 14, ///< Compare as a TYPE_UNKNOWN
SUB_INT_CHAR = 13, ///< Signed 1-byte character, sub-type of TYPE_INT
SUB_UINT_CHAR = 12, ///< Unsigned 1-byte character, sub-type of TYPE_UINT
SUB_INT_PLAIN = 11, ///< Compare as a plain TYPE_INT
SUB_UINT_PLAIN = 10, ///< Compare as a plain TYPE_UINT
SUB_INT_ENUM = 9, ///< Signed enum, sub-type of TYPE_INT
SUB_UINT_ENUM = 8, ///< Unsigned enum, sub-type of TYPE_UINT
SUB_INT_UNICODE = 7, ///< Signed wide character, sub-type of TYPE_INT
SUB_UINT_UNICODE = 6, ///< Unsigned wide character, sub-type of TYPE_UINT
SUB_BOOL = 5, ///< Compare as TYPE_BOOL
SUB_CODE = 4, ///< Compare as TYPE_CODE
SUB_FLOAT = 3, ///< Compare as TYPE_FLOAT
SUB_PTR = 2, ///< Compare as TYPE_PTR
SUB_ARRAY = 1, ///< Compare as TYPE_ARRAY
SUB_VOID = 20, ///< Compare as a TYPE_VOID
SUB_SPACEBASE = 19, ///< Compare as a TYPE_SPACEBASE
SUB_UNKNOWN = 18, ///< Compare as a TYPE_UNKNOWN
SUB_INT_CHAR = 17, ///< Signed 1-byte character, sub-type of TYPE_INT
SUB_UINT_CHAR = 16, ///< Unsigned 1-byte character, sub-type of TYPE_UINT
SUB_INT_PLAIN = 15, ///< Compare as a plain TYPE_INT
SUB_UINT_PLAIN = 14, ///< Compare as a plain TYPE_UINT
SUB_INT_ENUM = 13, ///< Signed enum, sub-type of TYPE_INT
SUB_UINT_ENUM = 12, ///< Unsigned enum, sub-type of TYPE_UINT
SUB_INT_UNICODE = 11, ///< Signed wide character, sub-type of TYPE_INT
SUB_UINT_UNICODE = 10, ///< Unsigned wide character, sub-type of TYPE_UINT
SUB_BOOL = 9, ///< Compare as TYPE_BOOL
SUB_CODE = 8, ///< Compare as TYPE_CODE
SUB_FLOAT = 7, ///< Compare as TYPE_FLOAT
SUB_PTRREL_UNK = 6, ///< Pointer to unknown field of struct, sub-type of TYPE_PTR
SUB_PTR = 5, ///< Compare as TYPE_PTR
SUB_PTRREL = 4, ///< Pointer relative to another data-type, sub-type of TYPE_PTR
SUB_PTR_STRUCT = 3, ///< Pointer into struct, sub-type of TYPE_PTR
SUB_ARRAY = 2, ///< Compare as TYPE_ARRAY
SUB_PARTIALSTRUCT = 1, ///< Compare as TYPE_PARTIALSTRUCT
SUB_STRUCT = 0 ///< Compare as TYPE_STRUCT
};
/// Convert type \b meta-type to name
@ -81,7 +86,7 @@ struct DatatypeCompare;
/// Used for symbols, function prototypes, type propagation etc.
class Datatype {
protected:
static sub_metatype base2sub[11];
static sub_metatype base2sub[13];
/// Boolean properties of datatypes
enum {
coretype = 1, ///< This is a basic type which will never be redefined
@ -96,7 +101,10 @@ protected:
utf16 = 16, ///< 16-bit wide chars in unicode UTF16
utf32 = 32, ///< 32-bit wide chars in unicode UTF32
opaque_string = 64, ///< Structure that should be treated as a string
variable_length = 128 ///< May be other structures with same name different lengths
variable_length = 128, ///< May be other structures with same name different lengths
has_stripped = 0x100, ///< Datatype has a stripped form for formal declarations
is_ptrrel = 0x200, ///< Datatype is a TypePointerRel
struct_incomplete = 0x400, ///< Set if \b this (recursive) structure has not been fully defined yet
};
friend class TypeFactory;
friend struct DatatypeCompare;
@ -108,7 +116,7 @@ protected:
uint8 id; ///< A unique id for the type (or 0 if an id is not assigned)
Datatype *typedefImm; ///< The immediate data-type being typedefed by \e this
void restoreXmlBasic(const Element *el); ///< Recover basic data-type properties
void saveXmlBasic(ostream &s) const; ///< Save basic data-type properties
void saveXmlBasic(type_metatype meta,ostream &s) const; ///< Save basic data-type properties
void saveXmlTypedef(ostream &s) const; ///< Write \b this as a \e typedef tag to stream
virtual void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore data-type from XML
virtual Datatype *clone(void) const=0; ///< Clone the data-type
@ -133,6 +141,10 @@ public:
bool isVariableLength(void) const { return ((flags&variable_length)!=0); } ///< Is \b this a variable length structure
bool hasSameVariableBase(const Datatype *ct) const; ///< Are these the same variable length data-type
bool isOpaqueString(void) const { return ((flags&opaque_string)!=0); } ///< Is \b this an opaquely encoded string
bool isPointerRel(void) const { return ((flags & is_ptrrel)!=0); } ///< Is \b this a TypePointerRel
bool isFormalPointerRel(void) const { return (flags & (is_ptrrel | has_stripped))==is_ptrrel; } ///< Is \b this a non-ephemeral TypePointerRel
bool hasStripped(void) const { return (flags & has_stripped)!=0; } ///< Return \b true if \b this has a stripped form
bool isIncompleteStruct(void) const { return (flags & struct_incomplete)!=0; } ///< Is \b this an incompletely defined struct
uint4 getInheritable(void) const { return (flags & coretype); } ///< Get properties pointers inherit
type_metatype getMetatype(void) const { return metatype; } ///< Get the type \b meta-type
uint8 getId(void) const { return id; } ///< Get the type id
@ -149,10 +161,11 @@ public:
virtual int4 compare(const Datatype &op,int4 level) const; ///< Order types for propagation
virtual int4 compareDependency(const Datatype &op) const; ///< Compare for storage in tree structure
virtual void saveXml(ostream &s) const; ///< Serialize the data-type to XML
virtual bool isPtrsubMatching(uintb off) const; ///< Is this data-type suitable as input to a CPUI_PTRSUB op
virtual Datatype *getStripped(void) const; ///< Get a stripped version of \b this for formal use in formal declarations
int4 typeOrder(const Datatype &op) const { if (this==&op) return 0; return compare(op,10); } ///< Order this with -op- datatype
int4 typeOrderBool(const Datatype &op) const; ///< Order \b this with -op-, treating \e bool data-type as special
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
@ -258,13 +271,15 @@ protected:
Datatype *ptrto; ///< Type being pointed to
uint4 wordsize; ///< What size unit does the pointer address
virtual void restoreXml(const Element *el,TypeFactory &typegrp);
void calcSubmeta(void); ///< Calculate specific submeta for \b this pointer
/// Internal constructor for use with restoreXml
TypePointer(void) : Datatype(0,TYPE_PTR) { ptrto = (Datatype *)0; wordsize=1; }
public:
/// Construct from another TypePointer
TypePointer(const TypePointer &op) : Datatype(op) { ptrto = op.ptrto; wordsize=op.wordsize; }
/// Construct from a size, pointed-to type, and wordsize
TypePointer(int4 s,Datatype *pt,uint4 ws) : Datatype(s,TYPE_PTR) { ptrto = pt; flags = ptrto->getInheritable(); wordsize=ws; }
TypePointer(int4 s,Datatype *pt,uint4 ws) : Datatype(s,TYPE_PTR) {
ptrto = pt; flags = ptrto->getInheritable(); wordsize=ws; calcSubmeta(); }
Datatype *getPtrTo(void) const { return ptrto; } ///< Get the pointed-to Datatype
uint4 getWordSize(void) const { return wordsize; } ///< Get the wordsize of the pointer
virtual void printRaw(ostream &s) const;
@ -275,7 +290,8 @@ public:
virtual int4 compareDependency(const Datatype &op) const; // For tree structure
virtual Datatype *clone(void) const { return new TypePointer(*this); }
virtual void saveXml(ostream &s) const;
virtual TypePointer *downChain(uintb &off,bool allowArrayWrap,TypeFactory &typegrp);
virtual TypePointer *downChain(uintb &off,TypePointer *&par,uintb &parOff,bool allowArrayWrap,TypeFactory &typegrp);
virtual bool isPtrsubMatching(uintb off) const;
};
/// \brief Datatype object representing an array of elements
@ -347,7 +363,7 @@ protected:
virtual void restoreXml(const Element *el,TypeFactory &typegrp);
public:
TypeStruct(const TypeStruct &op); ///< Construct from another TypeStruct
TypeStruct(const string &n) : Datatype(0,TYPE_STRUCT,n) {} ///< Construct empty TypeStruct from a name
TypeStruct(const string &n) : Datatype(0,TYPE_STRUCT,n) { flags |= struct_incomplete; } ///< Construct incomplete/empty TypeStruct from a name
vector<TypeField>::const_iterator beginField(void) const { return field.begin(); } ///< Beginning of fields
vector<TypeField>::const_iterator endField(void) const { return field.end(); } ///< End of fields
const TypeField *getField(int4 off,int4 sz,int4 *newoff) const; ///< Get field based on offset
@ -362,6 +378,45 @@ public:
virtual void saveXml(ostream &s) const;
};
/// \brief A pointer data-type that knows it is offset relative to another data-type
///
/// The other data, the \b container, is typically a TypeStruct or TypeArray. Even though \b this pointer
/// does not point directly to the start of the container, it is possible to access the container through \b this,
/// as the distance (the \b offset) to the start of the container is explicitly known.
class TypePointerRel : public TypePointer {
protected:
friend class TypeFactory;
TypePointer *stripped; ///< Same data-type with container info stripped
Datatype *parent; ///< Parent structure or array which \b this is pointing into
int4 offset; ///< Byte offset within the parent where \b this points to
void cacheStrippedType(TypeFactory &typegrp);
virtual void restoreXml(const Element *el,TypeFactory &typegrp);
/// Internal constructor for restoreXml
TypePointerRel(void) : TypePointer() { offset = 0; parent = (Datatype *)0; stripped = (TypePointer *)0; submeta = SUB_PTRREL; }
public:
/// Construct from another TypePointerRel
TypePointerRel(const TypePointerRel &op) : TypePointer((const TypePointer &)op) {
offset = op.offset; parent = op.parent; stripped = op.stripped; }
/// Construct given a size, pointed-to type, parent, and offset
TypePointerRel(int4 sz,Datatype *pt,uint4 ws,Datatype *par,int4 off) : TypePointer(sz,pt,ws) {
parent = par; offset = off; stripped = (TypePointer *)0; flags |= is_ptrrel;
submeta = pt->getMetatype()==TYPE_UNKNOWN ? SUB_PTRREL_UNK : SUB_PTRREL; }
Datatype *getParent(void) const { return parent; } ///< Get the parent data-type to which \b this pointer is offset
/// \brief Get offset of \b this pointer relative to start of the containing data-type
///
/// \return the offset value in \e address \e units
int4 getPointerOffset(void) const { return AddrSpace::byteToAddressInt(offset, wordsize); }
virtual void printRaw(ostream &s) const;
virtual int4 compareDependency(const Datatype &op) const;
virtual Datatype *clone(void) const { return new TypePointerRel(*this); }
virtual void saveXml(ostream &s) const;
virtual TypePointer *downChain(uintb &off,TypePointer *&par,uintb &parOff,bool allowArrayWrap,TypeFactory &typegrp);
virtual bool isPtrsubMatching(uintb off) const;
virtual Datatype *getStripped(void) const { return stripped; } ///< Get the plain form of the pointer
static Datatype *getPtrTo(Datatype *base,int4 off,TypeFactory &typegrp);
};
class FuncProto; // Forward declaration
class ProtoModel;
@ -484,6 +539,8 @@ public:
const vector<Datatype *> &intypes,
bool dotdotdot); ///< Create a "function" datatype
Datatype *getTypedef(Datatype *ct,const string &name,uint8 id); ///< Create a new \e typedef data-type
TypePointerRel *getTypePointerRel(TypePointer *parentPtr,Datatype *ptrTo,int4 off); ///< Get pointer offset relative to a container
TypePointerRel *getTypePointerRel(int4 sz,Datatype *parent,Datatype *ptrTo,int4 ws,int4 off,const string &nm);
void destroyType(Datatype *ct); ///< Remove a data-type from \b this
Datatype *concretize(Datatype *ct); ///< Convert given data-type to concrete form
void dependentOrder(vector<Datatype *> &deporder) const; ///< Place all data-types in dependency order
@ -512,4 +569,18 @@ inline int4 Datatype::typeOrderBool(const Datatype &op) const
return compare(op,10);
}
/// \brief Set up the base pointer data-type \b this is modeling
///
/// This base data-type is used for formal variable declarations in source code output.
/// Calling this method marks the TypePointerRel as an ephemeral data-type. The TypePointerRel
/// is not considered a formal data-type and is replaced with the base pointer data-type, after propagation,
/// in the final decompiler output.
/// \param typegrp is the factory from which to fetch the base pointer
inline void TypePointerRel::cacheStrippedType(TypeFactory &typegrp)
{
stripped = typegrp.getTypePointer(size,ptrto,wordsize);
flags |= has_stripped;
}
#endif

View file

@ -1572,7 +1572,7 @@ Datatype *TypeOpPiece::getOutputToken(const PcodeOp *op,CastStrategy *castStrate
{
const Varnode *vn = op->getOut();
Datatype *dt = vn->getType();
Datatype *dt = vn->getHigh()->getType();
type_metatype meta = dt->getMetatype();
if ((meta == TYPE_INT)||(meta == TYPE_UINT)) // PIECE casts to uint or int, based on output
return dt;
@ -1599,7 +1599,7 @@ Datatype *TypeOpSubpiece::getOutputToken(const PcodeOp *op,CastStrategy *castStr
{
const Varnode *vn = op->getOut();
Datatype *dt = vn->getType(); // SUBPIECE prints as cast to whatever its output is
Datatype *dt = vn->getHigh()->getType(); // SUBPIECE prints as cast to whatever its output is
if (dt->getMetatype() != TYPE_UNKNOWN)
return dt;
return tlst->getBase(vn->getSize(),TYPE_INT); // If output is unknown, treat as cast to int
@ -1711,7 +1711,9 @@ Datatype *TypeOpPtrsub::getOutputToken(const PcodeOp *op,CastStrategy *castStrat
TypePointer *ptype = (TypePointer *)op->getIn(0)->getHigh()->getType();
if (ptype->getMetatype() == TYPE_PTR) {
uintb offset = AddrSpace::addressToByte(op->getIn(1)->getOffset(),ptype->getWordSize());
Datatype *rettype = ptype->downChain(offset,false,*tlst);
uintb unusedOffset;
TypePointer *unusedParent;
Datatype *rettype = ptype->downChain(offset,unusedParent,unusedOffset,false,*tlst);
if ((offset==0)&&(rettype != (Datatype *)0))
return rettype;
rettype = tlst->getBase(1, TYPE_UNKNOWN);

View file

@ -153,6 +153,9 @@ void HighVariable::updateType(void) const
vn = getTypeRepresentative();
type = vn->getType();
if (type->hasStripped())
type = type->getStripped();
// Update lock flags
flags &= ~Varnode::typelock;
if (vn->isTypeLock())

View file

@ -723,7 +723,7 @@ int4 Varnode::isConstantExtended(uintb &val) const
/// to determine if the Varnode is getting used as an \b int, \b float, or \b pointer, etc.
/// Throw an exception if no Datatype can be found at all.
/// \return the determined Datatype
Datatype *Varnode::getLocalType(void) const
Datatype *Varnode::getLocalType(bool &blockup) const
{
Datatype *ct;
@ -733,8 +733,13 @@ Datatype *Varnode::getLocalType(void) const
return type; // Not a partial lock, return the locked type
ct = (Datatype *)0;
if (def != (PcodeOp *)0)
if (def != (PcodeOp *)0) {
ct = def->outputTypeLocal();
if (def->stopsPropagation()) {
blockup = true;
return ct;
}
}
list<PcodeOp *>::const_iterator iter;
PcodeOp *op;

View file

@ -116,8 +116,9 @@ public:
unsignedprint = 0x40, ///< Constant that must be explicitly printed as unsigned
stack_store = 0x80, ///< Created by an explicit STORE
locked_input = 0x100, ///< Input that exists even if its unused
spacebase_placeholder = 0x200 ///< This varnode is inserted artificially to track a register
spacebase_placeholder = 0x200, ///< This varnode is inserted artificially to track a register
///< value at a specific point in the code
stop_uppropagation = 0x400 ///< Data-types do not propagate from an output into \b this
};
private:
mutable uint4 flags; ///< The collection of boolean attributes for this Varnode
@ -243,6 +244,7 @@ public:
bool isActiveHeritage(void) const { return ((addlflags&Varnode::activeheritage)!=0); } ///< Is \b this currently being traced by the Heritage algorithm?
bool isStackStore(void) const { return ((addlflags&Varnode::stack_store)!=0); } ///< Was this originally produced by an explicit STORE
bool isLockedInput(void) const { return ((addlflags&Varnode::locked_input)!=0); } ///< Is always an input, even if unused
bool stopsUpPropagation(void) const { return ((addlflags&Varnode::stop_uppropagation)!=0); } ///< Is data-type propagation stopped
/// Is \b this just a special placeholder representing INDIRECT creation?
bool isIndirectZero(void) const { return ((flags&(Varnode::indirect_creation|Varnode::constant))==(Varnode::indirect_creation|Varnode::constant)); }
@ -301,12 +303,14 @@ public:
void setAutoLiveHold(void) { flags |= Varnode::autolive_hold; } ///< Place temporary hold on dead code removal
void clearAutoLiveHold(void) { flags &= ~Varnode::autolive_hold; } ///< Clear temporary hold on dead code removal
void setUnsignedPrint(void) { addlflags |= Varnode::unsignedprint; } ///< Force \b this to be printed as unsigned
void setStopUpPropagation(void) { addlflags |= Varnode::stop_uppropagation; } ///< Stop up-propagation thru \b this
void clearStopUpPropagation(void) { addlflags &= ~Varnode::stop_uppropagation; } ///< Stop up-propagation thru \b this
bool updateType(Datatype *ct,bool lock,bool override); ///< (Possibly) set the Datatype given various restrictions
void setStackStore(void) { addlflags |= Varnode::stack_store; } ///< Mark as produced by explicit CPUI_STORE
void setLockedInput(void) { addlflags |= Varnode::locked_input; } ///< Mark as existing input, even if unused
void copySymbol(const Varnode *vn); ///< Copy symbol info from \b vn
void copySymbolIfValid(const Varnode *vn); ///< Copy symbol info from \b vn if constant value matches
Datatype *getLocalType(void) const; ///< Calculate type of Varnode based on local information
Datatype *getLocalType(bool &blockup) const; ///< Calculate type of Varnode based on local information
bool copyShadow(const Varnode *op2) const; ///< Are \b this and \b op2 copied from the same source?
void saveXml(ostream &s) const; ///< Save a description of \b this as an XML tag
static bool comparePointers(const Varnode *a,const Varnode *b) { return (*a < *b); } ///< Compare Varnodes as pointers