mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Decompiler support for offset/relative pointers
This commit is contained in:
parent
513c9beb9d
commit
cce187a4c5
18 changed files with 746 additions and 174 deletions
|
@ -30,6 +30,8 @@ src/decompile/datatests/noforloop_alias.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/noforloop_globcall.xml||GHIDRA||||END|
|
src/decompile/datatests/noforloop_globcall.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/noforloop_iterused.xml||GHIDRA||||END|
|
src/decompile/datatests/noforloop_iterused.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/offsetarray.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/promotecompare.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/readvolatile.xml||GHIDRA||||END|
|
src/decompile/datatests/readvolatile.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/sbyte.xml||GHIDRA||||END|
|
src/decompile/datatests/sbyte.xml||GHIDRA||||END|
|
||||||
|
|
|
@ -2231,10 +2231,12 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
|
||||||
Datatype *outct,*ct,*tokenct;
|
Datatype *outct,*ct,*tokenct;
|
||||||
Varnode *vn,*outvn;
|
Varnode *vn,*outvn;
|
||||||
PcodeOp *newop;
|
PcodeOp *newop;
|
||||||
|
HighVariable *outHigh;
|
||||||
bool force=false;
|
bool force=false;
|
||||||
|
|
||||||
tokenct = op->getOpcode()->getOutputToken(op,castStrategy);
|
tokenct = op->getOpcode()->getOutputToken(op,castStrategy);
|
||||||
outvn = op->getOut();
|
outvn = op->getOut();
|
||||||
|
outHigh = outvn->getHigh();
|
||||||
if (outvn->isImplied()) {
|
if (outvn->isImplied()) {
|
||||||
// implied varnode must have parse type
|
// implied varnode must have parse type
|
||||||
if (outvn->isTypeLock()) {
|
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
|
// The Varnode input to a CPUI_RETURN is marked as implied but
|
||||||
// casting should act as if it were explicit
|
// casting should act as if it were explicit
|
||||||
if (outOp == (PcodeOp *)0 || outOp->code() != CPUI_RETURN) {
|
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
|
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
|
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();
|
type_metatype meta = outct->getMetatype();
|
||||||
// Preserve implied pointer if it points to a composite
|
// Preserve implied pointer if it points to a composite
|
||||||
if ((meta!=TYPE_ARRAY)&&(meta!=TYPE_STRUCT))
|
if ((meta!=TYPE_ARRAY)&&(meta!=TYPE_STRUCT))
|
||||||
|
@ -2256,7 +2258,7 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!force) {
|
if (!force) {
|
||||||
outct = outvn->getHigh()->getType(); // Type of result
|
outct = outHigh->getType(); // Type of result
|
||||||
ct = castStrategy->castStandard(outct,tokenct,false,true);
|
ct = castStrategy->castStandard(outct,tokenct,false,true);
|
||||||
if (ct == (Datatype *)0) return 0;
|
if (ct == (Datatype *)0) return 0;
|
||||||
}
|
}
|
||||||
|
@ -4237,7 +4239,10 @@ void ActionInferTypes::buildLocaltypes(Funcdata &data)
|
||||||
vn = *iter;
|
vn = *iter;
|
||||||
if (vn->isAnnotation()) continue;
|
if (vn->isAnnotation()) continue;
|
||||||
if ((!vn->isWritten())&&(vn->hasNoDescend())) continue;
|
if ((!vn->isWritten())&&(vn->hasNoDescend())) continue;
|
||||||
ct = vn->getLocalType();
|
bool needsBlock = false;
|
||||||
|
ct = vn->getLocalType(needsBlock);
|
||||||
|
if (needsBlock)
|
||||||
|
vn->setStopUpPropagation();
|
||||||
#ifdef TYPEPROP_DEBUG
|
#ifdef TYPEPROP_DEBUG
|
||||||
propagationDebug(data.getArch(),vn,ct,(PcodeOp *)0,0,(Varnode *)0);
|
propagationDebug(data.getArch(),vn,ct,(PcodeOp *)0,0,(Varnode *)0);
|
||||||
#endif
|
#endif
|
||||||
|
@ -4271,11 +4276,12 @@ bool ActionInferTypes::writeBack(Funcdata &data)
|
||||||
/// Determine if the given data-type edge looks like a pointer
|
/// Determine if the given data-type edge looks like a pointer
|
||||||
/// propagating through an "add a constant" operation. We assume the input
|
/// 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:
|
/// 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
|
/// - 0 indicates this is "add a constant" adding a zero (PTRSUB or PTRADD)
|
||||||
/// - 1 indicating the pointer does not propagate through
|
/// - 1 indicates this is "add a constant" and the constant is passed back
|
||||||
/// - 2 the input data-type propagates through untransformed
|
/// - 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 op is the PcodeOp propagating the data-type
|
||||||
/// \param slot is the input edge being propagated
|
/// \param slot is the input edge being propagated
|
||||||
/// \param sz is the size of the data-type being pointed to
|
/// \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 (op->code() == CPUI_PTRADD) {
|
||||||
if (slot != 0) return 1;
|
if (slot != 0) return 2;
|
||||||
Varnode *constvn = op->getIn(1);
|
Varnode *constvn = op->getIn(1);
|
||||||
uintb mult = op->getIn(2)->getOffset();
|
uintb mult = op->getIn(2)->getOffset();
|
||||||
if (constvn->isConstant()) {
|
if (constvn->isConstant()) {
|
||||||
off = (constvn->getOffset() * mult) & calc_mask(constvn->getSize()) ;
|
off = (constvn->getOffset() * mult) & calc_mask(constvn->getSize()) ;
|
||||||
return 0;
|
return (off == 0) ? 0 : 1;
|
||||||
}
|
}
|
||||||
if (sz != 0 && (mult % sz) != 0)
|
if (sz != 0 && (mult % sz) != 0)
|
||||||
return 1;
|
|
||||||
return 2;
|
return 2;
|
||||||
|
return 3;
|
||||||
}
|
}
|
||||||
if (op->code() == CPUI_PTRSUB) {
|
if (op->code() == CPUI_PTRSUB) {
|
||||||
if (slot != 0) return 1;
|
if (slot != 0) return 2;
|
||||||
off = op->getIn(1)->getOffset();
|
off = op->getIn(1)->getOffset();
|
||||||
return 0;
|
return (off == 0) ? 0 : 1;
|
||||||
}
|
}
|
||||||
if (op->code() == CPUI_INT_ADD) {
|
if (op->code() == CPUI_INT_ADD) {
|
||||||
Varnode *othervn = op->getIn(1-slot);
|
Varnode *othervn = op->getIn(1-slot);
|
||||||
|
@ -4311,23 +4317,23 @@ int4 ActionInferTypes::propagateAddPointer(uintb &off,PcodeOp *op,int4 slot,int4
|
||||||
if (constvn->isConstant()) {
|
if (constvn->isConstant()) {
|
||||||
uintb mult = constvn->getOffset();
|
uintb mult = constvn->getOffset();
|
||||||
if (mult == calc_mask(constvn->getSize())) // If multiplying by -1
|
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)
|
if (sz != 0 && (mult % sz) !=0)
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (sz == 1)
|
if (sz == 1)
|
||||||
|
return 3;
|
||||||
return 2;
|
return 2;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
if (othervn->getTempType()->getMetatype() == TYPE_PTR) // Check if othervn marked as ptr
|
if (othervn->getTempType()->getMetatype() == TYPE_PTR) // Check if othervn marked as ptr
|
||||||
return 1;
|
return 2;
|
||||||
off = othervn->getOffset();
|
off = othervn->getOffset();
|
||||||
return 0;
|
return (off == 0) ? 0 : 1;
|
||||||
}
|
}
|
||||||
return 1;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Propagate a pointer data-type through an ADD operation.
|
/// \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
|
TypePointer *pointer = (TypePointer *)op->getIn(inslot)->getTempType(); // We know this is a pointer type
|
||||||
uintb uoffset;
|
uintb uoffset;
|
||||||
int4 command = propagateAddPointer(uoffset,op,inslot,pointer->getPtrTo()->getSize());
|
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) return op->getOut()->getTempType(); // Doesn't look like a good pointer add
|
||||||
if (command != 2) {
|
TypePointer *parent = (TypePointer *)0;
|
||||||
|
uintb parentOff;
|
||||||
|
if (command != 3) {
|
||||||
uoffset = AddrSpace::addressToByte(uoffset,pointer->getWordSize());
|
uoffset = AddrSpace::addressToByte(uoffset,pointer->getWordSize());
|
||||||
bool allowWrap = (op->code() != CPUI_PTRSUB);
|
bool allowWrap = (op->code() != CPUI_PTRSUB);
|
||||||
do {
|
do {
|
||||||
pointer = pointer->downChain(uoffset,allowWrap,*typegrp);
|
pointer = pointer->downChain(uoffset,parent,parentOff,allowWrap,*typegrp);
|
||||||
if (pointer == (TypePointer *)0)
|
if (pointer == (TypePointer *)0)
|
||||||
return op->getOut()->getTempType();
|
break;
|
||||||
} while(uoffset != 0);
|
} while(uoffset != 0);
|
||||||
}
|
}
|
||||||
Datatype *rettype = pointer;
|
if (parent != (TypePointer *)0) {
|
||||||
if (rettype == (Datatype *)0)
|
// If the innermost containing object is a TYPE_STRUCT or TYPE_ARRAY
|
||||||
rettype = op->getOut()->getTempType();
|
// 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 (op->getIn(inslot)->isSpacebase()) {
|
||||||
if (rettype->getMetatype() == TYPE_PTR) {
|
if (pointer->getPtrTo()->getMetatype() == TYPE_SPACEBASE)
|
||||||
TypePointer *ptype = (TypePointer *)rettype;
|
pointer = typegrp->getTypePointer(pointer->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),pointer->getWordSize());
|
||||||
if (ptype->getPtrTo()->getMetatype() == TYPE_SPACEBASE)
|
|
||||||
rettype = typegrp->getTypePointer(ptype->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),ptype->getWordSize());
|
|
||||||
}
|
}
|
||||||
}
|
return pointer;
|
||||||
return rettype;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Determine if propagation should happen along the given edge
|
/// \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;
|
Varnode *invn,*outvn;
|
||||||
Datatype *newtype;
|
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->isAnnotation()) return false;
|
||||||
if (outvn->isTypeLock()) return false; // Can't propagate through typelock
|
if (outvn->isTypeLock()) return false; // Can't propagate through typelock
|
||||||
invn = (inslot==-1) ? op->getOut() : op->getIn(inslot);
|
invn = (inslot==-1) ? op->getOut() : op->getIn(inslot);
|
||||||
|
@ -4481,13 +4504,31 @@ bool ActionInferTypes::propagateTypeEdge(TypeFactory *typegrp,PcodeOp *op,int4 i
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch(op->code()) {
|
switch(op->code()) {
|
||||||
case CPUI_INDIRECT:
|
|
||||||
case CPUI_COPY:
|
|
||||||
case CPUI_MULTIEQUAL:
|
|
||||||
case CPUI_INT_LESS:
|
case CPUI_INT_LESS:
|
||||||
case CPUI_INT_LESSEQUAL:
|
case CPUI_INT_LESSEQUAL:
|
||||||
case CPUI_INT_EQUAL:
|
case CPUI_INT_EQUAL:
|
||||||
case CPUI_INT_NOTEQUAL:
|
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_AND:
|
||||||
case CPUI_INT_OR:
|
case CPUI_INT_OR:
|
||||||
case CPUI_INT_XOR:
|
case CPUI_INT_XOR:
|
||||||
|
@ -4805,6 +4846,7 @@ PcodeOp *ActionInferTypes::canonicalReturnOp(Funcdata &data)
|
||||||
void ActionInferTypes::propagateAcrossReturns(Funcdata &data)
|
void ActionInferTypes::propagateAcrossReturns(Funcdata &data)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
if (data.getFuncProto().isOutputLocked()) return;
|
||||||
PcodeOp *op = canonicalReturnOp(data);
|
PcodeOp *op = canonicalReturnOp(data);
|
||||||
if (op == (PcodeOp *)0) return;
|
if (op == (PcodeOp *)0) return;
|
||||||
TypeFactory *typegrp = data.getArch()->types;
|
TypeFactory *typegrp = data.getArch()->types;
|
||||||
|
@ -4826,7 +4868,7 @@ void ActionInferTypes::propagateAcrossReturns(Funcdata &data)
|
||||||
if (vn->getTempType() == ct) continue; // Already propagated
|
if (vn->getTempType() == ct) continue; // Already propagated
|
||||||
vn->setTempType(ct);
|
vn->setTempType(ct);
|
||||||
#ifdef TYPEPROP_DEBUG
|
#ifdef TYPEPROP_DEBUG
|
||||||
propagationDebug(typegrp->getArch(),vn,ct,retop,1,(Varnode *)0);
|
propagationDebug(typegrp->getArch(),vn,ct,op,1,(Varnode *)0);
|
||||||
#endif
|
#endif
|
||||||
propagateOneType(typegrp, vn);
|
propagateOneType(typegrp, vn);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2147,6 +2147,7 @@ void ScopeInternal::setAttribute(Symbol *sym,uint4 attr)
|
||||||
attr &= (Varnode::typelock | Varnode::namelock | Varnode::readonly | Varnode::incidental_copy |
|
attr &= (Varnode::typelock | Varnode::namelock | Varnode::readonly | Varnode::incidental_copy |
|
||||||
Varnode::nolocalalias | Varnode::volatil | Varnode::indirectstorage | Varnode::hiddenretparm);
|
Varnode::nolocalalias | Varnode::volatil | Varnode::indirectstorage | Varnode::hiddenretparm);
|
||||||
sym->flags |= attr;
|
sym->flags |= attr;
|
||||||
|
sym->checkSizeTypeLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScopeInternal::clearAttribute(Symbol *sym,uint4 attr)
|
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 |
|
attr &= (Varnode::typelock | Varnode::namelock | Varnode::readonly | Varnode::incidental_copy |
|
||||||
Varnode::nolocalalias | Varnode::volatil | Varnode::indirectstorage | Varnode::hiddenretparm);
|
Varnode::nolocalalias | Varnode::volatil | Varnode::indirectstorage | Varnode::hiddenretparm);
|
||||||
sym->flags &= ~attr;
|
sym->flags &= ~attr;
|
||||||
|
sym->checkSizeTypeLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScopeInternal::setDisplayFormat(Symbol *sym,uint4 attr)
|
void ScopeInternal::setDisplayFormat(Symbol *sym,uint4 attr)
|
||||||
|
|
|
@ -127,6 +127,7 @@ void IfaceDecompCapability::registerCommands(IfaceStatus *status)
|
||||||
status->registerCom(new IfcCallOtherFixup(),"fixup","callother");
|
status->registerCom(new IfcCallOtherFixup(),"fixup","callother");
|
||||||
status->registerCom(new IfcVolatile(),"volatile");
|
status->registerCom(new IfcVolatile(),"volatile");
|
||||||
status->registerCom(new IfcReadonly(),"readonly");
|
status->registerCom(new IfcReadonly(),"readonly");
|
||||||
|
status->registerCom(new IfcPointerSetting(),"pointer","setting");
|
||||||
status->registerCom(new IfcPreferSplit(),"prefersplit");
|
status->registerCom(new IfcPreferSplit(),"prefersplit");
|
||||||
status->registerCom(new IfcStructureBlocks(),"structure","blocks");
|
status->registerCom(new IfcStructureBlocks(),"structure","blocks");
|
||||||
status->registerCom(new IfcAnalyzeRange(), "analyze","range");
|
status->registerCom(new IfcAnalyzeRange(), "analyze","range");
|
||||||
|
@ -2889,6 +2890,48 @@ void IfcReadonly::execute(istream &s)
|
||||||
*status->optr << "Successfully marked range as readonly" << endl;
|
*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
|
/// \class IfcPreferSplit
|
||||||
/// \brief Mark a storage location to be split: `prefersplit <address+size> <splitsize>`
|
/// \brief Mark a storage location to be split: `prefersplit <address+size> <splitsize>`
|
||||||
///
|
///
|
||||||
|
|
|
@ -554,6 +554,11 @@ public:
|
||||||
virtual void execute(istream &s);
|
virtual void execute(istream &s);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IfcPointerSetting : public IfaceDecompCommand {
|
||||||
|
public:
|
||||||
|
virtual void execute(istream &s);
|
||||||
|
};
|
||||||
|
|
||||||
class IfcPreferSplit : public IfaceDecompCommand {
|
class IfcPreferSplit : public IfaceDecompCommand {
|
||||||
public:
|
public:
|
||||||
virtual void execute(istream &s);
|
virtual void execute(istream &s);
|
||||||
|
|
|
@ -105,7 +105,8 @@ public:
|
||||||
modified = 4, ///< This op has been modified by the current action
|
modified = 4, ///< This op has been modified by the current action
|
||||||
warning = 8, ///< Warning has been generated for this op
|
warning = 8, ///< Warning has been generated for this op
|
||||||
incidental_copy = 0x10, ///< Treat this as \e incidental for parameter recovery algorithms
|
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:
|
private:
|
||||||
TypeOp *opcode; ///< Pointer to class providing behavioral details of the operation
|
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
|
/// \brief Return \b true if we have already examined this cpool
|
||||||
bool isCpoolTransformed(void) const { return ((addlflags&PcodeOp::is_cpool_transformed)!=0); }
|
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 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
|
/// \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); }
|
bool usesSpacebasePtr(void) const { return ((flags&PcodeOp::spacebase_ptr)!=0); }
|
||||||
uintm getCseHash(void) const; ///< Return hash indicating possibility of common subexpression elimination
|
uintm getCseHash(void) const; ///< Return hash indicating possibility of common subexpression elimination
|
||||||
|
|
|
@ -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::array_expr = { "[]", 2, 66, false, OpToken::postsurround, 1, 0, (OpToken *)0 };
|
||||||
OpToken PrintC::enum_cat = { "|", 2, 26, true, OpToken::binary, 0, 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
|
// Constructing this registers the capability
|
||||||
PrintCCapability PrintCCapability::printCCapability;
|
PrintCCapability PrintCCapability::printCCapability;
|
||||||
|
|
||||||
|
@ -780,6 +782,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
||||||
|
|
||||||
{
|
{
|
||||||
TypePointer *ptype;
|
TypePointer *ptype;
|
||||||
|
TypePointerRel *ptrel;
|
||||||
Datatype *ct;
|
Datatype *ct;
|
||||||
const Varnode *in0;
|
const Varnode *in0;
|
||||||
bool valueon,flex,arrayvalue;
|
bool valueon,flex,arrayvalue;
|
||||||
|
@ -791,13 +794,24 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
||||||
clear();
|
clear();
|
||||||
throw LowlevelError("PTRSUB off of non-pointer type");
|
throw LowlevelError("PTRSUB off of non-pointer type");
|
||||||
}
|
}
|
||||||
|
if (ptype->isFormalPointerRel()) {
|
||||||
|
ptrel = (TypePointerRel *)ptype;
|
||||||
|
ct = ptrel->getParent();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ptrel = (TypePointerRel *)0;
|
||||||
ct = ptype->getPtrTo();
|
ct = ptype->getPtrTo();
|
||||||
|
}
|
||||||
m = mods & ~(print_load_value|print_store_value); // Current state of mods
|
m = mods & ~(print_load_value|print_store_value); // Current state of mods
|
||||||
valueon = (mods & (print_load_value|print_store_value)) != 0;
|
valueon = (mods & (print_load_value|print_store_value)) != 0;
|
||||||
flex = isValueFlexible(in0);
|
flex = isValueFlexible(in0);
|
||||||
|
|
||||||
if (ct->getMetatype() == TYPE_STRUCT) {
|
if (ct->getMetatype() == TYPE_STRUCT) {
|
||||||
uintb suboff = op->getIn(1)->getOffset(); // How far into container
|
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());
|
suboff = AddrSpace::addressToByte(suboff,ptype->getWordSize());
|
||||||
string fieldname;
|
string fieldname;
|
||||||
Datatype *fieldtype;
|
Datatype *fieldtype;
|
||||||
|
@ -832,12 +846,16 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
||||||
if (flex) { // EMIT &( ).name
|
if (flex) { // EMIT &( ).name
|
||||||
pushOp(&addressof,op);
|
pushOp(&addressof,op);
|
||||||
pushOp(&object_member,op);
|
pushOp(&object_member,op);
|
||||||
|
if (ptrel != (TypePointerRel *)0)
|
||||||
|
pushTypePointerRel(op);
|
||||||
pushVnImplied(in0,op,m | print_load_value);
|
pushVnImplied(in0,op,m | print_load_value);
|
||||||
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
|
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
|
||||||
}
|
}
|
||||||
else { // EMIT &( )->name
|
else { // EMIT &( )->name
|
||||||
pushOp(&addressof,op);
|
pushOp(&addressof,op);
|
||||||
pushOp(&pointer_member,op);
|
pushOp(&pointer_member,op);
|
||||||
|
if (ptrel != (TypePointerRel *)0)
|
||||||
|
pushTypePointerRel(op);
|
||||||
pushVnImplied(in0,op,m);
|
pushVnImplied(in0,op,m);
|
||||||
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
|
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
|
||||||
}
|
}
|
||||||
|
@ -847,11 +865,15 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
||||||
pushOp(&subscript,op);
|
pushOp(&subscript,op);
|
||||||
if (flex) { // EMIT ( ).name
|
if (flex) { // EMIT ( ).name
|
||||||
pushOp(&object_member,op);
|
pushOp(&object_member,op);
|
||||||
|
if (ptrel != (TypePointerRel *)0)
|
||||||
|
pushTypePointerRel(op);
|
||||||
pushVnImplied(in0,op,m | print_load_value);
|
pushVnImplied(in0,op,m | print_load_value);
|
||||||
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
|
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
|
||||||
}
|
}
|
||||||
else { // EMIT ( )->name
|
else { // EMIT ( )->name
|
||||||
pushOp(&pointer_member,op);
|
pushOp(&pointer_member,op);
|
||||||
|
if (ptrel != (TypePointerRel *)0)
|
||||||
|
pushTypePointerRel(op);
|
||||||
pushVnImplied(in0,op,m);
|
pushVnImplied(in0,op,m);
|
||||||
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
|
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
|
||||||
}
|
}
|
||||||
|
@ -912,22 +934,30 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
||||||
if (flex) { // EMIT ( )
|
if (flex) { // EMIT ( )
|
||||||
// (*&struct->arrayfield)[i]
|
// (*&struct->arrayfield)[i]
|
||||||
// becomes struct->arrayfield[i]
|
// becomes struct->arrayfield[i]
|
||||||
|
if (ptrel != (TypePointerRel *)0)
|
||||||
|
pushTypePointerRel(op);
|
||||||
pushVnImplied(in0,op,m);
|
pushVnImplied(in0,op,m);
|
||||||
}
|
}
|
||||||
else { // EMIT *( )
|
else { // EMIT *( )
|
||||||
pushOp(&dereference,op);
|
pushOp(&dereference,op);
|
||||||
|
if (ptrel != (TypePointerRel *)0)
|
||||||
|
pushTypePointerRel(op);
|
||||||
pushVnImplied(in0,op,m);
|
pushVnImplied(in0,op,m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (flex) { // EMIT ( )[0]
|
if (flex) { // EMIT ( )[0]
|
||||||
pushOp(&subscript,op);
|
pushOp(&subscript,op);
|
||||||
|
if (ptrel != (TypePointerRel *)0)
|
||||||
|
pushTypePointerRel(op);
|
||||||
pushVnImplied(in0,op,m);
|
pushVnImplied(in0,op,m);
|
||||||
push_integer(0,4,false,(Varnode *)0,op);
|
push_integer(0,4,false,(Varnode *)0,op);
|
||||||
}
|
}
|
||||||
else { // EMIT (* )[0]
|
else { // EMIT (* )[0]
|
||||||
pushOp(&subscript,op);
|
pushOp(&subscript,op);
|
||||||
pushOp(&dereference,op);
|
pushOp(&dereference,op);
|
||||||
|
if (ptrel != (TypePointerRel *)0)
|
||||||
|
pushTypePointerRel(op);
|
||||||
pushVnImplied(in0,op,m);
|
pushVnImplied(in0,op,m);
|
||||||
push_integer(0,4,false,(Varnode *)0,op);
|
push_integer(0,4,false,(Varnode *)0,op);
|
||||||
}
|
}
|
||||||
|
@ -1561,6 +1591,7 @@ void PrintC::pushConstant(uintb val,const Datatype *ct,
|
||||||
clear();
|
clear();
|
||||||
throw LowlevelError("Cannot have a constant of type void");
|
throw LowlevelError("Cannot have a constant of type void");
|
||||||
case TYPE_PTR:
|
case TYPE_PTR:
|
||||||
|
case TYPE_PTRSTRUCT:
|
||||||
if (option_NULL&&(val==0)) { // A null pointer
|
if (option_NULL&&(val==0)) { // A null pointer
|
||||||
pushAtom(Atom(nullToken,vartoken,EmitXml::var_color,op,vn));
|
pushAtom(Atom(nullToken,vartoken,EmitXml::var_color,op,vn));
|
||||||
return;
|
return;
|
||||||
|
@ -1582,6 +1613,7 @@ void PrintC::pushConstant(uintb val,const Datatype *ct,
|
||||||
case TYPE_CODE:
|
case TYPE_CODE:
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
case TYPE_STRUCT:
|
case TYPE_STRUCT:
|
||||||
|
case TYPE_PARTIALSTRUCT:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Default printing
|
// Default printing
|
||||||
|
|
|
@ -113,6 +113,7 @@ protected:
|
||||||
static OpToken ptr_expr; ///< Pointer adornment for a type declaration
|
static OpToken ptr_expr; ///< Pointer adornment for a type declaration
|
||||||
static OpToken array_expr; ///< Array 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 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_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_inplace_ops; ///< Set to \b true if we should use '+=' '&=' etc.
|
||||||
bool option_convention; ///< Set to \b true if we should print calling convention
|
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 emitFunctionDeclaration(const Funcdata *fd);
|
||||||
virtual void emitTypeDefinition(const Datatype *ct);
|
virtual void emitTypeDefinition(const Datatype *ct);
|
||||||
virtual bool checkPrintNegation(const Varnode *vn);
|
virtual bool checkPrintNegation(const Varnode *vn);
|
||||||
|
void pushTypePointerRel(const PcodeOp *op);
|
||||||
public:
|
public:
|
||||||
PrintC(Architecture *g,const string &nm="c-language"); ///< Constructor
|
PrintC(Architecture *g,const string &nm="c-language"); ///< Constructor
|
||||||
void setNULLPrinting(bool val) { option_NULL = val; } ///< Toggle the printing of a 'NULL' token
|
void setNULLPrinting(bool val) { option_NULL = val; } ///< Toggle the printing of a 'NULL' token
|
||||||
|
@ -313,4 +315,16 @@ public:
|
||||||
virtual void callback(EmitXml *emit);
|
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
|
#endif
|
||||||
|
|
|
@ -5619,6 +5619,10 @@ void AddTreeState::clear(void)
|
||||||
{
|
{
|
||||||
multsum = 0;
|
multsum = 0;
|
||||||
nonmultsum = 0;
|
nonmultsum = 0;
|
||||||
|
if (pRelType != (const TypePointerRel *)0) {
|
||||||
|
nonmultsum = ((TypePointerRel *)ct)->getPointerOffset();
|
||||||
|
nonmultsum &= ptrmask;
|
||||||
|
}
|
||||||
multiple.clear();
|
multiple.clear();
|
||||||
coeff.clear();
|
coeff.clear();
|
||||||
nonmult.clear();
|
nonmult.clear();
|
||||||
|
@ -5630,6 +5634,29 @@ void AddTreeState::clear(void)
|
||||||
distributeOp = (PcodeOp *)0;
|
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)
|
AddTreeState::AddTreeState(Funcdata &d,PcodeOp *op,int4 slot)
|
||||||
: data(d)
|
: data(d)
|
||||||
{
|
{
|
||||||
|
@ -5639,12 +5666,19 @@ AddTreeState::AddTreeState(Funcdata &d,PcodeOp *op,int4 slot)
|
||||||
ptrsize = ptr->getSize();
|
ptrsize = ptr->getSize();
|
||||||
ptrmask = calc_mask(ptrsize);
|
ptrmask = calc_mask(ptrsize);
|
||||||
baseType = ct->getPtrTo();
|
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())
|
if (baseType->isVariableLength())
|
||||||
size = 0; // Open-ended size being pointed to, there will be no "multiples" component
|
size = 0; // Open-ended size being pointed to, there will be no "multiples" component
|
||||||
else
|
else
|
||||||
size = AddrSpace::byteToAddressInt(baseType->getSize(),ct->getWordSize());
|
size = AddrSpace::byteToAddressInt(baseType->getSize(),ct->getWordSize());
|
||||||
multsum = 0; // Sums start out as zero
|
|
||||||
nonmultsum = 0;
|
|
||||||
correct = 0;
|
correct = 0;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
valid = true; // Valid until proven otherwise
|
valid = true; // Valid until proven otherwise
|
||||||
|
@ -5652,6 +5686,8 @@ AddTreeState::AddTreeState(Funcdata &d,PcodeOp *op,int4 slot)
|
||||||
isDistributeUsed = false;
|
isDistributeUsed = false;
|
||||||
isSubtype = false;
|
isSubtype = false;
|
||||||
distributeOp = (PcodeOp *)0;
|
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
|
/// 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;
|
isDistributeUsed = true;
|
||||||
}
|
}
|
||||||
nonmultsum += val;
|
nonmultsum += val;
|
||||||
|
nonmultsum &= ptrmask;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (treeCoeff != 1)
|
if (treeCoeff != 1)
|
||||||
isDistributeUsed = true;
|
isDistributeUsed = true;
|
||||||
multsum += val; // Add multiples of size into multsum
|
multsum += val; // Add multiples of size into multsum
|
||||||
|
multsum &= ptrmask;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (vn->isWritten()) {
|
if (vn->isWritten()) {
|
||||||
|
@ -5861,6 +5899,12 @@ bool AddTreeState::spanAddTree(PcodeOp *op,uintb treeCoeff)
|
||||||
two_is_non = checkTerm(op->getIn(1),treeCoeff);
|
two_is_non = checkTerm(op->getIn(1),treeCoeff);
|
||||||
if (!valid) return false;
|
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&&two_is_non) return true;
|
||||||
if (one_is_non)
|
if (one_is_non)
|
||||||
nonmult.push_back(op->getIn(0));
|
nonmult.push_back(op->getIn(0));
|
||||||
|
@ -5874,8 +5918,6 @@ bool AddTreeState::spanAddTree(PcodeOp *op,uintb treeCoeff)
|
||||||
void AddTreeState::calcSubtype(void)
|
void AddTreeState::calcSubtype(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
nonmultsum &= ptrmask; // Make sure we are modulo ptr's space
|
|
||||||
multsum &= ptrmask;
|
|
||||||
if (size == 0 || nonmultsum < size)
|
if (size == 0 || nonmultsum < size)
|
||||||
offset = nonmultsum;
|
offset = nonmultsum;
|
||||||
else {
|
else {
|
||||||
|
@ -6018,10 +6060,34 @@ Varnode *AddTreeState::buildExtra(void)
|
||||||
return resNode;
|
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
|
/// \return \b true if a transform was applied
|
||||||
bool AddTreeState::apply(void)
|
bool AddTreeState::apply(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
if (isDegenerate)
|
||||||
|
return buildDegenerate();
|
||||||
spanAddTree(baseOp,1);
|
spanAddTree(baseOp,1);
|
||||||
if (!valid) return false; // Were there any show stoppers
|
if (!valid) return false; // Were there any show stoppers
|
||||||
if (distributeOp != (PcodeOp *)0 && !isDistributeUsed) {
|
if (distributeOp != (PcodeOp *)0 && !isDistributeUsed) {
|
||||||
|
@ -6060,13 +6126,18 @@ bool AddTreeState::apply(void)
|
||||||
return true;
|
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
|
/// \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
|
/// 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.
|
/// data-type offset has been calculated, and preserving and remaining terms.
|
||||||
void AddTreeState::buildTree(void)
|
void AddTreeState::buildTree(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
if (pRelType != (const TypePointerRel *)0) {
|
||||||
|
int4 ptrOff = ((TypePointerRel *)ct)->getPointerOffset();
|
||||||
|
offset -= ptrOff;
|
||||||
|
offset &= ptrmask;
|
||||||
|
}
|
||||||
Varnode *multNode = buildMultiples();
|
Varnode *multNode = buildMultiples();
|
||||||
Varnode *extraNode = buildExtra();
|
Varnode *extraNode = buildExtra();
|
||||||
PcodeOp *newop = (PcodeOp *)0;
|
PcodeOp *newop = (PcodeOp *)0;
|
||||||
|
@ -6082,6 +6153,8 @@ void AddTreeState::buildTree(void)
|
||||||
// Create PTRSUB portion of operation
|
// Create PTRSUB portion of operation
|
||||||
if (isSubtype) {
|
if (isSubtype) {
|
||||||
newop = data.newOpBefore(baseOp,CPUI_PTRSUB,multNode,data.newConstant(ptrsize,offset));
|
newop = data.newOpBefore(baseOp,CPUI_PTRSUB,multNode,data.newConstant(ptrsize,offset));
|
||||||
|
if (size != 0)
|
||||||
|
newop->setStopPropagation();
|
||||||
multNode = newop->getOut();
|
multNode = newop->getOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6216,29 +6289,12 @@ int4 RulePtrArith::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
if (evaluatePointerExpression(op, slot) != 2) return 0;
|
if (evaluatePointerExpression(op, slot) != 2) return 0;
|
||||||
if (!verifyPreferredPointer(op, slot)) 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);
|
AddTreeState state(data,op,slot);
|
||||||
if (!state.apply())
|
if (state.apply()) return 1;
|
||||||
|
if (state.initAlternateForm()) {
|
||||||
|
if (state.apply()) return 1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \class RuleStructOffset0
|
/// \class RuleStructOffset0
|
||||||
|
@ -6259,10 +6315,7 @@ void RuleStructOffset0::getOpList(vector<uint4> &oplist) const
|
||||||
int4 RuleStructOffset0::applyOp(PcodeOp *op,Funcdata &data)
|
int4 RuleStructOffset0::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
|
|
||||||
{
|
{
|
||||||
Datatype *ct,*sub_ct;
|
|
||||||
PcodeOp *newop;
|
|
||||||
int4 movesize; // Number of bytes being moved by load or store
|
int4 movesize; // Number of bytes being moved by load or store
|
||||||
uintb offset;
|
|
||||||
|
|
||||||
if (!data.isTypeRecoveryOn()) return 0;
|
if (!data.isTypeRecoveryOn()) return 0;
|
||||||
if (op->code()==CPUI_LOAD) {
|
if (op->code()==CPUI_LOAD) {
|
||||||
|
@ -6274,25 +6327,37 @@ int4 RuleStructOffset0::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ct = op->getIn(1)->getType();
|
Datatype *ct = op->getIn(1)->getType();
|
||||||
if (ct->getMetatype() != TYPE_PTR) return 0;
|
if (ct->getMetatype() != TYPE_PTR) return 0;
|
||||||
ct = ((TypePointer *)ct)->getPtrTo();
|
Datatype *baseType = ((TypePointer *)ct)->getPtrTo();
|
||||||
if (ct->getMetatype() == TYPE_STRUCT) {
|
uintb offset = 0;
|
||||||
if (ct->getSize() < movesize)
|
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
|
return 0; // Moving something bigger than entire structure
|
||||||
sub_ct = ct->getSubType(0,&offset); // Get field at offset 0
|
Datatype *subType = baseType->getSubType(offset,&offset); // Get field at pointer's offset
|
||||||
if (sub_ct==(Datatype *)0) return 0;
|
if (subType==(Datatype *)0) return 0;
|
||||||
if (sub_ct->getSize() < movesize) return 0; // Subtype is too small to handle LOAD/STORE
|
if (subType->getSize() < movesize) return 0; // Subtype is too small to handle LOAD/STORE
|
||||||
// if (ct->getSize() == movesize) {
|
// if (baseType->getSize() == movesize) {
|
||||||
// If we reach here, move is same size as the structure, which is the same size as
|
// If we reach here, move is same size as the structure, which is the same size as
|
||||||
// the first element.
|
// the first element.
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
else if (ct->getMetatype() == TYPE_ARRAY) {
|
else if (baseType->getMetatype() == TYPE_ARRAY) {
|
||||||
if (ct->getSize() < movesize)
|
if (baseType->getSize() < movesize)
|
||||||
return 0; // Moving something bigger than entire array
|
return 0; // Moving something bigger than entire array
|
||||||
if (ct->getSize() == movesize) { // Moving something the size of entire array
|
if (baseType->getSize() == movesize) { // Moving something the size of entire array
|
||||||
if (((TypeArray *)ct)->numElements() != 1)
|
if (((TypeArray *)baseType)->numElements() != 1)
|
||||||
return 0;
|
return 0;
|
||||||
// If we reach here, moving something size of single element. Assume this is normal access.
|
// 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
|
else
|
||||||
return 0;
|
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);
|
data.opSetInput(op,newop->getOut(),1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -6499,6 +6565,7 @@ int4 RulePtrsubUndo::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
data.opSetOpcode(op,CPUI_INT_ADD);
|
data.opSetOpcode(op,CPUI_INT_ADD);
|
||||||
|
op->clearStopPropagation();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ class AddTreeState {
|
||||||
Varnode *ptr; ///< The pointer varnode
|
Varnode *ptr; ///< The pointer varnode
|
||||||
const TypePointer *ct; ///< The pointer data-type
|
const TypePointer *ct; ///< The pointer data-type
|
||||||
const Datatype *baseType; ///< The base data-type being pointed at
|
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 ptrsize; ///< Size of the pointer
|
||||||
int4 size; ///< Size of data-type being pointed to (in address units) or 0 for open ended 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
|
uintb ptrmask; ///< Mask for modulo calculations in ptr space
|
||||||
|
@ -60,6 +61,7 @@ class AddTreeState {
|
||||||
bool isDistributeUsed; ///< Are terms produced by distributing used
|
bool isDistributeUsed; ///< Are terms produced by distributing used
|
||||||
bool isSubtype; ///< Is there a sub-type (using CPUI_PTRSUB)
|
bool isSubtype; ///< Is there a sub-type (using CPUI_PTRSUB)
|
||||||
bool valid; ///< Set to \b true if the whole expression can be transformed
|
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
|
uint4 findArrayHint(void) const; ///< Look for evidence of an array in a sub-component
|
||||||
bool hasMatchingSubType(uintb off,uint4 arrayHint,uintb *newoff) const;
|
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
|
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
|
void calcSubtype(void); ///< Calculate final sub-type offset
|
||||||
Varnode *buildMultiples(void); ///< Build part of tree that is multiple of base size
|
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
|
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 buildTree(void); ///< Build the transformed ADD tree
|
||||||
void clear(void); ///< Reset for a new ADD tree traversal
|
void clear(void); ///< Reset for a new ADD tree traversal
|
||||||
public:
|
public:
|
||||||
AddTreeState(Funcdata &d,PcodeOp *op,int4 slot); ///< Construct given root of ADD tree and pointer
|
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 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 {
|
class RuleEarlyRemoval : public Rule {
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
#include "type.hh"
|
#include "type.hh"
|
||||||
#include "funcdata.hh"
|
#include "funcdata.hh"
|
||||||
|
|
||||||
sub_metatype Datatype::base2sub[11] = {
|
sub_metatype Datatype::base2sub[13] = {
|
||||||
SUB_STRUCT, SUB_ARRAY, SUB_PTR, SUB_FLOAT, SUB_CODE, SUB_BOOL,
|
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
|
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:
|
case TYPE_PTR:
|
||||||
res = "ptr";
|
res = "ptr";
|
||||||
break;
|
break;
|
||||||
|
case TYPE_PTRSTRUCT:
|
||||||
|
res = "ptrstruct";
|
||||||
|
break;
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
res = "array";
|
res = "array";
|
||||||
break;
|
break;
|
||||||
|
case TYPE_PARTIALSTRUCT:
|
||||||
|
res = "part";
|
||||||
|
break;
|
||||||
case TYPE_STRUCT:
|
case TYPE_STRUCT:
|
||||||
res = "struct";
|
res = "struct";
|
||||||
break;
|
break;
|
||||||
|
@ -218,6 +224,10 @@ type_metatype string2metatype(const string &metastring)
|
||||||
case 'p':
|
case 'p':
|
||||||
if (metastring=="ptr")
|
if (metastring=="ptr")
|
||||||
return TYPE_PTR;
|
return TYPE_PTR;
|
||||||
|
else if (metastring=="part")
|
||||||
|
return TYPE_PARTIALSTRUCT;
|
||||||
|
else if (metastring=="ptrstruct")
|
||||||
|
return TYPE_PTRSTRUCT;
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
if (metastring=="array")
|
if (metastring=="array")
|
||||||
|
@ -269,14 +279,15 @@ void Datatype::saveXml(ostream &s) const
|
||||||
|
|
||||||
{
|
{
|
||||||
s << "<type";
|
s << "<type";
|
||||||
saveXmlBasic(s);
|
saveXmlBasic(metatype,s);
|
||||||
s << "/>";
|
s << "/>";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write out basic data-type properties (name,size,id) as XML attributes.
|
/// Write out basic data-type properties (name,size,id) as XML attributes.
|
||||||
/// This routine presumes the initial tag is already written to the stream.
|
/// 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
|
/// \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);
|
a_v(s,"name",name);
|
||||||
|
@ -290,7 +301,7 @@ void Datatype::saveXmlBasic(ostream &s) const
|
||||||
}
|
}
|
||||||
a_v_i(s,"size",size);
|
a_v_i(s,"size",size);
|
||||||
string metastring;
|
string metastring;
|
||||||
metatype2string(metatype,metastring);
|
metatype2string(meta,metastring);
|
||||||
a_v(s,"metatype",metastring);
|
a_v(s,"metatype",metastring);
|
||||||
if ((flags & coretype)!=0)
|
if ((flags & coretype)!=0)
|
||||||
a_v_b(s,"core",true);
|
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.
|
/// A CPUI_PTRSUB must act on a pointer data-type where the given offset addresses a component.
|
||||||
/// Perform this check.
|
/// 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
|
/// \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();
|
/// Some data-types are ephemeral, and, in the final decompiler output, get replaced with a formal version
|
||||||
uint4 wordsize = ((TypePointer *)this)->getWordSize();
|
/// that is a stripped down version of the original. This method returns this stripped down version, if it
|
||||||
if (basetype->metatype==TYPE_SPACEBASE) {
|
/// exists, or null otherwise. A non-null return should correspond with hasStripped returning \b true.
|
||||||
uintb newoff = AddrSpace::addressToByte(offset,wordsize);
|
/// \return the stripped version or null
|
||||||
basetype->getSubType(newoff,&newoff);
|
Datatype *Datatype::getStripped(void) const
|
||||||
if (newoff != 0)
|
|
||||||
return false;
|
{
|
||||||
}
|
return (Datatype *)0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Restore the basic properties (name,size,id) of a data-type from an XML element
|
/// Restore the basic properties (name,size,id) of a data-type from an XML element
|
||||||
|
@ -469,7 +471,7 @@ void TypeChar::saveXml(ostream &s) const
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s << "<type";
|
s << "<type";
|
||||||
saveXmlBasic(s);
|
saveXmlBasic(metatype,s);
|
||||||
a_v_b(s,"char",true);
|
a_v_b(s,"char",true);
|
||||||
s << "/>";
|
s << "/>";
|
||||||
}
|
}
|
||||||
|
@ -511,7 +513,7 @@ void TypeUnicode::saveXml(ostream &s) const
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s << "<type";
|
s << "<type";
|
||||||
saveXmlBasic(s);
|
saveXmlBasic(metatype,s);
|
||||||
a_v_b(s,"utf",true);
|
a_v_b(s,"utf",true);
|
||||||
s << "/>";
|
s << "/>";
|
||||||
}
|
}
|
||||||
|
@ -569,7 +571,7 @@ void TypePointer::saveXml(ostream &s) const
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s << "<type";
|
s << "<type";
|
||||||
saveXmlBasic(s);
|
saveXmlBasic(metatype,s);
|
||||||
if (wordsize != 1)
|
if (wordsize != 1)
|
||||||
a_v_i(s,"wordsize",wordsize);
|
a_v_i(s,"wordsize",wordsize);
|
||||||
s << '>';
|
s << '>';
|
||||||
|
@ -588,21 +590,37 @@ void TypePointer::restoreXml(const Element *el,TypeFactory &typegrp)
|
||||||
s >> wordsize;
|
s >> wordsize;
|
||||||
}
|
}
|
||||||
ptrto = typegrp.restoreXmlType( *el->getChildren().begin() );
|
ptrto = typegrp.restoreXmlType( *el->getChildren().begin() );
|
||||||
|
calcSubmeta();
|
||||||
if (name.size() == 0) // Inherit only coretype only if no name
|
if (name.size() == 0) // Inherit only coretype only if no name
|
||||||
flags = ptrto->getInheritable();
|
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
|
/// \brief Find a sub-type pointer given an offset into \b this
|
||||||
///
|
///
|
||||||
/// Add a constant offset to \b this pointer.
|
/// Add a constant offset to \b this pointer.
|
||||||
/// If there is a valid component at that offset, return a pointer
|
/// If there is a valid component at that offset, return a pointer
|
||||||
/// to the data-type of the component or NULL otherwise.
|
/// to the data-type of the component or NULL otherwise.
|
||||||
/// This routine only goes down one level at most. Pass back the
|
/// 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 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 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
|
/// \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();
|
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
|
type_metatype meta = ptrto->getMetatype();
|
||||||
bool doStrip = (ptrto->getMetatype() != TYPE_ARRAY);
|
bool isArray = (meta == TYPE_ARRAY);
|
||||||
|
if (isArray || meta == TYPE_STRUCT) {
|
||||||
|
par = this;
|
||||||
|
parOff = off;
|
||||||
|
}
|
||||||
|
|
||||||
Datatype *pt = ptrto->getSubType(off,&off);
|
Datatype *pt = ptrto->getSubType(off,&off);
|
||||||
if (pt == (Datatype *)0)
|
if (pt == (Datatype *)0)
|
||||||
return (TypePointer *)0;
|
return (TypePointer *)0;
|
||||||
if (doStrip)
|
if (!isArray)
|
||||||
return typegrp.getTypePointerStripArray(size, pt, wordsize);
|
return typegrp.getTypePointerStripArray(size, pt, wordsize);
|
||||||
return typegrp.getTypePointer(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
|
void TypeArray::printRaw(ostream &s) const
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -696,7 +739,7 @@ void TypeArray::saveXml(ostream &s) const
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s << "<type";
|
s << "<type";
|
||||||
saveXmlBasic(s);
|
saveXmlBasic(metatype,s);
|
||||||
a_v_i(s,"arraysize",arraysize);
|
a_v_i(s,"arraysize",arraysize);
|
||||||
s << '>';
|
s << '>';
|
||||||
arrayof->saveXmlRef(s);
|
arrayof->saveXmlRef(s);
|
||||||
|
@ -870,7 +913,7 @@ void TypeEnum::saveXml(ostream &s) const
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s << "<type";
|
s << "<type";
|
||||||
saveXmlBasic(s);
|
saveXmlBasic(metatype,s);
|
||||||
a_v(s,"enum","true");
|
a_v(s,"enum","true");
|
||||||
s << ">\n";
|
s << ">\n";
|
||||||
map<uintb,string>::const_iterator iter;
|
map<uintb,string>::const_iterator iter;
|
||||||
|
@ -1142,7 +1185,7 @@ void TypeStruct::saveXml(ostream &s) const
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s << "<type";
|
s << "<type";
|
||||||
saveXmlBasic(s);
|
saveXmlBasic(metatype,s);
|
||||||
s << ">\n";
|
s << ">\n";
|
||||||
vector<TypeField>::const_iterator iter;
|
vector<TypeField>::const_iterator iter;
|
||||||
for(iter=field.begin();iter!=field.end();++iter) {
|
for(iter=field.begin();iter!=field.end();++iter) {
|
||||||
|
@ -1181,6 +1224,125 @@ void TypeStruct::restoreXml(const Element *el,TypeFactory &typegrp)
|
||||||
}
|
}
|
||||||
if (maxoffset > size)
|
if (maxoffset > size)
|
||||||
throw LowlevelError("Size too small for fields of structure "+name);
|
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
|
/// Turn on the data-type's function prototype
|
||||||
|
@ -1374,7 +1536,7 @@ void TypeCode::saveXml(ostream &s) const
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s << "<type";
|
s << "<type";
|
||||||
saveXmlBasic(s);
|
saveXmlBasic(metatype,s);
|
||||||
s << ">\n";
|
s << ">\n";
|
||||||
if (proto != (FuncProto *)0)
|
if (proto != (FuncProto *)0)
|
||||||
proto->saveXml(s);
|
proto->saveXml(s);
|
||||||
|
@ -1552,7 +1714,7 @@ void TypeSpacebase::saveXml(ostream &s) const
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s << "<type";
|
s << "<type";
|
||||||
saveXmlBasic(s);
|
saveXmlBasic(metatype,s);
|
||||||
a_v(s,"space",spaceid->getName());
|
a_v(s,"space",spaceid->getName());
|
||||||
s << '>';
|
s << '>';
|
||||||
localframe.saveXml(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
|
/// 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 fd is the list of fields to set
|
||||||
/// \param ot is the TypeStruct object to modify
|
/// \param ot is the TypeStruct object to modify
|
||||||
/// \param fixedsize is 0 or the forced size of the structure
|
/// \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;
|
int4 offset,cursize,curalign;
|
||||||
|
|
||||||
|
if (!ot->isIncompleteStruct())
|
||||||
|
throw LowlevelError("Can only set fields on an incomplete structure");
|
||||||
offset = 0;
|
offset = 0;
|
||||||
vector<TypeField>::iterator iter;
|
vector<TypeField>::iterator iter;
|
||||||
|
|
||||||
|
@ -1916,7 +2081,8 @@ bool TypeFactory::setFields(vector<TypeField> &fd,TypeStruct *ot,int4 fixedsize,
|
||||||
|
|
||||||
tree.erase(ot);
|
tree.erase(ot);
|
||||||
ot->setFields(fd);
|
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 > 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
|
if (fixedsize > ot->size) // If the forced size is bigger than the size required for fields
|
||||||
ot->size = fixedsize; // Force the bigger size
|
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)
|
TypePointer *TypeFactory::getTypePointerStripArray(int4 s,Datatype *pt,uint4 ws)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
if (pt->hasStripped())
|
||||||
|
pt = pt->getStripped();
|
||||||
if (pt->getMetatype() == TYPE_ARRAY)
|
if (pt->getMetatype() == TYPE_ARRAY)
|
||||||
pt = ((TypeArray *)pt)->getBase(); // Strip the first ARRAY type
|
pt = ((TypeArray *)pt)->getBase(); // Strip the first ARRAY type
|
||||||
TypePointer tmp(s,pt,ws);
|
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)
|
TypePointer *TypeFactory::getTypePointer(int4 s,Datatype *pt,uint4 ws)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
if (pt->hasStripped())
|
||||||
|
pt = pt->getStripped();
|
||||||
TypePointer tmp(s,pt,ws);
|
TypePointer tmp(s,pt,ws);
|
||||||
return (TypePointer *) findAdd(tmp);
|
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)
|
TypePointer *TypeFactory::getTypePointer(int4 s,Datatype *pt,uint4 ws,const string &n)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
if (pt->hasStripped())
|
||||||
|
pt = pt->getStripped();
|
||||||
TypePointer tmp(s,pt,ws);
|
TypePointer tmp(s,pt,ws);
|
||||||
tmp.name = n;
|
tmp.name = n;
|
||||||
tmp.id = Datatype::hashName(n);
|
tmp.id = Datatype::hashName(n);
|
||||||
|
@ -2219,7 +2391,7 @@ TypePointer *TypeFactory::getTypePointerNoDepth(int4 s,Datatype *pt,uint4 ws)
|
||||||
type_metatype meta = basetype->getMetatype();
|
type_metatype meta = basetype->getMetatype();
|
||||||
// Make sure that at least we return a pointer to something the size of -pt-
|
// Make sure that at least we return a pointer to something the size of -pt-
|
||||||
if (meta == TYPE_PTR)
|
if (meta == TYPE_PTR)
|
||||||
return (TypePointer *)pt;
|
pt = getBase(pt->getSize(),TYPE_UNKNOWN); // Pass back unknown *
|
||||||
else if (meta == TYPE_UNKNOWN) {
|
else if (meta == TYPE_UNKNOWN) {
|
||||||
if (basetype->getSize() == pt->getSize()) // If -pt- is pointer to UNKNOWN of the size of a pointer
|
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
|
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);
|
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
|
/// \param n is the name of the structure
|
||||||
/// \return the TypeStruct object
|
/// \return the TypeStruct object
|
||||||
TypeStruct *TypeFactory::getTypeStruct(const string &n)
|
TypeStruct *TypeFactory::getTypeStruct(const string &n)
|
||||||
|
@ -2290,6 +2462,35 @@ TypeCode *TypeFactory::getTypeCode(ProtoModel *model,Datatype *outtype,
|
||||||
return (TypeCode *) findAdd(tc);
|
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.
|
/// The indicated Datatype object is removed from this container.
|
||||||
/// Indirect references (via TypeArray TypeStruct etc.) are not affected
|
/// Indirect references (via TypeArray TypeStruct etc.) are not affected
|
||||||
/// \param ct is the data-type to destroy
|
/// \param ct is the data-type to destroy
|
||||||
|
@ -2542,19 +2743,17 @@ Datatype *TypeFactory::restoreXmlTypeNoRef(const Element *el,bool forcecore)
|
||||||
if (isVarLength)
|
if (isVarLength)
|
||||||
newid = Datatype::hashSize(newid, structsize);
|
newid = Datatype::hashSize(newid, structsize);
|
||||||
ct = findByIdLocal(structname,newid);
|
ct = findByIdLocal(structname,newid);
|
||||||
bool stubfirst = false;
|
|
||||||
if (ct == (Datatype *)0) {
|
if (ct == (Datatype *)0) {
|
||||||
ts.id = newid;
|
ts.id = newid;
|
||||||
ts.size = structsize; // Include size if we have it, so arrays can be defined without knowing struct fields
|
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
|
ct = findAdd(ts); // Create stub to allow recursive definitions
|
||||||
stubfirst = true;
|
|
||||||
}
|
}
|
||||||
else if (ct->getMetatype() != TYPE_STRUCT)
|
else if (ct->getMetatype() != TYPE_STRUCT)
|
||||||
throw LowlevelError("Trying to redefine type: "+structname);
|
throw LowlevelError("Trying to redefine type: "+structname);
|
||||||
ts.restoreXml(el,*this);
|
ts.restoreXml(el,*this);
|
||||||
if (forcecore)
|
if (forcecore)
|
||||||
ts.flags |= Datatype::coretype;
|
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))
|
if (0!=ct->compareDependency(ts))
|
||||||
throw LowlevelError("Redefinition of structure: "+structname);
|
throw LowlevelError("Redefinition of structure: "+structname);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
/// the number, the more \b specific the type, in calculations involving the generality
|
||||||
/// of a type.
|
/// of a type.
|
||||||
enum type_metatype {
|
enum type_metatype {
|
||||||
TYPE_VOID = 10, ///< Standard "void" type, absence of type
|
TYPE_VOID = 12, ///< Standard "void" type, absence of type
|
||||||
TYPE_SPACEBASE = 9, ///< Placeholder for symbol/type look-up calculations
|
TYPE_SPACEBASE = 11, ///< Placeholder for symbol/type look-up calculations
|
||||||
TYPE_UNKNOWN = 8, ///< An unknown low-level type. Treated as an unsigned integer.
|
TYPE_UNKNOWN = 10, ///< 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_INT = 9, ///< Signed integer. Signed is considered less specific than unsigned in C
|
||||||
TYPE_UINT = 6, ///< Unsigned integer
|
TYPE_UINT = 8, ///< Unsigned integer
|
||||||
TYPE_BOOL = 5, ///< Boolean
|
TYPE_BOOL = 7, ///< Boolean
|
||||||
TYPE_CODE = 4, ///< Data is actual executable code
|
TYPE_CODE = 6, ///< Data is actual executable code
|
||||||
TYPE_FLOAT = 3, ///< Floating-point
|
TYPE_FLOAT = 5, ///< Floating-point
|
||||||
|
|
||||||
TYPE_PTR = 2, ///< Pointer data-type
|
TYPE_PTR = 4, ///< Pointer data-type
|
||||||
TYPE_ARRAY = 1, ///< Array data-type, made up of a sequence of "element" datatype
|
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
|
TYPE_STRUCT = 0 ///< Structure data-type, made up of component datatypes
|
||||||
};
|
};
|
||||||
|
|
||||||
enum sub_metatype {
|
enum sub_metatype {
|
||||||
SUB_VOID = 16, ///< Compare as a TYPE_VOID
|
SUB_VOID = 20, ///< Compare as a TYPE_VOID
|
||||||
SUB_SPACEBASE = 15, ///< Compare as a TYPE_SPACEBASE
|
SUB_SPACEBASE = 19, ///< Compare as a TYPE_SPACEBASE
|
||||||
SUB_UNKNOWN = 14, ///< Compare as a TYPE_UNKNOWN
|
SUB_UNKNOWN = 18, ///< Compare as a TYPE_UNKNOWN
|
||||||
SUB_INT_CHAR = 13, ///< Signed 1-byte character, sub-type of TYPE_INT
|
SUB_INT_CHAR = 17, ///< Signed 1-byte character, sub-type of TYPE_INT
|
||||||
SUB_UINT_CHAR = 12, ///< Unsigned 1-byte character, sub-type of TYPE_UINT
|
SUB_UINT_CHAR = 16, ///< Unsigned 1-byte character, sub-type of TYPE_UINT
|
||||||
SUB_INT_PLAIN = 11, ///< Compare as a plain TYPE_INT
|
SUB_INT_PLAIN = 15, ///< Compare as a plain TYPE_INT
|
||||||
SUB_UINT_PLAIN = 10, ///< Compare as a plain TYPE_UINT
|
SUB_UINT_PLAIN = 14, ///< Compare as a plain TYPE_UINT
|
||||||
SUB_INT_ENUM = 9, ///< Signed enum, sub-type of TYPE_INT
|
SUB_INT_ENUM = 13, ///< Signed enum, sub-type of TYPE_INT
|
||||||
SUB_UINT_ENUM = 8, ///< Unsigned enum, sub-type of TYPE_UINT
|
SUB_UINT_ENUM = 12, ///< Unsigned enum, sub-type of TYPE_UINT
|
||||||
SUB_INT_UNICODE = 7, ///< Signed wide character, sub-type of TYPE_INT
|
SUB_INT_UNICODE = 11, ///< Signed wide character, sub-type of TYPE_INT
|
||||||
SUB_UINT_UNICODE = 6, ///< Unsigned wide character, sub-type of TYPE_UINT
|
SUB_UINT_UNICODE = 10, ///< Unsigned wide character, sub-type of TYPE_UINT
|
||||||
SUB_BOOL = 5, ///< Compare as TYPE_BOOL
|
SUB_BOOL = 9, ///< Compare as TYPE_BOOL
|
||||||
SUB_CODE = 4, ///< Compare as TYPE_CODE
|
SUB_CODE = 8, ///< Compare as TYPE_CODE
|
||||||
SUB_FLOAT = 3, ///< Compare as TYPE_FLOAT
|
SUB_FLOAT = 7, ///< Compare as TYPE_FLOAT
|
||||||
|
SUB_PTRREL_UNK = 6, ///< Pointer to unknown field of struct, sub-type of TYPE_PTR
|
||||||
SUB_PTR = 2, ///< Compare as TYPE_PTR
|
SUB_PTR = 5, ///< Compare as TYPE_PTR
|
||||||
SUB_ARRAY = 1, ///< Compare as TYPE_ARRAY
|
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
|
SUB_STRUCT = 0 ///< Compare as TYPE_STRUCT
|
||||||
};
|
};
|
||||||
/// Convert type \b meta-type to name
|
/// Convert type \b meta-type to name
|
||||||
|
@ -81,7 +86,7 @@ struct DatatypeCompare;
|
||||||
/// Used for symbols, function prototypes, type propagation etc.
|
/// Used for symbols, function prototypes, type propagation etc.
|
||||||
class Datatype {
|
class Datatype {
|
||||||
protected:
|
protected:
|
||||||
static sub_metatype base2sub[11];
|
static sub_metatype base2sub[13];
|
||||||
/// Boolean properties of datatypes
|
/// Boolean properties of datatypes
|
||||||
enum {
|
enum {
|
||||||
coretype = 1, ///< This is a basic type which will never be redefined
|
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
|
utf16 = 16, ///< 16-bit wide chars in unicode UTF16
|
||||||
utf32 = 32, ///< 32-bit wide chars in unicode UTF32
|
utf32 = 32, ///< 32-bit wide chars in unicode UTF32
|
||||||
opaque_string = 64, ///< Structure that should be treated as a string
|
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 class TypeFactory;
|
||||||
friend struct DatatypeCompare;
|
friend struct DatatypeCompare;
|
||||||
|
@ -108,7 +116,7 @@ protected:
|
||||||
uint8 id; ///< A unique id for the type (or 0 if an id is not assigned)
|
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
|
Datatype *typedefImm; ///< The immediate data-type being typedefed by \e this
|
||||||
void restoreXmlBasic(const Element *el); ///< Recover basic data-type properties
|
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
|
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 void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore data-type from XML
|
||||||
virtual Datatype *clone(void) const=0; ///< Clone the data-type
|
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 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 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 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
|
uint4 getInheritable(void) const { return (flags & coretype); } ///< Get properties pointers inherit
|
||||||
type_metatype getMetatype(void) const { return metatype; } ///< Get the type \b meta-type
|
type_metatype getMetatype(void) const { return metatype; } ///< Get the type \b meta-type
|
||||||
uint8 getId(void) const { return id; } ///< Get the type id
|
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 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 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 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 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
|
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
|
void saveXmlRef(ostream &s) const; ///< Write an XML reference of \b this to stream
|
||||||
bool isPtrsubMatching(uintb offset) const; ///< Is this data-type suitable as input to a CPUI_PTRSUB op
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Specifies subfields of a structure or what a pointer points to
|
/// \brief Specifies subfields of a structure or what a pointer points to
|
||||||
|
@ -258,13 +271,15 @@ protected:
|
||||||
Datatype *ptrto; ///< Type being pointed to
|
Datatype *ptrto; ///< Type being pointed to
|
||||||
uint4 wordsize; ///< What size unit does the pointer address
|
uint4 wordsize; ///< What size unit does the pointer address
|
||||||
virtual void restoreXml(const Element *el,TypeFactory &typegrp);
|
virtual void restoreXml(const Element *el,TypeFactory &typegrp);
|
||||||
|
void calcSubmeta(void); ///< Calculate specific submeta for \b this pointer
|
||||||
/// Internal constructor for use with restoreXml
|
/// Internal constructor for use with restoreXml
|
||||||
TypePointer(void) : Datatype(0,TYPE_PTR) { ptrto = (Datatype *)0; wordsize=1; }
|
TypePointer(void) : Datatype(0,TYPE_PTR) { ptrto = (Datatype *)0; wordsize=1; }
|
||||||
public:
|
public:
|
||||||
/// Construct from another TypePointer
|
/// Construct from another TypePointer
|
||||||
TypePointer(const TypePointer &op) : Datatype(op) { ptrto = op.ptrto; wordsize=op.wordsize; }
|
TypePointer(const TypePointer &op) : Datatype(op) { ptrto = op.ptrto; wordsize=op.wordsize; }
|
||||||
/// Construct from a size, pointed-to type, and 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
|
Datatype *getPtrTo(void) const { return ptrto; } ///< Get the pointed-to Datatype
|
||||||
uint4 getWordSize(void) const { return wordsize; } ///< Get the wordsize of the pointer
|
uint4 getWordSize(void) const { return wordsize; } ///< Get the wordsize of the pointer
|
||||||
virtual void printRaw(ostream &s) const;
|
virtual void printRaw(ostream &s) const;
|
||||||
|
@ -275,7 +290,8 @@ public:
|
||||||
virtual int4 compareDependency(const Datatype &op) const; // For tree structure
|
virtual int4 compareDependency(const Datatype &op) const; // For tree structure
|
||||||
virtual Datatype *clone(void) const { return new TypePointer(*this); }
|
virtual Datatype *clone(void) const { return new TypePointer(*this); }
|
||||||
virtual void saveXml(ostream &s) const;
|
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
|
/// \brief Datatype object representing an array of elements
|
||||||
|
@ -347,7 +363,7 @@ protected:
|
||||||
virtual void restoreXml(const Element *el,TypeFactory &typegrp);
|
virtual void restoreXml(const Element *el,TypeFactory &typegrp);
|
||||||
public:
|
public:
|
||||||
TypeStruct(const TypeStruct &op); ///< Construct from another TypeStruct
|
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 beginField(void) const { return field.begin(); } ///< Beginning of fields
|
||||||
vector<TypeField>::const_iterator endField(void) const { return field.end(); } ///< End 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
|
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;
|
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 FuncProto; // Forward declaration
|
||||||
class ProtoModel;
|
class ProtoModel;
|
||||||
|
|
||||||
|
@ -484,6 +539,8 @@ public:
|
||||||
const vector<Datatype *> &intypes,
|
const vector<Datatype *> &intypes,
|
||||||
bool dotdotdot); ///< Create a "function" datatype
|
bool dotdotdot); ///< Create a "function" datatype
|
||||||
Datatype *getTypedef(Datatype *ct,const string &name,uint8 id); ///< Create a new \e typedef data-type
|
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
|
void destroyType(Datatype *ct); ///< Remove a data-type from \b this
|
||||||
Datatype *concretize(Datatype *ct); ///< Convert given data-type to concrete form
|
Datatype *concretize(Datatype *ct); ///< Convert given data-type to concrete form
|
||||||
void dependentOrder(vector<Datatype *> &deporder) const; ///< Place all data-types in dependency order
|
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);
|
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
|
#endif
|
||||||
|
|
|
@ -1572,7 +1572,7 @@ Datatype *TypeOpPiece::getOutputToken(const PcodeOp *op,CastStrategy *castStrate
|
||||||
|
|
||||||
{
|
{
|
||||||
const Varnode *vn = op->getOut();
|
const Varnode *vn = op->getOut();
|
||||||
Datatype *dt = vn->getType();
|
Datatype *dt = vn->getHigh()->getType();
|
||||||
type_metatype meta = dt->getMetatype();
|
type_metatype meta = dt->getMetatype();
|
||||||
if ((meta == TYPE_INT)||(meta == TYPE_UINT)) // PIECE casts to uint or int, based on output
|
if ((meta == TYPE_INT)||(meta == TYPE_UINT)) // PIECE casts to uint or int, based on output
|
||||||
return dt;
|
return dt;
|
||||||
|
@ -1599,7 +1599,7 @@ Datatype *TypeOpSubpiece::getOutputToken(const PcodeOp *op,CastStrategy *castStr
|
||||||
|
|
||||||
{
|
{
|
||||||
const Varnode *vn = op->getOut();
|
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)
|
if (dt->getMetatype() != TYPE_UNKNOWN)
|
||||||
return dt;
|
return dt;
|
||||||
return tlst->getBase(vn->getSize(),TYPE_INT); // If output is unknown, treat as cast to int
|
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();
|
TypePointer *ptype = (TypePointer *)op->getIn(0)->getHigh()->getType();
|
||||||
if (ptype->getMetatype() == TYPE_PTR) {
|
if (ptype->getMetatype() == TYPE_PTR) {
|
||||||
uintb offset = AddrSpace::addressToByte(op->getIn(1)->getOffset(),ptype->getWordSize());
|
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))
|
if ((offset==0)&&(rettype != (Datatype *)0))
|
||||||
return rettype;
|
return rettype;
|
||||||
rettype = tlst->getBase(1, TYPE_UNKNOWN);
|
rettype = tlst->getBase(1, TYPE_UNKNOWN);
|
||||||
|
|
|
@ -153,6 +153,9 @@ void HighVariable::updateType(void) const
|
||||||
vn = getTypeRepresentative();
|
vn = getTypeRepresentative();
|
||||||
|
|
||||||
type = vn->getType();
|
type = vn->getType();
|
||||||
|
if (type->hasStripped())
|
||||||
|
type = type->getStripped();
|
||||||
|
|
||||||
// Update lock flags
|
// Update lock flags
|
||||||
flags &= ~Varnode::typelock;
|
flags &= ~Varnode::typelock;
|
||||||
if (vn->isTypeLock())
|
if (vn->isTypeLock())
|
||||||
|
|
|
@ -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.
|
/// 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.
|
/// Throw an exception if no Datatype can be found at all.
|
||||||
/// \return the determined Datatype
|
/// \return the determined Datatype
|
||||||
Datatype *Varnode::getLocalType(void) const
|
Datatype *Varnode::getLocalType(bool &blockup) const
|
||||||
|
|
||||||
{
|
{
|
||||||
Datatype *ct;
|
Datatype *ct;
|
||||||
|
@ -733,8 +733,13 @@ Datatype *Varnode::getLocalType(void) const
|
||||||
return type; // Not a partial lock, return the locked type
|
return type; // Not a partial lock, return the locked type
|
||||||
|
|
||||||
ct = (Datatype *)0;
|
ct = (Datatype *)0;
|
||||||
if (def != (PcodeOp *)0)
|
if (def != (PcodeOp *)0) {
|
||||||
ct = def->outputTypeLocal();
|
ct = def->outputTypeLocal();
|
||||||
|
if (def->stopsPropagation()) {
|
||||||
|
blockup = true;
|
||||||
|
return ct;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
list<PcodeOp *>::const_iterator iter;
|
list<PcodeOp *>::const_iterator iter;
|
||||||
PcodeOp *op;
|
PcodeOp *op;
|
||||||
|
|
|
@ -116,8 +116,9 @@ public:
|
||||||
unsignedprint = 0x40, ///< Constant that must be explicitly printed as unsigned
|
unsignedprint = 0x40, ///< Constant that must be explicitly printed as unsigned
|
||||||
stack_store = 0x80, ///< Created by an explicit STORE
|
stack_store = 0x80, ///< Created by an explicit STORE
|
||||||
locked_input = 0x100, ///< Input that exists even if its unused
|
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
|
///< value at a specific point in the code
|
||||||
|
stop_uppropagation = 0x400 ///< Data-types do not propagate from an output into \b this
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
mutable uint4 flags; ///< The collection of boolean attributes for this Varnode
|
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 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 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 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?
|
/// 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)); }
|
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 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 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 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
|
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 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 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 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
|
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?
|
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
|
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
|
static bool comparePointers(const Varnode *a,const Varnode *b) { return (*a < *b); } ///< Compare Varnodes as pointers
|
||||||
|
|
|
@ -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->arr; pchar < \&ptr->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>
|
|
@ -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\)->c \+ ADJ\(ptrrel\)->d;</stringmatch>
|
||||||
|
<stringmatch name="Relative pointers #3" min="1" max="1">fSum = ADJ\(ptrrel\)->b \+ fSum;</stringmatch>
|
||||||
|
<stringmatch name="Relative pointers #4" min="1" max="1">ptrrel = &ptr->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 < fSum\)</stringmatch>
|
||||||
|
<stringmatch name="Relative pointers #8" min="1" max="1">for \(i = 0; i < count; i = i \+ 1\)</stringmatch>
|
||||||
|
</decompilertest>
|
Loading…
Add table
Add a link
Reference in a new issue