mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
GP-2291 Support for unions through partial containers
This commit is contained in:
parent
d3efd60d54
commit
cb9c12894e
21 changed files with 678 additions and 182 deletions
|
@ -35,6 +35,7 @@ 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/packstructaccess.xml||GHIDRA||||END|
|
src/decompile/datatests/packstructaccess.xml||GHIDRA||||END|
|
||||||
|
src/decompile/datatests/partialunion.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/pointercmp.xml||GHIDRA||||END|
|
src/decompile/datatests/pointercmp.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/pointerrel.xml||GHIDRA||||END|
|
src/decompile/datatests/pointerrel.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/pointersub.xml||GHIDRA||||END|
|
src/decompile/datatests/pointersub.xml||GHIDRA||||END|
|
||||||
|
|
|
@ -2334,6 +2334,8 @@ int4 ActionSetCasts::resolveUnion(PcodeOp *op,int4 slot,Funcdata &data)
|
||||||
Datatype *dt = vn->getHigh()->getType();
|
Datatype *dt = vn->getHigh()->getType();
|
||||||
if (!dt->needsResolution())
|
if (!dt->needsResolution())
|
||||||
return 0;
|
return 0;
|
||||||
|
if (dt != vn->getType())
|
||||||
|
dt->resolveInFlow(op, slot); // Last chance to resolve data-type based on flow
|
||||||
const ResolvedUnion *resUnion = data.getUnionField(dt, op,slot);
|
const ResolvedUnion *resUnion = data.getUnionField(dt, op,slot);
|
||||||
if (resUnion != (ResolvedUnion*)0 && resUnion->getFieldNum() >= 0) {
|
if (resUnion != (ResolvedUnion*)0 && resUnion->getFieldNum() >= 0) {
|
||||||
// Insert specific placeholder indicating which field is accessed
|
// Insert specific placeholder indicating which field is accessed
|
||||||
|
@ -2383,8 +2385,12 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
|
||||||
// Short circuit more sophisticated casting tests. If they are the same type, there is no cast
|
// Short circuit more sophisticated casting tests. If they are the same type, there is no cast
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (outHighType->needsResolution())
|
Datatype *outHighResolve = outHighType;
|
||||||
outHighType = outHighType->findResolve(op, -1); // Finish fetching DefFacing data-type
|
if (outHighType->needsResolution()) {
|
||||||
|
if (outHighType != outvn->getType())
|
||||||
|
outHighType->resolveInFlow(op, -1); // Last chance to resolve data-type based on flow
|
||||||
|
outHighResolve = outHighType->findResolve(op, -1); // Finish fetching DefFacing data-type
|
||||||
|
}
|
||||||
if (outvn->isImplied()) {
|
if (outvn->isImplied()) {
|
||||||
// implied varnode must have parse type
|
// implied varnode must have parse type
|
||||||
if (outvn->isTypeLock()) {
|
if (outvn->isTypeLock()) {
|
||||||
|
@ -2392,25 +2398,25 @@ 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(outHighType, tokenct);
|
force = !isOpIdentical(outHighResolve, tokenct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (outHighType->getMetatype() != TYPE_PTR) { // If implied varnode has an atomic (non-pointer) type
|
else if (outHighResolve->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
|
||||||
outHighType = outvn->getHighTypeDefFacing();
|
outHighResolve = outvn->getHighTypeDefFacing();
|
||||||
}
|
}
|
||||||
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 *)outHighType)->getPtrTo();
|
outct = ((TypePointer *)outHighResolve)->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)&&(meta!=TYPE_UNION)) {
|
if ((meta!=TYPE_ARRAY)&&(meta!=TYPE_STRUCT)&&(meta!=TYPE_UNION)) {
|
||||||
outvn->updateType(tokenct,false,false); // Otherwise ignore it in favor of the token type
|
outvn->updateType(tokenct,false,false); // Otherwise ignore it in favor of the token type
|
||||||
outHighType = outvn->getHighTypeDefFacing();
|
outHighResolve = outvn->getHighTypeDefFacing();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!force) {
|
if (!force) {
|
||||||
outct = outHighType; // Type of result
|
outct = outHighResolve; // 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;
|
||||||
}
|
}
|
||||||
|
@ -2427,8 +2433,10 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
|
||||||
data.opSetInput(newop,vn,0);
|
data.opSetInput(newop,vn,0);
|
||||||
data.opSetOutput(op,vn);
|
data.opSetOutput(op,vn);
|
||||||
data.opInsertAfter(newop,op); // Cast comes AFTER this operation
|
data.opInsertAfter(newop,op); // Cast comes AFTER this operation
|
||||||
|
if (tokenct->needsResolution())
|
||||||
|
data.forceFacingType(tokenct, -1, newop, 0);
|
||||||
if (outHighType->needsResolution())
|
if (outHighType->needsResolution())
|
||||||
data.forceFacingType(outHighType, -1, newop, -1);
|
data.inheritWriteResolution(outHighType, newop, op);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -4483,6 +4491,12 @@ bool ActionInferTypes::propagateTypeEdge(TypeFactory *typegrp,PcodeOp *op,int4 i
|
||||||
{
|
{
|
||||||
Varnode *invn,*outvn;
|
Varnode *invn,*outvn;
|
||||||
|
|
||||||
|
invn = (inslot==-1) ? op->getOut() : op->getIn(inslot);
|
||||||
|
Datatype *alttype = invn->getTempType();
|
||||||
|
if (alttype->needsResolution()) {
|
||||||
|
// Always give incoming data-type a chance to resolve, even if it would not otherwise propagate
|
||||||
|
alttype = alttype->resolveInFlow(op, inslot);
|
||||||
|
}
|
||||||
if (inslot == outslot) return false; // don't backtrack
|
if (inslot == outslot) return false; // don't backtrack
|
||||||
if (outslot < 0)
|
if (outslot < 0)
|
||||||
outvn = op->getOut();
|
outvn = op->getOut();
|
||||||
|
@ -4490,11 +4504,6 @@ bool ActionInferTypes::propagateTypeEdge(TypeFactory *typegrp,PcodeOp *op,int4 i
|
||||||
outvn = op->getIn(outslot);
|
outvn = op->getIn(outslot);
|
||||||
if (outvn->isAnnotation()) return false;
|
if (outvn->isAnnotation()) return false;
|
||||||
}
|
}
|
||||||
invn = (inslot==-1) ? op->getOut() : op->getIn(inslot);
|
|
||||||
Datatype *alttype = invn->getTempType();
|
|
||||||
if (alttype->needsResolution()) {
|
|
||||||
alttype = alttype->resolveInFlow(op, inslot);
|
|
||||||
}
|
|
||||||
if (outvn->isTypeLock()) return false; // Can't propagate through typelock
|
if (outvn->isTypeLock()) return false; // Can't propagate through typelock
|
||||||
if (outvn->stopsUpPropagation() && outslot >= 0) return false; // Propagation is blocked
|
if (outvn->stopsUpPropagation() && outslot >= 0) return false; // Propagation is blocked
|
||||||
|
|
||||||
|
|
|
@ -1525,6 +1525,8 @@ SymbolEntry *Scope::addSymbol(const string &nm,Datatype *ct,
|
||||||
{
|
{
|
||||||
Symbol *sym;
|
Symbol *sym;
|
||||||
|
|
||||||
|
if (ct->hasStripped())
|
||||||
|
ct = ct->getStripped();
|
||||||
sym = new Symbol(owner,nm,ct);
|
sym = new Symbol(owner,nm,ct);
|
||||||
addSymbolInternal(sym);
|
addSymbolInternal(sym);
|
||||||
return addMapPoint(sym,addr,usepoint);
|
return addMapPoint(sym,addr,usepoint);
|
||||||
|
@ -1713,6 +1715,29 @@ Symbol *Scope::addEquateSymbol(const string &nm,uint4 format,uintb value,const A
|
||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Create a symbol forcing a field interpretation for a specific access to a variable with \e union data-type
|
||||||
|
///
|
||||||
|
/// The symbol is attached to a specific Varnode and a PcodeOp that reads or writes to it. The Varnode,
|
||||||
|
/// in the context of the PcodeOp, is forced to have the data-type of the selected field, and field's name is used
|
||||||
|
/// to represent the Varnode in output.
|
||||||
|
/// \param nm is the name of the symbol
|
||||||
|
/// \param dt is the union data-type containing the field to force
|
||||||
|
/// \param fieldNum is the index of the desired field, or -1 if the whole union should be forced
|
||||||
|
/// \param addr is the address of the p-code op reading/writing the Varnode
|
||||||
|
/// \param hash is the dynamic hash identifying the Varnode
|
||||||
|
/// \return the new UnionFacetSymbol
|
||||||
|
Symbol *Scope::addUnionFacetSymbol(const string &nm,Datatype *dt,int4 fieldNum,const Address &addr,uint8 hash)
|
||||||
|
|
||||||
|
{
|
||||||
|
Symbol *sym = new UnionFacetSymbol(owner,nm,dt,fieldNum);
|
||||||
|
addSymbolInternal(sym);
|
||||||
|
RangeList rnglist;
|
||||||
|
if (!addr.isInvalid())
|
||||||
|
rnglist.insertRange(addr.getSpace(),addr.getOffset(),addr.getOffset());
|
||||||
|
addDynamicMapInternal(sym,Varnode::mapped,hash,0,1,rnglist);
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
|
||||||
/// Create default name given information in the Symbol and possibly a representative Varnode.
|
/// Create default name given information in the Symbol and possibly a representative Varnode.
|
||||||
/// This method extracts the crucial properties and then uses the buildVariableName method to
|
/// This method extracts the crucial properties and then uses the buildVariableName method to
|
||||||
/// construct the actual name.
|
/// construct the actual name.
|
||||||
|
@ -2129,6 +2154,8 @@ void ScopeInternal::renameSymbol(Symbol *sym,const string &newname)
|
||||||
void ScopeInternal::retypeSymbol(Symbol *sym,Datatype *ct)
|
void ScopeInternal::retypeSymbol(Symbol *sym,Datatype *ct)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
if (ct->hasStripped())
|
||||||
|
ct = ct->getStripped();
|
||||||
if ((sym->type->getSize() == ct->getSize())||(sym->mapentry.empty())) {
|
if ((sym->type->getSize() == ct->getSize())||(sym->mapentry.empty())) {
|
||||||
// If size is the same, or no mappings nothing special to do
|
// If size is the same, or no mappings nothing special to do
|
||||||
sym->type = ct;
|
sym->type = ct;
|
||||||
|
|
|
@ -762,6 +762,7 @@ public:
|
||||||
LabSymbol *addCodeLabel(const Address &addr,const string &nm);
|
LabSymbol *addCodeLabel(const Address &addr,const string &nm);
|
||||||
Symbol *addDynamicSymbol(const string &nm,Datatype *ct,const Address &caddr,uint8 hash);
|
Symbol *addDynamicSymbol(const string &nm,Datatype *ct,const Address &caddr,uint8 hash);
|
||||||
Symbol *addEquateSymbol(const string &nm,uint4 format,uintb value,const Address &addr,uint8 hash);
|
Symbol *addEquateSymbol(const string &nm,uint4 format,uintb value,const Address &addr,uint8 hash);
|
||||||
|
Symbol *addUnionFacetSymbol(const string &nm,Datatype *dt,int4 fieldNum,const Address &addr,uint8 hash);
|
||||||
string buildDefaultName(Symbol *sym,int4 &base,Varnode *vn) const; ///< Create a default name for the given Symbol
|
string buildDefaultName(Symbol *sym,int4 &base,Varnode *vn) const; ///< Create a default name for the given Symbol
|
||||||
bool isReadOnly(const Address &addr,int4 size,const Address &usepoint) const;
|
bool isReadOnly(const Address &addr,int4 size,const Address &usepoint) const;
|
||||||
void printBounds(ostream &s) const { rangetree.printBounds(s); } ///< Print a description of \b this Scope's \e owned memory ranges
|
void printBounds(ostream &s) const { rangetree.printBounds(s); } ///< Print a description of \b this Scope's \e owned memory ranges
|
||||||
|
|
|
@ -858,50 +858,31 @@ bool Funcdata::syncVarnodesWithSymbols(const ScopeLocal *lm,bool typesyes)
|
||||||
return updateoccurred;
|
return updateoccurred;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the Varnode is a partial Symbol with \e union data-type, the best description of the Varnode's
|
/// If the Varnode is a partial of a Symbol with a \e union data-type component, we assign
|
||||||
/// data-type is delayed until data-type propagation is started.
|
/// a partial union data-type (TypePartialUnion) to the Varnode, so that facing resolutions
|
||||||
/// We attempt to resolve this description and also lay down any facing resolutions for the Varnode
|
/// can be provided.
|
||||||
/// \param vn is the given Varnode
|
/// \param vn is the given Varnode
|
||||||
/// \return the best data-type or null
|
/// \return the partial data-type or null
|
||||||
Datatype *Funcdata::checkSymbolType(Varnode *vn)
|
Datatype *Funcdata::checkSymbolType(Varnode *vn)
|
||||||
|
|
||||||
{
|
{
|
||||||
if (vn->isTypeLock()) return vn->getType();
|
if (vn->isTypeLock()) return vn->getType();
|
||||||
SymbolEntry *entry = vn->getSymbolEntry();
|
SymbolEntry *entry = vn->getSymbolEntry();
|
||||||
Symbol *sym = entry->getSymbol();
|
Symbol *sym = entry->getSymbol();
|
||||||
if (sym->getType()->getMetatype() != TYPE_UNION)
|
Datatype *curType = sym->getType();
|
||||||
|
if (curType->getSize() == vn->getSize())
|
||||||
return (Datatype *)0;
|
return (Datatype *)0;
|
||||||
TypeUnion *unionType = (TypeUnion *)sym->getType();
|
int4 curOff = (vn->getAddr().getOffset() - entry->getAddr().getOffset()) + entry->getOffset();
|
||||||
int4 off = (int4)(vn->getOffset() - entry->getAddr().getOffset()) + entry->getOffset();
|
// Drill down until we hit something that isn't a containing structure
|
||||||
if (off == 0 && unionType->getSize() == vn->getSize())
|
while(curType != (Datatype *)0 && curType->getMetatype() == TYPE_STRUCT && curType->getSize() > vn->getSize()) {
|
||||||
return (Datatype *)0;
|
uintb newOff;
|
||||||
const TypeField *finalField = (const TypeField *)0;
|
curType = curType->getSubType(curOff, &newOff);
|
||||||
uintb finalOff = 0;
|
curOff = newOff;
|
||||||
list<PcodeOp *>::const_iterator iter;
|
}
|
||||||
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
|
if (curType == (Datatype *)0 || curType->getSize() <= vn->getSize() || curType->getMetatype() != TYPE_UNION)
|
||||||
PcodeOp *op = *iter;
|
|
||||||
const TypeField *field = unionType->resolveTruncation(off, op, op->getSlot(vn),off);
|
|
||||||
if (field != (const TypeField *)0) {
|
|
||||||
finalField = field;
|
|
||||||
finalOff = off;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (vn->isWritten()) {
|
|
||||||
const TypeField *field = unionType->resolveTruncation(off, vn->getDef(), -1, off);
|
|
||||||
if (field != (const TypeField *)0) {
|
|
||||||
finalField = field;
|
|
||||||
finalOff = off;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (finalField != (const TypeField *)0) { // If any use of the Varnode resolves to a specific field
|
|
||||||
// Try to truncate down to a final data-type to assign to the Varnode
|
|
||||||
Datatype *ct = finalField->type;
|
|
||||||
while(ct != (Datatype *)0 && (finalOff != 0 || ct->getSize() != vn->getSize())) {
|
|
||||||
ct = ct->getSubType(finalOff, &finalOff);
|
|
||||||
}
|
|
||||||
return ct;
|
|
||||||
}
|
|
||||||
return (Datatype *)0;
|
return (Datatype *)0;
|
||||||
|
// If we hit a containing union
|
||||||
|
return glb->types->getTypePartialUnion((TypeUnion *)curType, curOff, vn->getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Varnode overlaps the given SymbolEntry. Make sure the Varnode is part of the variable
|
/// A Varnode overlaps the given SymbolEntry. Make sure the Varnode is part of the variable
|
||||||
|
|
|
@ -57,6 +57,7 @@ void IfaceDecompCapability::registerCommands(IfaceStatus *status)
|
||||||
status->registerCom(new IfcMapexternalref(),"map","externalref");
|
status->registerCom(new IfcMapexternalref(),"map","externalref");
|
||||||
status->registerCom(new IfcMaplabel(),"map","label");
|
status->registerCom(new IfcMaplabel(),"map","label");
|
||||||
status->registerCom(new IfcMapconvert(),"map","convert");
|
status->registerCom(new IfcMapconvert(),"map","convert");
|
||||||
|
status->registerCom(new IfcMapunionfacet(), "map", "unionfacet");
|
||||||
status->registerCom(new IfcPrintdisasm(),"disassemble");
|
status->registerCom(new IfcPrintdisasm(),"disassemble");
|
||||||
status->registerCom(new IfcDecompile(),"decompile");
|
status->registerCom(new IfcDecompile(),"decompile");
|
||||||
status->registerCom(new IfcDump(),"dump");
|
status->registerCom(new IfcDump(),"dump");
|
||||||
|
@ -711,6 +712,39 @@ void IfcMapconvert::execute(istream &s)
|
||||||
dcp->fd->getScopeLocal()->addEquateSymbol("", format, value, addr, hash);
|
dcp->fd->getScopeLocal()->addEquateSymbol("", format, value, addr, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \class IfcMapunionfacet
|
||||||
|
/// \brief Create a union field forcing directive: `map facet <union> <fieldnum> <address> <hash>`
|
||||||
|
///
|
||||||
|
/// Creates a \e facet directive that associates a given field of a \e union data-type with
|
||||||
|
/// a varnode in the context of a specific p-code op accessing it. The varnode and p-code op
|
||||||
|
/// are specified by dynamic hash.
|
||||||
|
void IfcMapunionfacet::execute(istream &s)
|
||||||
|
|
||||||
|
{
|
||||||
|
Datatype *ct;
|
||||||
|
string unionName;
|
||||||
|
int4 fieldNum;
|
||||||
|
int4 size;
|
||||||
|
uint8 hash;
|
||||||
|
|
||||||
|
if (dcp->fd == (Funcdata *)0)
|
||||||
|
throw IfaceExecutionError("No function loaded");
|
||||||
|
s >> ws >> unionName;
|
||||||
|
ct = dcp->conf->types->findByName(unionName);
|
||||||
|
if (ct == (Datatype *)0 || ct->getMetatype() != TYPE_UNION)
|
||||||
|
throw IfaceParseError("Bad union data-type: " + unionName);
|
||||||
|
s >> ws >> dec >> fieldNum;
|
||||||
|
if (fieldNum < -1 || fieldNum >= ct->numDepend())
|
||||||
|
throw IfaceParseError("Bad field index");
|
||||||
|
Address addr = parse_machaddr(s,size,*dcp->conf->types); // Read pc address of hash
|
||||||
|
|
||||||
|
s >> hex >> hash; // Parse the hash value
|
||||||
|
ostringstream s2;
|
||||||
|
s2 << "unionfacet" << dec << (fieldNum + 1) << '_' << hex << addr.getOffset();
|
||||||
|
Symbol *sym = dcp->fd->getScopeLocal()->addUnionFacetSymbol(s2.str(), ct, fieldNum, addr, hash);
|
||||||
|
dcp->fd->getScopeLocal()->setAttribute(sym, Varnode::typelock | Varnode::namelock);
|
||||||
|
}
|
||||||
|
|
||||||
/// \class IfcPrintdisasm
|
/// \class IfcPrintdisasm
|
||||||
/// \brief Print disassembly of a memory range: `disassemble [<address1> <address2>]`
|
/// \brief Print disassembly of a memory range: `disassemble [<address1> <address2>]`
|
||||||
///
|
///
|
||||||
|
|
|
@ -181,6 +181,11 @@ public:
|
||||||
virtual void execute(istream &s);
|
virtual void execute(istream &s);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IfcMapunionfacet : public IfaceDecompCommand {
|
||||||
|
public:
|
||||||
|
virtual void execute(istream &s);
|
||||||
|
};
|
||||||
|
|
||||||
class IfcPrintdisasm : public IfaceDecompCommand {
|
class IfcPrintdisasm : public IfaceDecompCommand {
|
||||||
public:
|
public:
|
||||||
virtual void execute(istream &s);
|
virtual void execute(istream &s);
|
||||||
|
|
|
@ -345,23 +345,30 @@ void Merge::mergeByDatatype(VarnodeLocSet::const_iterator startiter,VarnodeLocSe
|
||||||
/// output is created.
|
/// output is created.
|
||||||
/// \param inVn is the given input Varnode for the new COPY
|
/// \param inVn is the given input Varnode for the new COPY
|
||||||
/// \param addr is the address associated with the new COPY
|
/// \param addr is the address associated with the new COPY
|
||||||
|
/// \param trimOp is an exemplar PcodeOp whose read is being trimmed
|
||||||
/// \return the newly allocated COPY
|
/// \return the newly allocated COPY
|
||||||
PcodeOp *Merge::allocateCopyTrim(Varnode *inVn,const Address &addr)
|
PcodeOp *Merge::allocateCopyTrim(Varnode *inVn,const Address &addr,PcodeOp *trimOp)
|
||||||
|
|
||||||
{
|
{
|
||||||
PcodeOp *copyOp = data.newOp(1,addr);
|
PcodeOp *copyOp = data.newOp(1,addr);
|
||||||
data.opSetOpcode(copyOp,CPUI_COPY);
|
data.opSetOpcode(copyOp,CPUI_COPY);
|
||||||
Datatype *ct = inVn->getType();
|
Datatype *ct = inVn->getType();
|
||||||
Varnode *outVn = data.newUnique(inVn->getSize(),ct);
|
|
||||||
data.opSetOutput(copyOp,outVn);
|
|
||||||
data.opSetInput(copyOp,inVn,0);
|
|
||||||
copyTrims.push_back(copyOp);
|
|
||||||
if (ct->needsResolution()) { // If the data-type needs resolution
|
if (ct->needsResolution()) { // If the data-type needs resolution
|
||||||
if (inVn->isWritten()) {
|
if (inVn->isWritten()) {
|
||||||
int4 fieldNum = data.inheritWriteResolution(ct, copyOp, inVn->getDef());
|
int4 fieldNum = data.inheritWriteResolution(ct, copyOp, inVn->getDef());
|
||||||
data.forceFacingType(ct, fieldNum, copyOp, 0);
|
data.forceFacingType(ct, fieldNum, copyOp, 0);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
int4 slot = trimOp->getSlot(inVn);
|
||||||
|
const ResolvedUnion *resUnion = data.getUnionField(ct, trimOp, slot);
|
||||||
|
int4 fieldNum = (resUnion == (const ResolvedUnion *)0) ? -1 : resUnion->getFieldNum();
|
||||||
|
data.forceFacingType(ct, fieldNum, copyOp, 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Varnode *outVn = data.newUnique(inVn->getSize(),ct);
|
||||||
|
data.opSetOutput(copyOp,outVn);
|
||||||
|
data.opSetInput(copyOp,inVn,0);
|
||||||
|
copyTrims.push_back(copyOp);
|
||||||
return copyOp;
|
return copyOp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,7 +404,7 @@ void Merge::snipReads(Varnode *vn,list<PcodeOp *> &markedop)
|
||||||
else
|
else
|
||||||
afterop = vn->getDef();
|
afterop = vn->getDef();
|
||||||
}
|
}
|
||||||
copyop = allocateCopyTrim(vn, pc);
|
copyop = allocateCopyTrim(vn, pc, markedop.front());
|
||||||
if (afterop == (PcodeOp *)0)
|
if (afterop == (PcodeOp *)0)
|
||||||
data.opInsertBegin(copyop,bl);
|
data.opInsertBegin(copyop,bl);
|
||||||
else
|
else
|
||||||
|
@ -565,8 +572,15 @@ void Merge::trimOpOutput(PcodeOp *op)
|
||||||
else
|
else
|
||||||
afterop = op;
|
afterop = op;
|
||||||
vn = op->getOut();
|
vn = op->getOut();
|
||||||
uniq = data.newUnique(vn->getSize(),vn->getTypeDefFacing());
|
Datatype *ct = vn->getType();
|
||||||
copyop = data.newOp(1,op->getAddr());
|
copyop = data.newOp(1,op->getAddr());
|
||||||
|
if (ct->needsResolution()) {
|
||||||
|
int4 fieldNum = data.inheritWriteResolution(ct, copyop, op);
|
||||||
|
data.forceFacingType(ct, fieldNum, copyop, 0);
|
||||||
|
if (ct->getMetatype() == TYPE_PARTIALUNION)
|
||||||
|
ct = vn->getTypeDefFacing();
|
||||||
|
}
|
||||||
|
uniq = data.newUnique(vn->getSize(),ct);
|
||||||
data.opSetOutput(op,uniq); // Output of op is now stubby uniq
|
data.opSetOutput(op,uniq); // Output of op is now stubby uniq
|
||||||
data.opSetOpcode(copyop,CPUI_COPY);
|
data.opSetOpcode(copyop,CPUI_COPY);
|
||||||
data.opSetOutput(copyop,vn); // Original output is bumped forward slightly
|
data.opSetOutput(copyop,vn); // Original output is bumped forward slightly
|
||||||
|
@ -596,7 +610,7 @@ void Merge::trimOpInput(PcodeOp *op,int4 slot)
|
||||||
else
|
else
|
||||||
pc = op->getAddr();
|
pc = op->getAddr();
|
||||||
vn = op->getIn(slot);
|
vn = op->getIn(slot);
|
||||||
copyop = allocateCopyTrim(vn, pc);
|
copyop = allocateCopyTrim(vn, pc, op);
|
||||||
data.opSetInput(op,copyop->getOut(),slot);
|
data.opSetInput(op,copyop->getOut(),slot);
|
||||||
if (op->code() == CPUI_MULTIEQUAL)
|
if (op->code() == CPUI_MULTIEQUAL)
|
||||||
data.opInsertEnd(copyop,(BlockBasic *)op->getParent()->getIn(slot));
|
data.opInsertEnd(copyop,(BlockBasic *)op->getParent()->getIn(slot));
|
||||||
|
@ -752,7 +766,7 @@ void Merge::snipIndirect(PcodeOp *indop)
|
||||||
// an instance of the output high must
|
// an instance of the output high must
|
||||||
// all intersect so the varnodes must all be
|
// all intersect so the varnodes must all be
|
||||||
// traceable via COPY to the same root
|
// traceable via COPY to the same root
|
||||||
snipop = allocateCopyTrim(refvn, op->getAddr());
|
snipop = allocateCopyTrim(refvn, op->getAddr(), correctable.front());
|
||||||
data.opInsertBefore(snipop,op);
|
data.opInsertBefore(snipop,op);
|
||||||
list<PcodeOp *>::iterator oiter;
|
list<PcodeOp *>::iterator oiter;
|
||||||
int4 i,slot;
|
int4 i,slot;
|
||||||
|
@ -789,7 +803,7 @@ void Merge::mergeIndirect(PcodeOp *indop)
|
||||||
|
|
||||||
PcodeOp *newop;
|
PcodeOp *newop;
|
||||||
|
|
||||||
newop = allocateCopyTrim(invn0, indop->getAddr());
|
newop = allocateCopyTrim(invn0, indop->getAddr(), indop);
|
||||||
SymbolEntry *entry = outvn->getSymbolEntry();
|
SymbolEntry *entry = outvn->getSymbolEntry();
|
||||||
if (entry != (SymbolEntry *)0 && entry->getSymbol()->getType()->needsResolution()) {
|
if (entry != (SymbolEntry *)0 && entry->getSymbol()->getType()->needsResolution()) {
|
||||||
data.inheritWriteResolution(entry->getSymbol()->getType(), newop, indop);
|
data.inheritWriteResolution(entry->getSymbol()->getType(), newop, indop);
|
||||||
|
@ -1063,20 +1077,28 @@ void Merge::buildDominantCopy(HighVariable *high,vector<PcodeOp *> ©,int4 po
|
||||||
for(int4 i=0;i<size;++i)
|
for(int4 i=0;i<size;++i)
|
||||||
blockSet.push_back(copy[pos+i]->getParent());
|
blockSet.push_back(copy[pos+i]->getParent());
|
||||||
BlockBasic *domBl = (BlockBasic *)FlowBlock::findCommonBlock(blockSet);
|
BlockBasic *domBl = (BlockBasic *)FlowBlock::findCommonBlock(blockSet);
|
||||||
Varnode *rootVn = copy[pos]->getIn(0);
|
PcodeOp *domCopy = copy[pos];
|
||||||
|
Varnode *rootVn = domCopy->getIn(0);
|
||||||
|
Varnode *domVn = domCopy->getOut();
|
||||||
bool domCopyIsNew;
|
bool domCopyIsNew;
|
||||||
PcodeOp *domCopy;
|
if (domBl == domCopy->getParent()) {
|
||||||
Varnode *domVn;
|
|
||||||
if (domBl == copy[pos]->getParent()) {
|
|
||||||
domCopyIsNew = false;
|
domCopyIsNew = false;
|
||||||
domCopy = copy[pos];
|
|
||||||
domVn = domCopy->getOut();
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
domCopyIsNew = true;
|
domCopyIsNew = true;
|
||||||
|
PcodeOp *oldCopy = domCopy;
|
||||||
domCopy = data.newOp(1,domBl->getStop());
|
domCopy = data.newOp(1,domBl->getStop());
|
||||||
data.opSetOpcode(domCopy, CPUI_COPY);
|
data.opSetOpcode(domCopy, CPUI_COPY);
|
||||||
domVn = data.newUnique(rootVn->getSize(), rootVn->getType());
|
Datatype *ct = rootVn->getType();
|
||||||
|
if (ct->needsResolution()) {
|
||||||
|
const ResolvedUnion *resUnion = data.getUnionField(ct, oldCopy, 0);
|
||||||
|
int4 fieldNum = (resUnion == (const ResolvedUnion *)0) ? -1 : resUnion->getFieldNum();
|
||||||
|
data.forceFacingType(ct, fieldNum, domCopy, 0);
|
||||||
|
data.forceFacingType(ct, fieldNum, domCopy, -1);
|
||||||
|
if (ct->getMetatype() == TYPE_PARTIALUNION)
|
||||||
|
ct = rootVn->getTypeReadFacing(oldCopy);
|
||||||
|
}
|
||||||
|
domVn = data.newUnique(rootVn->getSize(), ct);
|
||||||
data.opSetOutput(domCopy,domVn);
|
data.opSetOutput(domCopy,domVn);
|
||||||
data.opSetInput(domCopy,rootVn,0);
|
data.opSetInput(domCopy,rootVn,0);
|
||||||
data.opInsertEnd(domCopy, domBl);
|
data.opInsertEnd(domCopy, domBl);
|
||||||
|
|
|
@ -96,7 +96,7 @@ class Merge {
|
||||||
void collectCovering(vector<Varnode *> &vlist,HighVariable *high,PcodeOp *op);
|
void collectCovering(vector<Varnode *> &vlist,HighVariable *high,PcodeOp *op);
|
||||||
bool collectCorrectable(const vector<Varnode *> &vlist,list<PcodeOp *> &oplist,vector<int4> &slotlist,
|
bool collectCorrectable(const vector<Varnode *> &vlist,list<PcodeOp *> &oplist,vector<int4> &slotlist,
|
||||||
PcodeOp *op);
|
PcodeOp *op);
|
||||||
PcodeOp *allocateCopyTrim(Varnode *inVn,const Address &addr);
|
PcodeOp *allocateCopyTrim(Varnode *inVn,const Address &addr,PcodeOp *trimOp);
|
||||||
void snipReads(Varnode *vn,list<PcodeOp *> &markedop);
|
void snipReads(Varnode *vn,list<PcodeOp *> &markedop);
|
||||||
void snipIndirect(PcodeOp *indop);
|
void snipIndirect(PcodeOp *indop);
|
||||||
void eliminateIntersect(Varnode *vn,const vector<BlockVarnode> &blocksort);
|
void eliminateIntersect(Varnode *vn,const vector<BlockVarnode> &blocksort);
|
||||||
|
|
|
@ -876,7 +876,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
||||||
fieldtype = fld->type;
|
fieldtype = fld->type;
|
||||||
}
|
}
|
||||||
else { // TYPE_STRUCT
|
else { // TYPE_STRUCT
|
||||||
const TypeField *fld = ((TypeStruct*)ct)->resolveTruncation((int4)suboff,0,&newoff);
|
const TypeField *fld = ct->findTruncation((int4)suboff,0,op,0,newoff);
|
||||||
if (fld == (const TypeField*)0) {
|
if (fld == (const TypeField*)0) {
|
||||||
if (ct->getSize() <= suboff) {
|
if (ct->getSize() <= suboff) {
|
||||||
clear();
|
clear();
|
||||||
|
@ -1691,6 +1691,7 @@ void PrintC::pushConstant(uintb val,const Datatype *ct,
|
||||||
case TYPE_STRUCT:
|
case TYPE_STRUCT:
|
||||||
case TYPE_UNION:
|
case TYPE_UNION:
|
||||||
case TYPE_PARTIALSTRUCT:
|
case TYPE_PARTIALSTRUCT:
|
||||||
|
case TYPE_PARTIALUNION:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Default printing
|
// Default printing
|
||||||
|
@ -1863,7 +1864,7 @@ void PrintC::pushPartialSymbol(const Symbol *sym,int4 off,int4 sz,
|
||||||
break; // Turns out we don't resolve to the field
|
break; // Turns out we don't resolve to the field
|
||||||
}
|
}
|
||||||
const TypeField *field;
|
const TypeField *field;
|
||||||
field = ((TypeStruct *)ct)->resolveTruncation(off,sz,&off);
|
field = ct->findTruncation(off,sz,op,inslot,off);
|
||||||
if (field != (const TypeField *)0) {
|
if (field != (const TypeField *)0) {
|
||||||
stack.emplace_back();
|
stack.emplace_back();
|
||||||
PartialSymbolEntry &entry( stack.back() );
|
PartialSymbolEntry &entry( stack.back() );
|
||||||
|
@ -1894,7 +1895,7 @@ void PrintC::pushPartialSymbol(const Symbol *sym,int4 off,int4 sz,
|
||||||
}
|
}
|
||||||
else if (ct->getMetatype() == TYPE_UNION) {
|
else if (ct->getMetatype() == TYPE_UNION) {
|
||||||
const TypeField *field;
|
const TypeField *field;
|
||||||
field = ((TypeUnion *)ct)->findTruncation(off,op,inslot,off);
|
field = ct->findTruncation(off,sz,op,inslot,off);
|
||||||
if (field != (const TypeField*)0) {
|
if (field != (const TypeField*)0) {
|
||||||
stack.emplace_back();
|
stack.emplace_back();
|
||||||
PartialSymbolEntry &entry(stack.back());
|
PartialSymbolEntry &entry(stack.back());
|
||||||
|
|
|
@ -18,9 +18,9 @@
|
||||||
|
|
||||||
/// The base propagation ordering associated with each meta-type.
|
/// The base propagation ordering associated with each meta-type.
|
||||||
/// The array elements correspond to the ordering of #type_metatype.
|
/// The array elements correspond to the ordering of #type_metatype.
|
||||||
sub_metatype Datatype::base2sub[14] = {
|
sub_metatype Datatype::base2sub[15] = {
|
||||||
SUB_UNION, SUB_STRUCT, SUB_PARTIALSTRUCT, SUB_ARRAY, SUB_PTRREL, SUB_PTR, SUB_FLOAT, SUB_CODE, SUB_BOOL,
|
SUB_PARTIALUNION, SUB_PARTIALSTRUCT, SUB_UNION, SUB_STRUCT, SUB_ARRAY, SUB_PTRREL, SUB_PTR, SUB_FLOAT, SUB_CODE,
|
||||||
SUB_UINT_PLAIN, SUB_INT_PLAIN, SUB_UNKNOWN, SUB_SPACEBASE, SUB_VOID
|
SUB_BOOL, SUB_UINT_PLAIN, SUB_INT_PLAIN, SUB_UNKNOWN, SUB_SPACEBASE, SUB_VOID
|
||||||
};
|
};
|
||||||
|
|
||||||
AttributeId ATTRIB_ALIGNMENT = AttributeId("alignment",47);
|
AttributeId ATTRIB_ALIGNMENT = AttributeId("alignment",47);
|
||||||
|
@ -142,6 +142,24 @@ void Datatype::printRaw(ostream &s) const
|
||||||
s << "unkbyte" << dec << size;
|
s << "unkbyte" << dec << size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Find an immediate subfield of \b this data-type
|
||||||
|
///
|
||||||
|
/// Given a byte range within \b this data-type, determine the field it is contained in
|
||||||
|
/// and pass back the renormalized offset. This method applies to TYPE_STRUCT, TYPE_UNION, and
|
||||||
|
/// TYPE_PARTIALUNION, data-types that have field components. For TYPE_UNION and TYPE_PARTIALUNION, the
|
||||||
|
/// field may depend on the p-code op extracting or writing the value.
|
||||||
|
/// \param off is the byte offset into \b this
|
||||||
|
/// \param sz is the size of the byte range
|
||||||
|
/// \param op is the PcodeOp reading/writing the data-type
|
||||||
|
/// \param slot is the index of the Varnode being accessed, -1 for the output, >=0 for an input
|
||||||
|
/// \param newoff points to the renormalized offset to pass back
|
||||||
|
/// \return the containing field or NULL if the range is not contained
|
||||||
|
const TypeField *Datatype::findTruncation(int4 off,int4 sz,const PcodeOp *op,int4 slot,int4 &newoff) const
|
||||||
|
|
||||||
|
{
|
||||||
|
return (const TypeField *)0;
|
||||||
|
}
|
||||||
|
|
||||||
/// Given an offset into \b this data-type, return the component data-type at that offset.
|
/// Given an offset into \b this data-type, return the component data-type at that offset.
|
||||||
/// Also, pass back a "renormalized" offset suitable for recursize getSubType() calls:
|
/// Also, pass back a "renormalized" offset suitable for recursize getSubType() calls:
|
||||||
/// i.e. if the original offset hits the exact start of the sub-type, 0 is passed back.
|
/// i.e. if the original offset hits the exact start of the sub-type, 0 is passed back.
|
||||||
|
@ -231,7 +249,10 @@ void metatype2string(type_metatype metatype,string &res)
|
||||||
res = "array";
|
res = "array";
|
||||||
break;
|
break;
|
||||||
case TYPE_PARTIALSTRUCT:
|
case TYPE_PARTIALSTRUCT:
|
||||||
res = "part";
|
res = "partstruct";
|
||||||
|
break;
|
||||||
|
case TYPE_PARTIALUNION:
|
||||||
|
res = "partunion";
|
||||||
break;
|
break;
|
||||||
case TYPE_STRUCT:
|
case TYPE_STRUCT:
|
||||||
res = "struct";
|
res = "struct";
|
||||||
|
@ -275,10 +296,12 @@ 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=="ptrrel")
|
else if (metastring=="ptrrel")
|
||||||
return TYPE_PTRREL;
|
return TYPE_PTRREL;
|
||||||
|
else if (metastring=="partunion")
|
||||||
|
return TYPE_PARTIALUNION;
|
||||||
|
else if (metastring=="partstruct")
|
||||||
|
return TYPE_PARTIALSTRUCT;
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
if (metastring=="array")
|
if (metastring=="array")
|
||||||
|
@ -461,6 +484,24 @@ int4 Datatype::findCompatibleResolve(Datatype *ct) const
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Resolve which union field is being used for a given PcodeOp when a truncation is involved
|
||||||
|
///
|
||||||
|
/// This method applies to the TYPE_UNION and TYPE_PARTIALUNION data-types, when a Varnode is backed
|
||||||
|
/// by a larger Symbol with a union data-type, or if the Varnode is produced by a CPUI_SUBPIECE where
|
||||||
|
/// the input Varnode has a union data-type.
|
||||||
|
/// Scoring is done to compute the best field and the result is cached with the function.
|
||||||
|
/// The record of the best field is returned or null if there is no appropriate field
|
||||||
|
/// \param offset is the byte offset into the union we are truncating to
|
||||||
|
/// \param op is either the PcodeOp reading the truncated Varnode or the CPUI_SUBPIECE doing the truncation
|
||||||
|
/// \param slot is either the input slot of the reading PcodeOp or the artificial SUBPIECE slot: 1
|
||||||
|
/// \param newoff is used to pass back how much offset is left to resolve
|
||||||
|
/// \return the field of the union best associated with the truncation or null
|
||||||
|
const TypeField *Datatype::resolveTruncation(int4 offset,PcodeOp *op,int4 slot,int4 &newoff)
|
||||||
|
|
||||||
|
{
|
||||||
|
return (const TypeField *)0;
|
||||||
|
}
|
||||||
|
|
||||||
/// Restore the basic properties (name,size,id) of a data-type from an XML element
|
/// Restore the basic properties (name,size,id) of a data-type from an XML element
|
||||||
/// Properties are read from the attributes of the element
|
/// Properties are read from the attributes of the element
|
||||||
/// \param decoder is the stream decoder
|
/// \param decoder is the stream decoder
|
||||||
|
@ -1332,13 +1373,7 @@ int4 TypeStruct::getLowerBoundField(int4 off) const
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a byte range within \b this data-type, determine the field it is contained in
|
const TypeField *TypeStruct::findTruncation(int4 off,int4 sz,const PcodeOp *op,int4 slot,int4 &newoff) const
|
||||||
/// and pass back the renormalized offset.
|
|
||||||
/// \param off is the byte offset into \b this
|
|
||||||
/// \param sz is the size of the byte range
|
|
||||||
/// \param newoff points to the renormalized offset to pass back
|
|
||||||
/// \return the containing field or NULL if the range is not contained
|
|
||||||
const TypeField *TypeStruct::resolveTruncation(int4 off,int4 sz,int4 *newoff) const
|
|
||||||
|
|
||||||
{
|
{
|
||||||
int4 i;
|
int4 i;
|
||||||
|
@ -1350,7 +1385,7 @@ const TypeField *TypeStruct::resolveTruncation(int4 off,int4 sz,int4 *newoff) co
|
||||||
noff = off - curfield.offset;
|
noff = off - curfield.offset;
|
||||||
if (noff+sz > curfield.type->getSize()) // Requested piece spans more than one field
|
if (noff+sz > curfield.type->getSize()) // Requested piece spans more than one field
|
||||||
return (const TypeField *)0;
|
return (const TypeField *)0;
|
||||||
*newoff = noff;
|
newoff = noff;
|
||||||
return &curfield;
|
return &curfield;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1785,17 +1820,6 @@ Datatype* TypeUnion::findResolve(const PcodeOp *op,int4 slot)
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Resolve which union field is being used for a given PcodeOp when a truncation is involved
|
|
||||||
///
|
|
||||||
/// This is used either when a Varnode is backed by a larger Symbol with a union data-type,
|
|
||||||
/// or if the Varnode is produced by a CPUI_SUBPIECE where the input Varnode has a union data-type.
|
|
||||||
/// Scoring is done to compute the best field and the result is cached with the function.
|
|
||||||
/// The record of the best field is returned or null if there is no appropriate field
|
|
||||||
/// \param offset is the byte offset into the union we are truncating to
|
|
||||||
/// \param op is either the PcodeOp reading the truncated Varnode or the CPUI_SUBPIECE doing the truncation
|
|
||||||
/// \param slot is either the input slot of the reading PcodeOp or the artificial SUBPIECE slot: 1
|
|
||||||
/// \param newoff is used to pass back how much offset is left to resolve
|
|
||||||
/// \return the field of the union best associated with the truncation or null
|
|
||||||
const TypeField *TypeUnion::resolveTruncation(int4 offset,PcodeOp *op,int4 slot,int4 &newoff)
|
const TypeField *TypeUnion::resolveTruncation(int4 offset,PcodeOp *op,int4 slot,int4 &newoff)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1826,23 +1850,23 @@ const TypeField *TypeUnion::resolveTruncation(int4 offset,PcodeOp *op,int4 slot,
|
||||||
return (const TypeField *)0;
|
return (const TypeField *)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Return a precalculated field associated with a truncation
|
|
||||||
///
|
|
||||||
/// This is the \e const version of resolveTruncation(). No new scoring is done, but if a cached result
|
|
||||||
/// is available, return it.
|
|
||||||
/// \param offset is the byte offset of the truncation
|
/// \param offset is the byte offset of the truncation
|
||||||
|
/// \param sz is the number of bytes in the resulting truncation
|
||||||
/// \param op is the PcodeOp reading the truncated value
|
/// \param op is the PcodeOp reading the truncated value
|
||||||
/// \param slot is the input slot being read
|
/// \param slot is the input slot being read
|
||||||
/// \param newoff is used to pass back any remaining offset into the field which still must be resolved
|
/// \param newoff is used to pass back any remaining offset into the field which still must be resolved
|
||||||
/// \return the field to use with truncation or null if there is no appropriate field
|
/// \return the field to use with truncation or null if there is no appropriate field
|
||||||
const TypeField *TypeUnion::findTruncation(int4 offset,const PcodeOp *op,int4 slot,int4 &newoff) const
|
const TypeField *TypeUnion::findTruncation(int4 offset,int4 sz,const PcodeOp *op,int4 slot,int4 &newoff) const
|
||||||
|
|
||||||
{
|
{
|
||||||
|
// No new scoring is done, but if a cached result is available, return it.
|
||||||
const Funcdata *fd = op->getParent()->getFuncdata();
|
const Funcdata *fd = op->getParent()->getFuncdata();
|
||||||
const ResolvedUnion *res = fd->getUnionField(this, op, slot);
|
const ResolvedUnion *res = fd->getUnionField(this, op, slot);
|
||||||
if (res != (ResolvedUnion *)0 && res->getFieldNum() >= 0) {
|
if (res != (ResolvedUnion *)0 && res->getFieldNum() >= 0) {
|
||||||
const TypeField *field = getField(res->getFieldNum());
|
const TypeField *field = getField(res->getFieldNum());
|
||||||
newoff = offset - field->offset;
|
newoff = offset - field->offset;
|
||||||
|
if (newoff + sz > field->type->getSize())
|
||||||
|
return (const TypeField *)0; // Truncation spans more than one field
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
return (const TypeField *)0;
|
return (const TypeField *)0;
|
||||||
|
@ -1870,6 +1894,142 @@ int4 TypeUnion::findCompatibleResolve(Datatype *ct) const
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypePartialUnion::TypePartialUnion(const TypePartialUnion &op)
|
||||||
|
: Datatype(op)
|
||||||
|
{
|
||||||
|
stripped = op.stripped;
|
||||||
|
container = op.container;
|
||||||
|
offset = op.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypePartialUnion::TypePartialUnion(TypeUnion *contain,int4 off,int4 sz,Datatype *strip)
|
||||||
|
: Datatype(sz,TYPE_PARTIALUNION)
|
||||||
|
{
|
||||||
|
flags |= (needs_resolution | has_stripped);
|
||||||
|
stripped = strip;
|
||||||
|
container = contain;
|
||||||
|
offset = off;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypePartialUnion::printRaw(ostream &s) const
|
||||||
|
|
||||||
|
{
|
||||||
|
container->printRaw(s);
|
||||||
|
s << "[off=" << dec << offset << ",sz=" << size << ']';
|
||||||
|
}
|
||||||
|
|
||||||
|
const TypeField *TypePartialUnion::findTruncation(int4 off,int4 sz,const PcodeOp *op,int4 slot,int4 &newoff) const
|
||||||
|
|
||||||
|
{
|
||||||
|
return container->findTruncation(off + offset, sz, op, slot, newoff);
|
||||||
|
}
|
||||||
|
|
||||||
|
int4 TypePartialUnion::numDepend(void)
|
||||||
|
|
||||||
|
{
|
||||||
|
return container->numDepend();
|
||||||
|
}
|
||||||
|
|
||||||
|
Datatype *TypePartialUnion::getDepend(int4 index)
|
||||||
|
|
||||||
|
{
|
||||||
|
// Treat dependents as coming from the underlying union
|
||||||
|
Datatype *res = container->getDepend(index);
|
||||||
|
if (res->getSize() != size) // But if the size doesn't match
|
||||||
|
return stripped; // Return the stripped data-type
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int4 TypePartialUnion::compare(const Datatype &op,int4 level) const
|
||||||
|
|
||||||
|
{
|
||||||
|
int4 res = Datatype::compare(op,level);
|
||||||
|
if (res != 0) return res;
|
||||||
|
// Both must be partial unions
|
||||||
|
TypePartialUnion *tp = (TypePartialUnion *) &op;
|
||||||
|
if (offset != tp->offset) return (offset < tp->offset) ? -1 : 1;
|
||||||
|
level -= 1;
|
||||||
|
if (level < 0) {
|
||||||
|
if (id == op.getId()) return 0;
|
||||||
|
return (id < op.getId()) ? -1 : 1;
|
||||||
|
}
|
||||||
|
return container->compare(*tp->container,level); // Compare the underlying union
|
||||||
|
}
|
||||||
|
|
||||||
|
int4 TypePartialUnion::compareDependency(const Datatype &op) const
|
||||||
|
|
||||||
|
{
|
||||||
|
if (submeta != op.getSubMeta()) return (submeta < op.getSubMeta()) ? -1 : 1;
|
||||||
|
TypePartialUnion *tp = (TypePartialUnion *) &op; // Both must be partial unions
|
||||||
|
if (container != tp->container) return (container < tp->container) ? -1 : 1; // Compare absolute pointers
|
||||||
|
if (offset != tp->offset) return (offset < tp->offset) ? -1 : 1;
|
||||||
|
return (op.getSize()-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypePartialUnion::encode(Encoder &encoder) const
|
||||||
|
|
||||||
|
{
|
||||||
|
encoder.openElement(ELEM_TYPE);
|
||||||
|
encodeBasic(metatype,encoder);
|
||||||
|
encoder.writeSignedInteger(ATTRIB_OFFSET, offset);
|
||||||
|
container->encodeRef(encoder);
|
||||||
|
encoder.closeElement(ELEM_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Datatype *TypePartialUnion::resolveInFlow(PcodeOp *op,int4 slot)
|
||||||
|
|
||||||
|
{
|
||||||
|
Datatype *curType = container;
|
||||||
|
int4 curOff = offset;
|
||||||
|
while(curType != (Datatype *)0 && curType->getSize() > size) {
|
||||||
|
if (curType->getMetatype() == TYPE_UNION) {
|
||||||
|
const TypeField *field = curType->resolveTruncation(curOff, op, slot, curOff);
|
||||||
|
curType = (field == (const TypeField *)0) ? (Datatype *)0 : field->type;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uintb newOff;
|
||||||
|
curType = curType->getSubType(curOff, &newOff);
|
||||||
|
curOff = newOff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (curType != (Datatype *)0 && curType->getSize() == size)
|
||||||
|
return curType;
|
||||||
|
return stripped;
|
||||||
|
}
|
||||||
|
|
||||||
|
Datatype* TypePartialUnion::findResolve(const PcodeOp *op,int4 slot)
|
||||||
|
|
||||||
|
{
|
||||||
|
Datatype *curType = container;
|
||||||
|
int4 curOff = offset;
|
||||||
|
while(curType != (Datatype *)0 && curType->getSize() > size) {
|
||||||
|
if (curType->getMetatype() == TYPE_UNION) {
|
||||||
|
Datatype *newType = curType->findResolve(op, slot);
|
||||||
|
curType = (newType == curType) ? (Datatype *)0 : newType;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uintb newOff;
|
||||||
|
curType = curType->getSubType(curOff, &newOff);
|
||||||
|
curOff = newOff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (curType != (Datatype *)0 && curType->getSize() == size)
|
||||||
|
return curType;
|
||||||
|
return stripped;
|
||||||
|
}
|
||||||
|
|
||||||
|
int4 TypePartialUnion::findCompatibleResolve(Datatype *ct) const
|
||||||
|
|
||||||
|
{
|
||||||
|
return container->findCompatibleResolve(ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TypeField *TypePartialUnion::resolveTruncation(int4 off,PcodeOp *op,int4 slot,int4 &newoff)
|
||||||
|
|
||||||
|
{
|
||||||
|
return container->resolveTruncation(off + offset, op, slot, newoff);
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse a \<type> element with children describing the data-type being pointed to
|
/// Parse a \<type> element with children describing the data-type being pointed to
|
||||||
/// and the parent data-type.
|
/// and the parent data-type.
|
||||||
/// \param decoder is the stream decoder
|
/// \param decoder is the stream decoder
|
||||||
|
@ -3222,6 +3382,14 @@ TypeUnion *TypeFactory::getTypeUnion(const string &n)
|
||||||
return (TypeUnion *) findAdd(tmp);
|
return (TypeUnion *) findAdd(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypePartialUnion *TypeFactory::getTypePartialUnion(TypeUnion *contain,int4 off,int4 sz)
|
||||||
|
|
||||||
|
{
|
||||||
|
Datatype *strip = getBase(sz, TYPE_UNKNOWN);
|
||||||
|
TypePartialUnion tpu(contain,off,sz,strip);
|
||||||
|
return (TypePartialUnion *) findAdd(tpu);
|
||||||
|
}
|
||||||
|
|
||||||
/// The created enumeration will have no named values and a default configuration
|
/// The created enumeration will have no named values and a default configuration
|
||||||
/// Named values must be added later.
|
/// Named values must be added later.
|
||||||
/// \param n is the name of the enumeration
|
/// \param n is the name of the enumeration
|
||||||
|
|
|
@ -73,50 +73,52 @@ extern void print_data(ostream &s,uint1 *buffer,int4 size,const Address &baseadd
|
||||||
//extern bool print_string(ostream &s,uint1 *buffer,int4 size);
|
//extern bool print_string(ostream &s,uint1 *buffer,int4 size);
|
||||||
|
|
||||||
/// The core meta-types supported by the decompiler. These are sizeless templates
|
/// The core meta-types supported by the decompiler. These are sizeless templates
|
||||||
/// for the elements making up the type algebra.
|
/// for the elements making up the type algebra. Index is important for Datatype::base2sub array.
|
||||||
enum type_metatype {
|
enum type_metatype {
|
||||||
TYPE_VOID = 13, ///< Standard "void" type, absence of type
|
TYPE_VOID = 14, ///< Standard "void" type, absence of type
|
||||||
TYPE_SPACEBASE = 12, ///< Placeholder for symbol/type look-up calculations
|
TYPE_SPACEBASE = 13, ///< Placeholder for symbol/type look-up calculations
|
||||||
TYPE_UNKNOWN = 11, ///< An unknown low-level type. Treated as an unsigned integer.
|
TYPE_UNKNOWN = 12, ///< An unknown low-level type. Treated as an unsigned integer.
|
||||||
TYPE_INT = 10, ///< Signed integer. Signed is considered less specific than unsigned in C
|
TYPE_INT = 11, ///< Signed integer. Signed is considered less specific than unsigned in C
|
||||||
TYPE_UINT = 9, ///< Unsigned integer
|
TYPE_UINT = 10, ///< Unsigned integer
|
||||||
TYPE_BOOL = 8, ///< Boolean
|
TYPE_BOOL = 9, ///< Boolean
|
||||||
TYPE_CODE = 7, ///< Data is actual executable code
|
TYPE_CODE = 8, ///< Data is actual executable code
|
||||||
TYPE_FLOAT = 6, ///< Floating-point
|
TYPE_FLOAT = 7, ///< Floating-point
|
||||||
|
|
||||||
TYPE_PTR = 5, ///< Pointer data-type
|
TYPE_PTR = 6, ///< Pointer data-type
|
||||||
TYPE_PTRREL = 4, ///< Pointer relative to another data-type (specialization of TYPE_PTR)
|
TYPE_PTRREL = 5, ///< Pointer relative to another data-type (specialization of TYPE_PTR)
|
||||||
TYPE_ARRAY = 3, ///< Array data-type, made up of a sequence of "element" datatype
|
TYPE_ARRAY = 4, ///< Array data-type, made up of a sequence of "element" datatype
|
||||||
TYPE_PARTIALSTRUCT = 2, ///< Part of a structure, stored separately from the whole
|
TYPE_STRUCT = 3, ///< Structure data-type, made up of component datatypes
|
||||||
TYPE_STRUCT = 1, ///< Structure data-type, made up of component datatypes
|
TYPE_UNION = 2, ///< An overlapping union of multiple datatypes
|
||||||
TYPE_UNION = 0 ///< An overlapping union of multiple datatypes
|
TYPE_PARTIALSTRUCT = 1, ///< Part of a structure, stored separately from the whole
|
||||||
|
TYPE_PARTIALUNION = 0 ///< Part of a union
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Specializations of the core meta-types. Each enumeration is associated with a specific #type_metatype.
|
/// Specializations of the core meta-types. Each enumeration is associated with a specific #type_metatype.
|
||||||
/// Ordering is important: The lower the number, the more \b specific the data-type, affecting propagation.
|
/// Ordering is important: The lower the number, the more \b specific the data-type, affecting propagation.
|
||||||
enum sub_metatype {
|
enum sub_metatype {
|
||||||
SUB_VOID = 21, ///< Compare as a TYPE_VOID
|
SUB_VOID = 22, ///< Compare as a TYPE_VOID
|
||||||
SUB_SPACEBASE = 20, ///< Compare as a TYPE_SPACEBASE
|
SUB_SPACEBASE = 21, ///< Compare as a TYPE_SPACEBASE
|
||||||
SUB_UNKNOWN = 19, ///< Compare as a TYPE_UNKNOWN
|
SUB_UNKNOWN = 20, ///< Compare as a TYPE_UNKNOWN
|
||||||
SUB_INT_CHAR = 18, ///< Signed 1-byte character, sub-type of TYPE_INT
|
SUB_INT_CHAR = 19, ///< Signed 1-byte character, sub-type of TYPE_INT
|
||||||
SUB_UINT_CHAR = 17, ///< Unsigned 1-byte character, sub-type of TYPE_UINT
|
SUB_UINT_CHAR = 18, ///< Unsigned 1-byte character, sub-type of TYPE_UINT
|
||||||
SUB_INT_PLAIN = 16, ///< Compare as a plain TYPE_INT
|
SUB_INT_PLAIN = 17, ///< Compare as a plain TYPE_INT
|
||||||
SUB_UINT_PLAIN = 15, ///< Compare as a plain TYPE_UINT
|
SUB_UINT_PLAIN = 16, ///< Compare as a plain TYPE_UINT
|
||||||
SUB_INT_ENUM = 14, ///< Signed enum, sub-type of TYPE_INT
|
SUB_INT_ENUM = 15, ///< Signed enum, sub-type of TYPE_INT
|
||||||
SUB_UINT_ENUM = 13, ///< Unsigned enum, sub-type of TYPE_UINT
|
SUB_UINT_ENUM = 14, ///< Unsigned enum, sub-type of TYPE_UINT
|
||||||
SUB_INT_UNICODE = 12, ///< Signed wide character, sub-type of TYPE_INT
|
SUB_INT_UNICODE = 13, ///< Signed wide character, sub-type of TYPE_INT
|
||||||
SUB_UINT_UNICODE = 11, ///< Unsigned wide character, sub-type of TYPE_UINT
|
SUB_UINT_UNICODE = 12, ///< Unsigned wide character, sub-type of TYPE_UINT
|
||||||
SUB_BOOL = 10, ///< Compare as TYPE_BOOL
|
SUB_BOOL = 11, ///< Compare as TYPE_BOOL
|
||||||
SUB_CODE = 9, ///< Compare as TYPE_CODE
|
SUB_CODE = 10, ///< Compare as TYPE_CODE
|
||||||
SUB_FLOAT = 8, ///< Compare as TYPE_FLOAT
|
SUB_FLOAT = 9, ///< Compare as TYPE_FLOAT
|
||||||
SUB_PTRREL_UNK = 7, ///< Pointer to unknown field of struct, sub-type of TYPE_PTR
|
SUB_PTRREL_UNK = 8, ///< Pointer to unknown field of struct, sub-type of TYPE_PTR
|
||||||
SUB_PTR = 6, ///< Compare as TYPE_PTR
|
SUB_PTR = 7, ///< Compare as TYPE_PTR
|
||||||
SUB_PTRREL = 5, ///< Pointer relative to another data-type, sub-type of TYPE_PTR
|
SUB_PTRREL = 6, ///< Pointer relative to another data-type, sub-type of TYPE_PTR
|
||||||
SUB_PTR_STRUCT = 4, ///< Pointer into struct, sub-type of TYPE_PTR
|
SUB_PTR_STRUCT = 5, ///< Pointer into struct, sub-type of TYPE_PTR
|
||||||
SUB_ARRAY = 3, ///< Compare as TYPE_ARRAY
|
SUB_ARRAY = 4, ///< Compare as TYPE_ARRAY
|
||||||
SUB_PARTIALSTRUCT = 2, ///< Compare as TYPE_PARTIALSTRUCT
|
SUB_PARTIALSTRUCT = 3, ///< Compare as TYPE_PARTIALSTRUCT
|
||||||
SUB_STRUCT = 1, ///< Compare as TYPE_STRUCT
|
SUB_STRUCT = 2, ///< Compare as TYPE_STRUCT
|
||||||
SUB_UNION = 0 ///< Compare as TYPE_UNION
|
SUB_UNION = 1, ///< Compare as TYPE_UNION
|
||||||
|
SUB_PARTIALUNION = 0 ///< Compare as a TYPE_PARTIALUNION
|
||||||
};
|
};
|
||||||
/// Convert type \b meta-type to name
|
/// Convert type \b meta-type to name
|
||||||
extern void metatype2string(type_metatype metatype,string &res);
|
extern void metatype2string(type_metatype metatype,string &res);
|
||||||
|
@ -128,6 +130,7 @@ class Architecture; // Forward declarations
|
||||||
class PcodeOp;
|
class PcodeOp;
|
||||||
class Scope;
|
class Scope;
|
||||||
class TypeFactory;
|
class TypeFactory;
|
||||||
|
class TypeField;
|
||||||
struct DatatypeCompare;
|
struct DatatypeCompare;
|
||||||
|
|
||||||
/// \brief The base datatype class for the decompiler.
|
/// \brief The base datatype class for the decompiler.
|
||||||
|
@ -135,7 +138,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[14];
|
static sub_metatype base2sub[15];
|
||||||
/// 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
|
||||||
|
@ -200,6 +203,7 @@ public:
|
||||||
const string &getName(void) const { return name; } ///< Get the type name
|
const string &getName(void) const { return name; } ///< Get the type name
|
||||||
Datatype *getTypedef(void) const { return typedefImm; } ///< Get the data-type immediately typedefed by \e this (or null)
|
Datatype *getTypedef(void) const { return typedefImm; } ///< Get the data-type immediately typedefed by \e this (or null)
|
||||||
virtual void printRaw(ostream &s) const; ///< Print a description of the type to stream
|
virtual void printRaw(ostream &s) const; ///< Print a description of the type to stream
|
||||||
|
virtual const TypeField *findTruncation(int4 off,int4 sz,const PcodeOp *op,int4 slot,int4 &newoff) const;
|
||||||
virtual Datatype *getSubType(uintb off,uintb *newoff) const; ///< Recover component data-type one-level down
|
virtual Datatype *getSubType(uintb off,uintb *newoff) const; ///< Recover component data-type one-level down
|
||||||
virtual Datatype *nearestArrayedComponentForward(uintb off,uintb *newoff,int4 *elSize) const;
|
virtual Datatype *nearestArrayedComponentForward(uintb off,uintb *newoff,int4 *elSize) const;
|
||||||
virtual Datatype *nearestArrayedComponentBackward(uintb off,uintb *newoff,int4 *elSize) const;
|
virtual Datatype *nearestArrayedComponentBackward(uintb off,uintb *newoff,int4 *elSize) const;
|
||||||
|
@ -214,6 +218,7 @@ public:
|
||||||
virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot); ///< Tailor data-type propagation based on Varnode use
|
virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot); ///< Tailor data-type propagation based on Varnode use
|
||||||
virtual Datatype* findResolve(const PcodeOp *op,int4 slot); ///< Find a previously resolved sub-type
|
virtual Datatype* findResolve(const PcodeOp *op,int4 slot); ///< Find a previously resolved sub-type
|
||||||
virtual int4 findCompatibleResolve(Datatype *ct) const; ///< Find a resolution compatible with the given data-type
|
virtual int4 findCompatibleResolve(Datatype *ct) const; ///< Find a resolution compatible with the given data-type
|
||||||
|
virtual const TypeField *resolveTruncation(int4 offset,PcodeOp *op,int4 slot,int4 &newoff);
|
||||||
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 encodeRef(Encoder &encoder) const; ///< Encode a reference of \b this to a stream
|
void encodeRef(Encoder &encoder) const; ///< Encode a reference of \b this to a stream
|
||||||
|
@ -434,7 +439,7 @@ public:
|
||||||
TypeStruct(void) : Datatype(0,TYPE_STRUCT) { flags |= type_incomplete; } ///< Construct incomplete/empty TypeStruct
|
TypeStruct(void) : Datatype(0,TYPE_STRUCT) { flags |= type_incomplete; } ///< Construct incomplete/empty TypeStruct
|
||||||
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 *resolveTruncation(int4 off,int4 sz,int4 *newoff) const; ///< Get field based on offset
|
virtual const TypeField *findTruncation(int4 off,int4 sz,const PcodeOp *op,int4 slot,int4 &newoff) const;
|
||||||
virtual Datatype *getSubType(uintb off,uintb *newoff) const;
|
virtual Datatype *getSubType(uintb off,uintb *newoff) const;
|
||||||
virtual Datatype *nearestArrayedComponentForward(uintb off,uintb *newoff,int4 *elSize) const;
|
virtual Datatype *nearestArrayedComponentForward(uintb off,uintb *newoff,int4 *elSize) const;
|
||||||
virtual Datatype *nearestArrayedComponentBackward(uintb off,uintb *newoff,int4 *elSize) const;
|
virtual Datatype *nearestArrayedComponentBackward(uintb off,uintb *newoff,int4 *elSize) const;
|
||||||
|
@ -464,7 +469,8 @@ public:
|
||||||
TypeUnion(const TypeUnion &op); ///< Construct from another TypeUnion
|
TypeUnion(const TypeUnion &op); ///< Construct from another TypeUnion
|
||||||
TypeUnion(void) : Datatype(0,TYPE_UNION) { flags |= (type_incomplete | needs_resolution); } ///< Construct incomplete TypeUnion
|
TypeUnion(void) : Datatype(0,TYPE_UNION) { flags |= (type_incomplete | needs_resolution); } ///< Construct incomplete TypeUnion
|
||||||
const TypeField *getField(int4 i) const { return &field[i]; } ///< Get the i-th field of the union
|
const TypeField *getField(int4 i) const { return &field[i]; } ///< Get the i-th field of the union
|
||||||
// virtual Datatype *getSubType(uintb off,uintb *newoff) const;
|
virtual const TypeField *findTruncation(int4 offset,int4 sz,const PcodeOp *op,int4 slot,int4 &newoff) const;
|
||||||
|
// virtual Datatype *getSubType(uintb off,uintb *newoff) const;
|
||||||
virtual int4 numDepend(void) const { return field.size(); }
|
virtual int4 numDepend(void) const { return field.size(); }
|
||||||
virtual Datatype *getDepend(int4 index) const { return field[index].type; }
|
virtual Datatype *getDepend(int4 index) const { return field[index].type; }
|
||||||
virtual int4 compare(const Datatype &op,int4 level) const; // For tree structure
|
virtual int4 compare(const Datatype &op,int4 level) const; // For tree structure
|
||||||
|
@ -474,11 +480,43 @@ public:
|
||||||
virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot);
|
virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot);
|
||||||
virtual Datatype* findResolve(const PcodeOp *op,int4 slot);
|
virtual Datatype* findResolve(const PcodeOp *op,int4 slot);
|
||||||
virtual int4 findCompatibleResolve(Datatype *ct) const;
|
virtual int4 findCompatibleResolve(Datatype *ct) const;
|
||||||
const TypeField *resolveTruncation(int4 offset,PcodeOp *op,int4 slot,int4 &newoff);
|
virtual const TypeField *resolveTruncation(int4 offset,PcodeOp *op,int4 slot,int4 &newoff);
|
||||||
const TypeField *findTruncation(int4 offset,const PcodeOp *op,int4 slot,int4 &newoff) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The other data, the \b container, is typically a TypeStruct or TypeArray. Even though \b this pointer
|
/// \brief An internal data-type for holding information about a variable's relative position within a union data-type
|
||||||
|
///
|
||||||
|
/// This is a data-type that can be assigned to a Varnode offset into a Symbol, where either the Symbol itself or
|
||||||
|
/// a sub-field is a TypeUnion. In these cases, we know the Varnode is properly contained within a TypeUnion,
|
||||||
|
/// but the lack of context prevents us from deciding which field of the TypeUnion applies (and possibly
|
||||||
|
/// the sub-field of the field).
|
||||||
|
class TypePartialUnion : public Datatype {
|
||||||
|
protected:
|
||||||
|
friend class TypeFactory;
|
||||||
|
Datatype *stripped; ///< The \e undefined data-type to use if a formal data-type is required.
|
||||||
|
TypeUnion *container; ///< Union data-type containing \b this partial data-type
|
||||||
|
int4 offset; ///< Offset (in bytes) into the \e container union
|
||||||
|
public:
|
||||||
|
TypePartialUnion(const TypePartialUnion &op); ///< Construct from another TypePartialUnion
|
||||||
|
TypePartialUnion(TypeUnion *contain,int4 off,int4 sz,Datatype *strip); ///< Constructor
|
||||||
|
TypeUnion *getParentUnion(void) const { return container; } ///< Get the union which \b this is part of
|
||||||
|
virtual void printRaw(ostream &s) const; ///< Print a description of the type to stream
|
||||||
|
virtual const TypeField *findTruncation(int4 off,int4 sz,const PcodeOp *op,int4 slot,int4 &newoff) const;
|
||||||
|
virtual int4 numDepend(void);
|
||||||
|
virtual Datatype *getDepend(int4 index);
|
||||||
|
virtual int4 compare(const Datatype &op,int4 level) const;
|
||||||
|
virtual int4 compareDependency(const Datatype &op) const;
|
||||||
|
virtual Datatype *clone(void) const { return new TypePartialUnion(*this); }
|
||||||
|
virtual void encode(Encoder &encoder) const;
|
||||||
|
virtual Datatype *getStripped(void) const { return stripped; }
|
||||||
|
virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot);
|
||||||
|
virtual Datatype* findResolve(const PcodeOp *op,int4 slot);
|
||||||
|
virtual int4 findCompatibleResolve(Datatype *ct) const;
|
||||||
|
virtual const TypeField *resolveTruncation(int4 off,PcodeOp *op,int4 slot,int4 &newoff);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Relative pointer: A pointer with a fixed offset into a specific structure or other data-type
|
||||||
|
///
|
||||||
|
/// The other data-type, 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,
|
/// 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.
|
/// as the distance (the \b offset) to the start of the container is explicitly known.
|
||||||
class TypePointerRel : public TypePointer {
|
class TypePointerRel : public TypePointer {
|
||||||
|
@ -643,6 +681,7 @@ public:
|
||||||
TypeArray *getTypeArray(int4 as,Datatype *ao); ///< Construct an array data-type
|
TypeArray *getTypeArray(int4 as,Datatype *ao); ///< Construct an array data-type
|
||||||
TypeStruct *getTypeStruct(const string &n); ///< Create an (empty) structure
|
TypeStruct *getTypeStruct(const string &n); ///< Create an (empty) structure
|
||||||
TypeUnion *getTypeUnion(const string &n); ///< Create an (empty) union
|
TypeUnion *getTypeUnion(const string &n); ///< Create an (empty) union
|
||||||
|
TypePartialUnion *getTypePartialUnion(TypeUnion *contain,int4 off,int4 sz); ///< Create a partial union
|
||||||
TypeEnum *getTypeEnum(const string &n); ///< Create an (empty) enumeration
|
TypeEnum *getTypeEnum(const string &n); ///< Create an (empty) enumeration
|
||||||
TypeSpacebase *getTypeSpacebase(AddrSpace *id,const Address &addr); ///< Create a "spacebase" type
|
TypeSpacebase *getTypeSpacebase(AddrSpace *id,const Address &addr); ///< Create a "spacebase" type
|
||||||
TypeCode *getTypeCode(ProtoModel *model,Datatype *outtype,
|
TypeCode *getTypeCode(ProtoModel *model,Datatype *outtype,
|
||||||
|
|
|
@ -1791,7 +1791,18 @@ TypeOpMulti::TypeOpMulti(TypeFactory *t) : TypeOp(t,CPUI_MULTIEQUAL,"?")
|
||||||
Datatype *TypeOpMulti::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
|
Datatype *TypeOpMulti::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
|
||||||
int4 inslot,int4 outslot)
|
int4 inslot,int4 outslot)
|
||||||
{
|
{
|
||||||
if ((inslot!=-1)&&(outslot!=-1)) return (Datatype *)0; // Must propagate input <-> output
|
if ((inslot!=-1)&&(outslot!=-1)) {
|
||||||
|
if (invn == outvn && outvn->getTempType()->needsResolution()) {
|
||||||
|
// If same Varnode occupies two input slots of the MULTIEQUAL
|
||||||
|
// the second input slot should inherit the resolution of the first
|
||||||
|
Funcdata *fd = op->getParent()->getFuncdata();
|
||||||
|
Datatype *unionType = outvn->getTempType();
|
||||||
|
const ResolvedUnion *res = fd->getUnionField(unionType, op, inslot);
|
||||||
|
if (res != (const ResolvedUnion *)0)
|
||||||
|
fd->setUnionField(unionType, op, outslot, *res);
|
||||||
|
}
|
||||||
|
return (Datatype *)0; // Must propagate input <-> output
|
||||||
|
}
|
||||||
Datatype *newtype;
|
Datatype *newtype;
|
||||||
if (invn->isSpacebase()) {
|
if (invn->isSpacebase()) {
|
||||||
AddrSpace *spc = tlst->getArch()->getDefaultDataSpace();
|
AddrSpace *spc = tlst->getArch()->getDefaultDataSpace();
|
||||||
|
@ -1939,15 +1950,16 @@ Datatype *TypeOpSubpiece::propagateType(Datatype *alttype,PcodeOp *op,Varnode *i
|
||||||
int4 byteOff;
|
int4 byteOff;
|
||||||
int4 newoff;
|
int4 newoff;
|
||||||
const TypeField *field;
|
const TypeField *field;
|
||||||
if (alttype->getMetatype() == TYPE_UNION) {
|
type_metatype meta = alttype->getMetatype();
|
||||||
|
if (meta == TYPE_UNION || meta == TYPE_PARTIALUNION) {
|
||||||
// NOTE: We use an artificial slot here to store the field being truncated to
|
// NOTE: We use an artificial slot here to store the field being truncated to
|
||||||
// as the facing data-type for slot 0 is already to the parent (this TYPE_UNION)
|
// as the facing data-type for slot 0 is already to the parent (this TYPE_UNION)
|
||||||
byteOff = computeByteOffsetForComposite(op);
|
byteOff = computeByteOffsetForComposite(op);
|
||||||
field = ((TypeUnion *)alttype)->resolveTruncation(byteOff,op,1,newoff);
|
field = alttype->resolveTruncation(byteOff,op,1,newoff);
|
||||||
}
|
}
|
||||||
else if (alttype->getMetatype() == TYPE_STRUCT) {
|
else if (alttype->getMetatype() == TYPE_STRUCT) {
|
||||||
int4 byteOff = computeByteOffsetForComposite(op);
|
int4 byteOff = computeByteOffsetForComposite(op);
|
||||||
field = ((TypeStruct *)alttype)->resolveTruncation(byteOff, outvn->getSize(), &newoff);
|
field = alttype->findTruncation(byteOff, outvn->getSize(), op, 1, newoff);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return (Datatype *)0;
|
return (Datatype *)0;
|
||||||
|
@ -1972,22 +1984,13 @@ const TypeField *TypeOpSubpiece::testExtraction(bool useHigh,const PcodeOp *op,D
|
||||||
|
|
||||||
{
|
{
|
||||||
const Varnode *vn = op->getIn(0);
|
const Varnode *vn = op->getIn(0);
|
||||||
Datatype *ct = useHigh ? vn->getHigh()->getType() : vn->getType();
|
Datatype *ct = useHigh ? vn->getHighTypeReadFacing(op) : vn->getTypeReadFacing(op);
|
||||||
if (ct->getMetatype() == TYPE_STRUCT) {
|
type_metatype meta = ct->getMetatype();
|
||||||
|
if (meta != TYPE_STRUCT && meta != TYPE_UNION && meta != TYPE_PARTIALUNION)
|
||||||
|
return (const TypeField *)0;
|
||||||
parent = ct;
|
parent = ct;
|
||||||
int4 byteOff = computeByteOffsetForComposite(op);
|
int4 byteOff = computeByteOffsetForComposite(op);
|
||||||
return ((TypeStruct *)ct)->resolveTruncation(byteOff,op->getOut()->getSize(),&offset);
|
return ct->findTruncation(byteOff,op->getOut()->getSize(),op,1,offset); // Use artificial slot
|
||||||
}
|
|
||||||
else if (ct->getMetatype() == TYPE_UNION) {
|
|
||||||
const Funcdata *fd = op->getParent()->getFuncdata();
|
|
||||||
const ResolvedUnion *res = fd->getUnionField(ct, op, 1); // Use artificial slot
|
|
||||||
if (res != (const ResolvedUnion *)0 && res->getFieldNum() >= 0) {
|
|
||||||
parent = ct;
|
|
||||||
offset = 0;
|
|
||||||
return ((TypeUnion *)ct)->getField(res->getFieldNum());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (const TypeField *)0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Compute the byte offset into an assumed composite data-type produced by the given CPUI_SUBPIECE
|
/// \brief Compute the byte offset into an assumed composite data-type produced by the given CPUI_SUBPIECE
|
||||||
|
|
|
@ -39,6 +39,8 @@ ResolvedUnion::ResolvedUnion(Datatype *parent)
|
||||||
ResolvedUnion::ResolvedUnion(Datatype *parent,int4 fldNum,TypeFactory &typegrp)
|
ResolvedUnion::ResolvedUnion(Datatype *parent,int4 fldNum,TypeFactory &typegrp)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
if (parent->getMetatype() == TYPE_PARTIALUNION)
|
||||||
|
parent = ((TypePartialUnion *)parent)->getParentUnion();
|
||||||
baseType = parent;
|
baseType = parent;
|
||||||
fieldNum = fldNum;
|
fieldNum = fldNum;
|
||||||
lock = false;
|
lock = false;
|
||||||
|
@ -67,6 +69,8 @@ ResolveEdge::ResolveEdge(const Datatype *parent,const PcodeOp *op,int4 slot)
|
||||||
typeId = ((TypePointer *)parent)->getPtrTo()->getId(); // Strip pointer
|
typeId = ((TypePointer *)parent)->getPtrTo()->getId(); // Strip pointer
|
||||||
encoding += 0x1000; // Encode the fact that a pointer is getting accessed
|
encoding += 0x1000; // Encode the fact that a pointer is getting accessed
|
||||||
}
|
}
|
||||||
|
else if (parent->getMetatype() == TYPE_PARTIALUNION)
|
||||||
|
typeId = ((TypePartialUnion *)parent)->getParentUnion()->getId();
|
||||||
else
|
else
|
||||||
typeId = parent->getId();
|
typeId = parent->getId();
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,7 +159,7 @@ void HighVariable::updateType(void) const
|
||||||
vn = getTypeRepresentative();
|
vn = getTypeRepresentative();
|
||||||
|
|
||||||
type = vn->getType();
|
type = vn->getType();
|
||||||
if (type->hasStripped())
|
if (type->hasStripped() && type->getMetatype() != TYPE_PARTIALUNION)
|
||||||
type = type->getStripped();
|
type = type->getStripped();
|
||||||
|
|
||||||
// Update lock flags
|
// Update lock flags
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
<decompilertest>
|
||||||
|
<binaryimage arch="x86:LE:64:default:gcc">
|
||||||
|
<!--
|
||||||
|
Contrived examples of varnodes labeled as partial unions
|
||||||
|
-->
|
||||||
|
<bytechunk space="ram" offset="0x10068a" readonly="true">
|
||||||
|
554889e5f30f
|
||||||
|
1145fcf30f1045fcf30f110578092000
|
||||||
|
8b05760920005dc3
|
||||||
|
</bytechunk>
|
||||||
|
<bytechunk space="ram" offset="0x1006a8" readonly="true">
|
||||||
|
554889e5897dfc89
|
||||||
|
75f8837dfc01750b8b45f889055b0920
|
||||||
|
00eb33837dfc02750e8b45f883c00789
|
||||||
|
0543092000eb1f837dfc0475198b45f8
|
||||||
|
890536092000f30f100516010000f30f
|
||||||
|
110522092000905dc3
|
||||||
|
</bytechunk>
|
||||||
|
<bytechunk space="ram" offset="0x100804" readonly="true">
|
||||||
|
0000003f
|
||||||
|
</bytechunk>
|
||||||
|
<symbol space="ram" offset="0x10068a" name="partialunion"/>
|
||||||
|
<symbol space="ram" offset="0x1006a8" name="partial1"/>
|
||||||
|
</binaryimage>
|
||||||
|
<script>
|
||||||
|
<com>option readonly on</com>
|
||||||
|
<com>parse line struct astruct { int4 aval1; int4 aval2; int4 aval3; };</com>
|
||||||
|
<com>parse line struct bstruct { float4 bval1; int4 bval2; float4 bval3; };</com>
|
||||||
|
<com>parse line union structunion { astruct a; bstruct b; };</com>
|
||||||
|
<com>parse line extern int4 partialunion(float4 val);</com>
|
||||||
|
<com>map addr r0x301018 structunion globvar</com>
|
||||||
|
<com>lo fu partialunion</com>
|
||||||
|
<com>dec</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>lo fu partial1</com>
|
||||||
|
<com>map unionfacet structunion 1 r0x1006ee 20603f6a8a0b89</com>
|
||||||
|
<com>dec</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>quit</com>
|
||||||
|
</script>
|
||||||
|
<stringmatch name="Partial union #1" min="1" max="1">globvar\.b\.bval1 = val;</stringmatch>
|
||||||
|
<stringmatch name="Partial union #2" min="1" max="1">return globvar\.a\.aval2;</stringmatch>
|
||||||
|
<stringmatch name="Partial union #3" min="1" max="1">Var1 = globvar\.a\.aval2;</stringmatch>
|
||||||
|
<stringmatch name="Partial union #4" min="1" max="1">globvar\.a\.aval1 = param_2 \+ 7;</stringmatch>
|
||||||
|
<stringmatch name="Partial union #5" min="1" max="1">globvar\.b\.bval1 = 0\.5;</stringmatch>
|
||||||
|
<stringmatch name="Partial union #6" min="1" max="1">globvar\.a\.aval2 = .Var1;</stringmatch>
|
||||||
|
</decompilertest>
|
|
@ -31,6 +31,7 @@ import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.pcode.*;
|
import ghidra.program.model.pcode.*;
|
||||||
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.task.CancelledListener;
|
import ghidra.util.task.CancelledListener;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
@ -775,14 +776,9 @@ public class DecompInterface {
|
||||||
AddressXML.encode(activeSet.mainQuery, funcEntry);
|
AddressXML.encode(activeSet.mainQuery, funcEntry);
|
||||||
decompProcess.sendCommandTimeout("decompileAt", timeoutSecs, activeSet);
|
decompProcess.sendCommandTimeout("decompileAt", timeoutSecs, activeSet);
|
||||||
decompileMessage = decompCallback.getNativeMessage();
|
decompileMessage = decompCallback.getNativeMessage();
|
||||||
if (debug != null) {
|
|
||||||
XmlEncode xmlEncode = new XmlEncode();
|
|
||||||
options.encode(xmlEncode, this);
|
|
||||||
debug.shutdown(pcodelanguage, xmlEncode.toString());
|
|
||||||
debug = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
|
decoder.clear(); // Clear any partial result
|
||||||
decompileMessage = "Exception while decompiling " + func.getEntryPoint() + ": " +
|
decompileMessage = "Exception while decompiling " + func.getEntryPoint() + ": " +
|
||||||
ex.getMessage() + '\n';
|
ex.getMessage() + '\n';
|
||||||
}
|
}
|
||||||
|
@ -792,6 +788,17 @@ public class DecompInterface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (debug != null) {
|
||||||
|
XmlEncode xmlEncode = new XmlEncode();
|
||||||
|
options.encode(xmlEncode, this);
|
||||||
|
debug.shutdown(pcodelanguage, xmlEncode.toString());
|
||||||
|
debug = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
Msg.error(debug, "Could not dump debug info");
|
||||||
|
}
|
||||||
DecompileProcess.DisposeState processState;
|
DecompileProcess.DisposeState processState;
|
||||||
if (decompProcess != null) {
|
if (decompProcess != null) {
|
||||||
processState = decompProcess.getDisposeState();
|
processState = decompProcess.getDisposeState();
|
||||||
|
|
|
@ -93,6 +93,12 @@ public class ForceUnionAction extends AbstractDecompilerAction {
|
||||||
if (innerType instanceof Pointer) {
|
if (innerType instanceof Pointer) {
|
||||||
innerType = ((Pointer) innerType).getDataType();
|
innerType = ((Pointer) innerType).getDataType();
|
||||||
}
|
}
|
||||||
|
else if (innerType instanceof PartialUnion) {
|
||||||
|
innerType = ((PartialUnion) innerType).getParent();
|
||||||
|
if (innerType instanceof TypeDef) {
|
||||||
|
innerType = ((TypeDef) innerType).getBaseDataType();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (innerType == unionDt) {
|
if (innerType == unionDt) {
|
||||||
return dt;
|
return dt;
|
||||||
}
|
}
|
||||||
|
@ -168,17 +174,26 @@ public class ForceUnionAction extends AbstractDecompilerAction {
|
||||||
/**
|
/**
|
||||||
* Build a list of all the union field names for the user to select from, when determining
|
* Build a list of all the union field names for the user to select from, when determining
|
||||||
* which data-type to force. Two lists are produced. The first contains every possible
|
* which data-type to force. Two lists are produced. The first contains every possible
|
||||||
* field name. The second list is filtered by the size of the Varnode being forced,
|
* field name. The second list is filtered by the size and offset of the Varnode being forced.
|
||||||
* which must match the size of the selected field data-type.
|
|
||||||
* @param allFields will hold the unfiltered list of names
|
* @param allFields will hold the unfiltered list of names
|
||||||
* @param size is the size of the Varnode to filter on
|
|
||||||
* @return the filtered list of names
|
* @return the filtered list of names
|
||||||
*/
|
*/
|
||||||
private String[] buildFieldOptions(ArrayList<String> allFields, int size) {
|
private String[] buildFieldOptions(ArrayList<String> allFields) {
|
||||||
|
int size = accessVn.getSize();
|
||||||
|
int startOff = 0;
|
||||||
|
boolean exactMatch = true;
|
||||||
|
if (parentDt instanceof Pointer) {
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
if (parentDt instanceof PartialUnion) {
|
||||||
|
startOff = ((PartialUnion) parentDt).getOffset();
|
||||||
|
exactMatch = false;
|
||||||
|
}
|
||||||
|
int endOff = startOff + size;
|
||||||
DataTypeComponent[] components = unionDt.getDefinedComponents();
|
DataTypeComponent[] components = unionDt.getDefinedComponents();
|
||||||
ArrayList<String> res = new ArrayList<>();
|
ArrayList<String> res = new ArrayList<>();
|
||||||
allFields.add("(no field)");
|
allFields.add("(no field)");
|
||||||
if (size == 0 || unionDt.getLength() == size) {
|
if (size == 0 || !exactMatch || size == parentDt.getLength()) {
|
||||||
res.add("(no field)");
|
res.add("(no field)");
|
||||||
}
|
}
|
||||||
for (DataTypeComponent component : components) {
|
for (DataTypeComponent component : components) {
|
||||||
|
@ -187,7 +202,11 @@ public class ForceUnionAction extends AbstractDecompilerAction {
|
||||||
nm = component.getDefaultFieldName();
|
nm = component.getDefaultFieldName();
|
||||||
}
|
}
|
||||||
allFields.add(nm);
|
allFields.add(nm);
|
||||||
if (size == 0 || component.getDataType().getLength() == size) {
|
int compStart = component.getOffset();
|
||||||
|
int compEnd = compStart + component.getLength();
|
||||||
|
|
||||||
|
if (size == 0 || (exactMatch && startOff == compStart && endOff == compEnd) ||
|
||||||
|
(!exactMatch && startOff >= compStart && endOff <= compEnd)) {
|
||||||
res.add(nm);
|
res.add(nm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,12 +225,8 @@ public class ForceUnionAction extends AbstractDecompilerAction {
|
||||||
* @return the index of the selected field or -1 if "no field" was selected
|
* @return the index of the selected field or -1 if "no field" was selected
|
||||||
*/
|
*/
|
||||||
private boolean selectFieldNumber(String defaultFieldName) {
|
private boolean selectFieldNumber(String defaultFieldName) {
|
||||||
int size = 0;
|
|
||||||
if (!(parentDt instanceof Pointer)) {
|
|
||||||
size = accessVn.getSize();
|
|
||||||
}
|
|
||||||
ArrayList<String> allFields = new ArrayList<>();
|
ArrayList<String> allFields = new ArrayList<>();
|
||||||
String[] choices = buildFieldOptions(allFields, size);
|
String[] choices = buildFieldOptions(allFields);
|
||||||
if (choices.length < 2) { // If only one field fits the Varnode
|
if (choices.length < 2) { // If only one field fits the Varnode
|
||||||
OkDialog.show("No Field Choices", "Only one field fits the selected variable");
|
OkDialog.show("No Field Choices", "Only one field fits the selected variable");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -742,7 +742,7 @@ public class HighFunctionDBUtil {
|
||||||
* pieces for building the dynamic LocalVariable. This method clears out any preexisting
|
* pieces for building the dynamic LocalVariable. This method clears out any preexisting
|
||||||
* union facet with the same dynamic hash and firstUseOffset.
|
* union facet with the same dynamic hash and firstUseOffset.
|
||||||
* @param function is the function affected by the union facet
|
* @param function is the function affected by the union facet
|
||||||
* @param dt is the parent data-type, either the union or a pointer to it
|
* @param dt is the parent data-type; a union, a pointer to a union, or a partial union
|
||||||
* @param fieldNum is the ordinal of the desired union field
|
* @param fieldNum is the ordinal of the desired union field
|
||||||
* @param addr is the first use address of the facet
|
* @param addr is the first use address of the facet
|
||||||
* @param hash is the dynamic hash
|
* @param hash is the dynamic hash
|
||||||
|
@ -752,6 +752,9 @@ public class HighFunctionDBUtil {
|
||||||
*/
|
*/
|
||||||
public static void writeUnionFacet(Function function, DataType dt, int fieldNum, Address addr,
|
public static void writeUnionFacet(Function function, DataType dt, int fieldNum, Address addr,
|
||||||
long hash, SourceType source) throws InvalidInputException, DuplicateNameException {
|
long hash, SourceType source) throws InvalidInputException, DuplicateNameException {
|
||||||
|
if (dt instanceof PartialUnion) {
|
||||||
|
dt = ((PartialUnion) dt).getParent();
|
||||||
|
}
|
||||||
int firstUseOffset = (int) addr.subtract(function.getEntryPoint());
|
int firstUseOffset = (int) addr.subtract(function.getEntryPoint());
|
||||||
String symbolName = UnionFacetSymbol.buildSymbolName(fieldNum, addr);
|
String symbolName = UnionFacetSymbol.buildSymbolName(fieldNum, addr);
|
||||||
boolean nameCollision = false;
|
boolean nameCollision = false;
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.program.model.pcode;
|
||||||
|
|
||||||
|
import javax.help.UnsupportedOperationException;
|
||||||
|
|
||||||
|
import ghidra.docking.settings.Settings;
|
||||||
|
import ghidra.docking.settings.SettingsDefinition;
|
||||||
|
import ghidra.program.model.data.*;
|
||||||
|
import ghidra.program.model.mem.MemBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data-type representing an unspecified piece of a parent Union data-type. This is used
|
||||||
|
* internally by the decompiler to label Varnodes representing partial symbols, where the
|
||||||
|
* part is known to be contained in a Union data-type. Within the isolated context of a Varnode,
|
||||||
|
* its not possible to resolve to a specific field of the Union because the Varnode may be used
|
||||||
|
* in multiple ways.
|
||||||
|
*/
|
||||||
|
public class PartialUnion extends AbstractDataType {
|
||||||
|
private DataType unionDataType; // Either a Union or a Typedef of a Union
|
||||||
|
private int offset; // Offset in bytes of partial within parent
|
||||||
|
private int size; // Number of bytes in partial
|
||||||
|
|
||||||
|
PartialUnion(DataTypeManager dtm, DataType parent, int off, int sz) {
|
||||||
|
super(CategoryPath.ROOT, "partialunion", dtm);
|
||||||
|
unionDataType = parent;
|
||||||
|
offset = off;
|
||||||
|
size = sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the Union data-type of which this is a part
|
||||||
|
*/
|
||||||
|
public DataType getParent() {
|
||||||
|
return unionDataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the offset, in bytes, of this part within its parent Union
|
||||||
|
*/
|
||||||
|
public int getOffset() {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataType clone(DataTypeManager dtm) {
|
||||||
|
// Internal to the PcodeDataTypeManager
|
||||||
|
throw new UnsupportedOperationException("may not be cloned");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLength() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Partial Union (internal)";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValue(MemBuffer buf, Settings settings, int length) {
|
||||||
|
return null; // Should not be placed on memory
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
|
||||||
|
return null; // Should not be placed on memory
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SettingsDefinition[] getSettingsDefinitions() {
|
||||||
|
return unionDataType.getSettingsDefinitions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Settings getDefaultSettings() {
|
||||||
|
return unionDataType.getDefaultSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataType copy(DataTypeManager dtm) {
|
||||||
|
// Internal to the PcodeDataTypeManager
|
||||||
|
throw new UnsupportedOperationException("may not be copied");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> getValueClass(Settings settings) {
|
||||||
|
return unionDataType.getValueClass(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEquivalent(DataType dt) {
|
||||||
|
if (dt == null || !(dt instanceof PartialUnion)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
PartialUnion op = (PartialUnion) dt;
|
||||||
|
if (offset != op.offset || size != op.size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return unionDataType.isEquivalent(op.unionDataType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAlignment() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -251,6 +251,13 @@ public class PcodeDataTypeManager {
|
||||||
decoder.closeElement(el);
|
decoder.closeElement(el);
|
||||||
return AbstractFloatDataType.getFloatDataType(size, progDataTypes);
|
return AbstractFloatDataType.getFloatDataType(size, progDataTypes);
|
||||||
}
|
}
|
||||||
|
else if (meta.equals("partunion")) {
|
||||||
|
int size = (int) decoder.readSignedInteger(ATTRIB_SIZE);
|
||||||
|
int offset = (int) decoder.readSignedInteger(ATTRIB_OFFSET);
|
||||||
|
DataType dt = decodeDataType(decoder);
|
||||||
|
decoder.closeElement(el);
|
||||||
|
return new PartialUnion(progDataTypes, dt, offset, size);
|
||||||
|
}
|
||||||
else { // We typically reach here if the decompiler invents a new type
|
else { // We typically reach here if the decompiler invents a new type
|
||||||
// probably an unknown with a non-standard size
|
// probably an unknown with a non-standard size
|
||||||
int size = (int) decoder.readSignedInteger(ATTRIB_SIZE);
|
int size = (int) decoder.readSignedInteger(ATTRIB_SIZE);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue