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

@ -30,6 +30,8 @@ src/decompile/datatests/noforloop_alias.xml||GHIDRA||||END|
src/decompile/datatests/noforloop_globcall.xml||GHIDRA||||END|
src/decompile/datatests/noforloop_iterused.xml||GHIDRA||||END|
src/decompile/datatests/offsetarray.xml||GHIDRA||||END|
src/decompile/datatests/pointercmp.xml||GHIDRA||||END|
src/decompile/datatests/pointerrel.xml||GHIDRA||||END|
src/decompile/datatests/promotecompare.xml||GHIDRA||||END|
src/decompile/datatests/readvolatile.xml||GHIDRA||||END|
src/decompile/datatests/sbyte.xml||GHIDRA||||END|

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 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 3;
}
}
if (sz == 1)
return 3;
return 2;
return 1;
}
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 (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);
}
if (pointer == (TypePointer *)0) {
if (command == 0)
return op->getIn(inslot)->getTempType();
return 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 (pointer->getPtrTo()->getMetatype() == TYPE_SPACEBASE)
pointer = typegrp->getTypePointer(pointer->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),pointer->getWordSize());
}
}
return rettype;
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");
}
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())
if (state.apply()) return 1;
if (state.initAlternateForm()) {
if (state.apply()) return 1;
}
return 0;
return 1;
}
/// \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;
}
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

View file

@ -0,0 +1,23 @@
<decompilertest>
<binaryimage arch="x86:LE:64:default:gcc">
<bytechunk space="ram" offset="0x10066a" readonly="true">
554889e54889
7de8488b45e84883c008488945f8eb0c
488b45f8c60061488345f801488b45e8
4883c018483945f872e6905dc3
</bytechunk>
<symbol name="myinit" space="ram" offset="0x10066a"/>
</binaryimage>
<script>
<com>parse line struct mystruct { int8 val; char arr[16]; float4 fval; };</com>
<com>parse line extern void myinit(mystruct *ptr);</com>
<com>lo fu myinit</com>
<com>map addr s0xfffffffffffffff0 xunknown8 pchar</com>
<com>dec</com>
<com>print C</com>
<com>quit</com>
</script>
<stringmatch name="Pointer Compare #1" min="1" max="1">for \(pchar = ptr-&gt;arr; pchar &lt; \&amp;ptr-&gt;fval; pchar = pchar \+ 1\)</stringmatch>
<stringmatch name="Pointer Compare #2" min="1" max="1">char \*pchar;</stringmatch>
<stringmatch name="Pointer Compare #3" min="1" max="1">\*pchar = 'a';</stringmatch>
</decompilertest>

View file

@ -0,0 +1,50 @@
<decompilertest>
<binaryimage arch="x86:LE:64:default:gcc">
<!--
A function that uses a "relative pointer" that knows it points to the
interior of a structure. We should see the initialization of the pointer
based on a particular field, and we should see accesses into the structure
from the pointer using the special functional syntax. The are accesses
of different types occuring both before and after the original pointer.
-->
<bytechunk space="ram" offset="0x1006fa" readonly="true">
554889e54889
7dd88975d4c745ec00000000f30f1005
a0010000f30f1145f0488b45d84883c0
08488945f8c745f400000000eb39488b
45f88b000145ec488b45f84883c0048b
000145ec488b45f84883e804f30f1000
f30f104df0f30f58c1f30f1145f04883
45f8508345f4018b45f43b45d47cbff3
0f1045f00f2e053d01000076048345ec
058b45ec5dc3
</bytechunk>
<bytechunk space="ram" offset="0x1008b4" readonly="true">
000020410000a841
</bytechunk>
<symbol name="process_array" space="ram" offset="0x1006fa"/>
</binaryimage>
<script>
<com>option readonly on</com>
<com>parse line struct mystruct { int4 a; float4 b; int4 c; int4 d; int4 arr[16]; };</com>
<com>pointer setting myptroff mystruct offset 8</com>
<com>parse line extern int4 process_array(mystruct *ptr,int4 count);</com>
<com>lo fu process_array</com>
<com>dec</com>
<com>retype piStack16 myptroff ptrrel</com>
<com>rename iStack20 i</com>
<com>rename fStack24 fSum</com>
<com>rename iStack28 iSum</com>
<com>dec</com>
<com>print C</com>
<com>quit</com>
</script>
<stringmatch name="Relative pointers #1" min="2" max="2">ADJ</stringmatch>
<stringmatch name="Relative pointers #2" min="1" max="1">iSum = iSum \+ ADJ\(ptrrel\)-&gt;c \+ ADJ\(ptrrel\)-&gt;d;</stringmatch>
<stringmatch name="Relative pointers #3" min="1" max="1">fSum = ADJ\(ptrrel\)-&gt;b \+ fSum;</stringmatch>
<stringmatch name="Relative pointers #4" min="1" max="1">ptrrel = &amp;ptr-&gt;c;</stringmatch>
<stringmatch name="Relative pointers #5" min="1" max="1">myptroff ptrrel;</stringmatch>
<stringmatch name="Relative pointers #6" min="1" max="1">ptrrel = ptrrel \+ 0x14;</stringmatch>
<stringmatch name="Relative pointers #7" min="1" max="1">if \(21.0 &lt; fSum\)</stringmatch>
<stringmatch name="Relative pointers #8" min="1" max="1">for \(i = 0; i &lt; count; i = i \+ 1\)</stringmatch>
</decompilertest>