From e4451fcd49cd047723077f1cbb4fff7bf1f8edaa Mon Sep 17 00:00:00 2001 From: caheckman <48068198+caheckman@users.noreply.github.com> Date: Tue, 16 Nov 2021 12:14:34 -0500 Subject: [PATCH] Refactor TypeStruct and TypeCode restoration --- .../Decompiler/src/decompile/cpp/fspec.hh | 1 - .../src/decompile/cpp/ifacedecomp.cc | 4 +- .../src/decompile/cpp/ifacedecomp.hh | 4 - .../Decompiler/src/decompile/cpp/op.hh | 2 +- .../Decompiler/src/decompile/cpp/printc.cc | 2 +- .../src/decompile/cpp/ruleaction.cc | 12 +- .../src/decompile/cpp/slgh_compile.cc | 1 - .../Decompiler/src/decompile/cpp/subflow.cc | 8 + .../Decompiler/src/decompile/cpp/type.cc | 262 +++++++++++------- .../Decompiler/src/decompile/cpp/type.hh | 53 ++-- 10 files changed, 204 insertions(+), 145 deletions(-) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh index 1264bde081..64ea8e62ec 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh @@ -78,7 +78,6 @@ private: bool isLeftJustified(void) const { return (((flags&force_left_justify)!=0)||(!spaceid->isBigEndian())); } public: ParamEntry(int4 grp) { group=grp; } ///< Constructor for use with restoreXml - ParamEntry(type_metatype t,int4 grp,int4 grpsize,const Address &loc,int4 sz,int4 mnsz,int4 align,bool normalstack); int4 getGroup(void) const { return group; } ///< Get the group id \b this belongs to int4 getGroupSize(void) const { return groupsize; } ///< Get the number of groups occupied by \b this int4 getSize(void) const { return size; } ///< Get the size of the memory range in bytes. diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc index e6e4c745ea..efef7468a8 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc @@ -3212,7 +3212,7 @@ void IfcLoadTestFile::execute(istream &s) *status->optr << filename << " test successfully loaded: " << dcp->conf->getDescription() << endl; } -/// \class IfaceListTestCommands +/// \class IfcListTestCommands /// \brief List all the script commands in the current test: `list test commands` void IfcListTestCommands::execute(istream &s) @@ -3224,7 +3224,7 @@ void IfcListTestCommands::execute(istream &s) } } -/// \class IfcExecuteTestCommands +/// \class IfcExecuteTestCommand /// \brief Execute a specified range of the test script: `execute test command <#>-<#> void IfcExecuteTestCommand::execute(istream &s) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.hh index a5ea99a824..3509f332ed 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.hh @@ -46,10 +46,6 @@ public: CallGraph *cgraph; ///< Call-graph information for the program FunctionTestCollection *testCollection; ///< Executable environment from a datatest - map prototypePieces; - void storePrototypePieces( Funcdata *fd_in, PrototypePieces pp_in ) { prototypePieces.insert(pair(fd_in,pp_in)); } - PrototypePieces findPrototypePieces( Funcdata *fd_in ) { return (*prototypePieces.find(fd_in)).second; } - #ifdef CPUI_RULECOMPILE string experimental_file; // File containing experimental rules #endif diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh index 3aee0f533b..9d65f96397 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh @@ -106,7 +106,7 @@ public: warning = 8, ///< Warning has been generated for this op incidental_copy = 0x10, ///< Treat this as \e incidental for parameter recovery algorithms is_cpool_transformed = 0x20, ///< Have we checked for cpool transforms - stop_propagation = 40 ///< Stop propagation into output from descendants + stop_propagation = 0x40 ///< Stop propagation into output from descendants }; private: TypeOp *opcode; ///< Pointer to class providing behavioral details of the operation diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc index 2b9851dd64..4ba4da1625 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc @@ -1591,7 +1591,7 @@ void PrintC::pushConstant(uintb val,const Datatype *ct, clear(); throw LowlevelError("Cannot have a constant of type void"); case TYPE_PTR: - case TYPE_PTRSTRUCT: + case TYPE_PTRREL: if (option_NULL&&(val==0)) { // A null pointer pushAtom(Atom(nullToken,vartoken,EmitXml::var_color,op,vn)); return; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc index 1ab814d28c..4622aa44dc 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc @@ -1859,7 +1859,7 @@ int4 RuleDoubleShift::applyOp(PcodeOp *op,Funcdata &data) } /// \class RuleDoubleArithShift -/// \brief Simplify two sequential INT_SRIGHT: `(x s>> #c) s>> #d => x s>> saturate(#c + #d)` +/// \brief Simplify two sequential INT_SRIGHT: `(x s>> c) s>> d => x s>> saturate(c + d)` /// /// Division optimization in particular can produce a sequence of signed right shifts. /// The shift amounts add up to the point where the sign bit has saturated the entire result. @@ -5300,8 +5300,8 @@ Varnode *RuleSLess2Zero::getHiBit(PcodeOp *op) /// Forms include: /// - `0 s< V * -1 => V s< 0` /// - `V * -1 s< 0 => 0 s< V` -/// - `-1 s< SUB(V,#hi) => -1 s< V` -/// - `SUB(V,#hi) s< 0 => V s< 0` +/// - `-1 s< SUB(V,hi) => -1 s< V` +/// - `SUB(V,hi) s< 0 => V s< 0` /// - `-1 s< ~V => V s< 0` /// - `~V s< 0 => -1 s< V` /// - `(V & 0xf000) s< 0 => V s< 0` @@ -7171,9 +7171,9 @@ int4 RuleDivTermAdd2::applyOp(PcodeOp *op,Funcdata &data) /// \brief Check for INT_(S)RIGHT and/or SUBPIECE followed by INT_MULT /// /// Look for the forms: -/// - `sub(ext(X) * #y,#c)` or -/// - `sub(ext(X) * #y,#c) >> n` or -/// - `(ext(X) * #y) >> n` +/// - `sub(ext(X) * y,c)` or +/// - `sub(ext(X) * y,c) >> n` or +/// - `(ext(X) * y) >> n` /// /// Looks for truncation/multiplication consistent with an optimized division. The /// truncation can come as either a SUBPIECE operation and/or right shifts. diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc index 45ccc9225b..40d775b2db 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc @@ -1512,7 +1512,6 @@ bool ConsistencyChecker::testSizeRestrictions(void) /// Update truncated Varnodes given complete size information. Print errors /// for any invalid truncation constructions. -/// \param isbigendian is \b true if the SLEIGH spec is big endian /// \return \b true if there are no invalid truncations bool ConsistencyChecker::testTruncations(void) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.cc index 9c4d872f9c..9b001103b5 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/subflow.cc @@ -997,6 +997,7 @@ bool SubvariableFlow::createCompareBridge(PcodeOp *op,ReplaceVarnode *inrvn,int4 /// \param mask is the set of bits holding the logical value (within a bigger value) /// \param slot is the input slot to the operation /// \param constvn is the original constant +/// \return the new constant variable node SubvariableFlow::ReplaceVarnode *SubvariableFlow::addConstant(ReplaceOp *rop,uintb mask, uint4 slot,Varnode *constvn) { @@ -1018,6 +1019,13 @@ SubvariableFlow::ReplaceVarnode *SubvariableFlow::addConstant(ReplaceOp *rop,uin return res; } +/// \brief Add a new constant variable node as an input to a logical operation. +/// +/// The constant is new and isn't associated with a constant in the original graph. +/// \param rop is the logical operation taking the constant as input +/// \param slot is the input slot to the operation +/// \param val is the constant value +/// \return the new constant variable node SubvariableFlow::ReplaceVarnode *SubvariableFlow::addNewConstant(ReplaceOp *rop,uint4 slot,uintb val) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc index 885231d4a5..78a60526b2 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc @@ -16,6 +16,8 @@ #include "type.hh" #include "funcdata.hh" +/// The base propagation ordering associated with each meta-type. +/// The array elements correspond to the ordering of #type_metatype. sub_metatype Datatype::base2sub[13] = { SUB_STRUCT, SUB_PARTIALSTRUCT, SUB_ARRAY, SUB_PTRREL, SUB_PTR, SUB_FLOAT, SUB_CODE, SUB_BOOL, SUB_UINT_PLAIN, SUB_INT_PLAIN, SUB_UNKNOWN, SUB_SPACEBASE, SUB_VOID @@ -176,8 +178,8 @@ void metatype2string(type_metatype metatype,string &res) case TYPE_PTR: res = "ptr"; break; - case TYPE_PTRSTRUCT: - res = "ptrstruct"; + case TYPE_PTRREL: + res = "ptrrel"; break; case TYPE_ARRAY: res = "array"; @@ -226,8 +228,8 @@ type_metatype string2metatype(const string &metastring) return TYPE_PTR; else if (metastring=="part") return TYPE_PARTIALSTRUCT; - else if (metastring=="ptrstruct") - return TYPE_PTRSTRUCT; + else if (metastring=="ptrrel") + return TYPE_PTRREL; break; case 'a': if (metastring=="array") @@ -412,15 +414,6 @@ void Datatype::restoreXmlBasic(const Element *el) } } -/// Restore a Datatype object from an XML element -/// \param el is the XML element -/// \param typegrp is the underlying TypeFactory that will hold the new object -void Datatype::restoreXml(const Element *el,TypeFactory &typegrp) - -{ - restoreXmlBasic(el); -} - /// If a type id is explicitly provided for a data-type, this routine is used /// to produce an id based on a hash of the name. IDs produced this way will /// have their sign-bit set to distinguish it from other IDs. @@ -456,6 +449,9 @@ uint8 Datatype::hashSize(uint8 id,int4 size) return id; } +/// Parse a \ tag for attributes of the character data-type +/// \param el is the root XML element +/// \param typegrp is the factory owning \b this data-type void TypeChar::restoreXml(const Element *el,TypeFactory &typegrp) { @@ -489,6 +485,9 @@ void TypeUnicode::setflags(void) flags |= Datatype::chartype; // This ultimately should be UTF8 but we default to basic char } +/// Parse a \ tag for properties of the data-type +/// \param el is the root XML element +/// \param typegrp is the factory owning \b this data-type void TypeUnicode::restoreXml(const Element *el,TypeFactory &typegrp) { @@ -577,6 +576,9 @@ void TypePointer::saveXml(ostream &s) const s << ""; } +/// Parse a \ tag with a child describing the data-type being pointed to +/// \param el is the root XML element +/// \param typegrp is the factory owning \b this data-type void TypePointer::restoreXml(const Element *el,TypeFactory &typegrp) { @@ -598,7 +600,7 @@ void TypePointer::calcSubmeta(void) { if (ptrto->getMetatype() == TYPE_STRUCT) { - if (ptrto->numDepend() > 1 || ptrto->isIncompleteStruct()) + if (ptrto->numDepend() > 1 || ptrto->isIncomplete()) submeta = SUB_PTR_STRUCT; else submeta = SUB_PTR; @@ -745,6 +747,9 @@ void TypeArray::saveXml(ostream &s) const s << ""; } +/// Parse a \ tag with a child describing the array element data-type. +/// \param el is the root XML element +/// \param typegrp is the factory owning \b this data-type void TypeArray::restoreXml(const Element *el,TypeFactory &typegrp) { @@ -925,6 +930,9 @@ void TypeEnum::saveXml(ostream &s) const s << ""; } +/// Parse a \ tag with children describing each specific enumeration value. +/// \param el is the root XML element +/// \param typegrp is the factory owning \b this data-type void TypeEnum::restoreXml(const Element *el,TypeFactory &typegrp) { @@ -1198,10 +1206,12 @@ void TypeStruct::saveXml(ostream &s) const s << ""; } -void TypeStruct::restoreXml(const Element *el,TypeFactory &typegrp) +/// Children of the structure element describe each field. +/// \param el is the root structure element +/// \param typegrp is the factory owning the new structure +void TypeStruct::restoreFields(const Element *el,TypeFactory &typegrp) { - restoreXmlBasic(el); const List &list(el->getChildren()); List::const_iterator iter; int4 maxoffset = 0; @@ -1224,11 +1234,14 @@ void TypeStruct::restoreXml(const Element *el,TypeFactory &typegrp) if (maxoffset > size) throw LowlevelError("Size too small for fields of structure "+name); if (size == 0) // We can restore an incomplete structure, indicated by 0 size - flags |= struct_incomplete; + flags |= type_incomplete; else - flags &= ~(uint4)struct_incomplete; // Otherwise the structure is complete + markComplete(); // Otherwise the structure is complete } +/// Parse a \ tag with children describing the data-type being pointed to and the parent data-type. +/// \param el is the root XML element +/// \param typegrp is the factory owning \b this data-type void TypePointerRel::restoreXml(const Element *el,TypeFactory &typegrp) { @@ -1284,7 +1297,7 @@ void TypePointerRel::saveXml(ostream &s) const { s << "\n"; @@ -1349,9 +1362,9 @@ Datatype *TypePointerRel::getPtrTo(Datatype *base,int4 off,TypeFactory &typegrp) /// \param intypes is the list of input parameters /// \param dotdotdot is true if the prototype takes variable arguments /// \param voidtype is the reference "void" data-type -void TypeCode::set(TypeFactory *tfact,ProtoModel *model, - Datatype *outtype,const vector &intypes, - bool dotdotdot,Datatype *voidtype) +void TypeCode::setPrototype(TypeFactory *tfact,ProtoModel *model, + Datatype *outtype,const vector &intypes, + bool dotdotdot,Datatype *voidtype) { factory = tfact; flags |= variable_length; @@ -1373,6 +1386,24 @@ void TypeCode::set(TypeFactory *tfact,ProtoModel *model, proto->setOutputLock(true); } +/// The prototype is copied in. +/// \param typegrp is the factory owning \b this +/// \param fp is the prototype to set (may be null) +void TypeCode::setPrototype(TypeFactory *typegrp,const FuncProto *fp) + +{ + if (proto != (FuncProto *)0) { + delete proto; + proto = (FuncProto *)0; + factory = (TypeFactory *)0; + } + if (fp != (const FuncProto *)0) { + factory = typegrp; + proto = new FuncProto(); + proto->copy(*fp); + } +} + TypeCode::TypeCode(const TypeCode &op) : Datatype(op) { @@ -1384,11 +1415,12 @@ TypeCode::TypeCode(const TypeCode &op) : Datatype(op) } } -TypeCode::TypeCode(const string &nm) : Datatype(1,TYPE_CODE,nm) +TypeCode::TypeCode(void) : Datatype(1,TYPE_CODE) { proto = (FuncProto *)0; factory = (TypeFactory *)0; + flags |= type_incomplete; } TypeCode::~TypeCode(void) @@ -1408,17 +1440,6 @@ void TypeCode::printRaw(ostream &s) const s << "()"; } -/// Assuming \b this has an underlying function prototype, set some of its boolean properties -/// \param isConstructor toggles whether the function is a constructor -/// \param isDestructor toggles whether the function is a destructor -void TypeCode::setProperties(bool isConstructor,bool isDestructor) - -{ - proto->setConstructor(isConstructor); - proto->setDestructor(isDestructor); -} - - /// Compare basic characteristics of \b this with another TypeCode, not including the prototype /// - -1 or 1 if -this- and -op- are different in surface characteristics /// - 0 if they are exactly equal and have no parameters @@ -1540,27 +1561,38 @@ void TypeCode::saveXml(ostream &s) const s << ""; } -void TypeCode::restoreXml(const Element *el,TypeFactory &typegrp) +/// \param el is the root XML element describing the code object +void TypeCode::restoreStub(const Element *el) + +{ + if (!el->getChildren().empty()) { + // Traditionally a tag implies variable length, without a "varlength" attribute + flags |= variable_length; + } + restoreXmlBasic(el); +} + +/// A single child element indicates a full function prototype. +/// \param el is the root XML tag describing the code object +/// \param isConstructor is \b true if the prototype is a constructor +/// \param isDestructor is \b true if the prototype is a destructor +/// \param typegrp is the factory owning the code object +void TypeCode::restorePrototype(const Element *el,bool isConstructor,bool isDestructor,TypeFactory &typegrp) { const List &list(el->getChildren()); List::const_iterator iter; iter = list.begin(); if (iter != list.end()) { - // Traditionally a tag implies variable length, without a "varlength" attribute - flags |= variable_length; + Architecture *glb = typegrp.getArch(); + factory = &typegrp; + proto = new FuncProto(); + proto->setInternal( glb->defaultfp, typegrp.getTypeVoid() ); + proto->restoreXml(*iter,glb); + proto->setConstructor(isConstructor); + proto->setDestructor(isDestructor); } - restoreXmlBasic(el); - if (proto != (FuncProto *)0) { - delete proto; - proto = (FuncProto *)0; - } - if (iter == list.end()) return; // No underlying prototype - Architecture *glb = typegrp.getArch(); - factory = &typegrp; - proto = new FuncProto(); - proto->setInternal( glb->defaultfp, typegrp.getTypeVoid() ); - proto->restoreXml(*iter,glb); + markComplete(); } /// This data-type can index either a local or the global scope @@ -1718,6 +1750,9 @@ void TypeSpacebase::saveXml(ostream &s) const s << ""; } +/// Parse the \ tag. +/// \param el is the root XML element +/// \param typegrp is the factory owning \b this data-type void TypeSpacebase::restoreXml(const Element *el,TypeFactory &typegrp) { @@ -2036,7 +2071,7 @@ bool TypeFactory::setFields(vector &fd,TypeStruct *ot,int4 fixedsize, { int4 offset,cursize,curalign; - if (!ot->isIncompleteStruct()) + if (!ot->isIncomplete()) throw LowlevelError("Can only set fields on an incomplete structure"); offset = 0; vector::iterator iter; @@ -2078,8 +2113,8 @@ bool TypeFactory::setFields(vector &fd,TypeStruct *ot,int4 fixedsize, tree.erase(ot); ot->setFields(fd); - ot->flags &= ~(uint4)Datatype::struct_incomplete; - ot->flags |= (flags & (Datatype::opaque_string | Datatype::variable_length | Datatype::struct_incomplete)); + ot->flags &= ~(uint4)Datatype::type_incomplete; + ot->flags |= (flags & (Datatype::opaque_string | Datatype::variable_length | Datatype::type_incomplete)); if (fixedsize > 0) { // If the caller is trying to force a size if (fixedsize > ot->size) // If the forced size is bigger than the size required for fields ot->size = fixedsize; // Force the bigger size @@ -2092,6 +2127,23 @@ bool TypeFactory::setFields(vector &fd,TypeStruct *ot,int4 fixedsize, return true; } +/// The given prototype is copied into the given code data-type +/// This method should only be used on an incomplete TypeCode. It will mark the TypeCode as complete. +/// \param fp is the given prototype to copy +/// \param newCode is the given code data-type +/// \param flags are additional flags to transfer into the code data-type +void TypeFactory::setPrototype(const FuncProto *fp,TypeCode *newCode,uint4 flags) + +{ + if (!newCode->isIncomplete()) + throw LowlevelError("Can only set prototype on incomplete data-type"); + tree.erase(newCode); + newCode->setPrototype(this,fp); + newCode->flags &= ~(uint4)Datatype::type_incomplete; + newCode->flags |= (flags & (Datatype::variable_length | Datatype::type_incomplete)); + tree.insert(newCode); +} + /// Set the list of enumeration values and identifiers for a TypeEnum /// Fill in any values for any names that weren't explicitly assigned /// and check for duplicates. @@ -2284,7 +2336,8 @@ TypeCode *TypeFactory::getTypeCode(void) Datatype *ct = typecache[1][TYPE_CODE-TYPE_FLOAT]; if (ct != (Datatype *)0) return (TypeCode *)ct; - TypeCode tmp(""); + TypeCode tmp; // A generic code object + tmp.markComplete(); // which is considered complete return (TypeCode *) findAdd(tmp); } @@ -2296,8 +2349,10 @@ TypeCode *TypeFactory::getTypeCode(const string &nm) { if (nm.size()==0) return getTypeCode(); - TypeCode tmp(nm); + TypeCode tmp; // Generic code data-type + tmp.name = nm; // with a name tmp.id = Datatype::hashName(nm); + tmp.markComplete(); // considered complete return (TypeCode *) findAdd(tmp); } @@ -2445,7 +2500,8 @@ TypeStruct *TypeFactory::getTypeStruct(const string &n) { // We should probably strip offsets here // But I am currently choosing not to - TypeStruct tmp(n); + TypeStruct tmp; + tmp.name = n; tmp.id = Datatype::hashName(n); return (TypeStruct *) findAdd(tmp); } @@ -2483,8 +2539,9 @@ TypeCode *TypeFactory::getTypeCode(ProtoModel *model,Datatype *outtype, const vector &intypes, bool dotdotdot) { - TypeCode tc(""); // getFuncdata type with no name - tc.set(this,model,outtype,intypes,dotdotdot,getTypeVoid()); + TypeCode tc; // getFuncdata type with no name + tc.setPrototype(this,model,outtype,intypes,dotdotdot,getTypeVoid()); + tc.markComplete(); return (TypeCode *) findAdd(tc); } @@ -2609,10 +2666,7 @@ Datatype *TypeFactory::restoreXmlTypeWithCodeFlags(const Element *el,bool isCons const Element *subel = *iter; if (subel->getAttributeValue("metatype") != "code") throw LowlevelError("Special type restoreXml does not see code"); - TypeCode tc(""); - tc.restoreXml(subel,*this); - tc.setProperties(isConstructor,isDestructor); // Add in flags - tp.ptrto = findAdd(tc); // THEN add to container + tp.ptrto = restoreCode(subel, isConstructor, isDestructor, false); return findAdd(tp); } @@ -2701,49 +2755,27 @@ Datatype *TypeFactory::restoreTypedef(const Element *el) return getTypedef(defedType, nm, id); } +/// If necessary create a stub object before parsing the field descriptions, to deal with recursive definitions +/// \param el is the XML element describing the structure +/// \param forcecore is \b true if the data-type is considered core +/// \return the newly minted structure data-type Datatype* TypeFactory::restoreStruct(const Element *el,bool forcecore) { - string structname = el->getAttributeValue("name"); - TypeStruct ts(structname); - int4 num = el->getNumAttributes(); - uint8 newid = 0; - int4 structsize = 0; - bool isVarLength = false; - for(int4 i = 0;i < num;++i) { - const string &attribName(el->getAttributeName(i)); - if (attribName == "id") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> newid; - } - else if (attribName == "size") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> structsize; - } - else if (attribName == "varlength") { - isVarLength = xml_readbool(el->getAttributeValue(i)); - } - } - if (newid == 0) - newid = Datatype::hashName(structname); - if (isVarLength) - newid = Datatype::hashSize(newid,structsize); - Datatype *ct = findByIdLocal(structname,newid); + TypeStruct ts; + ts.restoreXmlBasic(el); + if (forcecore) + ts.flags |= Datatype::coretype; + Datatype *ct = findByIdLocal(ts.name,ts.id); if (ct == (Datatype*)0) { - ts.id = newid; - ts.size = structsize; // Include size if we have it, so arrays can be defined without knowing struct fields ct = findAdd(ts); // Create stub to allow recursive definitions } else if (ct->getMetatype() != TYPE_STRUCT) - throw LowlevelError("Trying to redefine type: " + structname); - ts.restoreXml(el,*this); - if (forcecore) - ts.flags |= Datatype::coretype; - if (!ct->isIncompleteStruct()) { // Structure of this name was already present + throw LowlevelError("Trying to redefine type: " + ts.name); + ts.restoreFields(el,*this); + if (!ct->isIncomplete()) { // Structure of this name was already present if (0 != ct->compareDependency(ts)) - throw LowlevelError("Redefinition of structure: " + structname); + throw LowlevelError("Redefinition of structure: " + ts.name); } else { // If structure is a placeholder stub if (!setFields(ts.field,(TypeStruct*)ct,ts.size,ts.flags)) // Define structure now by copying fields @@ -2752,6 +2784,36 @@ Datatype* TypeFactory::restoreStruct(const Element *el,bool forcecore) return ct; } +/// If necessary create a stub object before parsing the prototype description, to deal with recursive definitions +/// \param el is the XML element describing the code object +/// \param isConstructor is \b true if any prototype should be treated as a constructor +/// \param isDestructor is \b true if any prototype should be treated as a destructor +/// \param forcecore is \b true if the data-type is considered core +/// \return the newly minted code data-type +Datatype *TypeFactory::restoreCode(const Element *el,bool isConstructor,bool isDestructor,bool forcecore) + +{ + TypeCode tc; + tc.restoreStub(el); + if (forcecore) + tc.flags |= Datatype::coretype; + Datatype *ct = findByIdLocal(tc.name,tc.id); + if (ct == (Datatype *)0) { + ct = findAdd(tc); // Create stub to allow recursive definitions + } + else if (ct->getMetatype() != TYPE_CODE) + throw LowlevelError("Trying to redefine type: " + tc.name); + tc.restorePrototype(el, isConstructor, isDestructor, *this); + if (!ct->isIncomplete()) { // Code data-type of this name was already present + if (0 != ct->compareDependency(tc)) + throw LowlevelError("Redefinition of code data-type: " + tc.name); + } + else { // If there was a placeholder stub + setPrototype(tc.proto, (TypeCode *)ct, tc.flags); + } + return ct; +} + /// Restore a Datatype object from an XML \ tag. (Don't use for \ tags) /// The new Datatype is added to \b this container /// \param el is the XML element @@ -2804,13 +2866,7 @@ Datatype *TypeFactory::restoreXmlTypeNoRef(const Element *el,bool forcecore) } break; case TYPE_CODE: - { - TypeCode tc(""); - tc.restoreXml(el,*this); - if (forcecore) - tc.flags |= Datatype::coretype; - ct = findAdd(tc); - } + ct = restoreCode(el,false, false, forcecore); break; default: for(int4 i=0;igetNumAttributes();++i) { @@ -2844,7 +2900,7 @@ Datatype *TypeFactory::restoreXmlTypeNoRef(const Element *el,bool forcecore) } { TypeBase tb(0,TYPE_UNKNOWN); - tb.restoreXml(el,*this); + tb.restoreXmlBasic(el); if (forcecore) tb.flags |= Datatype::coretype; ct = findAdd(tb); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh index eb92e5b13a..2885d18264 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh @@ -27,9 +27,7 @@ extern void print_data(ostream &s,uint1 *buffer,int4 size,const Address &baseadd //extern bool print_string(ostream &s,uint1 *buffer,int4 size); /// The core meta-types supported by the decompiler. These are sizeless templates -/// for the elements making up the type algebra. Ordering is important: The lower -/// the number, the more \b specific the type, in calculations involving the generality -/// of a type. +/// for the elements making up the type algebra. enum type_metatype { TYPE_VOID = 12, ///< Standard "void" type, absence of type TYPE_SPACEBASE = 11, ///< Placeholder for symbol/type look-up calculations @@ -41,12 +39,14 @@ enum type_metatype { TYPE_FLOAT = 5, ///< Floating-point TYPE_PTR = 4, ///< Pointer data-type - TYPE_PTRSTRUCT = 3, ///< Pointer into a structure data-type (specialization of TYPE_PTR) + TYPE_PTRREL = 3, ///< Pointer relative to another 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 }; +/// 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. enum sub_metatype { SUB_VOID = 20, ///< Compare as a TYPE_VOID SUB_SPACEBASE = 19, ///< Compare as a TYPE_SPACEBASE @@ -104,7 +104,7 @@ protected: 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 + type_incomplete = 0x400, ///< Set if \b this (recursive) data-type has not been fully defined yet }; friend class TypeFactory; friend struct DatatypeCompare; @@ -118,7 +118,7 @@ protected: void restoreXmlBasic(const Element *el); ///< Recover basic data-type properties void saveXmlBasic(type_metatype meta,ostream &s) const; ///< Save basic data-type properties void saveXmlTypedef(ostream &s) const; ///< Write \b this as a \e typedef tag to stream - virtual void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore data-type from XML + void markComplete(void) { flags &= ~(uint4)type_incomplete; } ///< Mark \b this data-type as completely defined virtual Datatype *clone(void) const=0; ///< Clone the data-type static uint8 hashName(const string &nm); ///< Produce a data-type id by hashing the type name static uint8 hashSize(uint8 id,int4 size); ///< Reversibly hash size into id @@ -128,8 +128,6 @@ public: id=op.id; typedefImm=op.typedefImm; } /// Construct the base data-type providing size and meta-type Datatype(int4 s,type_metatype m) { size=s; metatype=m; submeta=base2sub[m]; flags=0; id=0; typedefImm=(Datatype *)0; } - /// Construct the base data-type providing size, meta-type, and name - Datatype(int4 s,type_metatype m,const string &n) { name=n; size=s; metatype=m; submeta=base2sub[m]; flags=0; id=0; typedefImm=(Datatype *)0; } virtual ~Datatype(void) {} ///< Destructor bool isCoreType(void) const { return ((flags&coretype)!=0); } ///< Is this a core data-type bool isCharPrint(void) const { return ((flags&(chartype|utf16|utf32|opaque_string))!=0); } ///< Does this print as a 'char' @@ -144,7 +142,7 @@ public: 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 + bool isIncomplete(void) const { return (flags & type_incomplete)!=0; } ///< Is \b this an incompletely defined data-type uint4 getInheritable(void) const { return (flags & coretype); } ///< Get properties pointers inherit type_metatype getMetatype(void) const { return metatype; } ///< Get the type \b meta-type sub_metatype getSubMeta(void) const { return submeta; } ///< Get the \b sub-metatype @@ -213,7 +211,7 @@ public: /// Construct TypeBase from a size and meta-type TypeBase(int4 s,type_metatype m) : Datatype(s,m) {} /// Construct TypeBase from a size, meta-type, and name - TypeBase(int4 s,type_metatype m,const string &n) : Datatype(s,m,n) {} + TypeBase(int4 s,type_metatype m,const string &n) : Datatype(s,m) { name = n; } virtual Datatype *clone(void) const { return new TypeBase(*this); } }; @@ -223,7 +221,7 @@ public: class TypeChar : public TypeBase { protected: friend class TypeFactory; - virtual void restoreXml(const Element *el,TypeFactory &typegrp); + void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore \b this char data-type from an XML element public: /// Construct TypeChar copying properties from another data-type TypeChar(const TypeChar &op) : TypeBase(op) { flags |= Datatype::chartype; } @@ -240,7 +238,7 @@ class TypeUnicode : public TypeBase { // Unicode character type void setflags(void); ///< Set unicode property flags protected: friend class TypeFactory; - virtual void restoreXml(const Element *el,TypeFactory &typegrp); + void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore \b this unicode data-type from an XML element public: TypeUnicode(void) : TypeBase(0,TYPE_INT) {} ///< For use with restoreXml TypeUnicode(const TypeUnicode &op) : TypeBase(op) {} ///< Construct from another TypeUnicode @@ -260,7 +258,7 @@ public: /// Construct from another TypeVoid TypeVoid(const TypeVoid &op) : Datatype(op) { flags |= Datatype::coretype; } /// Constructor - TypeVoid(void) : Datatype(0,TYPE_VOID,"void") { flags |= Datatype::coretype; } + TypeVoid(void) : Datatype(0,TYPE_VOID) { name = "void"; flags |= Datatype::coretype; } virtual Datatype *clone(void) const { return new TypeVoid(*this); } virtual void saveXml(ostream &s) const; }; @@ -271,7 +269,7 @@ protected: friend class TypeFactory; Datatype *ptrto; ///< Type being pointed to uint4 wordsize; ///< What size unit does the pointer address - virtual void restoreXml(const Element *el,TypeFactory &typegrp); + void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore \b this pointer data-type from an XML element void calcSubmeta(void); ///< Calculate specific submeta for \b this pointer /// Internal constructor for use with restoreXml TypePointer(void) : Datatype(0,TYPE_PTR) { ptrto = (Datatype *)0; wordsize=1; } @@ -301,7 +299,7 @@ protected: friend class TypeFactory; Datatype *arrayof; ///< type of which we have an array int4 arraysize; ///< Number of elements in the array - virtual void restoreXml(const Element *el,TypeFactory &typegrp); + void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore \b this array from an XML element /// Internal constructor for restoreXml TypeArray(void) : Datatype(0,TYPE_ARRAY) { arraysize = 0; arrayof = (Datatype *)0; } public: @@ -334,7 +332,7 @@ protected: map namemap; ///< Map from integer to name vector masklist; ///< Masks for each bitfield within the enum void setNameMap(const map &nmap); ///< Establish the value -> name map - virtual void restoreXml(const Element *el,TypeFactory &typegrp); + void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore \b this enum data-type from an XML element public: /// Construct from another TypeEnum TypeEnum(const TypeEnum &op); @@ -361,10 +359,10 @@ protected: void setFields(const vector &fd); ///< Establish fields for \b this int4 getFieldIter(int4 off) const; ///< Get index into field list int4 getLowerBoundField(int4 off) const; ///< Get index of last field before or equal to given offset - virtual void restoreXml(const Element *el,TypeFactory &typegrp); + void restoreFields(const Element *el,TypeFactory &typegrp); ///< Restore fields from XML description public: TypeStruct(const TypeStruct &op); ///< Construct from another TypeStruct - TypeStruct(const string &n) : Datatype(0,TYPE_STRUCT,n) { flags |= struct_incomplete; } ///< Construct incomplete/empty TypeStruct from a name + TypeStruct(void) : Datatype(0,TYPE_STRUCT) { flags |= type_incomplete; } ///< Construct incomplete/empty TypeStruct vector::const_iterator beginField(void) const { return field.begin(); } ///< Beginning of fields vector::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 @@ -391,7 +389,7 @@ protected: 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); + void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore \b this relative pointer data-type from an XML element /// Internal constructor for restoreXml TypePointerRel(void) : TypePointer() { offset = 0; parent = (Datatype *)0; stripped = (TypePointer *)0; submeta = SUB_PTRREL; } public: @@ -429,16 +427,17 @@ protected: friend class TypeFactory; FuncProto *proto; ///< If non-null, this describes the prototype of the underlying function TypeFactory *factory; ///< Factory owning \b this - void set(TypeFactory *tfact,ProtoModel *model, - Datatype *outtype,const vector &intypes, - bool dotdotdot,Datatype *voidtype); ///< Establish a function pointer - virtual void restoreXml(const Element *el,TypeFactory &typegrp); + void setPrototype(TypeFactory *tfact,ProtoModel *model, + Datatype *outtype,const vector &intypes, + bool dotdotdot,Datatype *voidtype); ///< Establish a function pointer + void setPrototype(TypeFactory *typegrp,const FuncProto *fp); ///< Set a particular function prototype on \b this + void restoreStub(const Element *el); ///< Restore stub of data-type without the full prototype + void restorePrototype(const Element *el,bool isConstructor,bool isDestructor,TypeFactory &typegrp); ///< Restore any prototype description public: TypeCode(const TypeCode &op); ///< Construct from another TypeCode - TypeCode(const string &nm); ///< Construct from a name + TypeCode(void); ///< Construct an incomplete TypeCode int4 compareBasic(const TypeCode *op) const; ///< Compare surface characteristics of two TypeCodes const FuncProto *getPrototype(void) const { return proto; } ///< Get the function prototype - void setProperties(bool isConstructor,bool isDestructor); ///< Set additional function properties virtual ~TypeCode(void); virtual void printRaw(ostream &s) const; virtual Datatype *getSubType(uintb off,uintb *newoff) const; @@ -458,7 +457,7 @@ class TypeSpacebase : public Datatype { AddrSpace *spaceid; ///< The address space we are treating as a structure Address localframe; ///< Address of function whose symbol table is indexed (or INVALID for "global") Architecture *glb; ///< Architecture for accessing symbol table - virtual void restoreXml(const Element *el,TypeFactory &typegrp); + void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore \b this spacebase data-type from an XML element public: /// Construct from another TypeSpacebase TypeSpacebase(const TypeSpacebase &op) : Datatype(op) { @@ -496,6 +495,7 @@ class TypeFactory { void orderRecurse(vector &deporder,DatatypeSet &mark,Datatype *ct) const; ///< Write out dependency list Datatype *restoreTypedef(const Element *el); ///< Restore a \ XML tag describing a typedef Datatype *restoreStruct(const Element *el,bool forcecore); ///< Restore a \ XML tag describing a structure + Datatype *restoreCode(const Element *el,bool isConstructor,bool isDestructor,bool forcecore); ///< Restore XML tag describing a code object Datatype *restoreXmlTypeNoRef(const Element *el,bool forcecore); ///< Restore from an XML tag void clearCache(void); ///< Clear the common type cache TypeChar *getTypeChar(const string &n); ///< Create a default "char" type @@ -519,6 +519,7 @@ public: Datatype *findByName(const string &n); ///< Return type of given name Datatype *setName(Datatype *ct,const string &n); ///< Set the given types name bool setFields(vector &fd,TypeStruct *ot,int4 fixedsize,uint4 flags); ///< Set fields on a TypeStruct + void setPrototype(const FuncProto *fp,TypeCode *newCode,uint4 flags); ///< Set the prototype on a TypeCode bool setEnumValues(const vector &namelist, const vector &vallist, const vector &assignlist,