diff --git a/Ghidra/Features/Decompiler/buildNatives.gradle b/Ghidra/Features/Decompiler/buildNatives.gradle index da6bb3a0ff..bba7acf636 100644 --- a/Ghidra/Features/Decompiler/buildNatives.gradle +++ b/Ghidra/Features/Decompiler/buildNatives.gradle @@ -51,6 +51,7 @@ model { source { srcDir "src/decompile/cpp" + include "marshal.cc" include "space.cc" include "float.cc" include "address.cc" @@ -152,6 +153,7 @@ model { source { srcDir "src/decompile/cpp" + include "marshal.cc" include "space.cc" include "float.cc" include "address.cc" diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/Makefile b/Ghidra/Features/Decompiler/src/decompile/cpp/Makefile index 6b22889fd7..3343f54ec5 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/Makefile +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/Makefile @@ -77,7 +77,7 @@ EXTERNAL_CONSOLEEXT_NAMES=$(subst .cc,,$(notdir $(EXTERNAL_CONSOLEEXT_SOURCE))) # The following macros partition all the source files, there should be no overlaps # Some core source files used in all projects -CORE= xml space float address pcoderaw translate opcodes globalcontext +CORE= xml marshal space float address pcoderaw translate opcodes globalcontext # Additional core files for any projects that decompile DECCORE=capability architecture options graph cover block cast typeop database cpool \ comment stringmanage fspec action loadimage grammar varnode op \ diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/action.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/action.hh index de2c30cea5..645c811199 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/action.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/action.hh @@ -128,8 +128,6 @@ public: virtual int4 apply(Funcdata &data)=0; virtual int4 print(ostream &s,int4 num,int4 depth) const; ///< Print a description of this Action to stream virtual void printState(ostream &s) const; ///< Print status to stream - virtual void saveXml(ostream &s) const {} ///< Save specifics of this action to stream - virtual void restoreXml(const Element *el,Funcdata *fd) {} ///< Load specifics of action from XML virtual Action *getSubAction(const string &specify); ///< Retrieve a specific sub-action by name virtual Rule *getSubRule(const string &specify); ///< Retrieve a specific sub-rule by name }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/address.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/address.cc index bd0d84d504..cc56143bde 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/address.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/address.cc @@ -16,6 +16,17 @@ #include "address.hh" #include "translate.hh" +AttributeId ATTRIB_FIRST = AttributeId("first",27); +AttributeId ATTRIB_LAST = AttributeId("last",28); +AttributeId ATTRIB_UNIQ = AttributeId("uniq",29); + +ElementId ELEM_ADDR = ElementId("addr",11); +ElementId ELEM_RANGE = ElementId("range",12); +ElementId ELEM_RANGELIST = ElementId("rangelist",13); +ElementId ELEM_REGISTER = ElementId("register",14); +ElementId ELEM_SEQNUM = ElementId("seqnum",15); +ElementId ELEM_VARNODE = ElementId("varnode",16); + ostream &operator<<(ostream &s,const SeqNum &sq) { @@ -44,27 +55,30 @@ SeqNum::SeqNum(Address::mach_extreme ex) : pc(ex) uniq = (ex == Address::m_minimal) ? 0 : ~((uintm)0); } -void SeqNum::saveXml(ostream &s) const +void SeqNum::encode(Encoder &encoder) const { - s << "saveXmlAttributes(s,pc.getOffset()); - a_v_u(s,"uniq",uniq); - s << "/>"; + encoder.openElement(ELEM_SEQNUM); + pc.getSpace()->encodeAttributes(encoder,pc.getOffset()); + encoder.writeUnsignedInteger(ATTRIB_UNIQ, uniq); + encoder.closeElement(ELEM_SEQNUM); } -SeqNum SeqNum::restoreXml(const Element *el,const AddrSpaceManager *manage) +SeqNum SeqNum::decode(Decoder &decoder,const AddrSpaceManager *manage) { uintm uniq = ~((uintm)0); - Address pc = Address::restoreXml(el,manage); // Recover address - for(int4 i=0;igetNumAttributes();++i) - if (el->getAttributeName(i) == "uniq") { - istringstream s2(el->getAttributeValue(i)); // Recover unique (if present) - s2.unsetf(ios::dec | ios::hex | ios::oct); - s2 >> uniq; + uint4 elemId = decoder.openElement(ELEM_SEQNUM); + Address pc = Address::decode(decoder,manage); // Recover address + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_UNIQ) { + uniq = decoder.readUnsignedInteger(); break; } + } + decoder.closeElement(elemId); return SeqNum(pc,uniq); } @@ -85,16 +99,6 @@ Address::Address(mach_extreme ex) } } -/// \deprecated Convert this to the most basic physical address. -/// This routine is only present for backward compatibility -/// with SLED -void Address::toPhysical(void) - -{ AddrSpace *phys = base->getContain(); - if ((phys != (AddrSpace *)0)&&(base->getType()==IPTR_SPACEBASE)) - base = phys; -} - /// Return \b true if the range starting at \b this extending the given number of bytes /// is contained by the second given range. /// \param sz is the given number of bytes in \b this range @@ -187,29 +191,27 @@ void Address::renormalize(int4 size) { base->getManager()->renormalizeJoinAddress(*this,size); } -/// This is usually used to build an address from an \b \ -/// tag, but it can be used to create an address from any tag -/// with the appropriate attributes +/// This is usually used to decode an address from an \b \ +/// element, but any element can be used if it has the appropriate attributes /// - \e space indicates the address space of the tag /// - \e offset indicates the offset within the space /// /// or a \e name attribute can be used to recover an address /// based on a register name. -/// \param el is the parsed tag +/// \param decoder is the stream decoder /// \param manage is the address space manager for the program /// \return the resulting Address -Address Address::restoreXml(const Element *el,const AddrSpaceManager *manage) +Address Address::decode(Decoder &decoder,const AddrSpaceManager *manage) { VarnodeData var; - var.restoreXml(el,manage); + var.decode(decoder,manage); return Address(var.space,var.offset); } -/// This is usually used to build an address from an \b \ -/// tag, but it can be used to create an address from any tag -/// with the appropriate attributes +/// This is usually used to decode an address from an \b \ +/// element, but any element can be used if it has the appropriate attributes /// - \e space indicates the address space of the tag /// - \e offset indicates the offset within the space /// - \e size indicates the size of an address range @@ -217,20 +219,46 @@ Address Address::restoreXml(const Element *el,const AddrSpaceManager *manage) /// or a \e name attribute can be used to recover an address /// and size based on a register name. If a size is recovered /// it is stored in \e size reference. -/// \param el is the parsed tag +/// \param decoder is the stream decoder /// \param manage is the address space manager for the program /// \param size is the reference to any recovered size /// \return the resulting Address -Address Address::restoreXml(const Element *el,const AddrSpaceManager *manage,int4 &size) +Address Address::decode(Decoder &decoder,const AddrSpaceManager *manage,int4 &size) { VarnodeData var; - var.restoreXml(el,manage); + var.decode(decoder,manage); size = var.size; return Address(var.space,var.offset); } +Range::Range(const RangeProperties &properties,const AddrSpaceManager *manage) + +{ + if (properties.isRegister) { + const Translate *trans = manage->getDefaultCodeSpace()->getTrans(); + const VarnodeData &point(trans->getRegister(properties.spaceName)); + spc = point.space; + first = point.offset; + last = (first-1) + point.size; + return; + } + spc = manage->getSpaceByName(properties.spaceName); + if (spc == (AddrSpace *)0) + throw LowlevelError("Undefined space: "+properties.spaceName); + + if (spc == (AddrSpace *)0) + throw LowlevelError("No address space indicated in range tag"); + first = properties.first; + last = properties.last; + if (!properties.seenLast) { + last = spc->getHighest(); + } + if (first > spc->getHighest() || last > spc->getHighest() || last < first) + throw LowlevelError("Illegal range tag"); +} + /// Get the last address +1, updating the space, or returning /// the extremal address if necessary /// \param manage is used to fetch the next address space @@ -259,48 +287,60 @@ void Range::printBounds(ostream &s) const s << hex << first << '-' << last; } -/// Write this object to a stream as a \ tag. -/// \param s is the output stream -void Range::saveXml(ostream &s) const +/// Encode \b this to a stream as a \ element. +/// \param encoder is the stream encoder +void Range::encode(Encoder &encoder) const { - s << "getName()); - a_v_u(s,"first",first); - a_v_u(s,"last",last); - s << "/>\n"; + encoder.openElement(ELEM_RANGE); + encoder.writeString(ATTRIB_SPACE, spc->getName()); + encoder.writeUnsignedInteger(ATTRIB_FIRST, first); + encoder.writeUnsignedInteger(ATTRIB_LAST, last); + encoder.closeElement(ELEM_RANGE); } -/// Reconstruct this object from an XML \ element -/// \param el is the XML element -/// \param manage is the space manage for recovering AddrSpace objects -void Range::restoreXml(const Element *el,const AddrSpaceManager *manage) +/// Reconstruct this object from a \ or \ element +/// \param decoder is the stream decoder +/// \param manage is the space manager for recovering AddrSpace objects +void Range::decode(Decoder &decoder,const AddrSpaceManager *manage) + +{ + uint4 elemId = decoder.openElement(); + if (elemId != ELEM_RANGE && elemId != ELEM_REGISTER) + throw XmlError("Expecting or element"); + decodeFromAttributes(decoder,manage); + decoder.closeElement(elemId); +} + +/// Reconstruct from attributes that may not be part of a \ element. +/// \param decoder is the stream decoder +/// \param manage is the space manager for recovering AddrSpace objects +void Range::decodeFromAttributes(Decoder &decoder,const AddrSpaceManager *manage) { spc = (AddrSpace *)0; bool seenLast = false; first = 0; last = 0; - for(int4 i=0;igetNumAttributes();++i) { - if (el->getAttributeName(i) == "space") { - spc = manage->getSpaceByName(el->getAttributeValue(i)); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_SPACE) { + string spcname = decoder.readString(); + spc = manage->getSpaceByName(spcname); if (spc == (AddrSpace *)0) - throw LowlevelError("Undefined space: "+el->getAttributeValue(i)); + throw LowlevelError("Undefined space: "+spcname); } - else if (el->getAttributeName(i) == "first") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> first; + else if (attribId == ATTRIB_FIRST) { + first = decoder.readUnsignedInteger(); } - else if (el->getAttributeName(i) == "last") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> last; + else if (attribId == ATTRIB_LAST) { + last = decoder.readUnsignedInteger(); seenLast = true; } - else if (el->getAttributeName(i) == "name") { + else if (attribId == ATTRIB_NAME) { const Translate *trans = manage->getDefaultCodeSpace()->getTrans(); - const VarnodeData &point(trans->getRegister(el->getAttributeValue(i))); + const VarnodeData &point(trans->getRegister(decoder.readString())); spc = point.space; first = point.offset; last = (first-1) + point.size; @@ -316,6 +356,31 @@ void Range::restoreXml(const Element *el,const AddrSpaceManager *manage) throw LowlevelError("Illegal range tag"); } +void RangeProperties::decode(Decoder &decoder) + +{ + uint4 elemId = decoder.openElement(); + if (elemId != ELEM_RANGE && elemId != ELEM_REGISTER) + throw XmlError("Expecting or element"); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_SPACE) + spaceName = decoder.readString(); + else if (attribId == ATTRIB_FIRST) + first = decoder.readUnsignedInteger(); + else if (attribId == ATTRIB_LAST) { + last = decoder.readUnsignedInteger(); + seenLast = true; + } + else if (attribId == ATTRIB_NAME) { + spaceName = decoder.readString(); + isRegister = true; + } + } + decoder.closeElement(elemId); +} + /// Insert a new Range merging as appropriate to maintain the disjoint cover /// \param spc is the address space containing the new range /// \param first is the offset of the first byte in the new range @@ -539,36 +604,33 @@ void RangeList::printBounds(ostream &s) const } } -/// Serialize this object to an XML \ tag -/// \param s is the output stream -void RangeList::saveXml(ostream &s) const +/// Encode \b this as a \ element +/// \param encoder is the stream encoder +void RangeList::encode(Encoder &encoder) const { set::const_iterator iter; - s << "\n"; + encoder.openElement(ELEM_RANGELIST); for(iter=tree.begin();iter!=tree.end();++iter) { - (*iter).saveXml(s); + (*iter).encode(encoder); } - s << "\n"; + encoder.closeElement(ELEM_RANGELIST); } -/// Recover each individual disjoint Range for \b this RangeList as encoded -/// in a \ tag. -/// \param el is the XML element +/// Recover each individual disjoint Range for \b this RangeList. +/// \param decoder is the stream decoder /// \param manage is manager for retrieving address spaces -void RangeList::restoreXml(const Element *el,const AddrSpaceManager *manage) +void RangeList::decode(Decoder &decoder,const AddrSpaceManager *manage) { - const List &list(el->getChildren()); - List::const_iterator iter; - - for(iter=list.begin();iter!=list.end();++iter) { - const Element *subel = *iter; + uint4 elemId = decoder.openElement(ELEM_RANGELIST); + while(decoder.peekElement() != 0) { Range range; - range.restoreXml(subel,manage); + range.decode(decoder,manage); tree.insert(range); } + decoder.closeElement(elemId); } #ifdef UINTB4 diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh index 08ce40ca06..c7a63ca952 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh @@ -30,6 +30,17 @@ class AddrSpaceManager; +extern AttributeId ATTRIB_FIRST; ///< Marshaling attribute "first" +extern AttributeId ATTRIB_LAST; ///< Marshaling attribute "last" +extern AttributeId ATTRIB_UNIQ; ///< Marshaling attribute "uniq" + +extern ElementId ELEM_ADDR; ///< Marshaling element \ +extern ElementId ELEM_RANGE; ///< Marshaling element \ +extern ElementId ELEM_RANGELIST; ///< Marshaling element \ +extern ElementId ELEM_REGISTER; ///< Marshaling element \ +extern ElementId ELEM_SEQNUM; ///< Marshaling element \ +extern ElementId ELEM_VARNODE; ///< Marshaling element \ + /// \brief A low-level machine address for labelling bytes and data. /// /// All data that can be manipulated within the processor reverse @@ -65,7 +76,6 @@ public: int4 read(const string &s); ///< Read in the address from a string AddrSpace *getSpace(void) const; ///< Get the address space uintb getOffset(void) const; ///< Get the address offset - void toPhysical(void); ///< Convert this to a physical address char getShortcut(void) const; ///< Get the shortcut character for the address space Address &operator=(const Address &op2); ///< Copy an address bool operator==(const Address &op2) const; ///< Compare two addresses for equality @@ -82,14 +92,14 @@ public: bool isConstant(void) const; ///< Is this a \e constant \e value void renormalize(int4 size); ///< Make sure there is a backing JoinRecord if \b this is in the \e join space bool isJoin(void) const; ///< Is this a \e join \e value - void saveXml(ostream &s) const; ///< Save this to a stream as an XML tag - void saveXml(ostream &s,int4 size) const; ///< Save this and a size to a stream as an XML tag + void encode(Encoder &encoder) const; ///< Encode \b this to a stream + void encode(Encoder &encoder,int4 size) const; ///< Encode \b this and a size to a stream /// Restore an address from parsed XML - static Address restoreXml(const Element *el,const AddrSpaceManager *manage); + static Address decode(Decoder &decoder,const AddrSpaceManager *manage); /// Restore an address and size from parsed XML - static Address restoreXml(const Element *el,const AddrSpaceManager *manage,int4 &size); + static Address decode(Decoder &decoder,const AddrSpaceManager *manage,int4 &size); }; /// \brief A class for uniquely labelling and comparing PcodeOps @@ -144,16 +154,18 @@ public: return (pc < op2.pc); } - /// Save a SeqNum to a stream as an XML tag - void saveXml(ostream &s) const; + /// Encode a SeqNum to a stream + void encode(Encoder &encoder) const; - /// Restore a SeqNum from parsed XML - static SeqNum restoreXml(const Element *el,const AddrSpaceManager *manage); + /// Decode a SeqNum from a stream + static SeqNum decode(Decoder &decoder,const AddrSpaceManager *manage); - /// Write out a SeqNum to a stream + /// Write out a SeqNum in human readable form to a stream friend ostream &operator<<(ostream &s,const SeqNum &sq); }; +class RangeProperties; + /// \brief A contiguous range of bytes in some address space class Range { friend class RangeList; @@ -169,7 +181,8 @@ public: /// \param l is the offset of the last byte in the range Range(AddrSpace *s,uintb f,uintb l) { spc = s; first = f; last = l; } - Range(void) {} ///< Constructor for use with restoreXml + Range(void) {} ///< Constructor for use with decode + Range(const RangeProperties &properties,const AddrSpaceManager *manage); ///< Construct range out of basic properties AddrSpace *getSpace(void) const { return spc; } ///< Get the address space containing \b this Range uintb getFirst(void) const { return first; } ///< Get the offset of the first byte in \b this Range uintb getLast(void) const { return last; } ///< Get the offset of the last byte in \b this Range @@ -188,8 +201,24 @@ public: return (spc->getIndex() < op2.spc->getIndex()); return (first < op2.first); } void printBounds(ostream &s) const; ///< Print \b this Range to a stream - void saveXml(ostream &s) const; ///< Save \b this Range to an XML stream - void restoreXml(const Element *el,const AddrSpaceManager *manage); ///< Restore \b this from XML stream + void encode(Encoder &encoder) const; ///< Encode \b this Range to a stream + void decode(Decoder &decoder,const AddrSpaceManager *manage); ///< Restore \b this from a stream + void decodeFromAttributes(Decoder &decoder,const AddrSpaceManager *manage); ///< Read \b from attributes on another tag +}; + +/// \brief A partially parsed description of a Range +/// +/// Class that allows \ tags to be parsed, when the address space doesn't yet exist +class RangeProperties { + friend class Range; + string spaceName; ///< Name of the address space containing the range + uintb first; ///< Offset of first byte in the Range + uintb last; ///< Offset of last byte in the Range + bool isRegister; ///< Range is specified a register name + bool seenLast; ///< End of the range is actively specified +public: + RangeProperties(void) { first = 0; last = 0; isRegister = false; seenLast = false; } + void decode(Decoder &decoder); ///< Restore \b this from an XML stream }; /// \brief A disjoint set of Ranges, possibly across multiple address spaces @@ -217,8 +246,8 @@ public: bool inRange(const Address &addr,int4 size) const; ///< Check containment an address range uintb longestFit(const Address &addr,uintb maxsize) const; ///< Find size of biggest Range containing given address void printBounds(ostream &s) const; ///< Print a description of \b this RangeList to stream - void saveXml(ostream &s) const; ///< Write \b this RangeList to an XML stream - void restoreXml(const Element *el,const AddrSpaceManager *manage); ///< Restore \b this RangeList from an XML stream + void encode(Encoder &encoder) const; ///< Encode \b this RangeList to a stream + void decode(Decoder &decoder,const AddrSpaceManager *manage); ///< Decode \b this RangeList from a \ element }; /// Precalculated masks indexed by size @@ -416,27 +445,27 @@ inline bool Address::isJoin(void) const { return (base->getType() == IPTR_JOIN); } -/// Save an \b \ tag corresponding to this address to a +/// Save an \ element corresponding to this address to a /// stream. The exact format is determined by the address space, /// but this generally has a \e space and an \e offset attribute. -/// \param s is the stream being written to -inline void Address::saveXml(ostream &s) const { - s << "saveXmlAttributes(s,offset); - s << "/>"; + base->encodeAttributes(encoder,offset); + encoder.closeElement(ELEM_ADDR); } -/// Save an \b \ tag corresponding to this address to a +/// Encode an \ element corresponding to this address to a /// stream. The tag will also include an extra \e size attribute /// so that it can describe an entire memory range. -/// \param s is the stream being written to +/// \param encoder is the stream encoder /// \param size is the number of bytes in the range -inline void Address::saveXml(ostream &s,int4 size) const { - s << "saveXmlAttributes(s,offset,size); - s << "/>"; + base->encodeAttributes(encoder,offset,size); + encoder.closeElement(ELEM_ADDR); } /// \param addr is the Address to test for containment diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc index 0decce3481..32a96dc184 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc @@ -29,6 +29,47 @@ vector ArchitectureCapability::thelist; const uint4 ArchitectureCapability::majorversion = 4; const uint4 ArchitectureCapability::minorversion = 1; +AttributeId ATTRIB_ADJUSTVMA = AttributeId("adjustvma",30); +AttributeId ATTRIB_ENABLE = AttributeId("enable",31); +AttributeId ATTRIB_GROUP = AttributeId("group",32); +AttributeId ATTRIB_GROWTH = AttributeId("growth",33); +AttributeId ATTRIB_LOADERSYMBOLS = AttributeId("loadersymbols",34); +AttributeId ATTRIB_PARENT = AttributeId("parent",35); +AttributeId ATTRIB_REGISTER = AttributeId("register",36); +AttributeId ATTRIB_REVERSEJUSTIFY = AttributeId("reversejustify",37); +AttributeId ATTRIB_SIGNEXT = AttributeId("signext",38); +AttributeId ATTRIB_STYLE = AttributeId("style",39); + +ElementId ELEM_ADDRESS_SHIFT_AMOUNT = ElementId("address_shift_amount",17); +ElementId ELEM_AGGRESSIVETRIM = ElementId("aggressivetrim",18); +ElementId ELEM_COMPILER_SPEC = ElementId("compiler_spec",19); +ElementId ELEM_DATA_SPACE = ElementId("data_space",20); +ElementId ELEM_DEFAULT_MEMORY_BLOCKS = ElementId("default_memory_blocks",21); +ElementId ELEM_DEFAULT_PROTO = ElementId("default_proto",22); +ElementId ELEM_DEFAULT_SYMBOLS = ElementId("default_symbols",23); +ElementId ELEM_EVAL_CALLED_PROTOTYPE = ElementId("eval_called_prototype",24); +ElementId ELEM_EVAL_CURRENT_PROTOTYPE = ElementId("eval_current_prototype",25); +ElementId ELEM_EXPERIMENTAL_RULES = ElementId("experimental_rules",26); +ElementId ELEM_FLOWOVERRIDELIST = ElementId("flowoverridelist",27); +ElementId ELEM_FUNCPTR = ElementId("funcptr",28); +ElementId ELEM_GLOBAL = ElementId("global",29); +ElementId ELEM_INCIDENTALCOPY = ElementId("incidentalcopy",30); +ElementId ELEM_INFERPTRBOUNDS = ElementId("inferptrbounds",31); +ElementId ELEM_MODELALIAS = ElementId("modelalias",32); +ElementId ELEM_NOHIGHPTR = ElementId("nohighptr",33); +ElementId ELEM_PROCESSOR_SPEC = ElementId("processor_spec",34); +ElementId ELEM_PROGRAMCOUNTER = ElementId("programcounter",35); +ElementId ELEM_PROPERTIES = ElementId("properties",36); +ElementId ELEM_READONLY = ElementId("readonly",37); +ElementId ELEM_REGISTER_DATA = ElementId("register_data",38); +ElementId ELEM_RULE = ElementId("rule",39); +ElementId ELEM_SAVE_STATE = ElementId("save_state",40); +ElementId ELEM_SEGMENTED_ADDRESS = ElementId("segmented_address",41); +ElementId ELEM_SPACEBASE = ElementId("spacebase",42); +ElementId ELEM_SPECEXTENSIONS = ElementId("specextensions",43); +ElementId ELEM_STACKPOINTER = ElementId("stackpointer",44); +ElementId ELEM_VOLATILE = ElementId("volatile",45); + /// This builds a list of just the ArchitectureCapability extensions void ArchitectureCapability::initialize(void) @@ -395,43 +436,41 @@ void Architecture::globalify(void) } } -/// Insert a series of out-of-band flow overrides based on a \ tag. -/// \param el is the XML element -void Architecture::restoreFlowOverride(const Element *el) +/// Insert a series of out-of-band flow overrides based on a \ element. +/// \param decoder is the stream decoder +void Architecture::decodeFlowOverride(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - - for(iter=list.begin();iter!=list.end();++iter) { - const Element *subel = *iter; - const List &sublist(subel->getChildren()); - List::const_iterator subiter = sublist.begin(); - Address funcaddr = Address::restoreXml(*subiter,this); - ++subiter; - Address overaddr = Address::restoreXml(*subiter,this); + uint4 elemId = decoder.openElement(ELEM_FLOWOVERRIDELIST); + for(;;) { + uint4 subId = decoder.openElement(); + if (subId != ELEM_FLOW) break; + string flowType = decoder.readString(ATTRIB_TYPE); + Address funcaddr = Address::decode(decoder,this); + Address overaddr = Address::decode(decoder,this); Funcdata *fd = symboltab->getGlobalScope()->queryFunction(funcaddr); if (fd != (Funcdata *)0) - fd->getOverride().insertFlowOverride(overaddr,Override::stringToType(subel->getAttributeValue("type"))); + fd->getOverride().insertFlowOverride(overaddr,Override::stringToType(flowType)); + decoder.closeElement(subId); } + decoder.closeElement(elemId); } -/// Write the current state of all types, symbols, functions, etc. an XML stream -/// \param s is the output stream -void Architecture::saveXml(ostream &s) const +/// Write the current state of all types, symbols, functions, etc. to a stream. +/// \param encoder is the stream encoder +void Architecture::encode(Encoder &encoder) const { - s << "\n"; - types->saveXml(s); - symboltab->saveXml(s); - context->saveXml(s); - commentdb->saveXml(s); - stringManager->saveXml(s); + encoder.openElement(ELEM_SAVE_STATE); + encoder.writeBool(ATTRIB_LOADERSYMBOLS, loadersymbols_parsed); + types->encode(encoder); + symboltab->encode(encoder); + context->encode(encoder); + commentdb->encode(encoder); + stringManager->encode(encoder); if (!cpool->empty()) - cpool->saveXml(s); - s << "\n"; + cpool->encode(encoder); + encoder.closeElement(ELEM_SAVE_STATE); } /// Read in all the sub-component state from a \ XML tag @@ -440,40 +479,44 @@ void Architecture::saveXml(ostream &s) const void Architecture::restoreXml(DocumentStorage &store) { - const Element *el = store.getTag("save_state"); + const Element *el = store.getTag(ELEM_SAVE_STATE.getName()); if (el == (const Element *)0) throw LowlevelError("Could not find save_state tag"); - if (el->getNumAttributes() != 0) - loadersymbols_parsed = xml_readbool(el->getAttributeValue("loadersymbols")); - else - loadersymbols_parsed = false; - - const List &list(el->getChildren()); - List::const_iterator iter; - - for(iter=list.begin();iter!=list.end();++iter) { - const Element *subel = *iter; - if (subel->getName() == "typegrp") - types->restoreXml(subel); - else if (subel->getName() == "db") - symboltab->restoreXml(subel); - else if (subel->getName() == "context_points") - context->restoreXml(subel,this); - else if (subel->getName() == "commentdb") - commentdb->restoreXml(subel,this); - else if (subel->getName() == "stringmanage") - stringManager->restoreXml(subel,this); - else if (subel->getName() == "constantpool") - cpool->restoreXml(subel,*types); - else if (subel->getName() == "optionslist") - options->restoreXml(subel); - else if (subel->getName() == "flowoverridelist") - restoreFlowOverride(subel); - else if (subel->getName() == "injectdebug") - pcodeinjectlib->restoreDebug(subel); - else - throw LowlevelError("XML error restoring architecture: " + subel->getName()); + XmlDecode decoder(el); + uint4 elemId = decoder.openElement(ELEM_SAVE_STATE); + loadersymbols_parsed = false; + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_LOADERSYMBOLS) + loadersymbols_parsed = decoder.readBool(); } + + for(;;) { + uint4 subId = decoder.peekElement(); + if (subId == 0) break; + if (subId == ELEM_TYPEGRP) + types->decode(decoder); + else if (subId == ELEM_DB) + symboltab->decode(decoder); + else if (subId == ELEM_CONTEXT_POINTS) + context->decode(decoder,this); + else if (subId == ELEM_COMMENTDB) + commentdb->decode(decoder,this); + else if (subId == ELEM_STRINGMANAGE) + stringManager->decode(decoder,this); + else if (subId == ELEM_CONSTANTPOOL) + cpool->decode(decoder,*types); + else if (subId == ELEM_OPTIONSLIST) + options->decode(decoder); + else if (subId == ELEM_FLOWOVERRIDELIST) + decodeFlowOverride(decoder); + else if (subId == ELEM_INJECTDEBUG) + pcodeinjectlib->decodeDebug(decoder); + else + throw LowlevelError("XML error restoring architecture"); + } + decoder.closeElement(elemId); } /// If no better name is available, this method can be used to generate @@ -563,8 +606,10 @@ void Architecture::buildTypegrp(DocumentStorage &store) { const Element *el = store.getTag("coretypes"); types = new TypeFactory(this); // Initialize the object - if (el != (const Element *)0) - types->restoreXmlCoreTypes(el); + if (el != (const Element *)0) { + XmlDecode decoder(el); + types->decodeCoreTypes(decoder); + } else { // Put in the core types types->setCoreType("void",1,TYPE_VOID,false); @@ -715,51 +760,57 @@ void Architecture::cacheAddrSpaceProperties(void) } } -/// Recover information out of a \ tag and build the new Rule object. -/// \param el is the XML element -void Architecture::parseDynamicRule(const Element *el) +/// Recover information out of a \ element and build the new Rule object. +/// \param decoder is the stream decoder +void Architecture::decodeDynamicRule(Decoder &decoder) { - string rulename,groupname,enabled; - for(int4 i=0;igetNumAttributes();++i) { - if (el->getAttributeName(i) == "name") - rulename = el->getAttributeValue(i); - else if (el->getAttributeName(i) == "group") - groupname = el->getAttributeValue(i); - else if (el->getAttributeName(i) == "enable") - enabled = el->getAttributeValue(i); + uint4 elemId = decoder.openElement(ELEM_RULE); + string rulename,groupname; + bool enabled = false; + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_NAME) + rulename = decoder.readString(); + else if (attribId == ATTRIB_GROUP) + groupname = decoder.readString(); + else if (attribId == ATTRIB_ENABLE) + enabled = decoder.readBool(); else - throw LowlevelError("Dynamic rule tag contains unknown attribute: "+el->getAttributeName(i)); + throw LowlevelError("Dynamic rule tag contains illegal attribute"); } if (rulename.size()==0) throw LowlevelError("Dynamic rule has no name"); if (groupname.size()==0) throw LowlevelError("Dynamic rule has no group"); - if (enabled == "false") return; + if (!enabled) return; #ifdef CPUI_RULECOMPILE Rule *dynrule = RuleGeneric::build(rulename,groupname,el->getContent()); extra_pool_rules.push_back(dynrule); #else throw LowlevelError("Dynamic rules have not been enabled for this decompiler"); #endif + decoder.closeElement(elemId); } -/// This handles the \ and \ tags. It builds the +/// This handles the \ and \ elements. It builds the /// ProtoModel object based on the tag and makes it available generally to the decompiler. -/// \param el is the XML tag element +/// \param decoder is the stream decoder /// \return the new ProtoModel object -ProtoModel *Architecture::parseProto(const Element *el) +ProtoModel *Architecture::decodeProto(Decoder &decoder) { ProtoModel *res; - if (el->getName() == "prototype") + uint4 elemId = decoder.peekElement(); + if (elemId == ELEM_PROTOTYPE) res = new ProtoModel(this); - else if (el->getName() == "resolveprototype") + else if (elemId == ELEM_RESOLVEPROTOTYPE) res = new ProtoModelMerged(this); else throw LowlevelError("Expecting or tag"); - res->restoreXml(el); + res->decode(decoder); ProtoModel *other = protoModels[res->getName()]; if (other != (ProtoModel *)0) { @@ -771,18 +822,20 @@ ProtoModel *Architecture::parseProto(const Element *el) return res; } -/// This supports the \ and \ tag. +/// This decodes the \ and \ elements. /// This determines which prototype model to assume when recovering the prototype /// for a \e called function and the \e current function respectively. -/// \param el is the XML element -void Architecture::parseProtoEval(const Element *el) +/// \param decoder is the stream decoder +void Architecture::decodeProtoEval(Decoder &decoder) { - ProtoModel *res = protoModels[ el->getAttributeValue("name") ]; + uint4 elemId = decoder.openElement(); + string modelName = decoder.readString(ATTRIB_NAME); + ProtoModel *res = protoModels[ modelName ]; if (res == (ProtoModel *)0) - throw LowlevelError("Unknown prototype model name: "+el->getAttributeValue("name")); + throw LowlevelError("Unknown prototype model name: "+modelName); - if (el->getName() == "eval_called_prototype") { + if (elemId == ELEM_EVAL_CALLED_PROTOTYPE) { if (evalfp_called != (ProtoModel *)0) throw LowlevelError("Duplicate tag"); evalfp_called = res; @@ -792,50 +845,59 @@ void Architecture::parseProtoEval(const Element *el) throw LowlevelError("Duplicate tag"); evalfp_current = res; } + decoder.closeElement(elemId); } -/// There should be exactly one \ tag that specifies what the +/// There should be exactly one \ element that specifies what the /// default prototype model is. This builds the ProtoModel object and sets it /// as the default. -/// \param el is the XML element -void Architecture::parseDefaultProto(const Element *el) +/// \param decoder is the stream decoder +void Architecture::decodeDefaultProto(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - - for(iter=list.begin();iter!=list.end();++iter) { + uint4 elemId = decoder.openElement(ELEM_DEFAULT_PROTO); + while(decoder.peekElement() != 0) { if (defaultfp != (ProtoModel *)0) throw LowlevelError("More than one default prototype model"); - defaultfp = parseProto(*iter); + defaultfp = decodeProto(decoder); } + decoder.closeElement(elemId); } -/// This handles the \ tag adding an address space (or part of the space) -/// to the global scope. Varnodes in this region will be assumed to be global variables. -/// \param el is the XML element -void Architecture::parseGlobal(const Element *el) +/// Parse a \ element for child \ elements that will be added to the global scope. +/// Ranges are stored in partial form so that elements can be parsed before all address spaces exist. +/// \param decoder is the stream decoder +/// \param rangeProps is where the partially parsed ranges are stored +void Architecture::decodeGlobal(Decoder &decoder,vector &rangeProps) + +{ + uint4 elemId = decoder.openElement(ELEM_GLOBAL); + while(decoder.peekElement() != 0) { + rangeProps.emplace_back(); + rangeProps.back().decode(decoder); + } + decoder.closeElement(elemId); +} + +/// Add a memory range parse from a \ tag to the global scope. +/// Varnodes in this region will be assumed to be global variables. +/// \param props is information about a specific range +void Architecture::addToGlobalScope(const RangeProperties &props) { Scope *scope = symboltab->getGlobalScope(); - const List &list(el->getChildren()); - List::const_iterator iter; - - for(iter=list.begin();iter!=list.end();++iter) { - Range range; - range.restoreXml(*iter,this); - AddrSpace *spc = range.getSpace(); - inferPtrSpaces.push_back(spc); - symboltab->addRange(scope,spc,range.getFirst(),range.getLast()); - if (range.getSpace()->isOverlayBase()) { // If the address space is overlayed - // We need to duplicate the range being marked as global into the overlay space(s) - int4 num = numSpaces(); - for(int4 i=0;iisOverlay()) continue; - if (ospc->getContain() != range.getSpace()) continue; - symboltab->addRange(scope,ospc,range.getFirst(),range.getLast()); - } + Range range(props,this); + AddrSpace *spc = range.getSpace(); + inferPtrSpaces.push_back(spc); + symboltab->addRange(scope,spc,range.getFirst(),range.getLast()); + if (range.getSpace()->isOverlayBase()) { // If the address space is overlayed + // We need to duplicate the range being marked as global into the overlay space(s) + int4 num = numSpaces(); + for(int4 i=0;iisOverlay()) continue; + if (ospc->getContain() != range.getSpace()) continue; + symboltab->addRange(scope,ospc,range.getFirst(),range.getLast()); } } } @@ -858,91 +920,88 @@ void Architecture::addOtherSpace(void) } } -/// This applies info from a \ tag marking a specific region +/// This applies info from a \ element marking a specific region /// of the executable as \e read-only. -/// \param el is the XML element -void Architecture::parseReadOnly(const Element *el) +/// \param decoder is the stream decoder +void Architecture::decodeReadOnly(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - - for(iter=list.begin();iter!=list.end();++iter) { + uint4 elemId = decoder.openElement(ELEM_READONLY); + while(decoder.peekElement() != 0) { Range range; - range.restoreXml(*iter,this); + range.decode(decoder,this); symboltab->setPropertyRange(Varnode::readonly,range); } + decoder.closeElement(elemId); } -/// This applies info from a \ tag marking specific regions +/// This applies info from a \ element marking specific regions /// of the executable as holding \e volatile memory or registers. -/// \param el is the XML element -void Architecture::parseVolatile(const Element *el) +/// \param decoder is the stream decoder +void Architecture::decodeVolatile(Decoder &decoder) { - userops.parseVolatile(el,this); - const List &list(el->getChildren()); - List::const_iterator iter; - - for(iter=list.begin();iter!=list.end();++iter) { + uint4 elemId = decoder.openElement(ELEM_VOLATILE); + userops.decodeVolatile(decoder,this); + while(decoder.peekElement() != 0) { Range range; - range.restoreXml(*iter,this); // Tag itself is range + range.decode(decoder,this); // Tag itself is range symboltab->setPropertyRange(Varnode::volatil,range); } + decoder.closeElement(elemId); } -/// This applies info from \ tag and sets the default +/// This applies info from \ element and sets the default /// storage location for the \e return \e address of a function. -/// \param el is the XML element -void Architecture::parseReturnAddress(const Element *el) +/// \param decoder is the stream decoder +void Architecture::decodeReturnAddress(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - - iter = list.begin(); - if (iter == list.end()) return; - if (defaultReturnAddr.space != (AddrSpace *)0) - throw LowlevelError("Multiple tags in .cspec"); - defaultReturnAddr.restoreXml(*iter,this); + uint4 elemId = decoder.openElement(ELEM_RETURNADDRESS); + uint4 subId = decoder.peekElement(); + if (subId != 0) { + if (defaultReturnAddr.space != (AddrSpace *)0) + throw LowlevelError("Multiple tags in .cspec"); + defaultReturnAddr.decode(decoder,this); + } + decoder.closeElement(elemId); } -/// Apply information from an \ tag, which marks a set of addresses +/// Apply information from an \ element, which marks a set of addresses /// as being copied to incidentally. This allows the decompiler to ignore certain side-effects. -/// \param el is the XML element -void Architecture::parseIncidentalCopy(const Element *el) +/// \param decoder is the stream decoder +void Architecture::decodeIncidentalCopy(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - - for(iter=list.begin();iter!=list.end();++iter) { + uint4 elemId = decoder.openElement(ELEM_INCIDENTALCOPY); + while(decoder.peekElement() != 0) { VarnodeData vdata; - vdata.restoreXml(*iter,this); + vdata.decode(decoder,this); Range range( vdata.space, vdata.offset, vdata.offset+vdata.size-1); symboltab->setPropertyRange(Varnode::incidental_copy,range); } + decoder.closeElement(elemId); } -/// Look for \ tags that have a \e vector_lane_size attribute. +/// Look for \ elements that have a \e vector_lane_size attribute. /// Record these so that the decompiler can split large registers into appropriate lane size pieces. -/// \param el is the XML element -void Architecture::parseLaneSizes(const Element *el) +/// \param decoder is the stream decoder +void Architecture::decodeLaneSizes(Decoder &decoder) { vector maskList; - const List &childList(el->getChildren()); - List::const_iterator iter; - LanedRegister lanedRegister; // Only allocate once - for(iter=childList.begin();iter!=childList.end();++iter) { - if (lanedRegister.restoreXml(*iter, this)) { + + uint4 elemId = decoder.openElement(ELEM_REGISTER_DATA); + while(decoder.peekElement() != 0) { + if (lanedRegister.decode(decoder, this)) { int4 sizeIndex = lanedRegister.getWholeSize(); while (maskList.size() <= sizeIndex) maskList.push_back(0); maskList[sizeIndex] |= lanedRegister.getSizeBitMask(); } } + decoder.closeElement(elemId); lanerecords.clear(); for(int4 i=0;i element -/// \param el is the XML element -void Architecture::parseStackPointer(const Element *el) +/// Create a stack space and a stack-pointer register from a \ element +/// \param decoder is the stream decoder +void Architecture::decodeStackPointer(Decoder &decoder) { - AddrSpace *basespace = getSpaceByName(el->getAttributeValue("space")); - bool stackGrowth = true; // Default stack growth is in negative direction - if (basespace == (AddrSpace *)0) - throw LowlevelError("Unknown space name: "+el->getAttributeValue("space")); + uint4 elemId = decoder.openElement(ELEM_STACKPOINTER); + string spaceName; + string registerName; + bool stackGrowth = true; // Default stack growth is in negative direction bool isreversejustify = false; - int4 numattr = el->getNumAttributes(); - for(int4 i=0;igetAttributeName(i) ); - if (attr == "reversejustify") - isreversejustify = xml_readbool(el->getAttributeValue(i)); - else if (attr == "growth") - stackGrowth = el->getAttributeValue(i) == "negative"; + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_REVERSEJUSTIFY) + isreversejustify = decoder.readBool(); + else if (attribId == ATTRIB_GROWTH) + stackGrowth = decoder.readString() == "negative"; + else if (attribId == ATTRIB_SPACE) + spaceName = decoder.readString(); + else if (attribId == ATTRIB_REGISTER) + registerName = decoder.readString(); } - VarnodeData point = translate->getRegister(el->getAttributeValue("register")); + AddrSpace *basespace = getSpaceByName(spaceName); + if (basespace == (AddrSpace *)0) + throw LowlevelError("Unknown space name: "+spaceName); + + VarnodeData point = translate->getRegister(registerName); + decoder.closeElement(elemId); + // If creating a stackpointer to a truncated space, make sure to truncate the stackpointer int4 truncSize = point.size; if (basespace->isTruncated() && (point.size > basespace->getAddrSize())) { @@ -981,49 +1050,47 @@ void Architecture::parseStackPointer(const Element *el) } /// Manually alter the dead-code delay for a specific address space, -/// based on a \ tag. -/// \param el is the XML element -void Architecture::parseDeadcodeDelay(const Element *el) +/// based on a \ element. +/// \param decoder is the stream decoder +void Architecture::decodeDeadcodeDelay(Decoder &decoder) { - AddrSpace *spc = getSpaceByName(el->getAttributeValue("space")); + uint4 elemId = decoder.openElement(ELEM_DEADCODEDELAY); + string spaceName = decoder.readString(ATTRIB_SPACE); + AddrSpace *spc = getSpaceByName(spaceName); if (spc == (AddrSpace *)0) - throw LowlevelError("Unknown space name: "+el->getAttributeValue("space")); - istringstream s(el->getAttributeValue("delay")); - s.unsetf(ios::dec | ios::hex | ios::oct); - int4 delay = -1; - s >> delay; + throw LowlevelError("Unknown space name: "+spaceName); + int4 delay = decoder.readSignedInteger(ATTRIB_DELAY); if (delay >= 0) setDeadcodeDelay(spc,delay); else throw LowlevelError("Bad tag"); + decoder.closeElement(elemId); } /// Alter the range of addresses for which a pointer is allowed to be inferred. -void Architecture::parseInferPtrBounds(const Element *el) +void Architecture::decodeInferPtrBounds(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - for(iter=list.begin();iter!=list.end();++iter) { - const Element *subel = *iter; + uint4 elemId = decoder.openElement(ELEM_INFERPTRBOUNDS); + while(decoder.peekElement() != 0) { Range range; - range.restoreXml(subel,this); + range.decode(decoder,this); setInferPtrBounds(range); } + decoder.closeElement(elemId); } -/// Pull information from a \ tag. Turn on alignment analysis of +/// Pull information from a \ element. Turn on alignment analysis of /// function pointers, some architectures have aligned function pointers /// and encode extra information in the unused bits. -/// \param el is the XML element -void Architecture::parseFuncPtrAlign(const Element *el) +/// \param decoder is the stream decoder +void Architecture::decodeFuncPtrAlign(Decoder &decoder) { - int4 align; - istringstream s(el->getAttributeValue("align")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> align; + uint4 elemId = decoder.openElement(ELEM_FUNCPTR); + int4 align = decoder.readSignedInteger(ATTRIB_ALIGN); + decoder.closeElement(elemId); if (align == 0) { funcptr_align = 0; // No alignment @@ -1038,68 +1105,73 @@ void Architecture::parseFuncPtrAlign(const Element *el) } /// Designate a new index register and create a new address space associated with it, -/// based on a \ tag. -/// \param el is the XML element -void Architecture::parseSpacebase(const Element *el) +/// based on a \ element. +/// \param decoder is the stream decoder +void Architecture::decodeSpacebase(Decoder &decoder) { - const string &namestring(el->getAttributeValue("name")); - const VarnodeData &point(translate->getRegister(el->getAttributeValue("register"))); - AddrSpace *basespace = getSpaceByName(el->getAttributeValue("space")); + uint4 elemId = decoder.openElement(ELEM_SPACEBASE); + string nameString = decoder.readString(ATTRIB_NAME); + string registerName = decoder.readString(ATTRIB_REGISTER); + string spaceName = decoder.readString(ATTRIB_SPACE); + decoder.closeElement(elemId); + const VarnodeData &point(translate->getRegister(registerName)); + AddrSpace *basespace = getSpaceByName(spaceName); if (basespace == (AddrSpace *)0) - throw LowlevelError("Unknown space name: "+el->getAttributeValue("space")); - addSpacebase(basespace,namestring,point,point.size,false,false); + throw LowlevelError("Unknown space name: "+spaceName); + addSpacebase(basespace,nameString,point,point.size,false,false); } -/// Configure memory based on a \ tag. Mark specific address ranges +/// Configure memory based on a \ element. Mark specific address ranges /// to indicate the decompiler will not encounter pointers (aliases) into the range. -/// \param el is the XML element -void Architecture::parseNoHighPtr(const Element *el) +/// \param decoder is the stream decoder +void Architecture::decodeNoHighPtr(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - - for(iter=list.begin();iter!=list.end();++iter) { // Iterate over every range tag in the list + uint4 elemId = decoder.openElement(ELEM_NOHIGHPTR); + while(decoder.peekElement() != 0) { // Iterate over every range tag in the list Range range; - range.restoreXml(*iter,this); + range.decode(decoder,this); addNoHighPtr(range); } + decoder.closeElement(elemId); } -/// Configure registers based on a \ tag. Mark specific varnodes that +/// Configure registers based on a \ element. Mark specific varnodes that /// the decompiler should automatically split when it first sees them. -/// \param el is the XML element -void Architecture::parsePreferSplit(const Element *el) +/// \param decoder is the stream decoder +void Architecture::decodePreferSplit(Decoder &decoder) { - string style = el->getAttributeValue("style"); + uint4 elemId = decoder.openElement(ELEM_PREFERSPLIT); + string style = decoder.readString(ATTRIB_STYLE); if (style != "inhalf") throw LowlevelError("Unknown prefersplit style: "+style); - const List &list(el->getChildren()); - List::const_iterator iter; - for(iter=list.begin();iter!=list.end();++iter) { + while(decoder.peekElement() != 0) { splitrecords.emplace_back(); PreferSplitRecord &record( splitrecords.back() ); - record.storage.restoreXml( *iter, this ); + record.storage.decode( decoder, this ); record.splitoffset = record.storage.size/2; } + decoder.closeElement(elemId); } -/// Configure based on the \ tag, how aggressively the +/// Configure, based on the \ element, how aggressively the /// decompiler will remove extension operations. -/// \param el is the XML element -void Architecture::parseAggressiveTrim(const Element *el) +/// \param decoder is the stream decoder +void Architecture::decodeAggressiveTrim(Decoder &decoder) { - int4 sz = el->getNumAttributes(); - for(int4 i=0;igetAttributeName(i) ); - if (nm == "signext") { - aggressive_ext_trim = xml_readbool(el->getAttributeValue(i)); + uint4 elemId = decoder.openElement(ELEM_AGGRESSIVETRIM); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_SIGNEXT) { + aggressive_ext_trim = decoder.readBool(); } } + decoder.closeElement(elemId); } /// Clone the named ProtoModel, attaching it to another name. @@ -1131,49 +1203,65 @@ void Architecture::parseProcessorConfig(DocumentStorage &store) const Element *el = store.getTag("processor_spec"); if (el == (const Element *)0) throw LowlevelError("No processor configuration tag found"); - const List &list(el->getChildren()); - List::const_iterator iter; + XmlDecode decoder(el); - for(iter=list.begin();iter!=list.end();++iter) { - const string &elname( (*iter)->getName() ); - if (elname == "programcounter") { + uint4 elemId = decoder.openElement(ELEM_PROCESSOR_SPEC); + for(;;) { + uint4 subId = decoder.peekElement(); + if (subId == 0) break; + if (subId == ELEM_PROGRAMCOUNTER) { + decoder.openElement(); + decoder.closeElementSkipping(subId); } - else if (elname == "volatile") - parseVolatile(*iter); - else if (elname == "incidentalcopy") - parseIncidentalCopy(*iter); - else if (elname == "context_data") - context->restoreFromSpec(*iter,this); - else if (elname == "jumpassist") - userops.parseJumpAssist(*iter, this); - else if (elname == "segmentop") - userops.parseSegmentOp(*iter,this); - else if (elname == "register_data") { - parseLaneSizes(*iter); + else if (subId == ELEM_VOLATILE) + decodeVolatile(decoder); + else if (subId == ELEM_INCIDENTALCOPY) + decodeIncidentalCopy(decoder); + else if (subId == ELEM_CONTEXT_DATA) + context->decodeFromSpec(decoder,this); + else if (subId == ELEM_JUMPASSIST) + userops.decodeJumpAssist(decoder, this); + else if (subId == ELEM_SEGMENTOP) + userops.decodeSegmentOp(decoder,this); + else if (subId == ELEM_REGISTER_DATA) { + decodeLaneSizes(decoder); } - else if (elname == "data_space") { - const string &spaceName( (*iter)->getAttributeValue("space")); + else if (subId == ELEM_DATA_SPACE) { + uint4 elemId = decoder.openElement(); + string spaceName = decoder.readString(ATTRIB_SPACE); + decoder.closeElement(elemId); AddrSpace *spc = getSpaceByName(spaceName); if (spc == (AddrSpace *)0) throw LowlevelError("Undefined space: "+spaceName); setDefaultDataSpace(spc->getIndex()); } - else if (elname == "inferptrbounds") { - parseInferPtrBounds(*iter); + else if (subId == ELEM_INFERPTRBOUNDS) { + decodeInferPtrBounds(decoder); } - else if (elname == "segmented_address") { + else if (subId == ELEM_SEGMENTED_ADDRESS) { + decoder.openElement(); + decoder.closeElementSkipping(subId); } - else if (elname == "default_symbols") { + else if (subId == ELEM_DEFAULT_SYMBOLS) { + decoder.openElement(); + decoder.closeElementSkipping(subId); } - else if (elname == "default_memory_blocks") { + else if (subId == ELEM_DEFAULT_MEMORY_BLOCKS) { + decoder.openElement(); + decoder.closeElementSkipping(subId); } - else if (elname == "address_shift_amount") { + else if (subId == ELEM_ADDRESS_SHIFT_AMOUNT) { + decoder.openElement(); + decoder.closeElementSkipping(subId); } - else if (elname == "properties") { + else if (subId == ELEM_PROPERTIES) { + decoder.openElement(); + decoder.closeElementSkipping(subId); } else - throw LowlevelError("Unknown element in : "+elname); + throw LowlevelError("Unknown element in "); } + decoder.closeElement(elemId); } /// This looks for the \ tag and sets configuration parameters based on it. @@ -1181,94 +1269,98 @@ void Architecture::parseProcessorConfig(DocumentStorage &store) void Architecture::parseCompilerConfig(DocumentStorage &store) { - vector globaltags; + vector globalRanges; const Element *el = store.getTag("compiler_spec"); if (el == (const Element *)0) throw LowlevelError("No compiler configuration tag found"); - const List &list(el->getChildren()); - List::const_iterator iter; + XmlDecode decoder(el); - for(iter=list.begin();iter!=list.end();++iter) { - const string &elname( (*iter)->getName() ); - if (elname == "default_proto") - parseDefaultProto(*iter); - else if (elname == "prototype") - parseProto(*iter); - else if (elname == "stackpointer") - parseStackPointer(*iter); - else if (elname == "returnaddress") - parseReturnAddress(*iter); - else if (elname == "spacebase") - parseSpacebase(*iter); - else if (elname == "nohighptr") - parseNoHighPtr(*iter); - else if (elname == "prefersplit") - parsePreferSplit(*iter); - else if (elname == "aggressivetrim") - parseAggressiveTrim(*iter); - else if (elname == "data_organization") - types->parseDataOrganization(*iter); - else if (elname == "enum") - types->parseEnumConfig(*iter); - else if (elname == "global") - globaltags.push_back(*iter); - else if (elname == "segmentop") - userops.parseSegmentOp(*iter,this); - else if (elname == "readonly") - parseReadOnly(*iter); - else if (elname == "context_data") - context->restoreFromSpec(*iter,this); - else if (elname == "resolveprototype") - parseProto(*iter); - else if (elname == "eval_called_prototype") - parseProtoEval(*iter); - else if (elname == "eval_current_prototype") - parseProtoEval(*iter); - else if (elname == "callfixup") { - pcodeinjectlib->restoreXmlInject(archid+" : compiler spec", (*iter)->getAttributeValue("name"), - InjectPayload::CALLFIXUP_TYPE, *iter); + uint4 elemId = decoder.openElement(ELEM_COMPILER_SPEC); + for(;;) { + uint subId = decoder.peekElement(); + if (subId == 0) break; + if (subId == ELEM_DEFAULT_PROTO) + decodeDefaultProto(decoder); + else if (subId == ELEM_PROTOTYPE) + decodeProto(decoder); + else if (subId == ELEM_STACKPOINTER) + decodeStackPointer(decoder); + else if (subId == ELEM_RETURNADDRESS) + decodeReturnAddress(decoder); + else if (subId == ELEM_SPACEBASE) + decodeSpacebase(decoder); + else if (subId == ELEM_NOHIGHPTR) + decodeNoHighPtr(decoder); + else if (subId == ELEM_PREFERSPLIT) + decodePreferSplit(decoder); + else if (subId == ELEM_AGGRESSIVETRIM) + decodeAggressiveTrim(decoder); + else if (subId == ELEM_DATA_ORGANIZATION) + types->decodeDataOrganization(decoder); + else if (subId == ELEM_ENUM) + types->parseEnumConfig(decoder); + else if (subId == ELEM_GLOBAL) + decodeGlobal(decoder, globalRanges); + else if (subId == ELEM_SEGMENTOP) + userops.decodeSegmentOp(decoder,this); + else if (subId == ELEM_READONLY) + decodeReadOnly(decoder); + else if (subId == ELEM_CONTEXT_DATA) + context->decodeFromSpec(decoder,this); + else if (subId == ELEM_RESOLVEPROTOTYPE) + decodeProto(decoder); + else if (subId == ELEM_EVAL_CALLED_PROTOTYPE) + decodeProtoEval(decoder); + else if (subId == ELEM_EVAL_CURRENT_PROTOTYPE) + decodeProtoEval(decoder); + else if (subId == ELEM_CALLFIXUP) { + pcodeinjectlib->decodeInject(archid+" : compiler spec", "", InjectPayload::CALLFIXUP_TYPE, decoder); } - else if (elname == "callotherfixup") { - userops.parseCallOtherFixup(*iter,this); + else if (subId == ELEM_CALLOTHERFIXUP) { + userops.decodeCallOtherFixup(decoder,this); } - else if (elname == "funcptr") - parseFuncPtrAlign(*iter); - else if (elname == "deadcodedelay") - parseDeadcodeDelay(*iter); - else if (elname == "inferptrbounds") - parseInferPtrBounds(*iter); - else if (elname == "modelalias") { - const Element *el = *iter; - string aliasName = el->getAttributeValue("name"); - string parentName = el->getAttributeValue("parent"); + else if (subId == ELEM_FUNCPTR) + decodeFuncPtrAlign(decoder); + else if (subId == ELEM_DEADCODEDELAY) + decodeDeadcodeDelay(decoder); + else if (subId == ELEM_INFERPTRBOUNDS) + decodeInferPtrBounds(decoder); + else if (subId == ELEM_MODELALIAS) { + uint4 elemId = decoder.openElement(); + string aliasName = decoder.readString(ATTRIB_NAME); + string parentName = decoder.readString(ATTRIB_PARENT); + decoder.closeElement(elemId); createModelAlias(aliasName, parentName); } } + decoder.closeElement(elemId); el = store.getTag("specextensions"); // Look for any user-defined configuration document if (el != (const Element *)0) { - const List &userlist(el->getChildren()); - for(iter=userlist.begin();iter!=userlist.end();++iter) { - const string &elname( (*iter)->getName() ); - if (elname == "prototype") - parseProto(*iter); - else if (elname == "callfixup") { - pcodeinjectlib->restoreXmlInject(archid+" : compiler spec", (*iter)->getAttributeValue("name"), - InjectPayload::CALLFIXUP_TYPE, *iter); + XmlDecode decoderExt(el); + elemId = decoderExt.openElement(ELEM_SPECEXTENSIONS); + for(;;) { + uint4 subId = decoderExt.peekElement(); + if (subId == 0) break; + if (subId == ELEM_PROTOTYPE) + decodeProto(decoderExt); + else if (subId == ELEM_CALLFIXUP) { + pcodeinjectlib->decodeInject(archid+" : compiler spec", "",InjectPayload::CALLFIXUP_TYPE, decoder); } - else if (elname == "callotherfixup") { - userops.parseCallOtherFixup(*iter,this); + else if (subId == ELEM_CALLOTHERFIXUP) { + userops.decodeCallOtherFixup(decoder,this); } - else if (elname == "global") - globaltags.push_back(*iter); + else if (subId == ELEM_GLOBAL) + decodeGlobal(decoder,globalRanges); } + decoderExt.closeElement(elemId); } // tags instantiate the base symbol table // They need to know about all spaces, so it must come // after parsing of and - for(int4 i=0;igetChildren()); - List::const_iterator iter; - - for(iter=list.begin();iter!=list.end();++iter) - parseDynamicRule( *iter ); + XmlDecode decoder(expertag); + uint4 elemId = decoder.openElement(ELEM_EXPERIMENTAL_RULES); + while(decoder.peekElement() != 0) + decodeDynamicRule( decoder ); + decoder.closeElement(elemId); } } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh index 1e42862ef0..6bc9772fbd 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh @@ -61,6 +61,47 @@ public: class Architecture; +extern AttributeId ATTRIB_ADJUSTVMA; ///< Marshaling attribute "adjustvma" +extern AttributeId ATTRIB_ENABLE; ///< Marshaling attribute "enable" +extern AttributeId ATTRIB_GROUP; ///< Marshaling attribute "group" +extern AttributeId ATTRIB_GROWTH; ///< Marshaling attribute "growth" +extern AttributeId ATTRIB_LOADERSYMBOLS; ///< Marshaling attribute "loadersymbols" +extern AttributeId ATTRIB_PARENT; ///< Marshaling attribute "parent" +extern AttributeId ATTRIB_REGISTER; ///< Marshaling attribute "register" +extern AttributeId ATTRIB_REVERSEJUSTIFY; ///< Marshaling attribute "reversejustify" +extern AttributeId ATTRIB_SIGNEXT; ///< Marshaling attribute "signext" +extern AttributeId ATTRIB_STYLE; ///< Marshaling attribute "style" + +extern ElementId ELEM_ADDRESS_SHIFT_AMOUNT; ///< Marshaling element \ +extern ElementId ELEM_AGGRESSIVETRIM; ///< Marshaling element \ +extern ElementId ELEM_COMPILER_SPEC; ///< Marshaling element \ +extern ElementId ELEM_DATA_SPACE; ///< Marshaling element \ +extern ElementId ELEM_DEFAULT_MEMORY_BLOCKS; ///< Marshaling element \ +extern ElementId ELEM_DEFAULT_PROTO; ///< Marshaling element \ +extern ElementId ELEM_DEFAULT_SYMBOLS; ///< Marshaling element \ +extern ElementId ELEM_EVAL_CALLED_PROTOTYPE; ///< Marshaling element \ +extern ElementId ELEM_EVAL_CURRENT_PROTOTYPE; ///< Marshaling element \ +extern ElementId ELEM_EXPERIMENTAL_RULES; ///< Marshaling element \ +extern ElementId ELEM_FLOWOVERRIDELIST; ///< Marshaling element \ +extern ElementId ELEM_FUNCPTR; ///< Marshaling element \ +extern ElementId ELEM_GLOBAL; ///< Marshaling element \ +extern ElementId ELEM_INCIDENTALCOPY; ///< Marshaling element \ +extern ElementId ELEM_INFERPTRBOUNDS; ///< Marshaling element \ +extern ElementId ELEM_MODELALIAS; ///< Marshaling element \ +extern ElementId ELEM_NOHIGHPTR; ///< Marshaling element \ +extern ElementId ELEM_PROCESSOR_SPEC; ///< Marshaling element \ +extern ElementId ELEM_PROGRAMCOUNTER; ///< Marshaling element \ +extern ElementId ELEM_PROPERTIES; ///< Marshaling element \ +extern ElementId ELEM_READONLY; ///< Marshaling element \ +extern ElementId ELEM_REGISTER_DATA; ///< Marshaling element \ +extern ElementId ELEM_RULE; ///< Marshaling element \ +extern ElementId ELEM_SAVE_STATE; ///< Marshaling element \ +extern ElementId ELEM_SEGMENTED_ADDRESS; ///< Marshaling element \ +extern ElementId ELEM_SPACEBASE; ///< Marshaling element \ +extern ElementId ELEM_SPECEXTENSIONS; ///< Marshaling element \ +extern ElementId ELEM_STACKPOINTER; ///< Marshaling element \ +extern ElementId ELEM_VOLATILE; ///< Marshaling element \ + /// \brief Abstract extension point for building Architecture objects /// /// Decompilation hinges on initially recognizing the format of code then @@ -185,7 +226,7 @@ public: void setPrototype(const PrototypePieces &pieces); ///< Set the prototype for a particular function void setPrintLanguage(const string &nm); ///< Establish a particular output language void globalify(void); ///< Mark \e all spaces as global - void restoreFlowOverride(const Element *el); ///< Set flow overrides from XML + void decodeFlowOverride(Decoder &decoder); ///< Set flow overrides from XML virtual ~Architecture(void); ///< Destructor virtual string getDescription(void) const { return archid; } ///< Get a string describing \b this architecture @@ -195,8 +236,8 @@ public: /// Write the given message to whatever the registered error stream is /// \param message is the error message virtual void printMessage(const string &message) const=0; - virtual void saveXml(ostream &s) const; ///< Serialize this architecture to XML - virtual void restoreXml(DocumentStorage &store); ///< Restore the Architecture state from an XML stream + virtual void encode(Encoder &encoder) const; ///< Encode \b this architecture to a stream + virtual void restoreXml(DocumentStorage &store); ///< Restore the Architecture state from XML documents virtual void nameFunction(const Address &addr,string &name) const; ///< Pick a default name for a function #ifdef OPACTION_DEBUG void setDebugStream(ostream *s) { debugstream = s; } ///< Establish the debug console stream @@ -264,25 +305,26 @@ protected: void parseCompilerConfig(DocumentStorage &store); ///< Apply compiler specific configuration void parseExtraRules(DocumentStorage &store); ///< Apply any Rule tags - void parseDynamicRule(const Element *el); ///< Apply details of a dynamic Rule object - ProtoModel *parseProto(const Element *el); ///< Build a proto-type model from an XML tag - void parseProtoEval(const Element *el); ///< Apply prototype evaluation configuration - void parseDefaultProto(const Element *el); ///< Apply default prototype model configuration - void parseGlobal(const Element *el); ///< Apply global space configuration + void decodeDynamicRule(Decoder &decoder); ///< Apply details of a dynamic Rule object + ProtoModel *decodeProto(Decoder &decoder); ///< Parse a proto-type model from a stream + void decodeProtoEval(Decoder &decoder); ///< Apply prototype evaluation configuration + void decodeDefaultProto(Decoder &decoder); ///< Apply default prototype model configuration + void decodeGlobal(Decoder &decoder,vector &rangeProps); ///< Parse information about global ranges + void addToGlobalScope(const RangeProperties &props); ///< Add a memory range to the set of addresses considered \e global void addOtherSpace(void); ///< Add OTHER space and all of its overlays to the symboltab - void parseReadOnly(const Element *el); ///< Apply read-only region configuration - void parseVolatile(const Element *el); ///< Apply volatile region configuration - void parseReturnAddress(const Element *el); ///< Apply return address configuration - void parseIncidentalCopy(const Element *el); ///< Apply incidental copy configuration - void parseLaneSizes(const Element *el); ///< Apply lane size configuration - void parseStackPointer(const Element *el); ///< Apply stack pointer configuration - void parseDeadcodeDelay(const Element *el); ///< Apply dead-code delay configuration - void parseInferPtrBounds(const Element *el); ///< Apply pointer inference bounds - void parseFuncPtrAlign(const Element *el); ///< Apply function pointer alignment configuration - void parseSpacebase(const Element *el); ///< Create an additional indexed space - void parseNoHighPtr(const Element *el); ///< Apply memory alias configuration - void parsePreferSplit(const Element *el); ///< Designate registers to be split - void parseAggressiveTrim(const Element *el); ///< Designate how to trim extension p-code ops + void decodeReadOnly(Decoder &decoder); ///< Apply read-only region configuration + void decodeVolatile(Decoder &decoder); ///< Apply volatile region configuration + void decodeReturnAddress(Decoder &decoder); ///< Apply return address configuration + void decodeIncidentalCopy(Decoder &decoder); ///< Apply incidental copy configuration + void decodeLaneSizes(Decoder &decoder); ///< Apply lane size configuration + void decodeStackPointer(Decoder &decoder); ///< Apply stack pointer configuration + void decodeDeadcodeDelay(Decoder &decoder); ///< Apply dead-code delay configuration + void decodeInferPtrBounds(Decoder &decoder); ///< Apply pointer inference bounds + void decodeFuncPtrAlign(Decoder &decoder); ///< Apply function pointer alignment configuration + void decodeSpacebase(Decoder &decoder); ///< Create an additional indexed space + void decodeNoHighPtr(Decoder &decoder); ///< Apply memory alias configuration + void decodePreferSplit(Decoder &decoder); ///< Designate registers to be split + void decodeAggressiveTrim(Decoder &decoder); ///< Designate how to trim extension p-code ops }; /// \brief A resolver for segmented architectures diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/bfd_arch.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/bfd_arch.cc index 4c28121b82..4660b988d2 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/bfd_arch.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/bfd_arch.cc @@ -19,6 +19,8 @@ // Constructing this object registers capability BfdArchitectureCapability BfdArchitectureCapability::bfdArchitectureCapability; +ElementId ELEM_BFD_SAVEFILE = ElementId("bfd_savefile",46); + BfdArchitectureCapability::BfdArchitectureCapability(void) { @@ -125,16 +127,15 @@ BfdArchitecture::BfdArchitecture(const string &fname,const string &targ,ostream adjustvma = 0; } -void BfdArchitecture::saveXml(ostream &s) const +void BfdArchitecture::encode(Encoder &encoder) const { // prepend extra stuff to specify binary file and spec - s << "\n"; - types->saveXmlCoreTypes(s); - SleighArchitecture::saveXml(s); // Save the rest of the state - s << "\n"; + encoder.openElement(ELEM_BFD_SAVEFILE); + encodeHeader(encoder); + encoder.writeUnsignedInteger(ATTRIB_ADJUSTVMA, adjustvma); + types->encodeCoreTypes(encoder); + SleighArchitecture::encode(encoder); // Save the rest of the state + encoder.closeElement(ELEM_BFD_SAVEFILE); } void BfdArchitecture::restoreXml(DocumentStorage &store) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/bfd_arch.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/bfd_arch.hh index 9d1f21d04d..875d3bb78c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/bfd_arch.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/bfd_arch.hh @@ -20,6 +20,8 @@ #include "sleigh_arch.hh" #include "loadimage_bfd.hh" +extern ElementId ELEM_BFD_SAVEFILE; ///< Marshaling element \ + /// \brief Extension point for building a GNU BFD capable Architecture class BfdArchitectureCapability : public ArchitectureCapability { static BfdArchitectureCapability bfdArchitectureCapability; ///< The singleton instance @@ -40,7 +42,7 @@ class BfdArchitecture : public SleighArchitecture { virtual void resolveArchitecture(void); virtual void postSpecFile(void); public: - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; virtual void restoreXml(DocumentStorage &store); BfdArchitecture(const string &fname,const string &targ,ostream *estream); ///< Constructor virtual ~BfdArchitecture(void) {} diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc index 8cbbe63956..3f072e85b4 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc @@ -17,34 +17,43 @@ #include "block.hh" #include "funcdata.hh" -/// The edge is saved assuming we already know what block we are in -/// \param s is the output stream -void BlockEdge::saveXml(ostream &s) const +AttributeId ATTRIB_ALTINDEX = AttributeId("altindex",40); +AttributeId ATTRIB_DEPTH = AttributeId("depth",41); +AttributeId ATTRIB_END = AttributeId("end",42); +AttributeId ATTRIB_OPCODE = AttributeId("opcode",43); +AttributeId ATTRIB_REV = AttributeId("rev",44); + +ElementId ELEM_BHEAD = ElementId("bhead",47); +ElementId ELEM_BLOCK = ElementId("block",48); +ElementId ELEM_BLOCKEDGE = ElementId("blockedge",49); +ElementId ELEM_EDGE = ElementId("edge",50); + +/// The edge is saved assuming we already know what block we are in. +/// \param encoder is the stream encoder +void BlockEdge::encode(Encoder &encoder) const { - s << "getIndex()); // Reference to other end of edge - a_v_i(s,"rev",reverse_index); // Position within other blocks edgelist - s << "/>\n"; + encoder.writeSignedInteger(ATTRIB_END, point->getIndex()); // Reference to other end of edge + encoder.writeSignedInteger(ATTRIB_REV, reverse_index); // Position within other blocks edgelist + encoder.closeElement(ELEM_EDGE); } -/// \param el is the \ tag +/// Parse an \ element +/// \param decoder is the stream decoder /// \param resolver is used to cross-reference the edge's FlowBlock endpoints -void BlockEdge::restoreXml(const Element *el,BlockMap &resolver) +void BlockEdge::decode(Decoder &decoder,BlockMap &resolver) { + uint4 elemId = decoder.openElement(ELEM_EDGE); label = 0; // Tag does not currently contain info about label - int4 endIndex; - istringstream s(el->getAttributeValue("end")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> endIndex; + int4 endIndex = decoder.readSignedInteger(ATTRIB_END); point = resolver.findLevelBlock(endIndex); if (point == (FlowBlock *)0) throw LowlevelError("Bad serialized edge in block graph"); - istringstream s2(el->getAttributeValue("rev")); - s2.unsetf(ios::dec | ios::hex | ios::oct); - s2 >> reverse_index; + reverse_index = decoder.readSignedInteger(ATTRIB_REV); + decoder.closeElement(elemId); } FlowBlock::FlowBlock(void) @@ -68,14 +77,15 @@ void FlowBlock::addInEdge(FlowBlock *b,uint4 lab) b->outofthis.push_back(BlockEdge(this,lab,brev)); } -/// \param el is the \ element +/// Parse the next \ element in the stream +/// \param decoder is the stream decoder /// \param resolver is used to resolve block references -void FlowBlock::restoreNextInEdge(const Element *el,BlockMap &resolver) +void FlowBlock::decodeNextInEdge(Decoder &decoder,BlockMap &resolver) { intothis.emplace_back(); BlockEdge &inedge(intothis.back()); - inedge.restoreXml(el,resolver); + inedge.decode(decoder,resolver); while(inedge.point->outofthis.size() <= inedge.reverse_index) inedge.point->outofthis.emplace_back(); BlockEdge &outedge(inedge.point->outofthis[inedge.reverse_index]); @@ -621,7 +631,7 @@ JumpTable *FlowBlock::getJumptable(void) const } /// Given a string describing a FlowBlock type, return the block_type. -/// This is currently only used by the restoreXml() process. +/// This is currently only used by the decode() process. /// TODO: Fill in the remaining names and types /// \param nm is the name string /// \return the corresponding block_type @@ -1286,14 +1296,14 @@ void BlockGraph::finalizePrinting(Funcdata &data) const (*iter)->finalizePrinting(data); } -void BlockGraph::saveXmlBody(ostream &s) const +void BlockGraph::encodeBody(Encoder &encoder) const { - FlowBlock::saveXmlBody(s); + FlowBlock::encodeBody(encoder); for(int4 i=0;igetIndex()); + encoder.openElement(ELEM_BHEAD); + encoder.writeSignedInteger(ATTRIB_INDEX, bl->getIndex()); FlowBlock::block_type bt = bl->getType(); string nm; if (bt == FlowBlock::t_if) { @@ -1307,54 +1317,47 @@ void BlockGraph::saveXmlBody(ostream &s) const } else nm = FlowBlock::typeToName(bt); - a_v(s,"type",nm); - s << "/>\n"; + encoder.writeString(ATTRIB_TYPE, nm); + encoder.closeElement(ELEM_BHEAD); } for(int4 i=0;isaveXml(s); + list[i]->encode(encoder); } -void BlockGraph::restoreXmlBody(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver) +void BlockGraph::decodeBody(Decoder &decoder,BlockMap &resolver) { BlockMap newresolver(resolver); - FlowBlock::restoreXmlBody(iter,enditer,newresolver); vector tmplist; - while(iter != enditer) { - const Element *el = *iter; - if (el->getName() != "bhead") break; - ++iter; - int4 newindex; - istringstream s(el->getAttributeValue("index")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> newindex; - const string &nm( el->getAttributeValue("type") ); - FlowBlock *bl = newresolver.createBlock(nm); + for(;;) { + uint4 subId = decoder.peekElement(); + if (subId != ELEM_BHEAD) break; + decoder.openElement(); + int4 newindex = decoder.readSignedInteger(ATTRIB_INDEX); + FlowBlock *bl = newresolver.createBlock(decoder.readString(ATTRIB_TYPE)); bl->index = newindex; // Need to set index here for sort tmplist.push_back(bl); + decoder.closeElement(subId); } newresolver.sortList(); for(int4 i=0;irestoreXml(*iter,newresolver); + bl->decode(decoder,newresolver); addBlock(bl); - ++iter; } } -/// This is currently just a wrapper around the FlowBlock::restoreXml() -/// that sets of the BlockMap resolver -/// \param el is the root \ tag +/// Parse a \ element. This is currently just a wrapper around the +/// FlowBlock::decode() that sets of the BlockMap resolver +/// \param decoder is the stream decoder /// \param m is the address space manager -void BlockGraph::restoreXml(const Element *el,const AddrSpaceManager *m) +void BlockGraph::decode(Decoder &decoder,const AddrSpaceManager *m) { BlockMap resolver(m); - FlowBlock::restoreXml(el,resolver); + FlowBlock::decode(decoder,resolver); // Restore goto references here } @@ -2353,77 +2356,70 @@ bool BlockBasic::isComplex(void) const return false; } -/// \param s is the output stream -void FlowBlock::saveXmlHeader(ostream &s) const +/// \param encoder is the stream encoder +void FlowBlock::encodeHeader(Encoder &encoder) const { - a_v_i(s,"index",index); + encoder.writeSignedInteger(ATTRIB_INDEX, index); } -/// \param el is the XML element to pull attributes from -void FlowBlock::restoreXmlHeader(const Element *el) +/// \param decoder is the stream decoder to pull attributes from +void FlowBlock::decodeHeader(Decoder &decoder) { - istringstream s(el->getAttributeValue("index")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> index; + index = decoder.readSignedInteger(ATTRIB_INDEX); } -/// Write \ tags to stream -/// \param s is the output stream -void FlowBlock::saveXmlEdges(ostream &s) const +/// Write \ element to a stream +/// \param encoder is the stream encoder +void FlowBlock::encodeEdges(Encoder &encoder) const { for(int4 i=0;i tags -/// \param enditer marks the end of the list of tags +/// \param decoder is the stream decoder /// \param resolver is used to recover FlowBlock cross-references -void FlowBlock::restoreXmlEdges(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver) +void FlowBlock::decodeEdges(Decoder &decoder,BlockMap &resolver) { - while(iter != enditer) { - const Element *el = *iter; - if (el->getName() != "edge") - return; - ++iter; - restoreNextInEdge(el,resolver); + for(;;) { + uint4 subId = decoder.peekElement(); + if (subId != ELEM_EDGE) + break; + decodeNextInEdge(decoder,resolver); } } -/// Serialize \b this and all its sub-components as an XML \ tag. -/// \param s is the output stream -void FlowBlock::saveXml(ostream &s) const +/// Encode \b this and all its sub-components as a \ element. +/// \param encoder is the stream encoder +void FlowBlock::encode(Encoder &encoder) const { - s << "\n"; - saveXmlBody(s); - saveXmlEdges(s); - s << "\n"; + encoder.openElement(ELEM_BLOCK); + encodeHeader(encoder); + encodeBody(encoder); + encodeEdges(encoder); + encoder.closeElement(ELEM_BLOCK); } -/// Recover \b this and all it sub-components from an XML \ tag. +/// Recover \b this and all it sub-components from a \ element. /// /// This will construct all the sub-components using \b resolver as a factory. -/// \param el is the root XML element +/// \param decoder is the stream decoder /// \param resolver acts as a factory and resolves cross-references -void FlowBlock::restoreXml(const Element *el,BlockMap &resolver) +void FlowBlock::decode(Decoder &decoder,BlockMap &resolver) { - restoreXmlHeader(el); - const List &list(el->getChildren()); - List::const_iterator iter; - - iter = list.begin(); - restoreXmlBody(iter,list.end(),resolver); - restoreXmlEdges(iter,list.end(),resolver); + uint4 elemId = decoder.openElement(ELEM_BLOCK); + decodeHeader(decoder); + decodeBody(decoder,resolver); + decodeEdges(decoder,resolver); + decoder.closeElement(elemId); } /// If there are two branches, pick the fall-thru branch @@ -2560,17 +2556,16 @@ void BlockBasic::setOrder(void) } } -void BlockBasic::saveXmlBody(ostream &s) const +void BlockBasic::encodeBody(Encoder &encoder) const { - cover.saveXml(s); + cover.encode(encoder); } -void BlockBasic::restoreXmlBody(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver) +void BlockBasic::decodeBody(Decoder &decoder,BlockMap &resolver) { - cover.restoreXml(*iter, resolver.getAddressManager()); - ++iter; + cover.decode(decoder, resolver.getAddressManager()); } void BlockBasic::printHeader(ostream &s) const @@ -2635,12 +2630,12 @@ void BlockCopy::printTree(ostream &s,int4 level) const copy->printTree(s,level); } -void BlockCopy::saveXmlHeader(ostream &s) const +void BlockCopy::encodeHeader(Encoder &encoder) const { - FlowBlock::saveXmlHeader(s); + FlowBlock::encodeHeader(encoder); int4 altindex = copy->getIndex(); - a_v_i(s,"altindex",altindex); + encoder.writeSignedInteger(ATTRIB_ALTINDEX, altindex); } void BlockGoto::markUnstructured(void) @@ -2692,17 +2687,17 @@ FlowBlock *BlockGoto::nextFlowAfter(const FlowBlock *bl) const return getGotoTarget()->getFrontLeaf(); } -void BlockGoto::saveXmlBody(ostream &s) const +void BlockGoto::encodeBody(Encoder &encoder) const { - BlockGraph::saveXmlBody(s); - s << "getFrontLeaf(); int4 depth = gototarget->calcDepth(leaf); - a_v_i(s,"index",leaf->getIndex()); - a_v_i(s,"depth",depth); - a_v_u(s,"type",gototype); - s << "/>\n"; + encoder.writeSignedInteger(ATTRIB_INDEX, leaf->getIndex()); + encoder.writeSignedInteger(ATTRIB_DEPTH, depth); + encoder.writeUnsignedInteger(ATTRIB_TYPE, gototype); + encoder.closeElement(ELEM_TARGET); } void BlockMultiGoto::scopeBreak(int4 curexit,int4 curloopexit) @@ -2725,18 +2720,18 @@ FlowBlock *BlockMultiGoto::nextFlowAfter(const FlowBlock *bl) const return (FlowBlock *)0; } -void BlockMultiGoto::saveXmlBody(ostream &s) const +void BlockMultiGoto::encodeBody(Encoder &encoder) const { - BlockGraph::saveXmlBody(s); + BlockGraph::encodeBody(encoder); for(int4 i=0;igetFrontLeaf(); int4 depth = gototarget->calcDepth(leaf); - s << "getIndex()); - a_v_i(s,"depth",depth); - s << "/>\n"; + encoder.openElement(ELEM_TARGET); + encoder.writeSignedInteger(ATTRIB_INDEX, leaf->getIndex()); + encoder.writeSignedInteger(ATTRIB_DEPTH, depth); + encoder.closeElement(ELEM_TARGET); } } @@ -2846,12 +2841,12 @@ FlowBlock *BlockCondition::nextFlowAfter(const FlowBlock *bl) const return (FlowBlock *)0; // Do not know where flow goes } -void BlockCondition::saveXmlHeader(ostream &s) const +void BlockCondition::encodeHeader(Encoder &encoder) const { - BlockGraph::saveXmlHeader(s); + BlockGraph::encodeHeader(encoder); string nm(get_opname(opc)); - a_v(s,"opcode",nm); + encoder.writeString(ATTRIB_OPCODE, nm); } void BlockIf::markUnstructured(void) @@ -2924,18 +2919,18 @@ FlowBlock *BlockIf::nextFlowAfter(const FlowBlock *bl) const return getParent()->nextFlowAfter(this); } -void BlockIf::saveXmlBody(ostream &s) const +void BlockIf::encodeBody(Encoder &encoder) const { - BlockGraph::saveXmlBody(s); + BlockGraph::encodeBody(encoder); if (getSize() == 1) { // If this is a if GOTO block const FlowBlock *leaf = gototarget->getFrontLeaf(); int4 depth = gototarget->calcDepth(leaf); - s << "getIndex()); - a_v_i(s,"depth",depth); - a_v_u(s,"type",gototype); - s << "/>\n"; + encoder.openElement(ELEM_TARGET); + encoder.writeSignedInteger(ATTRIB_INDEX, leaf->getIndex()); + encoder.writeSignedInteger(ATTRIB_DEPTH, depth); + encoder.writeUnsignedInteger(ATTRIB_TYPE, gototype); + encoder.closeElement(ELEM_TARGET); } } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh index b071e75b73..72dc9d81ee 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh @@ -35,6 +35,17 @@ class BlockSwitch; class PrintLanguage; class BlockMap; +extern AttributeId ATTRIB_ALTINDEX; ///< Marshaling attribute "altindex" +extern AttributeId ATTRIB_DEPTH; ///< Marshaling attribute "depth" +extern AttributeId ATTRIB_END; ///< Marshaling attribute "end" +extern AttributeId ATTRIB_OPCODE; ///< Marshaling attribute "opcode" +extern AttributeId ATTRIB_REV; ///< Marshaling attribute "rev" + +extern ElementId ELEM_BHEAD; ///< Marshaling element \ +extern ElementId ELEM_BLOCK; ///< Marshaling element \ +extern ElementId ELEM_BLOCKEDGE; ///< Marshaling element \ +extern ElementId ELEM_EDGE; ///< Marshaling element \ + /// \brief A control-flow edge between blocks (FlowBlock) /// /// The edge is owned by the source block and can have FlowBlock::edge_flags @@ -45,10 +56,10 @@ struct BlockEdge { uint4 label; ///< Label of the edge FlowBlock *point; ///< Other end of the edge int4 reverse_index; ///< Index for edge coming other way - BlockEdge(void) {} ///< Constructor for use with restoreXml + BlockEdge(void) {} ///< Constructor for use with decode BlockEdge(FlowBlock *pt,uint4 lab,int4 rev) { label=lab; point=pt; reverse_index = rev; } ///< Constructor - void saveXml(ostream &s) const; ///< Save the edge to an XML stream - void restoreXml(const Element *el,BlockMap &resolver); ///< Restore \b this edge from an XML stream + void encode(Encoder &encoder) const; ///< Encode \b this edge to a stream + void decode(Decoder &decoder,BlockMap &resolver); ///< Restore \b this edge from a stream }; /// \brief Description of a control-flow block containing PcodeOps @@ -119,7 +130,7 @@ private: // the result of the condition being false static void replaceEdgeMap(vector &vec); ///< Update block references in edges with copy map void addInEdge(FlowBlock *b,uint4 lab); ///< Add an edge coming into \b this - void restoreNextInEdge(const Element *el,BlockMap &resolver); ///< Restore the next input edge from XML + void decodeNextInEdge(Decoder &decoder,BlockMap &resolver); ///< Restore the next input edge from XML void halfDeleteInEdge(int4 slot); ///< Delete the \e in half of an edge, correcting indices void halfDeleteOutEdge(int4 slot); ///< Delete the \e out half of an edge, correcting indices void removeInEdge(int4 slot); ///< Remove an incoming edge @@ -172,20 +183,19 @@ public: virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const; virtual void finalTransform(Funcdata &data) {} ///< Do any structure driven final transforms virtual void finalizePrinting(Funcdata &data) const {} ///< Make any final configurations necessary to print the block - virtual void saveXmlHeader(ostream &s) const; ///< Save basic information as XML attributes - virtual void restoreXmlHeader(const Element *el); ///< Restore basic information for XML attributes - virtual void saveXmlBody(ostream &s) const {} ///< Save detail about components to an XML stream + virtual void encodeHeader(Encoder &encoder) const; ///< Encode basic information as attributes + virtual void decodeHeader(Decoder &decoder); ///< Decode basic information from element attributes + virtual void encodeBody(Encoder &encoder) const {} ///< Encode detail about components to a stream - /// \brief Restore details about \b this FlowBlock from an XML stream + /// \brief Restore details about \b this FlowBlock from an element stream /// - /// \param iter is an iterator to XML elements containing component tags etc. - /// \param enditer marks the end of the XML tags - /// \param resolver is used to recover FlowBlock objects based on XML references - virtual void restoreXmlBody(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver) {} - void saveXmlEdges(ostream &s) const; ///< Save edge information to an XML stream - void restoreXmlEdges(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver); - void saveXml(ostream &s) const; ///< Write out \b this to an XML stream - void restoreXml(const Element *el,BlockMap &resolver); ///< Restore \b this from an XML stream + /// \param decoder is the stream decoder + /// \param resolver is used to recover FlowBlock objects based on elment references + virtual void decodeBody(Decoder &decoder,BlockMap &resolver) {} + void encodeEdges(Encoder &encoder) const; ///< Encode edge information to a stream + void decodeEdges(Decoder &decoder,BlockMap &resolver); + void encode(Encoder &encoder) const; ///< Encode \b this to a stream + void decode(Decoder &decoder,BlockMap &resolver); ///< Decode \b this from a stream const FlowBlock *nextInFlow(void) const; ///< Return next block to be executed in flow void setVisitCount(int4 i) { visitcount = i; } ///< Set the number of times this block has been visited int4 getVisitCount(void) const { return visitcount; } ///< Get the count of visits @@ -299,9 +309,9 @@ public: virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const; virtual void finalTransform(Funcdata &data); virtual void finalizePrinting(Funcdata &data) const; - virtual void saveXmlBody(ostream &s) const; - virtual void restoreXmlBody(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver); - void restoreXml(const Element *el,const AddrSpaceManager *m); ///< Restore \b this BlockGraph from an XML stream + virtual void encodeBody(Encoder &encoder) const; + virtual void decodeBody(Decoder &decoder,BlockMap &resolver); + void decode(Decoder &decoder,const AddrSpaceManager *m); ///< Restore \b this BlockGraph from an XML stream void addEdge(FlowBlock *begin,FlowBlock *end); ///< Add a directed edge between component FlowBlocks void addLoopEdge(FlowBlock *begin,int4 outindex); ///< Mark a given edge as a \e loop edge void removeEdge(FlowBlock *begin,FlowBlock *end); ///< Remove an edge between component FlowBlocks @@ -383,8 +393,8 @@ public: virtual Address getStop(void) const; virtual block_type getType(void) const { return t_basic; } virtual FlowBlock *subBlock(int4 i) const { return (FlowBlock *)0; } - virtual void saveXmlBody(ostream &s) const; - virtual void restoreXmlBody(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver); + virtual void encodeBody(Encoder &encoder) const; + virtual void decodeBody(Decoder &decoder,BlockMap &resolver); virtual void printHeader(ostream &s) const; virtual void printRaw(ostream &s) const; virtual void emit(PrintLanguage *lng) const { lng->emitBlockBasic(this); } @@ -431,7 +441,7 @@ public: virtual bool negateCondition(bool toporbottom) { bool res = copy->negateCondition(true); FlowBlock::negateCondition(toporbottom); return res; } virtual FlowBlock *getSplitPoint(void) { return copy->getSplitPoint(); } virtual bool isComplex(void) const { return copy->isComplex(); } - virtual void saveXmlHeader(ostream &s) const; + virtual void encodeHeader(Encoder &encoder) const; }; /// \brief A block that terminates with an unstructured (goto) branch to another block @@ -458,7 +468,7 @@ public: virtual const FlowBlock *getExitLeaf(void) const { return getBlock(0)->getExitLeaf(); } virtual PcodeOp *lastOp(void) const { return getBlock(0)->lastOp(); } virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const; - virtual void saveXmlBody(ostream &s) const; + virtual void encodeBody(Encoder &encoder) const; }; /// \brief A block with multiple edges out, at least one of which is an unstructured (goto) branch. @@ -486,7 +496,7 @@ public: virtual const FlowBlock *getExitLeaf(void) const { return getBlock(0)->getExitLeaf(); } virtual PcodeOp *lastOp(void) const { return getBlock(0)->lastOp(); } virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const; - virtual void saveXmlBody(ostream &s) const; + virtual void encodeBody(Encoder &encoder) const; }; /// \brief A series of blocks that execute in sequence. @@ -531,7 +541,7 @@ public: virtual PcodeOp *lastOp(void) const; virtual bool isComplex(void) const { return getBlock(0)->isComplex(); } virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const; - virtual void saveXmlHeader(ostream &s) const; + virtual void encodeHeader(Encoder &encoder) const; }; /// \brief A basic "if" block @@ -569,7 +579,7 @@ public: virtual const FlowBlock *getExitLeaf(void) const; virtual PcodeOp *lastOp(void) const; virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const; - virtual void saveXmlBody(ostream &s) const; + virtual void encodeBody(Encoder &encoder) const; }; /// \brief A loop structure where the condition is checked at the top. @@ -703,7 +713,7 @@ public: /// list of FlowBlock objects sorted by index and then looks up the FlowBlock matching a given /// index as edges specify them. class BlockMap { - const AddrSpaceManager *manage; ///< Address space manager used to restore FlowBlock address ranges + const AddrSpaceManager *manage; ///< Address space manager used to decode FlowBlock address ranges vector sortlist; ///< The list of deserialized FlowBlock objects FlowBlock *resolveBlock(FlowBlock::block_type bt); ///< Construct a FlowBlock of the given type static FlowBlock *findBlock(const vector &list,int4 ind); ///< Locate a FlowBlock with a given index diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/callgraph.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/callgraph.cc index 24524e79a3..bc310d4801 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/callgraph.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/callgraph.cc @@ -16,34 +16,30 @@ #include "callgraph.hh" #include "funcdata.hh" -void CallGraphEdge::saveXml(ostream &s) const +ElementId ELEM_CALLGRAPH = ElementId("callgraph",51); +ElementId ELEM_NODE = ElementId("node",52); + +void CallGraphEdge::encode(Encoder &encoder) const { - s << " \n"; - s << " "; - from->getAddr().saveXml(s); - s << "\n "; - to->getAddr().saveXml(s); - s << "\n "; - callsiteaddr.saveXml(s); - s << "\n \n"; + encoder.openElement(ELEM_EDGE); + from->getAddr().encode(encoder); + to->getAddr().encode(encoder); + callsiteaddr.encode(encoder); + encoder.closeElement(ELEM_EDGE); } -void CallGraphEdge::restoreXml(const Element *el,CallGraph *graph) +void CallGraphEdge::decode(Decoder &decoder,CallGraph *graph) { + uint4 elemId = decoder.openElement(ELEM_EDGE); const AddrSpaceManager *manage = graph->getArch(); Address fromaddr,toaddr,siteaddr; - const List &list(el->getChildren()); - List::const_iterator iter; - - iter = list.begin(); - fromaddr = Address::restoreXml(*iter,manage); - ++iter; - toaddr = Address::restoreXml(*iter,manage); - ++iter; - siteaddr = Address::restoreXml(*iter,manage); + fromaddr = Address::decode(decoder,manage); + toaddr = Address::decode(decoder,manage); + siteaddr = Address::decode(decoder,manage); + decoder.closeElement(elemId); CallGraphNode *fromnode = graph->findNode(fromaddr); if (fromnode == (CallGraphNode *)0) @@ -66,28 +62,29 @@ void CallGraphNode::setFuncdata(Funcdata *f) fd = f; } -void CallGraphNode::saveXml(ostream &s) const +void CallGraphNode::encode(Encoder &encoder) const { - s << " \n "; - entryaddr.saveXml(s); - s << "\n \n"; + encoder.writeString(ATTRIB_NAME, name); + entryaddr.encode(encoder); + encoder.closeElement(ELEM_NODE); } -void CallGraphNode::restoreXml(const Element *el,CallGraph *graph) +void CallGraphNode::decode(Decoder &decoder,CallGraph *graph) { - int4 num = el->getNumAttributes(); + uint4 elemId = decoder.openElement(ELEM_NODE); string name; - for(int4 i=0;igetAttributeName(i) == "name") - name = el->getAttributeValue(i); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_NAME) + name = decoder.readString(); } - Address addr = Address::restoreXml(*el->getChildren().begin(),graph->getArch()); - + Address addr = Address::decode(decoder,graph->getArch()); + decoder.closeElement(elemId); graph->addNode(addr,name); } @@ -431,41 +428,39 @@ void CallGraph::buildEdges(Funcdata *fd) } } -void CallGraph::saveXml(ostream &s) const +void CallGraph::encode(Encoder &encoder) const { map::const_iterator iter; - s << "\n"; + encoder.openElement(ELEM_CALLGRAPH); for(iter=graph.begin();iter!=graph.end();++iter) - (*iter).second.saveXml(s); + (*iter).second.encode(encoder); // Dump all the "in" edges for(iter=graph.begin();iter!=graph.end();++iter) { const CallGraphNode &node( (*iter).second ); for(uint4 i=0;i\n"; + encoder.closeElement(ELEM_CALLGRAPH); } -void CallGraph::restoreXml(const Element *el) +void CallGraph::decoder(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - - iter = list.begin(); - while(iter != list.end()) { - const Element *subel = *iter; - ++iter; - if (subel->getName() == "edge") - CallGraphEdge::restoreXml(subel,this); + uint4 elemId = decoder.openElement(ELEM_CALLGRAPH); + for(;;) { + uint4 subId = decoder.peekElement(); + if (subId == 0) break; + if (subId == ELEM_EDGE) + CallGraphEdge::decode(decoder,this); else - CallGraphNode::restoreXml(subel,this); + CallGraphNode::decode(decoder,this); } + decoder.closeElement(elemId); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/callgraph.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/callgraph.hh index ed6f3054ab..1fc0cc3cac 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/callgraph.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/callgraph.hh @@ -24,6 +24,9 @@ class Funcdata; class CallGraphNode; class CallGraph; +extern ElementId ELEM_CALLGRAPH; ///< Marshaling element \ +extern ElementId ELEM_NODE; ///< Marshaling element \ + class CallGraphEdge { public: enum { @@ -41,9 +44,9 @@ private: public: CallGraphEdge(void) { flags = 0; } bool isCycle(void) const { return ((flags&1)!=0); } - void saveXml(ostream &s) const; + void encode(Encoder &encoder) const; const Address &getCallSiteAddr(void) const { return callsiteaddr; } - static void restoreXml(const Element *el,CallGraph *graph); + static void decode(Decoder &decoder,CallGraph *graph); }; class CallGraphNode { @@ -77,8 +80,8 @@ public: const CallGraphEdge &getOutEdge(int4 i) const { return outedge[i]; } CallGraphNode *getOutNode(int4 i) const { return outedge[i].to; } void setFuncdata(Funcdata *f); - void saveXml(ostream &s) const; - static void restoreXml(const Element *el,CallGraph *graph); + void encode(Encoder &encoder) const; + static void decode(Decoder &decoder,CallGraph *graph); }; struct LeafIterator { @@ -116,8 +119,8 @@ public: map::iterator end(void) { return graph.end(); } void buildAllNodes(void); void buildEdges(Funcdata *fd); - void saveXml(ostream &s) const; - void restoreXml(const Element *el); + void encode(Encoder &encoder) const; + void decoder(Decoder &decoder); }; #endif diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/comment.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/comment.cc index 9dafc0e983..07eff2f4f8 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/comment.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/comment.cc @@ -16,6 +16,10 @@ #include "comment.hh" #include "funcdata.hh" +ElementId ELEM_COMMENT = ElementId("comment",53); +ElementId ELEM_COMMENTDB = ElementId("commentdb",54); +ElementId ELEM_TEXT = ElementId("text",55); + /// \param tp is the set of properties to associate with the comment (or 0 for no properties) /// \param fad is the Address of the function containing the comment /// \param ad is the Address of the instruction associated with the comment @@ -26,46 +30,45 @@ Comment::Comment(uint4 tp,const Address &fad,const Address &ad,int4 uq,const str { } -/// The single comment is saved as a \ tag. -/// \param s is the output stream -void Comment::saveXml(ostream &s) const +/// The single comment is encoded as a \ element. +/// \param encoder is the stream encoder +void Comment::encode(Encoder &encoder) const { string tpname = Comment::decodeCommentType(type); - s << "\n"; - s << " saveXmlAttributes(s,funcaddr.getOffset()); - s << "/>\n"; - s << " saveXmlAttributes(s,addr.getOffset()); - s << "/>\n"; - s << " "; - xml_escape(s,text.c_str()); - s << " \n"; - s << "\n"; + encoder.openElement(ELEM_COMMENT); + encoder.writeString(ATTRIB_TYPE, tpname); + encoder.openElement(ELEM_ADDR); + funcaddr.getSpace()->encodeAttributes(encoder,funcaddr.getOffset()); + encoder.closeElement(ELEM_ADDR); + encoder.openElement(ELEM_ADDR); + addr.getSpace()->encodeAttributes(encoder,addr.getOffset()); + encoder.closeElement(ELEM_ADDR); + encoder.openElement(ELEM_TEXT); + encoder.writeString(ATTRIB_CONTENT, text); + encoder.closeElement(ELEM_TEXT); + encoder.closeElement(ELEM_COMMENT); } -/// The comment is parsed from a \ tag. -/// \param el is the \ element +/// Parse a \ element from the given stream decoder +/// \param decoder is the given stream decoder /// \param manage is a manager for resolving address space references -void Comment::restoreXml(const Element *el,const AddrSpaceManager *manage) +void Comment::decode(Decoder &decoder,const AddrSpaceManager *manage) { emitted = false; type = 0; - type = Comment::encodeCommentType(el->getAttributeValue("type")); - const List &list(el->getChildren()); - List::const_iterator iter; - - iter = list.begin(); - funcaddr = Address::restoreXml(*iter,manage); - ++iter; - addr = Address::restoreXml(*iter,manage); - ++iter; - if (iter != list.end()) - text = (*iter)->getContent(); + uint4 elemId = decoder.openElement(ELEM_COMMENT); + type = Comment::encodeCommentType(decoder.readString(ATTRIB_TYPE)); + funcaddr = Address::decode(decoder,manage); + addr = Address::decode(decoder,manage); + uint4 subId = decoder.peekElement(); + if (subId != 0) { + decoder.openElement(); + text = decoder.readString(ATTRIB_CONTENT); + decoder.closeElement(subId); + } + decoder.closeElement(elemId); } /// \param name is a string representation of a single comment property @@ -235,28 +238,27 @@ CommentSet::const_iterator CommentDatabaseInternal::endComment(const Address &fa return commentset.lower_bound(&testcomm); } -void CommentDatabaseInternal::saveXml(ostream &s) const +void CommentDatabaseInternal::encode(Encoder &encoder) const { CommentSet::const_iterator iter; - s << "\n"; + encoder.openElement(ELEM_COMMENTDB); for(iter=commentset.begin();iter!=commentset.end();++iter) - (*iter)->saveXml(s); - s << "\n"; + (*iter)->encode(encoder); + encoder.closeElement(ELEM_COMMENTDB); } -void CommentDatabaseInternal::restoreXml(const Element *el,const AddrSpaceManager *manage) +void CommentDatabaseInternal::decode(Decoder &decoder,const AddrSpaceManager *manage) { - const List &list(el->getChildren()); - List::const_iterator iter; - - for(iter=list.begin();iter!=list.end();++iter) { + uint4 elemId = decoder.openElement(ELEM_COMMENTDB); + while(decoder.peekElement() != 0) { Comment com; - com.restoreXml(*iter,manage); + com.decode(decoder,manage); addComment(com.getType(),com.getFuncAddr(),com.getAddr(),com.getText()); } + decoder.closeElement(elemId); } /// Figure out position of given Comment and initialize its key. diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/comment.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/comment.hh index 73e70d6c8f..d9c0b2e43e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/comment.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/comment.hh @@ -25,6 +25,10 @@ class FlowBlock; class PcodeOp; class Funcdata; +extern ElementId ELEM_COMMENT; ///< Marshaling element \ +extern ElementId ELEM_COMMENTDB; ///< Marshaling element \ +extern ElementId ELEM_TEXT; ///< Marshaling element \ + /// \brief A comment attached to a specific function and code address /// /// Things contains the actual character data of the comment. It is @@ -53,7 +57,7 @@ public: warningheader = 32 ///< The comment is auto-generated and should be in the header }; Comment(uint4 tp,const Address &fad,const Address &ad,int4 uq,const string &txt); ///< Constructor - Comment(void) {} ///< Constructor for use with restoreXml + Comment(void) {} ///< Constructor for use with decode void setEmitted(bool val) const { emitted = val; } ///< Mark that \b this comment has been emitted bool isEmitted(void) const { return emitted; } ///< Return \b true if \b this comment is already emitted uint4 getType(void) const { return type; } ///< Get the properties associated with the comment @@ -61,8 +65,8 @@ public: const Address &getAddr(void) const { return addr; } ///< Get the address to which the instruction is attached int4 getUniq(void) const { return uniq; } ///< Get the sub-sorting index const string &getText(void) const { return text; } ///< Get the body of the comment - void saveXml(ostream &s) const; ///< Save the comment to an XML stream - void restoreXml(const Element *el,const AddrSpaceManager *manage); ///< Restore the comment from XML + void encode(Encoder &encoder) const; ///< Encode the comment to a stream + void decode(Decoder &decoder,const AddrSpaceManager *manage); ///< Restore the comment from XML static uint4 encodeCommentType(const string &name); ///< Convert name string to comment property static string decodeCommentType(uint4 val); ///< Convert comment property to string }; @@ -134,17 +138,17 @@ public: /// \return the ending iterator virtual CommentSet::const_iterator endComment(const Address &fad) const=0; - /// \brief Save all comments in the container to an XML stream + /// \brief Encode all comments in the container to a stream /// - /// Writes a \ tag, with \ sub-tags for each Comment object. - /// \param s is the output stream - virtual void saveXml(ostream &s) const=0; + /// Writes a \ element, with \ children for each Comment object. + /// \param encoder is the stream encoder + virtual void encode(Encoder &encoder) const=0; - /// \brief Restore all comments from XML + /// \brief Restore all comments from a \ element /// - /// \param el is the root \ element + /// \param decoder is the stream decoder /// \param manage is a manager for resolving address space references - virtual void restoreXml(const Element *el,const AddrSpaceManager *manage)=0; + virtual void decode(Decoder &decoder,const AddrSpaceManager *manage)=0; }; @@ -166,8 +170,8 @@ public: virtual void deleteComment(Comment *com); virtual CommentSet::const_iterator beginComment(const Address &fad) const; virtual CommentSet::const_iterator endComment(const Address &fad) const; - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el,const AddrSpaceManager *manage); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,const AddrSpaceManager *manage); }; /// \brief A class for sorting comments into and within basic blocks diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/comment_ghidra.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/comment_ghidra.cc index c1297034b8..7e10e12724 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/comment_ghidra.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/comment_ghidra.cc @@ -28,7 +28,6 @@ CommentDatabaseGhidra::CommentDatabaseGhidra(ArchitectureGhidra *g) void CommentDatabaseGhidra::fillCache(const Address &fad) const { - Document *doc; uint4 commentfilter; if (cachefilled) return; // Already queried ghidra @@ -41,10 +40,9 @@ void CommentDatabaseGhidra::fillCache(const Address &fad) const iter = cache.beginComment(fad); iterend = cache.endComment(fad); - doc = ghidra->getComments(fad,commentfilter); - if (doc != (Document *)0) { - cache.restoreXml(doc->getRoot(),ghidra); - delete doc; + XmlDecode decoder; + if (ghidra->getComments(fad,commentfilter,decoder)) { + cache.decode(decoder,ghidra); } } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/comment_ghidra.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/comment_ghidra.hh index d4f5442500..12183225ea 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/comment_ghidra.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/comment_ghidra.hh @@ -45,10 +45,10 @@ public: throw LowlevelError("deleteComment unimplemented"); } virtual CommentSet::const_iterator beginComment(const Address &fad) const; virtual CommentSet::const_iterator endComment(const Address &fad) const; - virtual void saveXml(ostream &s) const { - throw LowlevelError("commentdb::saveXml unimplemented"); } - virtual void restoreXml(const Element *el,const AddrSpaceManager *trans) { - throw LowlevelError("commentdb::restoreXml unimplemented"); } + virtual void encode(Encoder &encoder) const { + throw LowlevelError("commentdb::encode unimplemented"); } + virtual void decode(Decoder &decoder,const AddrSpaceManager *trans) { + throw LowlevelError("CommentDatabaseGhidra::decode unimplemented"); } }; #endif diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/consolemain.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/consolemain.cc index 23932bd539..b4555a9940 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/consolemain.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/consolemain.cc @@ -132,7 +132,8 @@ void IfcSave::execute(istream &s) if (!fs) throw IfaceExecutionError("Unable to open file: "+savefile); - dcp->conf->saveXml(fs); + XmlEncode encoder(fs); + dcp->conf->encode(encoder); fs.close(); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/cpool.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/cpool.cc index 1cb4617ede..56041a3dfa 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/cpool.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/cpool.cc @@ -15,41 +15,52 @@ */ #include "cpool.hh" -/// Save the constant pool object description as a \ tag. -/// \param s is the output stream -void CPoolRecord::saveXml(ostream &s) const +AttributeId ATTRIB_A = AttributeId("a",45); +AttributeId ATTRIB_B = AttributeId("b",46); +AttributeId ATTRIB_LENGTH = AttributeId("length",47); +AttributeId ATTRIB_TAG = AttributeId("tag",48); + +ElementId ELEM_CONSTANTPOOL = ElementId("constantpool",56); +ElementId ELEM_CPOOLREC = ElementId("cpoolrec",57); +ElementId ELEM_REF = ElementId("ref",58); +ElementId ELEM_TOKEN = ElementId("token",59); + +/// Encode the constant pool object description as a \ element. +/// \param encoder is the stream encoder +void CPoolRecord::encode(Encoder &encoder) const { - s << "\n"; + encoder.writeBool(ATTRIB_DESTRUCTOR, true); if (tag == primitive) { - s << " 0x"; - s << hex << value; - s << "\n"; + encoder.openElement(ELEM_VALUE); + encoder.writeUnsignedInteger(ATTRIB_CONTENT, value); + encoder.closeElement(ELEM_VALUE); } if (byteData != (uint1 *)0) { - s << " \n"; + encoder.openElement(ELEM_DATA); + encoder.writeSignedInteger(ATTRIB_LENGTH, byteDataLen); int4 wrap = 0; + ostringstream s; for(int4 i=0;i\n"; + encoder.writeString(ATTRIB_CONTENT, s.str()); + encoder.closeElement(ELEM_DATA); } else { - s << " "; - xml_escape(s,token.c_str()); - s << " \n"; + encoder.openElement(ELEM_TOKEN); + encoder.writeString(ATTRIB_CONTENT, token); + encoder.closeElement(ELEM_TOKEN); } - type->saveXml(s); - s << "\n"; + type->encode(encoder); + encoder.closeElement(ELEM_CPOOLREC); } -/// Initialize \b this CPoolRecord instance from a \ tag. -/// \param el is the \ element +/// Initialize \b this CPoolRecord instance from a \ element. +/// \param decoder is the stream decoder /// \param typegrp is the TypeFactory used to resolve data-types -void CPoolRecord::restoreXml(const Element *el,TypeFactory &typegrp) +void CPoolRecord::decode(Decoder &decoder,TypeFactory &typegrp) { tag = primitive; // Default tag value = 0; flags = 0; - int4 num = el->getNumAttributes(); - for(int4 i=0;igetAttributeName(i)); - if (attr == "tag") { - const string &tagstring(el->getAttributeValue(i)); + uint4 elemId = decoder.openElement(ELEM_CPOOLREC); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_TAG) { + string tagstring = decoder.readString(); if (tagstring == "method") tag = pointer_method; else if (tagstring == "field") @@ -98,36 +111,27 @@ void CPoolRecord::restoreXml(const Element *el,TypeFactory &typegrp) else if (tagstring == "classref") tag = class_reference; } - else if (attr == "constructor") { - if (xml_readbool(el->getAttributeValue(i))) + else if (attribId == ATTRIB_CONSTRUCTOR) { + if (decoder.readBool()) flags |= CPoolRecord::is_constructor; } - else if (attr == "destructor") { - if (xml_readbool(el->getAttributeValue(i))) + else if (attribId == ATTRIB_DESTRUCTOR) { + if (decoder.readBool()) flags |= CPoolRecord::is_destructor; } } - const List &list(el->getChildren()); - List::const_iterator iter; - - iter = list.begin(); - const Element *subel; + uint4 subId; if (tag == primitive) { // First tag must be value - subel = *iter; - istringstream s1(subel->getContent()); - s1.unsetf(ios::dec | ios::hex | ios::oct); - s1 >> value; - ++iter; + subId = decoder.openElement(ELEM_VALUE); + value = decoder.readUnsignedInteger(ATTRIB_CONTENT); + decoder.closeElement(subId); } - subel = *iter; - ++iter; - if (subel->getName() == "token") - token = subel->getContent(); + subId = decoder.openElement(); + if (subId == ELEM_TOKEN) + token = decoder.readString(ATTRIB_CONTENT); else { - istringstream s2(subel->getAttributeValue("length")); - s2.unsetf(ios::dec | ios::hex | ios::oct); - s2 >> byteDataLen; - istringstream s3(subel->getContent()); + byteDataLen = decoder.readSignedInteger(ATTRIB_LENGTH); + istringstream s3(decoder.readString(ATTRIB_CONTENT)); byteData = new uint1[byteDataLen]; for(int4 i=0;i"); - subel = *iter; if (flags != 0) { bool isConstructor = ((flags & is_constructor)!=0); bool isDestructor = ((flags & is_destructor)!=0); - type = typegrp.restoreXmlTypeWithCodeFlags(subel,isConstructor,isDestructor); + type = typegrp.decodeTypeWithCodeFlags(decoder,isConstructor,isDestructor); } else - type = typegrp.restoreXmlType(subel); + type = typegrp.decodeType(decoder); + decoder.closeElement(elemId); } void ConstantPool::putRecord(const vector &refs,uint4 tag,const string &tok,Datatype *ct) @@ -156,36 +161,34 @@ void ConstantPool::putRecord(const vector &refs,uint4 tag,const string &t newrec->type = ct; } -const CPoolRecord *ConstantPool::restoreXmlRecord(const vector &refs,const Element *el,TypeFactory &typegrp) +const CPoolRecord *ConstantPool::decodeRecord(const vector &refs,Decoder &decoder,TypeFactory &typegrp) { CPoolRecord *newrec = createRecord(refs); - newrec->restoreXml(el,typegrp); + newrec->decode(decoder,typegrp); return newrec; } -/// The reference is output as a \ tag. -/// \param s is the output stream -void ConstantPoolInternal::CheapSorter::saveXml(ostream &s) const +/// The reference is encoded as a \ element. +/// \param encoder is the stream encoder +void ConstantPoolInternal::CheapSorter::encode(Encoder &encoder) const { - s << "\n"; + encoder.openElement(ELEM_REF); + encoder.writeUnsignedInteger(ATTRIB_A, a); + encoder.writeUnsignedInteger(ATTRIB_B, b); + encoder.closeElement(ELEM_REF); } -/// Restore \b this \e reference from a \ XML tag -/// \param el is the XML element -void ConstantPoolInternal::CheapSorter::restoreXml(const Element *el) +/// Restore \b this \e reference from a \ element +/// \param decoder is the stream decoder +void ConstantPoolInternal::CheapSorter::decode(Decoder &decoder) { - istringstream s1(el->getAttributeValue("a")); - s1.unsetf(ios::dec | ios::hex | ios::oct); - s1 >> a; - istringstream s2(el->getAttributeValue("b")); - s2.unsetf(ios::dec | ios::hex | ios::oct); - s2 >> b; + uint4 elemId = decoder.openElement(ELEM_REF); + a = decoder.readUnsignedInteger(ATTRIB_A); + b = decoder.readUnsignedInteger(ATTRIB_B); + decoder.closeElement(elemId); } CPoolRecord *ConstantPoolInternal::createRecord(const vector &refs) @@ -210,32 +213,29 @@ const CPoolRecord *ConstantPoolInternal::getRecord(const vector &refs) co return &(*iter).second; } -void ConstantPoolInternal::saveXml(ostream &s) const +void ConstantPoolInternal::encode(Encoder &encoder) const { map::const_iterator iter; - s << "\n"; + encoder.openElement(ELEM_CONSTANTPOOL); for(iter=cpoolMap.begin();iter!=cpoolMap.end();++iter) { - (*iter).first.saveXml(s); - (*iter).second.saveXml(s); + (*iter).first.encode(encoder); + (*iter).second.encode(encoder); } - s << "\n"; + encoder.closeElement(ELEM_CONSTANTPOOL); } -void ConstantPoolInternal::restoreXml(const Element *el,TypeFactory &typegrp) +void ConstantPoolInternal::decode(Decoder &decoder,TypeFactory &typegrp) { - const List &list(el->getChildren()); - List::const_iterator iter; - for(iter=list.begin();iter!=list.end();++iter) { - const Element *subel = *iter; + uint4 elemId = decoder.openElement(ELEM_CONSTANTPOOL); + while(decoder.peekElement() != 0) { CheapSorter sorter; - sorter.restoreXml(subel); + sorter.decode(decoder); vector refs; sorter.apply(refs); - ++iter; - subel = *iter; CPoolRecord *newrec = createRecord(refs); - newrec->restoreXml(subel,typegrp); + newrec->decode(decoder,typegrp); } + decoder.closeElement(elemId); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/cpool.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/cpool.hh index 7a90f6e9f8..ce9b9809a2 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/cpool.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/cpool.hh @@ -21,6 +21,16 @@ #include "type.hh" +extern AttributeId ATTRIB_A; ///< Marshaling attribute "a" +extern AttributeId ATTRIB_B; ///< Marshaling attribute "b" +extern AttributeId ATTRIB_LENGTH; ///< Marshaling attribute "length" +extern AttributeId ATTRIB_TAG; ///< Marshaling attribute "tag" + +extern ElementId ELEM_CONSTANTPOOL; ///< Marshaling element \ +extern ElementId ELEM_CPOOLREC; ///< Marshaling element \ +extern ElementId ELEM_REF; ///< Marshaling element \ +extern ElementId ELEM_TOKEN; ///< Marshaling element \ + /// \brief A description of a byte-code object referenced by a constant /// /// Byte-code languages can make use of objects that the \e system knows about @@ -78,8 +88,8 @@ public: uintb getValue(void) const { return value; } ///< Get the constant value associated with \b this bool isConstructor(void) const { return ((flags & is_constructor)!=0); } ///< Is object a constructor method bool isDestructor(void) const { return ((flags & is_destructor)!=0); } ///< Is object a destructor method - void saveXml(ostream &s) const; ///< Save object to an XML stream - void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore object from XML stream + void encode(Encoder &encoder) const; ///< Encode \b this to a stream + void decode(Decoder &decoder,TypeFactory &typegrp); ///< Decode \b this from a stream }; /// \brief An interface to the pool of \b constant objects for byte-code languages @@ -116,33 +126,33 @@ public: /// \param ct is the data-type associated with the object void putRecord(const vector &refs,uint4 tag,const string &tok,Datatype *ct); - /// \brief Restore a CPoolRecord given a \e reference and an XML stream + /// \brief Restore a CPoolRecord given a \e reference and a stream decoder /// /// A \ element initializes the new record which is immediately associated /// with the \e reference. /// \param refs is the \e reference (made up of 1 or more identifying integers) - /// \param el is the XML element + /// \param decoder is the given stream decoder /// \param typegrp is the TypeFactory used to resolve data-type references in XML /// \return the newly allocated and initialized CPoolRecord - const CPoolRecord *restoreXmlRecord(const vector &refs,const Element *el,TypeFactory &typegrp); + const CPoolRecord *decodeRecord(const vector &refs,Decoder &decoder,TypeFactory &typegrp); virtual bool empty(void) const=0; ///< Is the container empty of records virtual void clear(void)=0; ///< Release any (local) resources - /// \brief Save all records in this container to an XML stream + /// \brief Encode all records in this container to a stream /// - /// (If supported) An \ element is written containing \ + /// (If supported) A \ element is written containing \ /// child elements for each CPoolRecord in the container. - /// \param s is the output stream - virtual void saveXml(ostream &s) const=0; + /// \param encoder is the stream encoder + virtual void encode(Encoder &encoder) const=0; - /// \brief Restore constant pool records from an XML stream + /// \brief Restore constant pool records from the given stream decoder /// - /// (If supported) The container is populated with CPooLRecords initialized - /// from a \ XML tag. - /// \param el is the XML element + /// (If supported) The container is populated with CPoolRecords initialized + /// from a \ element. + /// \param decoder is the given stream decoder /// \param typegrp is the TypeFactory used to resolve data-type references in the XML - virtual void restoreXml(const Element *el,TypeFactory &typegrp)=0; + virtual void decode(Decoder &decoder,TypeFactory &typegrp)=0; }; /// \brief An implementation of the ConstantPool interface storing records internally in RAM @@ -182,8 +192,8 @@ class ConstantPoolInternal : public ConstantPool { /// \param refs is the provided container of integers void apply(vector &refs) const { refs.push_back(a); refs.push_back(b); } - void saveXml(ostream &s) const; ///< Serialize the \e reference to an XML element - void restoreXml(const Element *el); ///< Deserialize the \e reference from an XML element + void encode(Encoder &encoder) const; ///< Encode the \e reference to a stream + void decode(Decoder &decoder); ///< Decode the \e reference from a stream }; map cpoolMap; ///< A map from \e reference to constant pool record virtual CPoolRecord *createRecord(const vector &refs); @@ -191,8 +201,8 @@ public: virtual const CPoolRecord *getRecord(const vector &refs) const; virtual bool empty(void) const { return cpoolMap.empty(); } virtual void clear(void) { cpoolMap.clear(); } - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el,TypeFactory &typegrp); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,TypeFactory &typegrp); }; #endif diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/cpool_ghidra.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/cpool_ghidra.cc index c669fa1243..e57c070796 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/cpool_ghidra.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/cpool_ghidra.cc @@ -32,9 +32,10 @@ const CPoolRecord *ConstantPoolGhidra::getRecord(const vector &refs) cons { const CPoolRecord *rec = cache.getRecord(refs); if (rec == (const CPoolRecord *)0) { - Document *doc; + XmlDecode decoder; + bool success; try { - doc = ghidra->getCPoolRef(refs); + success = ghidra->getCPoolRef(refs,decoder); } catch(JavaError &err) { throw LowlevelError("Error fetching constant pool record: " + err.explain); @@ -42,24 +43,23 @@ const CPoolRecord *ConstantPoolGhidra::getRecord(const vector &refs) cons catch(XmlError &err) { throw LowlevelError("Error in constant pool record xml: "+err.explain); } - if (doc == (Document *)0) { + if (!success) { ostringstream s; s << "Could not retrieve constant pool record for reference: 0x" << refs[0]; throw LowlevelError(s.str()); } - rec = cache.restoreXmlRecord(refs,doc->getRoot(),*ghidra->types); - delete doc; + rec = cache.decodeRecord(refs,decoder,*ghidra->types); } return rec; } -void ConstantPoolGhidra::saveXml(ostream &s) const +void ConstantPoolGhidra::encode(Encoder &encoder) const { throw LowlevelError("Cannot access constant pool with this method"); } -void ConstantPoolGhidra::restoreXml(const Element *el,TypeFactory &typegrp) +void ConstantPoolGhidra::decode(Decoder &decoder,TypeFactory &typegrp) { throw LowlevelError("Cannot access constant pool with this method"); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/cpool_ghidra.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/cpool_ghidra.hh index 7626a280bb..af65a8d2bb 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/cpool_ghidra.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/cpool_ghidra.hh @@ -25,7 +25,7 @@ /// /// The actual CPoolRecord objects are cached locally, but new queries are placed /// with the Ghidra client hosting the program currently being decompiled. The -/// queries and response records are sent via XML. The saveXml() and restoreXml() +/// queries and response records are sent via XML. The encode() and decode() /// methods are disabled. The clear() method only releases the local cache, /// no records on the Ghidra client are affected. class ConstantPoolGhidra : public ConstantPool { @@ -37,8 +37,8 @@ public: virtual const CPoolRecord *getRecord(const vector &refs) const; virtual bool empty(void) const { return false; } virtual void clear(void) { cache.clear(); } - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el,TypeFactory &typegrp); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,TypeFactory &typegrp); }; #endif diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc index 8ba62b9e74..2a7a6dfb8a 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/database.cc @@ -18,10 +18,32 @@ #include "crc32.hh" #include +AttributeId ATTRIB_CAT = AttributeId("cat",49); +AttributeId ATTRIB_FIELD = AttributeId("field",50); +AttributeId ATTRIB_MERGE = AttributeId("merge",51); +AttributeId ATTRIB_SCOPEIDBYNAME = AttributeId("scopeidbyname",52); +AttributeId ATTRIB_VOLATILE = AttributeId("volatile",53); + +ElementId ELEM_COLLISION = ElementId("collision",60); +ElementId ELEM_DB = ElementId("db",61); +ElementId ELEM_EQUATESYMBOL = ElementId("equatesymbol",62); +ElementId ELEM_EXTERNREFSYMBOL = ElementId("externrefsymbol",63); +ElementId ELEM_FACETSYMBOL = ElementId("facetsymbol",64); +ElementId ELEM_FUNCTIONSHELL = ElementId("functionshell",65); +ElementId ELEM_HASH = ElementId("hash",66); +ElementId ELEM_HOLE = ElementId("hole",67); +ElementId ELEM_LABELSYM = ElementId("labelsym",68); +ElementId ELEM_MAPSYM = ElementId("mapsym",69); +ElementId ELEM_PARENT = ElementId("parent",70); +ElementId ELEM_PROPERTY_CHANGEPOINT = ElementId("property_changepoint",71); +ElementId ELEM_RANGEEQUALSSYMBOLS = ElementId("rangeequalssymbols",72); +ElementId ELEM_SCOPE = ElementId("scope",73); +ElementId ELEM_SYMBOLLIST = ElementId("symbollist",74); + uint8 Symbol::ID_BASE = 0x4000000000000000L; /// This SymbolEntry is unintegrated. An address or hash must be provided -/// either directly or via restoreXml(). +/// either directly or via decode(). /// \param sym is the Symbol \b this will be a map for SymbolEntry::SymbolEntry(Symbol *sym) : symbol(sym) @@ -167,48 +189,45 @@ void SymbolEntry::printEntry(ostream &s) const uselimit.printBounds(s); } -/// This writes tags internal to the \ tag associated with the Symbol. -/// It outputs the address tag (or the \ tag for dynamic symbols) and -/// a \ tag associated with the \b uselimit. -/// \param s is the output stream -void SymbolEntry::saveXml(ostream &s) const +/// This writes elements internal to the \ element associated with the Symbol. +/// It encodes the address element (or the \ element for dynamic symbols) and +/// a \ element associated with the \b uselimit. +/// \param encoder is the stream encoder +void SymbolEntry::encode(Encoder &encoder) const { if (isPiece()) return; // Don't save a piece if (addr.isInvalid()) { - s << "\n"; + encoder.openElement(ELEM_HASH); + encoder.writeUnsignedInteger(ATTRIB_VAL, hash); + encoder.closeElement(ELEM_HASH); } else - addr.saveXml(s); - uselimit.saveXml(s); + addr.encode(encoder); + uselimit.encode(encoder); } -/// Given an iterator to children of a \ tag, restore the storage address -/// (or the hash if the symbol is dynamic) and the \b uselimit describing the valid -/// range of code addresses, then advance the iterator to the next tag. -/// \param iter is the iterator pointing to the address or hash tag +/// Parse either an \ element for storage information or a \ element +/// if the symbol is dynamic. Then parse the \b uselimit describing the valid +/// range of code addresses. +/// \param decoder is the stream decoder /// \param manage is an address space manager for constructing Address objects /// \return the advanced iterator -List::const_iterator SymbolEntry::restoreXml(List::const_iterator iter,const AddrSpaceManager *manage) +void SymbolEntry::decode(Decoder &decoder,const AddrSpaceManager *manage) { - const Element *storeel = *iter; - ++iter; - if (storeel->getName() == "hash") { - istringstream s(storeel->getAttributeValue("val")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> hash; + uint4 elemId = decoder.peekElement(); + if (elemId == ELEM_HASH) { + decoder.openElement(); + hash = decoder.readUnsignedInteger(ATTRIB_VAL); addr = Address(); + decoder.closeElement(elemId); } else { - addr = Address::restoreXml(storeel,manage); + addr = Address::decode(decoder,manage); hash = 0; } - const Element *rangeel = *iter; - ++iter; - uselimit.restoreXml(rangeel,manage); - return iter; + uselimit.decode(decoder,manage); } /// Examine the data-type to decide if the Symbol has the special property @@ -350,168 +369,138 @@ int4 Symbol::getResolutionDepth(const Scope *useScope) const return depthResolution; } -/// \param s is the output stream -void Symbol::saveXmlHeader(ostream &s) const +/// \param encoder is the stream encoder +void Symbol::encodeHeader(Encoder &encoder) const { - a_v(s,"name",name); - a_v_u(s,"id",getId()); + encoder.writeString(ATTRIB_NAME, name); + encoder.writeUnsignedInteger(ATTRIB_ID, getId()); if ((flags&Varnode::namelock)!=0) - a_v_b(s,"namelock",true); + encoder.writeBool(ATTRIB_NAMELOCK, true); if ((flags&Varnode::typelock)!=0) - a_v_b(s,"typelock",true); + encoder.writeBool(ATTRIB_TYPELOCK, true); if ((flags&Varnode::readonly)!=0) - a_v_b(s,"readonly",true); + encoder.writeBool(ATTRIB_READONLY, true); if ((flags&Varnode::volatil)!=0) - a_v_b(s,"volatile",true); + encoder.writeBool(ATTRIB_VOLATILE, true); if ((flags&Varnode::indirectstorage)!=0) - a_v_b(s,"indirectstorage",true); + encoder.writeBool(ATTRIB_INDIRECTSTORAGE, true); if ((flags&Varnode::hiddenretparm)!=0) - a_v_b(s,"hiddenretparm",true); + encoder.writeBool(ATTRIB_HIDDENRETPARM, true); if ((dispflags&isolate)!=0) - a_v_b(s,"merge",false); + encoder.writeBool(ATTRIB_MERGE, false); if ((dispflags&is_this_ptr)!=0) - a_v_b(s,"thisptr",true); + encoder.writeBool(ATTRIB_THISPTR, true); int4 format = getDisplayFormat(); if (format != 0) { - s << " format=\""; - s << Datatype::decodeIntegerFormat(format); - s << '\"'; + encoder.writeString(ATTRIB_FORMAT, Datatype::decodeIntegerFormat(format)); } - a_v_i(s,"cat",category); + encoder.writeSignedInteger(ATTRIB_CAT, category); if (category >= 0) - a_v_u(s,"index",catindex); + encoder.writeUnsignedInteger(ATTRIB_INDEX, catindex); } -/// \param el is the XML \ element -void Symbol::restoreXmlHeader(const Element *el) +/// \param decoder is the stream decoder +void Symbol::decodeHeader(Decoder &decoder) { name.clear(); category = no_category; symbolId = 0; - for(int4 i=0;igetNumAttributes();++i) { - const string &attName(el->getAttributeName(i)); - switch (attName[0]) { - case 'c': - if (attName == "cat") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> category; - } - break; - case 'f': - if (attName == "format") { - const string &formString(el->getAttributeValue(i)); - dispflags |= Datatype::encodeIntegerFormat(formString); - } - break; - case 'h': - if (attName == "hiddenretparm") { - if (xml_readbool(el->getAttributeValue(i))) - flags |= Varnode::hiddenretparm; - } - break; - case 'i': - if (attName == "id") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> symbolId; - if ((symbolId >> 56) == (ID_BASE >> 56)) - symbolId = 0; // Don't keep old internal id's - } - else if (attName == "indirectstorage") { - if (xml_readbool(el->getAttributeValue(i))) - flags |= Varnode::indirectstorage; - } - break; - case 'm': - if (attName == "merge") { - if (!xml_readbool(el->getAttributeValue(i))) { - dispflags |= isolate; - flags |= Varnode::typelock; - } - } - break; - case 'n': - if (attName == "name") - name = el->getAttributeValue(i); - else if (attName == "namelock") { - if (xml_readbool(el->getAttributeValue(i))) - flags |= Varnode::namelock; - } - break; - case 'r': - if (attName == "readonly") { - if (xml_readbool(el->getAttributeValue(i))) - flags |= Varnode::readonly; - } - break; - case 't': - if (attName == "typelock") { - if (xml_readbool(el->getAttributeValue(i))) - flags |= Varnode::typelock; - } - else if (attName == "thisptr") { - if (xml_readbool(el->getAttributeValue(i))) - dispflags |= is_this_ptr; - } - break; - case 'v': - if (attName == "volatile") { - if (xml_readbool(el->getAttributeValue(i))) - flags |= Varnode::volatil; - } - break; - default: - break; + for(;;) { + uintb attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_CAT) { + category = decoder.readSignedInteger(); + } + else if (attribId == ATTRIB_FORMAT) { + dispflags |= Datatype::encodeIntegerFormat(decoder.readString()); + } + else if (attribId == ATTRIB_HIDDENRETPARM) { + if (decoder.readBool()) + flags |= Varnode::hiddenretparm; + } + else if (attribId == ATTRIB_ID) { + symbolId = decoder.readUnsignedInteger(); + if ((symbolId >> 56) == (ID_BASE >> 56)) + symbolId = 0; // Don't keep old internal id's + } + else if (attribId == ATTRIB_INDIRECTSTORAGE) { + if (decoder.readBool()) + flags |= Varnode::indirectstorage; + } + else if (attribId == ATTRIB_MERGE) { + if (!decoder.readBool()) { + dispflags |= isolate; + flags |= Varnode::typelock; + } + } + else if (attribId == ATTRIB_NAME) + name = decoder.readString(); + else if (attribId == ATTRIB_NAMELOCK) { + if (decoder.readBool()) + flags |= Varnode::namelock; + } + else if (attribId == ATTRIB_READONLY) { + if (decoder.readBool()) + flags |= Varnode::readonly; + } + else if (attribId == ATTRIB_TYPELOCK) { + if (decoder.readBool()) + flags |= Varnode::typelock; + } + else if (attribId == ATTRIB_THISPTR) { + if (decoder.readBool()) + dispflags |= is_this_ptr; + } + else if (attribId == ATTRIB_VOLATILE) { + if (decoder.readBool()) + flags |= Varnode::volatil; } } if (category == function_parameter) { - istringstream s2(el->getAttributeValue("index")); - s2.unsetf(ios::dec | ios::hex | ios::oct); - s2 >> catindex; + catindex = decoder.readUnsignedInteger(ATTRIB_INDEX); } else catindex = 0; } -/// Save the data-type for the Symbol -/// \param s is the output stream -void Symbol::saveXmlBody(ostream &s) const +/// Encode the data-type for the Symbol +/// \param encoder is the stream encoder +void Symbol::encodeBody(Encoder &encoder) const { - type->saveXmlRef(s); + type->encodeRef(encoder); } -/// \param iter iterates over XML children of the root \ tag -void Symbol::restoreXmlBody(List::const_iterator iter) +/// \param decoder is the stream decoder +void Symbol::decodeBody(Decoder &decoder) { - const Element *el = *iter; - type = scope->getArch()->types->restoreXmlType(el); + type = scope->getArch()->types->decodeType(decoder); checkSizeTypeLock(); } -/// \param s is the output stream -void Symbol::saveXml(ostream &s) const +/// \param encoder is the stream encoder +void Symbol::encode(Encoder &encoder) const { - s << "\n"; - saveXmlBody(s); - s << "\n"; + encoder.openElement(ELEM_SYMBOL); + encodeHeader(encoder); + encodeBody(encoder); + encoder.closeElement(ELEM_SYMBOL); } -/// \param el is the root XML tag of the symbol -void Symbol::restoreXml(const Element *el) +/// Parse a Symbol from the next element in the stream +/// \param decoder is the stream decoder +void Symbol::decode(Decoder &decoder) { - restoreXmlHeader(el); - const List &list(el->getChildren()); + uint4 elemId = decoder.openElement(ELEM_SYMBOL); + decodeHeader(decoder); - restoreXmlBody(list.begin()); + decodeBody(decoder); + decoder.closeElement(elemId); } /// Get the number of bytes consumed by a SymbolEntry representing \b this Symbol. @@ -577,26 +566,32 @@ Funcdata *FunctionSymbol::getFunction(void) return fd; } -void FunctionSymbol::saveXml(ostream &s) const +void FunctionSymbol::encode(Encoder &encoder) const { if (fd != (Funcdata *)0) - fd->saveXml(s,symbolId,false); // Save the function itself + fd->encode(encoder,symbolId,false); // Save the function itself else { - s << "\n"; + encoder.writeUnsignedInteger(ATTRIB_ID, symbolId); + encoder.closeElement(ELEM_FUNCTIONSHELL); } } -void FunctionSymbol::restoreXml(const Element *el) +void FunctionSymbol::decode(Decoder &decoder) { - if (el->getName() == "function") { + uint4 elemId = decoder.peekElement(); + if (elemId == ELEM_FUNCTION) { fd = new Funcdata("",scope,Address(),this); - symbolId = fd->restoreXml(el); + try { + symbolId = fd->decode(decoder); + } catch(RecovError &err) { + // Caused by a duplicate scope name. Preserve the address so we can find the original symbol + throw DuplicateFunctionError(fd->getAddress(),fd->getName()); + } name = fd->getName(); if (consumeSize < fd->getSize()) { if ((fd->getSize()>1)&&(fd->getSize() <= 8)) @@ -604,17 +599,18 @@ void FunctionSymbol::restoreXml(const Element *el) } } else { // functionshell + decoder.openElement(); symbolId = 0; - for(int4 i=0;igetNumAttributes();++i) { - const string &attrName(el->getAttributeName(i)); - if (attrName == "name") - name = el->getAttributeValue(i); - else if (attrName == "id") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> symbolId; + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_NAME) + name = decoder.readString(); + else if (attribId == ATTRIB_ID) { + symbolId = decoder.readUnsignedInteger(); } } + decoder.closeElement(elemId); } } @@ -659,29 +655,30 @@ bool EquateSymbol::isValueClose(uintb op2Value,int4 size) const return false; } -void EquateSymbol::saveXml(ostream &s) const +void EquateSymbol::encode(Encoder &encoder) const { - s << "\n"; - s << " 0x" << hex << value << "\n"; - s << "\n"; + encoder.openElement(ELEM_EQUATESYMBOL); + encodeHeader(encoder); + encoder.openElement(ELEM_VALUE); + encoder.writeUnsignedInteger(ATTRIB_CONTENT, value); + encoder.closeElement(ELEM_VALUE); + encoder.closeElement(ELEM_EQUATESYMBOL); } -void EquateSymbol::restoreXml(const Element *el) +void EquateSymbol::decode(Decoder &decoder) { - restoreXmlHeader(el); - const List &list(el->getChildren()); + uint4 elemId = decoder.openElement(ELEM_EQUATESYMBOL); + decodeHeader(decoder); - const Element *subel = *list.begin(); - istringstream s(subel->getContent()); - s.unsetf(ios::dec|ios::hex|ios::oct); - s >> value; + uint4 subId = decoder.openElement(ELEM_VALUE); + value = decoder.readUnsignedInteger(ATTRIB_CONTENT); + decoder.closeElement(subId); TypeFactory *types = scope->getArch()->types; type = types->getBase(1,TYPE_UNKNOWN); + decoder.closeElement(elemId); } /// Create a symbol that forces a particular field of a union to propagate @@ -697,27 +694,25 @@ UnionFacetSymbol::UnionFacetSymbol(Scope *sc,const string &nm,Datatype *unionDt, category = union_facet; } -void UnionFacetSymbol::saveXml(ostream &s) const +void UnionFacetSymbol::encode(Encoder &encoder) const { - s << "\n"; - saveXmlBody(s); - s << "\n"; + encoder.openElement(ELEM_FACETSYMBOL); + encodeHeader(encoder); + encoder.writeSignedInteger(ATTRIB_FIELD, fieldNum); + encodeBody(encoder); + encoder.closeElement(ELEM_FACETSYMBOL); } -void UnionFacetSymbol::restoreXml(const Element *el) +void UnionFacetSymbol::decode(Decoder &decoder) { - restoreXmlHeader(el); - istringstream s(el->getAttributeValue("field")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> fieldNum; - const List &list(el->getChildren()); + uint4 elemId = decoder.openElement(ELEM_FACETSYMBOL); + decodeHeader(decoder); + fieldNum = decoder.readSignedInteger(ATTRIB_FIELD); - restoreXmlBody(list.begin()); + decodeBody(decoder); + decoder.closeElement(elemId); Datatype *testType = type; if (testType->getMetatype() == TYPE_PTR) testType = ((TypePointer *)testType)->getPtrTo(); @@ -751,18 +746,20 @@ LabSymbol::LabSymbol(Scope *sc) buildType(); } -void LabSymbol::saveXml(ostream &s) const +void LabSymbol::encode(Encoder &encoder) const { - s << "\n"; + encoder.openElement(ELEM_LABELSYM); + encodeHeader(encoder); // We never set category + encoder.closeElement(ELEM_LABELSYM); } -void LabSymbol::restoreXml(const Element *el) +void LabSymbol::decode(Decoder &decoder) { - restoreXmlHeader(el); + uint4 elemId = decoder.openElement(ELEM_LABELSYM); + decodeHeader(decoder); + decoder.closeElement(elemId); } /// Build name, type, and flags based on the placeholder address @@ -792,29 +789,28 @@ ExternRefSymbol::ExternRefSymbol(Scope *sc,const Address &ref,const string &nm) buildNameType(); } -void ExternRefSymbol::saveXml(ostream &s) const +void ExternRefSymbol::encode(Encoder &encoder) const { - s << "\n"; - refaddr.saveXml(s); - s << "\n"; + encoder.openElement(ELEM_EXTERNREFSYMBOL); + encoder.writeString(ATTRIB_NAME, name); + refaddr.encode(encoder); + encoder.closeElement(ELEM_EXTERNREFSYMBOL); } -void ExternRefSymbol::restoreXml(const Element *el) +void ExternRefSymbol::decode(Decoder &decoder) { + uint4 elemId = decoder.openElement(ELEM_EXTERNREFSYMBOL); name = ""; // Name is empty - for(int4 i=0;igetNumAttributes();++i) { - if (el->getAttributeName(i) == "name") // Unless we see it explicitly - name = el->getAttributeValue(i); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_NAME) // Unless we see it explicitly + name = decoder.readString(); } - const List &list(el->getChildren()); - List::const_iterator iter; - - iter = list.begin(); - refaddr = Address::restoreXml(*iter,scope->getArch()); + refaddr = Address::decode(decoder,scope->getArch()); + decoder.closeElement(elemId); buildNameType(); } @@ -1361,19 +1357,19 @@ Scope *Scope::discoverScope(const Address &addr,int4 sz,const Address &usepoint) return (Scope *)0; } -/// This Scope and all of its sub-scopes are saved as a sequence of \ tags -/// in post order. For each Scope, the saveXml() method is invoked. -/// \param s is the output stream +/// This Scope and all of its sub-scopes are encoded as a sequence of \ elements +/// in post order. For each Scope, the encode() method is invoked. +/// \param encoder is the stream encoder /// \param onlyGlobal is \b true if only non-local Scopes should be saved -void Scope::saveXmlRecursive(ostream &s,bool onlyGlobal) const +void Scope::encodeRecursive(Encoder &encoder,bool onlyGlobal) const { if (onlyGlobal && (!isGlobal())) return; // Only save global scopes - saveXml(s); + encode(encoder); ScopeMap::const_iterator iter = children.begin(); ScopeMap::const_iterator enditer = children.end(); for(;iter!=enditer;++iter) { - (*iter).second->saveXmlRecursive(s,onlyGlobal); + (*iter).second->encodeRecursive(encoder,onlyGlobal); } } @@ -1551,55 +1547,52 @@ SymbolEntry *Scope::addMapPoint(Symbol *sym, return addMap(entry); } -/// A tag describing the Symbol is parsed first, followed by sequences of -/// \ or \ and \ which define 1 or more mappings of the Symbol -/// The new Symbol and SymbolEntry mappings are integrated into \b this Scope -/// \param el is the \ XML element +/// A Symbol element is parsed first, followed by sequences of \ elements or +/// \ and \ elements which define 1 or more mappings of the Symbol. +/// The new Symbol and SymbolEntry mappings are integrated into \b this Scope. +/// \param decoder is the stream decoder /// \return the new Symbol -Symbol *Scope::addMapSym(const Element *el) +Symbol *Scope::addMapSym(Decoder &decoder) { - const List &sublist( el->getChildren()); - List::const_iterator subiter = sublist.begin(); - const Element *subel = *subiter; + uint4 elemId = decoder.openElement(ELEM_MAPSYM); + uint4 subId = decoder.peekElement(); Symbol *sym; - const string &symname( subel->getName() ); - if (symname == "symbol") + if (subId == ELEM_SYMBOL) sym = new Symbol(owner); - else if (symname == "dynsymbol") - sym = new Symbol(owner); - else if (symname == "equatesymbol") + else if (subId == ELEM_EQUATESYMBOL) sym = new EquateSymbol(owner); - else if (symname == "function") + else if (subId == ELEM_FUNCTION) sym = new FunctionSymbol(owner,glb->min_funcsymbol_size); - else if (symname == "functionshell") + else if (subId == ELEM_FUNCTIONSHELL) sym = new FunctionSymbol(owner,glb->min_funcsymbol_size); - else if (symname == "labelsym") + else if (subId == ELEM_LABELSYM) sym = new LabSymbol(owner); - else if (symname == "externrefsymbol") + else if (subId == ELEM_EXTERNREFSYMBOL) sym = new ExternRefSymbol(owner); - else if (symname == "facetsymbol") + else if (subId == ELEM_FACETSYMBOL) sym = new UnionFacetSymbol(owner); else - throw LowlevelError("Unknown symbol type: "+symname); + throw LowlevelError("Unknown symbol type"); try { // Protect against duplicate scope errors - sym->restoreXml(subel); + sym->decode(decoder); } catch(RecovError &err) { delete sym; - throw err; + throw; } addSymbolInternal(sym); // This routine may throw, but it will delete sym in this case - ++subiter; - while(subiter != sublist.end()) { + while(decoder.peekElement() != 0) { SymbolEntry entry(sym); - subiter = entry.restoreXml(subiter,glb); + entry.decode(decoder,glb); if (entry.isInvalid()) { - glb->printMessage("WARNING: Throwing out symbol with invalid mapping: "+symname); + glb->printMessage("WARNING: Throwing out symbol with invalid mapping: "+sym->getName()); removeSymbol(sym); + decoder.closeElement(elemId); return (Symbol *)0; } addMap(entry); } + decoder.closeElement(elemId); return sym; } @@ -2582,22 +2575,21 @@ string ScopeInternal::makeNameUnique(const string &nm) const return resString; } -void ScopeInternal::saveXml(ostream &s) const +void ScopeInternal::encode(Encoder &encoder) const { - s << "\n"; + encoder.openElement(ELEM_SCOPE); + encoder.writeString(ATTRIB_NAME, name); + encoder.writeUnsignedInteger(ATTRIB_ID, uniqueId); if (getParent() != (const Scope *)0) { - s << "getId()); - s << "/>\n"; + encoder.openElement(ELEM_PARENT); + encoder.writeUnsignedInteger(ATTRIB_ID, getParent()->getId()); + encoder.closeElement(ELEM_PARENT); } - getRangeTree().saveXml(s); + getRangeTree().encode(encoder); if (!nametree.empty()) { - s << "\n"; + encoder.openElement(ELEM_SYMBOLLIST); SymbolNameTree::const_iterator iter; for(iter=nametree.begin();iter!=nametree.end();++iter) { Symbol *sym = *iter; @@ -2610,60 +2602,64 @@ void ScopeInternal::saveXml(ostream &s) const symbolType = (sym->getCategory() == Symbol::equate) ? 2 : 1; } } - s << "\n"; - sym->saveXml(s); + encoder.writeString(ATTRIB_TYPE, "equate"); + sym->encode(encoder); vector::iterator>::const_iterator miter; for(miter=sym->mapentry.begin();miter!=sym->mapentry.end();++miter) { const SymbolEntry &entry((*(*miter))); - entry.saveXml(s); + entry.encode(encoder); } - s << "\n"; + encoder.closeElement(ELEM_MAPSYM); } - s << "\n"; + encoder.closeElement(ELEM_SYMBOLLIST); } - s << "\n"; + encoder.closeElement(ELEM_SCOPE); } -/// \brief Parse a \ XML tag that describes boolean properties of memory range. +/// \brief Parse a \ element describing boolean properties of a memory range. /// -/// The \ XML tag is allowed to contain \ tags, which are really descriptions +/// The \ element is allowed to contain \ elements, which are really descriptions /// of memory globally. This method parses them and passes the info to the Database /// object. -/// \param el is the \ element -void ScopeInternal::processHole(const Element *el) +/// \param decoder is the stream decoder +void ScopeInternal::decodeHole(Decoder &decoder) { + uint4 elemId = decoder.openElement(ELEM_HOLE); uint4 flags = 0; - for(int4 i=0;igetNumAttributes();++i) { - if ((el->getAttributeName(i)=="readonly")&& - xml_readbool(el->getAttributeValue(i))) + Range range; + range.decodeFromAttributes(decoder, glb); + decoder.rewindAttributes(); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if ((attribId==ATTRIB_READONLY) && decoder.readBool()) flags |= Varnode::readonly; - else if ((el->getAttributeName(i)=="volatile")&& - xml_readbool(el->getAttributeValue(i))) + else if ((attribId==ATTRIB_VOLATILE) && decoder.readBool()) flags |= Varnode::volatil; } if (flags != 0) { - Range range; - range.restoreXml(el,glb); glb->symboltab->setPropertyRange(flags,range); } + decoder.closeElement(elemId); } -/// \brief Parse a \ tag indicating a named symbol with no storage or data-type info +/// \brief Parse a \ element indicating a named symbol with no storage or data-type info /// /// Let the decompiler know that a name is occupied within the scope for isNameUsed queries, without /// specifying storage and data-type information about the symbol. This is modeled currently by /// creating an unmapped symbol. -/// \param el is the \ element -void ScopeInternal::processCollision(const Element *el) +/// \param decoder is the stream decoder +void ScopeInternal::decodeCollision(Decoder &decoder) { - const string &nm(el->getAttributeValue("name")); + uint4 elemId = decoder.openElement(ELEM_COLLISION); + string nm = decoder.readString(ATTRIB_NAME); + decoder.closeElement(elemId); SymbolNameTree::const_iterator iter = findFirstByName(nm); if (iter == nametree.end()) { Datatype *ct = glb->types->getBase(1,TYPE_INT); @@ -2707,54 +2703,50 @@ SymbolNameTree::const_iterator ScopeInternal::findFirstByName(const string &nm) return iter; } -void ScopeInternal::restoreXml(const Element *el) +void ScopeInternal::decode(Decoder &decoder) { +// uint4 elemId = decoder.openElement(ELEM_SCOPE); // name = el->getAttributeValue("name"); // Name must already be set in the constructor bool rangeequalssymbols = false; - const List &list(el->getChildren()); - List::const_iterator iter; - const Element *subel; - - iter = list.begin(); - subel = *iter; - if (subel->getName() == "parent") { - ++iter; // Skip tag processed elsewhere - subel = *iter; + uint4 subId = decoder.peekElement(); + if (subId == ELEM_PARENT) { + decoder.skipElement(); // Skip tag processed elsewhere + subId = decoder.peekElement(); } - if (subel->getName() == "rangelist") { + if (subId== ELEM_RANGELIST) { RangeList newrangetree; - newrangetree.restoreXml(subel,glb); + newrangetree.decode(decoder,glb); glb->symboltab->setRange(this,newrangetree); - ++iter; } - else if (subel->getName() == "rangeequalssymbols") { + else if (subId == ELEM_RANGEEQUALSSYMBOLS) { + decoder.openElement(); + decoder.closeElement(subId); rangeequalssymbols = true; - ++iter; } - if (iter != list.end()) { - const List &symlist((*iter)->getChildren()); - List::const_iterator iter2; - iter2 = symlist.begin(); - while(iter2 != symlist.end()) { - subel = *iter2; - if (subel->getName() == "mapsym") { - Symbol *sym = addMapSym(*iter2); + subId = decoder.openElement(ELEM_SYMBOLLIST); + if (subId != 0) { + for(;;) { + uint4 symId = decoder.peekElement(); + if (symId == 0) break; + if (symId == ELEM_MAPSYM) { + Symbol *sym = addMapSym(decoder); if (rangeequalssymbols) { SymbolEntry *e = sym->getFirstWholeMap(); glb->symboltab->addRange(this,e->getAddr().getSpace(),e->getFirst(),e->getLast()); } } - else if (subel->getName() == "hole") - processHole(subel); - else if (subel->getName() == "collision") - processCollision(subel); + else if (symId == ELEM_HOLE) + decodeHole(decoder); + else if (symId == ELEM_COLLISION) + decodeCollision(decoder); else - throw LowlevelError("Unknown symbollist tag: "+subel->getName()); - ++iter2; + throw LowlevelError("Unknown symbollist tag"); } + decoder.closeElement(subId); } +// decoder.closeElement(elemId); categorySanity(); } @@ -3119,8 +3111,6 @@ Scope *Database::resolveScopeFromSymbolName(const string &fullname,const string Scope *Database::findCreateScopeFromSymbolName(const string &fullname,const string &delim,string &basename, Scope *start) { - if (!idByNameHash) - throw LowlevelError("Scope name hashes not allowed"); if (start == (Scope *)0) start = globalscope; @@ -3129,6 +3119,8 @@ Scope *Database::findCreateScopeFromSymbolName(const string &fullname,const stri for(;;) { endmark = fullname.find(delim,mark); if (endmark == string::npos) break; + if (!idByNameHash) + throw LowlevelError("Scope name hashes not allowed"); string scopename = fullname.substr(mark,endmark-mark); uint8 nameId = Scope::hashScopeName(start->uniqueId, scopename); start = findCreateScope(nameId, scopename, start); @@ -3206,116 +3198,116 @@ void Database::setPropertyRange(uint4 flags,const Range &range) } } -/// This writes a single \ tag to the stream, which contains sub-tags -/// for each Scope (which contain Symbol sub-tags in turn). -/// \param s is the output stream -void Database::saveXml(ostream &s) const +/// Encode a single \ element to the stream, which contains child elements +/// for each Scope (which contain Symbol children in turn). +/// \param encoder is the stream encoder +void Database::encode(Encoder &encoder) const { partmap::const_iterator piter,penditer; - s << "\n"; + encoder.writeBool(ATTRIB_SCOPEIDBYNAME, true); // Save the property change points piter = flagbase.begin(); penditer = flagbase.end(); for(;piter!=penditer;++piter) { const Address &addr( (*piter).first ); uint4 val = (*piter).second; - s << "saveXmlAttributes(s,addr.getOffset() ); - a_v_u(s,"val",val); - s << "/>\n"; + encoder.openElement(ELEM_PROPERTY_CHANGEPOINT); + addr.getSpace()->encodeAttributes(encoder,addr.getOffset() ); + encoder.writeUnsignedInteger(ATTRIB_VAL, val); + encoder.closeElement(ELEM_PROPERTY_CHANGEPOINT); } if (globalscope != (Scope *)0) - globalscope->saveXmlRecursive(s,true); // Save the global scopes - s << "\n"; + globalscope->encodeRecursive(encoder,true); // Save the global scopes + encoder.closeElement(ELEM_DB); } -/// Parse the given element for the scope id of the parent. +/// Parse a \ element for the scope id of the parent namespace. /// Look up the parent scope and return it. /// Throw an error if there is no matching scope -/// \param el is the given element +/// \param decoder is the stream decoder /// \return the matching scope -Scope *Database::parseParentTag(const Element *el) +Scope *Database::parseParentTag(Decoder &decoder) { - istringstream s(el->getAttributeValue("id")); - uint8 id = -1; - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> id; + uint4 elemId = decoder.openElement(ELEM_PARENT); + uint8 id = decoder.readUnsignedInteger(ATTRIB_ID); Scope *res = resolveScope(id); if (res == (Scope *)0) throw LowlevelError("Could not find scope matching id"); + decoder.closeElement(elemId); return res; } -/// The children of a \ tag are examined to recover Scope and Symbol objects. -/// \param el is the \ element -void Database::restoreXml(const Element *el) +/// Parse a \ element to recover Scope and Symbol objects. +/// \param decoder is the stream decoder +void Database::decode(Decoder &decoder) { + uint4 elemId = decoder.openElement(ELEM_DB); idByNameHash = false; // Default - for(int4 i=0;igetNumAttributes();++i) { - if (el->getAttributeName(i) == "scopeidbyname") - idByNameHash = xml_readbool(el->getAttributeValue(i)); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_SCOPEIDBYNAME) + idByNameHash = decoder.readBool(); } - const List &list(el->getChildren()); - List::const_iterator iter; - - iter = list.begin(); // Restore readonly, volatile properties - while(iter != list.end()) { - const Element *subel = *iter; - if (subel->getName() != "property_changepoint") - break; - ++iter; - Address addr = Address::restoreXml(subel,glb); - uint4 val; - istringstream s(subel->getAttributeValue("val")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> val; + for(;;) { + uint4 subId = decoder.peekElement(); + if (subId != ELEM_PROPERTY_CHANGEPOINT) break; + decoder.openElement(); + uint4 val = decoder.readUnsignedInteger(ATTRIB_VAL); + VarnodeData vData; + vData.decodeFromAttributes(decoder, glb); + Address addr = vData.getAddr(); + decoder.closeElement(subId); flagbase.split(addr) = val; } - for(;iter!=list.end();++iter) { - const Element *subel = *iter; - string name = subel->getAttributeValue("name"); - istringstream s(subel->getAttributeValue("id")); - s.unsetf(ios::dec | ios::hex | ios::oct); - uint8 id; - s >> id; - const List &sublist(subel->getChildren()); + for(;;) { + uint4 subId = decoder.openElement(); + if (subId != ELEM_SCOPE) break; + string name = decoder.readString(ATTRIB_NAME); + uint8 id = decoder.readUnsignedInteger(ATTRIB_ID); Scope *parentScope = (Scope *)0; - if (!sublist.empty()) { - const Element *parTag = sublist.front(); - if (parTag->getName() == "parent") - parentScope = parseParentTag(parTag); + uint4 parentId = decoder.peekElement(); + if (parentId == ELEM_PARENT) { + parentScope = parseParentTag(decoder); } Scope *newScope = findCreateScope(id, name, parentScope); - newScope->restoreXml(subel); + newScope->decode(decoder); + decoder.closeElement(subId); } + decoder.closeElement(elemId); } -/// This allows incremental building of the Database from multiple XML sources. +/// This allows incremental building of the Database from multiple stream sources. /// An empty Scope must already be allocated. It is registered with \b this Database, -/// and then populated with Symbol objects based as the content of a given XML tag. -/// The tag can either be a \ itself, or another tag that wraps a \ tag -/// as its first child. -/// \param el is the given \ element +/// and then populated with Symbol objects based as the content of a given element. +/// The element can either be a \ itself, or another element that wraps a \ +/// element as its first child. +/// \param decoder is the stream decoder /// \param newScope is the empty Scope -void Database::restoreXmlScope(const Element *el,Scope *newScope) +void Database::decodeScope(Decoder &decoder,Scope *newScope) { - const List &list(el->getChildren()); - const Element *parTag = list.front(); - if (el->getName() != "scope") { - const List &sublist(parTag->getChildren()); - parTag = sublist.front(); + uint4 elemId = decoder.openElement(); + if (elemId == ELEM_SCOPE) { + Scope *parentScope = parseParentTag(decoder); + attachScope(newScope,parentScope); + newScope->decode(decoder); } - Scope *parentScope = parseParentTag(parTag); - attachScope(newScope,parentScope); - newScope->restoreXml(el); + else { + newScope->decodeWrappingAttributes(decoder); + uint4 subId = decoder.openElement(ELEM_SCOPE); + Scope *parentScope = parseParentTag(decoder); + attachScope(newScope,parentScope); + newScope->decode(decoder); + decoder.closeElement(subId); + } + decoder.closeElement(elemId); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh index 77df585871..a47b6219ea 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/database.hh @@ -34,6 +34,28 @@ class Database; class Symbol; class PrintLanguage; +extern AttributeId ATTRIB_CAT; ///< Marshaling attribute "cat" +extern AttributeId ATTRIB_FIELD; ///< Marshaling attribute "field" +extern AttributeId ATTRIB_MERGE; ///< Marshaling attribute "merge" +extern AttributeId ATTRIB_SCOPEIDBYNAME; ///< Marshaling attribute "scopeidbyname" +extern AttributeId ATTRIB_VOLATILE; ///< Marshaling attribute "volatile" + +extern ElementId ELEM_COLLISION; ///< Marshaling element \ +extern ElementId ELEM_DB; ///< Marshaling element \ +extern ElementId ELEM_EQUATESYMBOL; ///< Marshaling element \ +extern ElementId ELEM_EXTERNREFSYMBOL; ///< Marshaling element \ +extern ElementId ELEM_FACETSYMBOL; ///< Marshaling element \ +extern ElementId ELEM_FUNCTIONSHELL; ///< Marshaling element \ +extern ElementId ELEM_HASH; ///< Marshaling element \ +extern ElementId ELEM_HOLE; ///< Marshaling element \ +extern ElementId ELEM_LABELSYM; ///< Marshaling element \ +extern ElementId ELEM_MAPSYM; ///< Marshaling element \ +extern ElementId ELEM_PARENT; ///< Marshaling element \ +extern ElementId ELEM_PROPERTY_CHANGEPOINT; ///< Marshaling element \ +extern ElementId ELEM_RANGEEQUALSSYMBOLS; ///< Marshaling element \ +extern ElementId ELEM_SCOPE; ///< Marshaling element \ +extern ElementId ELEM_SYMBOLLIST; ///< Marshaling element \ + /// \brief A storage location for a particular Symbol /// /// Where a Symbol is stored, as a byte address and a size, is of particular importance @@ -134,8 +156,8 @@ public: bool updateType(Varnode *vn) const; ///< Update a Varnode data-type from \b this Datatype *getSizedType(const Address &addr,int4 sz) const; ///< Get the data-type associated with (a piece of) \b this void printEntry(ostream &s) const; ///< Dump a description of \b this to a stream - void saveXml(ostream &s) const; ///< Save \b this to an XML stream - List::const_iterator restoreXml(List::const_iterator iter,const AddrSpaceManager *manage); ///< Restore \b this from an XML stream + void encode(Encoder &encoder) const; ///< Encode \b this to a stream + void decode(Decoder &decoder,const AddrSpaceManager *manage); ///< Decode \b this from a stream }; typedef rangemap EntryMap; ///< A rangemap of SymbolEntry @@ -192,7 +214,7 @@ public: }; Symbol(Scope *sc,const string &nm,Datatype *ct); ///< Construct given a name and data-type - Symbol(Scope *sc); ///< Construct for use with restoreXml() + Symbol(Scope *sc); ///< Construct for use with decode() const string &getName(void) const { return name; } ///< Get the local name of the symbol Datatype *getType(void) const { return type; } ///< Get the data-type uint8 getId(void) const { return symbolId; } ///< Get a unique id for the symbol @@ -219,12 +241,12 @@ public: SymbolEntry *getMapEntry(int4 i) const { return &(*mapentry[i]); } ///< Return the i-th SymbolEntry for \b this Symbol int4 getMapEntryPosition(const SymbolEntry *entry) const; ///< Position of given SymbolEntry within \b this multi-entry Symbol int4 getResolutionDepth(const Scope *useScope) const; ///< Get number of scope names needed to resolve \b this symbol - void saveXmlHeader(ostream &s) const; ///< Save basic Symbol properties as XML attributes - void restoreXmlHeader(const Element *el); ///< Restore basic Symbol properties from XML - void saveXmlBody(ostream &s) const; ///< Save details of the Symbol to XML - void restoreXmlBody(List::const_iterator iter); ///< Restore details of the Symbol from XML - virtual void saveXml(ostream &s) const; ///< Save \b this Symbol to an XML stream - virtual void restoreXml(const Element *el); ///< Restore \b this Symbol from an XML stream + void encodeHeader(Encoder &encoder) const; ///< Encode basic Symbol properties as attributes + void decodeHeader(Decoder &decoder); ///< Decode basic Symbol properties from a \ element + void encodeBody(Encoder &encoder) const; ///< Encode details of the Symbol to a stream + void decodeBody(Decoder &decoder); ///< Decode details of the Symbol from a \ element + virtual void encode(Encoder &encoder) const; ///< Encode \b this Symbol to a stream + virtual void decode(Decoder &decoder); ///< Decode \b this Symbol from a stream virtual int4 getBytesConsumed(void) const; ///< Get number of bytes consumed within the address->symbol map static uint8 ID_BASE; ///< Base of internal ID's }; @@ -259,10 +281,10 @@ class FunctionSymbol : public Symbol { void buildType(void); ///< Build the data-type associated with \b this Symbol public: FunctionSymbol(Scope *sc,const string &nm,int4 size); ///< Construct given the name - FunctionSymbol(Scope *sc,int4 size); ///< Constructor for use with restoreXml + FunctionSymbol(Scope *sc,int4 size); ///< Constructor for use with decode Funcdata *getFunction(void); ///< Get the underlying Funcdata object - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder); virtual int4 getBytesConsumed(void) const { return consumeSize; } }; @@ -275,21 +297,21 @@ class EquateSymbol : public Symbol { uintb value; ///< Value of the constant being equated public: EquateSymbol(Scope *sc,const string &nm,uint4 format,uintb val); ///< Constructor - EquateSymbol(Scope *sc) : Symbol(sc) { value = 0; category = equate; } ///< Constructor for use with restoreXml + EquateSymbol(Scope *sc) : Symbol(sc) { value = 0; category = equate; } ///< Constructor for use with decode uintb getValue(void) const { return value; } ///< Get the constant value bool isValueClose(uintb op2Value,int4 size) const; ///< Is the given value similar to \b this equate - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder); }; class UnionFacetSymbol : public Symbol { int4 fieldNum; ///< Particular field to associate with Symbol access public: UnionFacetSymbol(Scope *sc,const string &nm,Datatype *unionDt,int4 fldNum); ///< Constructor from components - UnionFacetSymbol(Scope *sc) : Symbol(sc) { fieldNum = -1; category = union_facet; } ///< Constructor for restoreXml + UnionFacetSymbol(Scope *sc) : Symbol(sc) { fieldNum = -1; category = union_facet; } ///< Constructor for decode int4 getFieldNumber(void) const { return fieldNum; } ///< Get the particular field associate with \b this - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder); }; /// \brief A Symbol that labels code internal to a function @@ -297,9 +319,9 @@ class LabSymbol : public Symbol { void buildType(void); ///< Build placeholder data-type public: LabSymbol(Scope *sc,const string &nm); ///< Construct given name - LabSymbol(Scope *sc); ///< Constructor for use with restoreXml - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el); + LabSymbol(Scope *sc); ///< Constructor for use with decode + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder); }; /// \brief A function Symbol referring to an external location @@ -314,10 +336,10 @@ class ExternRefSymbol : public Symbol { virtual ~ExternRefSymbol(void) {} public: ExternRefSymbol(Scope *sc,const Address &ref,const string &nm); ///< Construct given a \e placeholder address - ExternRefSymbol(Scope *sc) : Symbol(sc) {} ///< For use with restoreXml + ExternRefSymbol(Scope *sc) : Symbol(sc) {} ///< For use with decode const Address &getRefAddr(void) const { return refaddr; } ///< Return the \e placeholder address - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder); }; /// \brief Comparator for sorting Symbol objects by name @@ -391,6 +413,17 @@ public: } }; +/// \brief Exception thrown when a function is added more than once to the database +/// +/// Stores off the address of the function, so a handler can recover from the exception +/// and pick up the original symbol. +struct DuplicateFunctionError : public RecovError { + Address address; ///< Address of function causing the error + string functionName; ///< Name of the function + DuplicateFunctionError(const Address &addr,const string &nm) : RecovError("Duplicate Function") { + address = addr; functionName = nm; } ///< Constructor +}; + typedef map ScopeMap; ///< A map from id to Scope /// \brief A collection of Symbol objects within a single (namespace or functional) scope @@ -661,8 +694,9 @@ public: /// \return return a unique version of the name virtual string makeNameUnique(const string &nm) const=0; - virtual void saveXml(ostream &s) const=0; ///< Write out \b this as a \ XML tag - virtual void restoreXml(const Element *el)=0; ///< Restore \b this Scope from a \ XML tag + virtual void encode(Encoder &encoder) const=0; ///< Encode \b this as a \ element + virtual void decode(Decoder &decoder)=0; ///< Decode \b this Scope from a \ element + virtual void decodeWrappingAttributes(Decoder &decoder) {} ///< Restore attributes for \b this Scope from wrapping element virtual void printEntries(ostream &s) const=0; ///< Dump a description of all SymbolEntry objects to a stream /// \brief Get the number of Symbols in the given category @@ -709,8 +743,8 @@ public: Scope *discoverScope(const Address &addr,int4 sz,const Address &usepoint); ///< Find the owning Scope of a given memory range ScopeMap::const_iterator childrenBegin() const { return children.begin(); } ///< Beginning iterator of child scopes ScopeMap::const_iterator childrenEnd() const { return children.end(); } ///< Ending iterator of child scopes - void saveXmlRecursive(ostream &s,bool onlyGlobal) const; ///< Save all contained scopes as an XML stream - void overrideSizeLockType(Symbol *sym,Datatype *ct); ///< Change the data-type of a Symbol that is \e sizelocked + void encodeRecursive(Encoder &encoder,bool onlyGlobal) const; ///< Encode all contained scopes to a stream + void overrideSizeLockType(Symbol *sym,Datatype *ct); ///< Change the data-type of a Symbol that is \e sizelocked void resetSizeLockType(Symbol *sym); ///< Clear a Symbol's \e size-locked data-type void setThisPointer(Symbol *sym,bool val) { sym->setThisPointer(val); } ///< Toggle the given Symbol as the "this" pointer bool isSubScope(const Scope *scp) const; ///< Is this a sub-scope of the given Scope @@ -722,7 +756,7 @@ public: Symbol *addSymbol(const string &nm,Datatype *ct); ///< Add a new Symbol \e without mapping it to an address SymbolEntry *addMapPoint(Symbol *sym,const Address &addr, const Address &usepoint); ///< Map a Symbol to a specific address - Symbol *addMapSym(const Element *el); ///< Add a mapped Symbol from a \ XML tag + Symbol *addMapSym(Decoder &decoder); ///< Parse a mapped Symbol from a \ element FunctionSymbol *addFunction(const Address &addr,const string &nm); ExternRefSymbol *addExternalRef(const Address &addr,const Address &refaddr,const string &nm); LabSymbol *addCodeLabel(const Address &addr,const string &nm); @@ -740,8 +774,8 @@ public: /// a set of Symbol objects (the set owns the Symbol objects). It also implements /// a \b maptable, which is a list of rangemaps that own the SymbolEntry objects. class ScopeInternal : public Scope { - void processHole(const Element *el); - void processCollision(const Element *el); + void decodeHole(Decoder &decoder); + void decodeCollision(Decoder &decoder); void insertNameTree(Symbol *sym); SymbolNameTree::const_iterator findFirstByName(const string &nm) const; protected: @@ -799,8 +833,8 @@ public: Datatype *ct,int4 &index,uint4 flags) const; virtual string buildUndefinedName(void) const; virtual string makeNameUnique(const string &nm) const; - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder); virtual void printEntries(ostream &s) const; virtual int4 getCategorySize(int4 cat) const; virtual Symbol *getCategorySymbol(int4 cat,int4 ind) const; @@ -867,7 +901,7 @@ class Database { void clearResolve(Scope *scope); ///< Clear the \e ownership ranges associated with the given Scope void clearReferences(Scope *scope); ///< Clear any map references to the given Scope and its children void fillResolve(Scope *scope); ///< Add the \e ownership ranges of the given Scope to the map - Scope *parseParentTag(const Element *el); ///< Figure out parent scope given \ tag. + Scope *parseParentTag(Decoder &decoder); ///< Figure out parent scope given \ tag. public: Database(Architecture *g,bool idByName); ///< Constructor ~Database(void); ///< Destructor @@ -891,9 +925,9 @@ public: void setPropertyRange(uint4 flags,const Range &range); ///< Set boolean properties over a given memory range void setProperties(const partmap &newflags) { flagbase = newflags; } ///< Replace the property map const partmap &getProperties(void) const { return flagbase; } ///< Get the entire property map - void saveXml(ostream &s) const; ///< Save the whole Database to an XML stream - void restoreXml(const Element *el); ///< Recover the whole database from XML - void restoreXmlScope(const Element *el,Scope *newScope); ///< Register and fill out a single Scope from an XML \ tag + void encode(Encoder &encoder) const; ///< Encode the whole Database to a stream + void decode(Decoder &decoder); ///< Decode the whole database from a stream + void decodeScope(Decoder &decoder,Scope *newScope); ///< Register and fill out a single Scope from an XML \ tag }; /// \param sc is the scope containing the new symbol diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.cc index 6004fa1d1c..d6c8a6f8d5 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.cc @@ -52,120 +52,103 @@ Scope *ScopeGhidra::reresolveScope(uint8 id) const if (cacheScope != (Scope *)0) return cacheScope; // Scope was previously cached - Document *doc = ghidra->getNamespacePath(id); - if (doc == (Document *)0) + XmlDecode decoder; + if (!ghidra->getNamespacePath(id,decoder)) throw LowlevelError("Could not get namespace info"); Scope *curscope = symboltab->getGlobalScope(); // Get pointer to ourselves (which is not const) - try { - const List &list(doc->getRoot()->getChildren()); - List::const_iterator iter = list.begin(); - ++iter; // Skip element describing the root scope - while(iter != list.end()) { - const Element *el = *iter; - ++iter; - uint8 scopeId; - istringstream s(el->getAttributeValue("id")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> scopeId; - curscope = symboltab->findCreateScope(scopeId, el->getContent(), curscope); - } - delete doc; - } - catch(LowlevelError &err) { - delete doc; - throw err; + uint4 elemId = decoder.openElement(); + uint4 subId = decoder.openElement(); + decoder.closeElementSkipping(subId); // Skip element describing the root scope + for(;;) { + subId = decoder.openElement(); + if (subId == 0) break; + uint8 scopeId = decoder.readUnsignedInteger(ATTRIB_ID); + curscope = symboltab->findCreateScope(scopeId, decoder.readString(ATTRIB_CONTENT), curscope); + decoder.closeElement(subId); } + decoder.closeElement(elemId); return curscope; } /// The Ghidra client can respond to a query negatively by sending a -/// \ tag, which describes the (largest) range of addresses containing +/// \ element, which describes the (largest) range of addresses containing /// the query address that do not have any Symbol mapped to them. This object /// stores this information in the \b holes map, which it consults to avoid /// sending queries for the same unmapped address repeatedly. The tag may /// also contain boolean property information about the memory range, which /// also gets stored. -/// \param el is the \ element -void ScopeGhidra::processHole(const Element *el) const +/// \param decoder is the stream decoder +void ScopeGhidra::decodeHole(Decoder &decoder) const { - Range range; - range.restoreXml(el,ghidra); - holes.insertRange(range.getSpace(),range.getFirst(),range.getLast()); + uint4 elemId = decoder.openElement(ELEM_HOLE); uint4 flags = 0; - for(int4 i=0;igetNumAttributes();++i) { - if ((el->getAttributeName(i)=="readonly")&& - xml_readbool(el->getAttributeValue(i))) + Range range; + range.decodeFromAttributes(decoder,ghidra); + decoder.rewindAttributes(); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId==ATTRIB_READONLY && decoder.readBool()) flags |= Varnode::readonly; - else if ((el->getAttributeName(i)=="volatile")&& - xml_readbool(el->getAttributeValue(i))) + else if (attribId==ATTRIB_VOLATILE && decoder.readBool()) flags |= Varnode::volatil; } + holes.insertRange(range.getSpace(),range.getFirst(),range.getLast()); + decoder.closeElement(elemId); if (flags != 0) { ghidra->symboltab->setPropertyRange(flags,range); cacheDirty = true; } } -/// Build the global object described by the XML document -/// and put it in the cache. The XML can either be a -/// \ tag, describing the absence of symbols at the queried -/// address, or one of the symbol tags -/// \param doc is the XML document +/// Build the global object described by the stream element +/// and put it in the cache. The element can either be a \, describing the absence +/// of symbols at the queried address, or one of the symbol elements. +/// \param decoder is the stream decoder /// \return the newly constructed Symbol or NULL if there was a hole -Symbol *ScopeGhidra::dump2Cache(Document *doc) const +Symbol *ScopeGhidra::dump2Cache(Decoder &decoder) const { - const Element *el = doc->getRoot(); Symbol *sym = (Symbol *)0; - if (el->getName() == "hole") { - processHole(el); + uint4 elemId = decoder.peekElement(); + if (elemId == ELEM_HOLE) { + decodeHole(decoder); return sym; } - List::const_iterator iter = el->getChildren().begin(); - uint8 scopeId; - { - istringstream s(el->getAttributeValue("id")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> scopeId; - } - + decoder.openElement(); + uint8 scopeId = decoder.readUnsignedInteger(ATTRIB_ID); Scope *scope = reresolveScope(scopeId); - el = *iter; + try { - sym = scope->addMapSym(el); + sym = scope->addMapSym(decoder); + decoder.closeElement(elemId); } - catch(RecovError &err) { + catch(DuplicateFunctionError &err) { // Duplicate name error (when trying to create the new function's scope) // Check for function object where the full size is not stored in the cache // Entries for functions always start at the entry address // of the function in order to deal with non-contiguous functions // But ghidra will still return the function for queries at addresses in the // interior of the function - const Element *symel = *el->getChildren().begin(); - if (symel->getName() == "function") { // Make sure new record is for a function - const Element *baseAddrEl = *symel->getChildren().begin(); - Address baseaddr = Address::restoreXml( baseAddrEl, glb ); // Decode address from record + if (!err.address.isInvalid()) { // Make sure the address was parsed vector symList; - scope->queryByName(symel->getAttributeValue("name"),symList); // Lookup symbols with duplicate name + scope->queryByName(err.functionName,symList); // Lookup symbols with duplicate name for(int4 i=0;i(symList[i]); if (funcSym != (FunctionSymbol *)0) { // If duplicate symbol is for function - if (funcSym->getFunction()->getAddress() == baseaddr) { // and the address matches + if (funcSym->getFunction()->getAddress() == err.address) { // and the address matches sym = funcSym; // use the old symbol break; } } } } - if (sym == (Symbol *)0) { - ostringstream s; - s << err.explain << ": entry didn't cache"; - throw LowlevelError(s.str()); - } + if (sym == (Symbol *)0) + throw LowlevelError("DuplicateFunctionError, but could not recover original symbol"); } if (sym != (Symbol *)0) { SymbolEntry *entry = sym->getFirstWholeMap(); @@ -208,7 +191,6 @@ Symbol *ScopeGhidra::dump2Cache(Document *doc) const Symbol *ScopeGhidra::removeQuery(const Address &addr) const { - Document *doc; Symbol *sym = (Symbol *)0; // Don't send up queries on constants or uniques @@ -230,10 +212,9 @@ Symbol *ScopeGhidra::removeQuery(const Address &addr) const // Have we queried this address before if (holes.inRange(addr,1)) return (Symbol *)0; - doc = ghidra->getMappedSymbolsXML(addr); // Query GHIDRA about this address - if (doc != (Document *)0) { - sym = dump2Cache(doc); // Add it to the cache - delete doc; + XmlDecode decoder; + if (ghidra->getMappedSymbolsXML(addr,decoder)) { // Query GHIDRA about this address + sym = dump2Cache(decoder); // Add it to the cache } return sym; } @@ -368,14 +349,12 @@ Funcdata *ScopeGhidra::resolveExternalRefFunction(ExternRefSymbol *sym) const if (resFd == (Funcdata *)0) { // If the function isn't in cache, we use the special // getExternalRefXML interface to recover the external function - Document *doc; SymbolEntry *entry = sym->getFirstWholeMap(); - doc = ghidra->getExternalRefXML(entry->getAddr()); - if (doc != (Document *)0) { + XmlDecode decoder; + if (ghidra->getExternalRefXML(entry->getAddr(),decoder)) { FunctionSymbol *funcSym; // Make sure referenced function is cached - funcSym = dynamic_cast(dump2Cache(doc)); - delete doc; + funcSym = dynamic_cast(dump2Cache(decoder)); if (funcSym != (FunctionSymbol *)0) resFd = funcSym->getFunction(); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.hh index c3f0773cc5..304bd2914b 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/database_ghidra.hh @@ -39,9 +39,9 @@ class ScopeGhidra : public Scope { vector spacerange; ///< List of address spaces that are in the global range partmap flagbaseDefault; ///< Default boolean properties on memory mutable bool cacheDirty; ///< Is flagbaseDefault different from cache - Symbol *dump2Cache(Document *doc) const; ///< Parse a response into the cache + Symbol *dump2Cache(Decoder &decoder) const; ///< Parse a response into the cache Symbol *removeQuery(const Address &addr) const; ///< Process a query that missed the cache - void processHole(const Element *el) const; ///< Process a response describing a hole + void decodeHole(Decoder &decoder) const; ///< Process a \ response element Scope *reresolveScope(uint8 id) const; ///< Find the Scope that will contain a result Symbol virtual void addRange(AddrSpace *spc,uintb first,uintb last); virtual void removeRange(AddrSpace *spc,uintb first,uintb last) { @@ -107,8 +107,8 @@ public: virtual void renameSymbol(Symbol *sym,const string &newname) { throw LowlevelError("renameSymbol unimplemented"); } virtual void retypeSymbol(Symbol *sym,Datatype *ct) { throw LowlevelError("retypeSymbol unimplemented"); } virtual string makeNameUnique(const string &nm) const { throw LowlevelError("makeNameUnique unimplemented"); } - virtual void saveXml(ostream &s) const { throw LowlevelError("saveXml unimplemented"); } - virtual void restoreXml(const Element *el) { throw LowlevelError("restoreXml unimplemented"); } + virtual void encode(Encoder &encoder) const { throw LowlevelError("encode unimplemented"); } + virtual void decode(Decoder &decoder) { throw LowlevelError("decode unimplemented"); } virtual void printEntries(ostream &s) const { throw LowlevelError("printEntries unimplemented"); } virtual int4 getCategorySize(int4 cat) const { throw LowlevelError("getCategorySize unimplemented"); } virtual Symbol *getCategorySymbol(int4 cat,int4 ind) const { throw LowlevelError("getCategorySymbol unimplemented"); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc index 3db1c67627..c4f1483548 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc @@ -16,6 +16,38 @@ #include "fspec.hh" #include "funcdata.hh" +AttributeId ATTRIB_CUSTOM = AttributeId("custom",54); +AttributeId ATTRIB_DOTDOTDOT = AttributeId("dotdotdot",55); +AttributeId ATTRIB_EXTENSION = AttributeId("extension",56); +AttributeId ATTRIB_HASTHIS = AttributeId("hasthis",57); +AttributeId ATTRIB_INLINE = AttributeId("inline",58); +AttributeId ATTRIB_KILLEDBYCALL = AttributeId("killedbycall",59); +AttributeId ATTRIB_MAXSIZE = AttributeId("maxsize",60); +AttributeId ATTRIB_MINSIZE = AttributeId("minsize",61); +AttributeId ATTRIB_MODELLOCK = AttributeId("modellock",62); +AttributeId ATTRIB_NORETURN = AttributeId("noreturn",63); +AttributeId ATTRIB_POINTERMAX = AttributeId("pointermax",64); +AttributeId ATTRIB_SEPARATEFLOAT = AttributeId("separatefloat",65); +AttributeId ATTRIB_STACKSHIFT = AttributeId("stackshift",66); +AttributeId ATTRIB_STRATEGY = AttributeId("strategy",67); +AttributeId ATTRIB_THISBEFORERETPOINTER = AttributeId("thisbeforeretpointer",68); +AttributeId ATTRIB_VOIDLOCK = AttributeId("voidlock",69); + +ElementId ELEM_GROUP = ElementId("group",75); +ElementId ELEM_INTERNALLIST = ElementId("internallist",76); +ElementId ELEM_KILLEDBYCALL = ElementId("killedbycall",77); +ElementId ELEM_LIKELYTRASH = ElementId("likelytrash",78); +ElementId ELEM_LOCALRANGE = ElementId("localrange",79); +ElementId ELEM_MODEL = ElementId("model",80); +ElementId ELEM_PARAM = ElementId("param",81); +ElementId ELEM_PARAMRANGE = ElementId("paramrange",82); +ElementId ELEM_PENTRY = ElementId("pentry",83); +ElementId ELEM_PROTOTYPE = ElementId("prototype",84); +ElementId ELEM_RESOLVEPROTOTYPE = ElementId("resolveprototype",85); +ElementId ELEM_RETPARAM = ElementId("retparam",86); +ElementId ELEM_RETURNSYM = ElementId("returnsym",87); +ElementId ELEM_UNAFFECTED = ElementId("unaffected",88); + /// \brief Find a ParamEntry matching the given storage Varnode /// /// Search through the list backward. @@ -399,25 +431,25 @@ Address ParamEntry::getAddrBySlot(int4 &slotnum,int4 sz) const index = numslots; index -= slotnum; index -= slotsused; - } + } else index = slotnum; res = Address(spaceid, addressbase + index * alignment); slotnum += slotsused; // Inform caller of number of slots used } if (!isLeftJustified()) // Adjust for right justified (big endian) - res = res + (spaceused - sz); + res = res + (spaceused - sz); return res; } -/// \brief Restore the entry from an XML stream +/// \brief Decode a \ element into \b this object /// -/// \param el is the root \ element +/// \param decoder is the stream decoder /// \param manage is a manager to resolve address space references /// \param normalstack is \b true if the parameters should be allocated from the front of the range /// \param grouped is \b true if \b this will be grouped with other entries /// \param curList is the list of ParamEntry defined up to this point -void ParamEntry::restoreXml(const Element *el,const AddrSpaceManager *manage,bool normalstack,bool grouped,list &curList) +void ParamEntry::decode(Decoder &decoder,const AddrSpaceManager *manage,bool normalstack,bool grouped,list &curList) { flags = 0; @@ -426,54 +458,49 @@ void ParamEntry::restoreXml(const Element *el,const AddrSpaceManager *manage,boo alignment = 0; // default numslots = 1; groupsize = 1; // default - int4 num = el->getNumAttributes(); - - for(int4 i=0;igetAttributeName(i) ); - if (attrname=="minsize") { - istringstream i1(el->getAttributeValue(i)); - i1.unsetf(ios::dec | ios::hex | ios::oct); - i1 >> minsize; + + uint4 elemId = decoder.openElement(ELEM_PENTRY); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_MINSIZE) { + minsize = decoder.readSignedInteger(); } - else if (attrname == "size") { // old style - istringstream i2(el->getAttributeValue(i)); - i2.unsetf(ios::dec | ios::hex | ios::oct); - i2 >> alignment; + else if (attribId == ATTRIB_SIZE) { // old style + alignment = decoder.readSignedInteger(); } - else if (attrname == "align") { // new style - istringstream i4(el->getAttributeValue(i)); - i4.unsetf(ios::dec | ios::hex | ios::oct); - i4 >> alignment; + else if (attribId == ATTRIB_ALIGN) { // new style + alignment = decoder.readSignedInteger(); } - else if (attrname == "maxsize") { - istringstream i3(el->getAttributeValue(i)); - i3.unsetf(ios::dec | ios::hex | ios::oct); - i3 >> size; + else if (attribId == ATTRIB_MAXSIZE) { + size = decoder.readSignedInteger(); } - else if (attrname == "metatype") - type = string2metatype(el->getAttributeValue(i)); - else if (attrname == "extension") { + else if (attribId == ATTRIB_METATYPE) + type = string2metatype(decoder.readString()); + else if (attribId == ATTRIB_EXTENSION) { flags &= ~((uint4)(smallsize_zext | smallsize_sext | smallsize_inttype)); - if (el->getAttributeValue(i) == "sign") + string ext = decoder.readString(); + if (ext == "sign") flags |= smallsize_sext; - else if (el->getAttributeValue(i) == "zero") + else if (ext == "zero") flags |= smallsize_zext; - else if (el->getAttributeValue(i) == "inttype") + else if (ext == "inttype") flags |= smallsize_inttype; - else if (el->getAttributeValue(i) == "float") + else if (ext == "float") flags |= smallsize_floatext; - else if (el->getAttributeValue(i) != "none") + else if (ext != "none") throw LowlevelError("Bad extension attribute"); } else - throw LowlevelError("Unknown ParamEntry attribute: "+attrname); + throw LowlevelError("Unknown attribute"); } if ((size==-1)||(minsize==-1)) throw LowlevelError("ParamEntry not fully specified"); if (alignment == size) alignment = 0; Address addr; - addr = Address::restoreXml( *el->getChildren().begin(),manage); + addr = Address::decode(decoder,manage); + decoder.closeElement(elemId); spaceid = addr.getSpace(); addressbase = addr.getOffset(); if (alignment != 0) { @@ -741,7 +768,7 @@ void ParamListStandard::buildTrialMap(ParamActive *active) const for(int4 i=0;i intCount) ? TYPE_FLOAT : TYPE_UNKNOWN); if (curentry == (const ParamEntry *)0) @@ -768,7 +795,7 @@ void ParamListStandard::buildTrialMap(ParamActive *active) const slot = endslot; endslot = tmp; } - + while(slotlist.size() <= endslot) slotlist.push_back(0); while(slot<=endslot) { @@ -831,7 +858,7 @@ void ParamListStandard::separateSections(ParamActive *active,int4 &oneStart,int4 /// /// Only one trial within an exclusion group can have active use, mark all others as unused. /// \param active is the set of trials, which must be sorted on group -/// \param groupUper is the biggest group number to be marked +/// \param groupUpper is the biggest group number to be marked /// \param groupStart is the index of the first trial in the smallest group to be marked /// \param index is the specified trial index that is \e not to be marked void ParamListStandard::markGroupNoUse(ParamActive *active,int4 groupUpper,int4 groupStart,int4 index) @@ -1077,9 +1104,9 @@ void ParamListStandard::populateResolver(void) } } -/// \brief Read a \ tag and add it to \b this list +/// \brief Parse a \ element and add it to \b this list /// -/// \param el is the \ &effectlist, +void ParamListStandard::parsePentry(Decoder &decoder,const AddrSpaceManager *manage,vector &effectlist, int4 groupid,bool normalstack,bool autokill,bool splitFloat,bool grouped) { entry.emplace_back(groupid); - entry.back().restoreXml(el,manage,normalstack,grouped,entry); + entry.back().decode(decoder,manage,normalstack,grouped,entry); if (splitFloat) { if (!grouped && entry.back().getType() == TYPE_FLOAT) { if (resourceTwoStart >= 0) @@ -1111,29 +1138,25 @@ void ParamListStandard::parsePentry(const Element *el,const AddrSpaceManager *ma numgroup = maxgroup; } -/// \brief Read a group of \ tags that are allocated as a group +/// \brief Parse a sequence of \ elements that are allocated as a group /// /// All ParamEntry objects will share the same \b group id. -/// \param el is the \ &effectlist, +void ParamListStandard::parseGroup(Decoder &decoder,const AddrSpaceManager *manage,vector &effectlist, int4 groupid,bool normalstack,bool autokill,bool splitFloat) { - const List &flist(el->getChildren()); - List::const_iterator iter = flist.begin(); int4 basegroup = numgroup; ParamEntry *previous1 = (ParamEntry *)0; ParamEntry *previous2 = (ParamEntry *)0; - for(;iter!=flist.end();++iter) { - const Element *subel = *iter; - if (subel->getName() != "pentry") - throw LowlevelError("Expected child of : " + subel->getName()); - parsePentry(subel, manage, effectlist, basegroup, normalstack, autokill, splitFloat, true); + uint4 elemId = decoder.openElement(ELEM_GROUP); + while(decoder.peekElement() != 0) { + parsePentry(decoder, manage, effectlist, basegroup, normalstack, autokill, splitFloat, true); ParamEntry &pentry( entry.back() ); if (pentry.getSpace()->getType() == IPTR_JOIN) throw LowlevelError(" in the join space not allowed in tag"); @@ -1145,6 +1168,7 @@ void ParamListStandard::parseGroup(const Element *el,const AddrSpaceManager *man previous2 = previous1; previous1 = &pentry; } + decoder.closeElement(elemId); } void ParamListStandard::fillinMap(ParamActive *active) const @@ -1306,8 +1330,8 @@ void ParamListStandard::getRangeList(AddrSpace *spc,RangeList &res) const } } -void ParamListStandard::restoreXml(const Element *el,const AddrSpaceManager *manage, - vector &effectlist,bool normalstack) +void ParamListStandard::decode(Decoder &decoder,const AddrSpaceManager *manage, + vector &effectlist,bool normalstack) { numgroup = 0; @@ -1316,35 +1340,35 @@ void ParamListStandard::restoreXml(const Element *el,const AddrSpaceManager *man thisbeforeret = false; bool splitFloat = true; // True if we should split FLOAT entries into their own resource section bool autokilledbycall = false; - for(int4 i=0;igetNumAttributes();++i) { - const string &attrname( el->getAttributeName(i) ); - if (attrname == "pointermax") { - istringstream i1(el->getAttributeValue(i)); - i1.unsetf(ios::dec | ios::hex | ios::oct); - i1 >> pointermax; + uint4 elemId = decoder.openElement(); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_POINTERMAX) { + pointermax = decoder.readSignedInteger(); } - else if (attrname == "thisbeforeretpointer") { - thisbeforeret = xml_readbool( el->getAttributeValue(i) ); + else if (attribId == ATTRIB_THISBEFORERETPOINTER) { + thisbeforeret = decoder.readBool(); } - else if (attrname == "killedbycall") { - autokilledbycall = xml_readbool( el->getAttributeValue(i) ); + else if (attribId == ATTRIB_KILLEDBYCALL) { + autokilledbycall = decoder.readBool(); } - else if (attrname == "separatefloat") { - splitFloat = xml_readbool( el->getAttributeValue(i) ); + else if (attribId == ATTRIB_SEPARATEFLOAT) { + splitFloat = decoder.readBool(); } } resourceTwoStart = splitFloat ? -1 : 0; - const List &flist(el->getChildren()); - List::const_iterator fiter; - for(fiter=flist.begin();fiter!=flist.end();++fiter) { - const Element *subel = *fiter; - if (subel->getName() == "pentry") { - parsePentry(subel, manage, effectlist, numgroup, normalstack, autokilledbycall, splitFloat, false); + for(;;) { + uint4 subId = decoder.peekElement(); + if (subId == 0) break; + if (subId == ELEM_PENTRY) { + parsePentry(decoder, manage, effectlist, numgroup, normalstack, autokilledbycall, splitFloat, false); } - else if (subel->getName() == "group") { - parseGroup(subel, manage, effectlist, numgroup, normalstack, autokilledbycall, splitFloat); + else if (subId == ELEM_GROUP) { + parseGroup(decoder, manage, effectlist, numgroup, normalstack, autokilledbycall, splitFloat); } } + decoder.closeElement(elemId); calcDelay(); populateResolver(); } @@ -1528,10 +1552,10 @@ void ParamListStandardOut::assignMap(const vector &proto,TypeFactory } } -void ParamListStandardOut::restoreXml(const Element *el,const AddrSpaceManager *manage,vector &effectlist,bool normalstack) +void ParamListStandardOut::decode(Decoder &decoder,const AddrSpaceManager *manage,vector &effectlist,bool normalstack) { - ParamListRegisterOut::restoreXml(el,manage,effectlist,normalstack); + ParamListRegisterOut::decode(decoder,manage,effectlist,normalstack); // Check for double precision entries list::iterator iter; ParamEntry *previous1 = (ParamEntry *)0; @@ -1762,7 +1786,7 @@ void ParamActive::deleteUnusedTrials(void) { vector newtrials; int4 slot = 1; - + for(int4 i=0;i newtrials; int4 slot = trial[i].getSlot(); - + for(int4 j=0;jgetEntryAddress().isInvalid()) - s << " space=\"fspec\""; + encoder.writeString(ATTRIB_SPACE, "fspec"); else { AddrSpace *id = fc->getEntryAddress().getSpace(); - a_v(s,"space",id->getName()); // Just append the proper attributes - s << ' ' << "offset=\""; - printOffset(s,fc->getEntryAddress().getOffset()); - s << "\""; + encoder.writeString(ATTRIB_SPACE, id->getName()); + encoder.writeUnsignedInteger(ATTRIB_OFFSET, fc->getEntryAddress().getOffset()); } } -void FspecSpace::saveXmlAttributes(ostream &s,uintb offset,int4 size) const +void FspecSpace::encodeAttributes(Encoder &encoder,uintb offset,int4 size) const { FuncCallSpecs *fc = (FuncCallSpecs *)(uintp)offset; if (fc->getEntryAddress().isInvalid()) - s << " space=\"fspec\""; + encoder.writeString(ATTRIB_SPACE, "fspec"); else { AddrSpace *id = fc->getEntryAddress().getSpace(); - a_v(s,"space",id->getName()); // Just append the proper attributes - s << ' ' << "offset=\""; - printOffset(s,fc->getEntryAddress().getOffset()); - s << "\""; - a_v_i(s,"size",size); + encoder.writeString(ATTRIB_SPACE, id->getName()); + encoder.writeUnsignedInteger(ATTRIB_OFFSET, fc->getEntryAddress().getOffset()); + encoder.writeSignedInteger(ATTRIB_SIZE, size); } } @@ -1917,13 +1937,13 @@ void FspecSpace::printRaw(ostream &s,uintb offset) const void FspecSpace::saveXml(ostream &s) const { - throw LowlevelError("Should never save fspec space to XML"); + throw LowlevelError("Should never encode fspec space to stream"); } -void FspecSpace::restoreXml(const Element *el) +void FspecSpace::decode(Decoder &decoder) { - throw LowlevelError("Should never restore fspec space from XML"); + throw LowlevelError("Should never decode fspec space from stream"); } /// The type is set to \e unknown_effect @@ -1958,27 +1978,27 @@ EffectRecord::EffectRecord(const VarnodeData &data,uint4 t) type = t; } -/// Writes just an \ tag. The effect type is indicated by the parent tag. -/// \param s is the output stream -void EffectRecord::saveXml(ostream &s) const +/// Encode just an \ element. The effect type is indicated by the parent element. +/// \param encoder is the stream encoder +void EffectRecord::encode(Encoder &encoder) const { Address addr(range.space,range.offset); if ((type == unaffected)||(type == killedbycall)||(type == return_address)) - addr.saveXml(s,range.size); + addr.encode(encoder,range.size); else throw LowlevelError("Bad EffectRecord type"); } -/// Reads an \ tag to get the memory range. The effect type is inherited from the parent. +/// Parse an \ element to get the memory range. The effect type is inherited from the parent. /// \param grouptype is the effect inherited from the parent -/// \param el is address element +/// \param decoder is the stream decoder /// \param manage is a manager to resolve address space references -void EffectRecord::restoreXml(uint4 grouptype,const Element *el,const AddrSpaceManager *manage) +void EffectRecord::decode(uint4 grouptype,Decoder &decoder,const AddrSpaceManager *manage) { type = grouptype; - range.restoreXml(el,manage); + range.decode(decoder,manage); } void ProtoModel::defaultLocalRange(void) @@ -2094,7 +2114,7 @@ ProtoModel::ProtoModel(const string &nm,const ProtoModel &op2) effectlist = op2.effectlist; likelytrash = op2.likelytrash; - + injectUponEntry = op2.injectUponEntry; injectUponReturn = op2.injectUponReturn; localrange = op2.localrange; @@ -2250,13 +2270,11 @@ uint4 ProtoModel::hasEffect(const Address &addr,int4 size) const return lookupEffect(effectlist,addr,size); } -/// Read in details about \b this model from a \ tag -/// \param el is the \ element -void ProtoModel::restoreXml(const Element *el) +/// Parse details about \b this model from a \ element +/// \param decoder is the stream decoder +void ProtoModel::decode(Decoder &decoder) { - int4 numattr = el->getNumAttributes(); - bool sawlocalrange = false; bool sawparamrange = false; bool sawretaddr = false; @@ -2274,32 +2292,36 @@ void ProtoModel::restoreXml(const Element *el) injectUponEntry = -1; injectUponReturn = -1; likelytrash.clear(); - for(int4 i=0;igetAttributeName(i) == "name") - name = el->getAttributeValue(i); - else if (el->getAttributeName(i) == "extrapop") { - if (el->getAttributeValue(i) == "unknown") + uint4 elemId = decoder.openElement(ELEM_PROTOTYPE); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_NAME) + name = decoder.readString(); + else if (attribId == ATTRIB_EXTRAPOP) { + string extrapopString = decoder.readString(); + if (extrapopString == "unknown") extrapop = extrapop_unknown; else { - istringstream s(el->getAttributeValue(i)); + istringstream s(extrapopString); s.unsetf(ios::dec | ios::hex | ios::oct); s >> extrapop; } } - else if (el->getAttributeName(i) == "stackshift") { + else if (attribId == ATTRIB_STACKSHIFT) { // Allow this attribute for backward compatibility } - else if (el->getAttributeName(i) == "strategy") { - strategystring = el->getAttributeValue(i); + else if (attribId == ATTRIB_STRATEGY) { + strategystring = decoder.readString(); } - else if (el->getAttributeName(i) == "hasthis") { - hasThis = xml_readbool(el->getAttributeValue(i)); + else if (attribId == ATTRIB_HASTHIS) { + hasThis = decoder.readBool(); } - else if (el->getAttributeName(i) == "constructor") { - isConstruct = xml_readbool(el->getAttributeValue(i)); + else if (attribId == ATTRIB_CONSTRUCTOR) { + isConstruct = decoder.readBool(); } else - throw LowlevelError("Unknown prototype attribute: "+el->getAttributeName(i)); + throw LowlevelError("Unknown prototype attribute"); } if (name == "__thiscall") hasThis = true; @@ -2307,91 +2329,86 @@ void ProtoModel::restoreXml(const Element *el) throw LowlevelError("Missing prototype attributes"); buildParamList(strategystring); // Allocate input and output ParamLists - const List &list(el->getChildren()); - List::const_iterator iter; - for(iter=list.begin();iter!=list.end();++iter) { - const Element *subnode = *iter; - if (subnode->getName() == "input") { - input->restoreXml(subnode,glb,effectlist,stackgrowsnegative); + for(;;) { + uint4 subId = decoder.peekElement(); + if (subId == 0) break; + if (subId == ELEM_INPUT) { + input->decode(decoder,glb,effectlist,stackgrowsnegative); if (stackspc != (AddrSpace *)0) { input->getRangeList(stackspc,paramrange); if (!paramrange.empty()) sawparamrange = true; } } - else if (subnode->getName() == "output") { - output->restoreXml(subnode,glb,effectlist,stackgrowsnegative); + else if (subId == ELEM_OUTPUT) { + output->decode(decoder,glb,effectlist,stackgrowsnegative); } - else if (subnode->getName() == "unaffected") { - const List &flist(subnode->getChildren()); - List::const_iterator fiter; - for(fiter=flist.begin();fiter!=flist.end();++fiter) { + else if (subId == ELEM_UNAFFECTED) { + decoder.openElement(); + while(decoder.peekElement() != 0) { effectlist.emplace_back(); - effectlist.back().restoreXml(EffectRecord::unaffected,*fiter,glb); + effectlist.back().decode(EffectRecord::unaffected,decoder,glb); } + decoder.closeElement(subId); } - else if (subnode->getName() == "killedbycall") { - const List &flist(subnode->getChildren()); - List::const_iterator fiter; - for(fiter=flist.begin();fiter!=flist.end();++fiter) { + else if (subId == ELEM_KILLEDBYCALL) { + decoder.openElement(); + while(decoder.peekElement() != 0) { effectlist.emplace_back(); - effectlist.back().restoreXml(EffectRecord::killedbycall,*fiter,glb); - } - } - else if (subnode->getName() == "returnaddress") { - const List &flist(subnode->getChildren()); - List::const_iterator fiter; - for(fiter=flist.begin();fiter!=flist.end();++fiter) { - effectlist.emplace_back(); - effectlist.back().restoreXml(EffectRecord::return_address,*fiter,glb); + effectlist.back().decode(EffectRecord::killedbycall,decoder,glb); } + decoder.closeElement(subId); + } + else if (subId == ELEM_RETURNADDRESS) { + decoder.openElement(); + while(decoder.peekElement() != 0) { + effectlist.emplace_back(); + effectlist.back().decode(EffectRecord::return_address,decoder,glb); + } + decoder.closeElement(subId); sawretaddr = true; } - else if (subnode->getName() == "localrange") { + else if (subId == ELEM_LOCALRANGE) { sawlocalrange = true; - const List &sublist(subnode->getChildren()); - List::const_iterator subiter; - for(subiter=sublist.begin();subiter!=sublist.end();++subiter) { + decoder.openElement(); + while(decoder.peekElement() != 0) { Range range; - range.restoreXml(*subiter,glb); + range.decode(decoder,glb); localrange.insertRange(range.getSpace(),range.getFirst(),range.getLast()); } + decoder.closeElement(subId); } - else if (subnode->getName() == "paramrange") { + else if (subId == ELEM_PARAMRANGE) { sawparamrange = true; - const List &sublist(subnode->getChildren()); - List::const_iterator subiter; - for(subiter=sublist.begin();subiter!=sublist.end();++subiter) { + decoder.openElement(); + while(decoder.peekElement() != 0) { Range range; - range.restoreXml(*subiter,glb); + range.decode(decoder,glb); paramrange.insertRange(range.getSpace(),range.getFirst(),range.getLast()); } + decoder.closeElement(subId); } - else if (subnode->getName() == "likelytrash") { - const List &flist(subnode->getChildren()); - List::const_iterator fiter; - for(fiter=flist.begin();fiter!=flist.end();++fiter) { + else if (subId == ELEM_LIKELYTRASH) { + decoder.openElement(); + while(decoder.peekElement() != 0) { likelytrash.emplace_back(); - likelytrash.back().restoreXml(*fiter,glb); - } - } - else if (subnode->getName() == "pcode") { - if (subnode->getAttributeValue("inject") == "uponentry") { - injectUponEntry = glb->pcodeinjectlib->restoreXmlInject("Protomodel : "+name, - name+"@@inject_uponentry", - InjectPayload::CALLMECHANISM_TYPE,subnode); - } - else { - injectUponReturn = glb->pcodeinjectlib->restoreXmlInject("Protomodel : "+name, - name+"@@inject_uponreturn", - InjectPayload::CALLMECHANISM_TYPE,subnode); + likelytrash.back().decode(decoder,glb); } + decoder.closeElement(subId); } - else if (subnode->getName() == "description") { + else if (subId == ELEM_PCODE) { + int4 injectId = glb->pcodeinjectlib->decodeInject("Protomodel : "+name, name, + InjectPayload::CALLMECHANISM_TYPE,decoder); + InjectPayload *payload = glb->pcodeinjectlib->getPayload(injectId); + if (payload->getName().find("uponentry") != string::npos) + injectUponEntry = injectId; + else + injectUponReturn = injectId; } else - throw LowlevelError("Unknown element in prototype: "+subnode->getName()); + throw LowlevelError("Unknown element in prototype"); } + decoder.closeElement(elemId); if ((!sawretaddr)&&(glb->defaultReturnAddr.space != (AddrSpace *)0)) { // Provide the default return address, if there isn't a specific one for the model effectlist.push_back(EffectRecord(glb->defaultReturnAddr,EffectRecord::return_address)); @@ -2520,7 +2537,7 @@ void ProtoModelMerged::intersectLikelyTrash(const vector &trashlist while((igetAttributeValue("name"); - const List &list(el->getChildren()); - List::const_iterator iter; - for(iter=list.begin();iter!=list.end();++iter) { // A tag for each merged prototype - const Element *subel = *iter; - ProtoModel *mymodel = glb->getModel( subel->getAttributeValue("name")); + uint4 elemId = decoder.openElement(ELEM_RESOLVEPROTOTYPE); + name = decoder.readString(ATTRIB_NAME); + for(;;) { // A tag for each merged prototype + uint4 subId = decoder.openElement(); + if (subId != ELEM_MODEL) break; + string modelName = decoder.readString(ATTRIB_NAME); + ProtoModel *mymodel = glb->getModel( modelName ); if (mymodel == (ProtoModel *)0) - throw LowlevelError("Missing prototype model: "+subel->getAttributeValue("name")); + throw LowlevelError("Missing prototype model: "+modelName); + decoder.closeElement(subId); foldIn(mymodel); modellist.push_back(mymodel); } + decoder.closeElement(elemId); ((ParamListMerged *)input)->finalize(); ((ParamListMerged *)output)->finalize(); } @@ -2679,10 +2699,10 @@ ProtoParameter *ParameterBasic::clone(void) const return res; } -const string &ParameterSymbol::getName(void) const +const string &ParameterSymbol::getName(void) const -{ - return sym->getName(); +{ + return sym->getName(); } Datatype *ParameterSymbol::getType(void) const @@ -2864,7 +2884,7 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame } if (res->sym == (Symbol *)0) { if (scope->discoverScope(pieces.addr,pieces.type->getSize(),usepoint) == (Scope *)0) - usepoint = restricted_usepoint; + usepoint = restricted_usepoint; res->sym = scope->addSymbol(nm,pieces.type,pieces.addr,usepoint)->getSymbol(); scope->setCategory(res->sym,Symbol::function_parameter,i); if (isindirect || ishidden) { @@ -2973,16 +2993,16 @@ ProtoStore *ProtoStoreSymbol::clone(void) const return res; } -void ProtoStoreSymbol::saveXml(ostream &s) const +void ProtoStoreSymbol::encode(Encoder &encoder) const { // Do not store anything explicitly for a symboltable backed store // as the symboltable will be stored separately } -void ProtoStoreSymbol::restoreXml(const Element *el,ProtoModel *model) +void ProtoStoreSymbol::decode(Decoder &decoder,ProtoModel *model) { - throw LowlevelError("Do not restore symbol-backed prototype through this interface"); + throw LowlevelError("Do not decode symbol-backed prototype through this interface"); } /// \param vt is the \b void data-type used for an unspecified return value @@ -3101,54 +3121,53 @@ ProtoStore *ProtoStoreInternal::clone(void) const return res; } -void ProtoStoreInternal::saveXml(ostream &s) const +void ProtoStoreInternal::encode(Encoder &encoder) const { - s << "\n"; + encoder.openElement(ELEM_INTERNALLIST); if (outparam != (ProtoParameter *)0) { - s << "isTypeLocked()) - a_v_b(s,"typelock",true); - s << ">\n"; - outparam->getAddress().saveXml(s); - outparam->getType()->saveXml(s); - s << "\n"; + encoder.writeBool(ATTRIB_TYPELOCK,true); + outparam->getAddress().encode(encoder); + outparam->getType()->encode(encoder); + encoder.closeElement(ELEM_RETPARAM); } else { - s << "\n \n \n\n"; + encoder.openElement(ELEM_RETPARAM); + encoder.openElement(ELEM_ADDR); + encoder.closeElement(ELEM_ADDR); + encoder.openElement(ELEM_VOID); + encoder.closeElement(ELEM_VOID); + encoder.closeElement(ELEM_RETPARAM); } for(int4 i=0;igetName().size()!=0) - a_v(s,"name",param->getName()); + encoder.writeString(ATTRIB_NAME,param->getName()); if (param->isTypeLocked()) - a_v_b(s,"typelock",true); + encoder.writeBool(ATTRIB_TYPELOCK, true); if (param->isNameLocked()) - a_v_b(s,"namelock",true); + encoder.writeBool(ATTRIB_NAMELOCK, true); if (param->isThisPointer()) - a_v_b(s,"thisptr",true); + encoder.writeBool(ATTRIB_THISPTR, true); if (param->isIndirectStorage()) - a_v_b(s,"indirectstorage",true); + encoder.writeBool(ATTRIB_INDIRECTSTORAGE, true); if (param->isHiddenReturn()) - a_v_b(s,"hiddenretparm",true); - s << ">\n"; - param->getAddress().saveXml(s); - param->getType()->saveXml(s); - s << "\n"; + encoder.writeBool(ATTRIB_HIDDENRETPARM, true); + param->getAddress().encode(encoder); + param->getType()->encode(encoder); + encoder.closeElement(ELEM_PARAM); } - s << "\n"; + encoder.closeElement(ELEM_INTERNALLIST); } -void ProtoStoreInternal::restoreXml(const Element *el,ProtoModel *model) +void ProtoStoreInternal::decode(Decoder &decoder,ProtoModel *model) { - if (el->getName() != "internallist") - throw LowlevelError("Mismatched ProtoStore tag: ProtoStoreInternal did not get "); Architecture *glb = model->getArch(); - const List &list(el->getChildren()); - List::const_iterator iter; vector pieces; vector namelist; bool addressesdetermined = true; @@ -3164,32 +3183,35 @@ void ProtoStoreInternal::restoreXml(const Element *el,ProtoModel *model) if (outparam->getAddress().isInvalid()) addressesdetermined = false; - for(iter=list.begin();iter!=list.end();++iter) { // This is only the input params - const Element *subel = *iter; + uint4 elemId = decoder.openElement(ELEM_INTERNALLIST); + for(;;) { // This is only the input params + uint subId = decoder.openElement(); // or + if (subId == 0) break; string name; uint4 flags = 0; - for(int4 i=0;igetNumAttributes();++i) { - const string &attr( subel->getAttributeName(i) ); - if (attr == "name") - name = subel->getAttributeValue(i); - else if (attr == "typelock") { - if (xml_readbool(subel->getAttributeValue(i))) + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_NAME) + name = decoder.readString(); + else if (attribId == ATTRIB_TYPELOCK) { + if (decoder.readBool()) flags |= ParameterPieces::typelock; } - else if (attr == "namelock") { - if (xml_readbool(subel->getAttributeValue(i))) + else if (attribId == ATTRIB_NAMELOCK) { + if (decoder.readBool()) flags |= ParameterPieces::namelock; } - else if (attr == "thisptr") { - if (xml_readbool(subel->getAttributeValue(i))) + else if (attribId == ATTRIB_THISPTR) { + if (decoder.readBool()) flags |= ParameterPieces::isthis; } - else if (attr == "indirectstorage") { - if (xml_readbool(subel->getAttributeValue(i))) + else if (attribId == ATTRIB_INDIRECTSTORAGE) { + if (decoder.readBool()) flags |= ParameterPieces::indirectstorage; } - else if (attr == "hiddenretparm") { - if (xml_readbool(subel->getAttributeValue(i))) + else if (attribId == ATTRIB_HIDDENRETPARM) { + if (decoder.readBool()) flags |= ParameterPieces::hiddenretparm; } } @@ -3197,22 +3219,20 @@ void ProtoStoreInternal::restoreXml(const Element *el,ProtoModel *model) namelist.push_back(name); pieces.emplace_back(); ParameterPieces &curparam( pieces.back() ); - const List &sublist(subel->getChildren()); - List::const_iterator subiter; - subiter = sublist.begin(); - curparam.addr = Address::restoreXml(*subiter,glb); - ++subiter; - curparam.type = glb->types->restoreXmlType(*subiter); + curparam.addr = Address::decode(decoder,glb); + curparam.type = glb->types->decodeType(decoder); curparam.flags = flags; if (curparam.addr.isInvalid()) addressesdetermined = false; + decoder.closeElement(subId); } + decoder.closeElement(elemId); ProtoParameter *curparam; if (!addressesdetermined) { // If addresses for parameters are not provided, use // the model to derive them from type info vector typelist; - for(int4 i=0;i addrPieces; model->assignParameterStorage(typelist,addrPieces,true); @@ -3244,7 +3264,7 @@ void ProtoStoreInternal::restoreXml(const Element *el,ProtoModel *model) } } -/// This is called after a new prototype is established (via restoreXml or updateAllTypes) +/// This is called after a new prototype is established (via decode or updateAllTypes) /// It makes sure that if the ProtoModel calls for a "this" parameter, then the appropriate parameter /// is explicitly marked as the "this". void FuncProto::updateThisPointer(void) @@ -3263,8 +3283,8 @@ void FuncProto::updateThisPointer(void) /// If the \e effectlist for \b this is non-empty, it contains the complete set of /// EffectRecords. Save just those that override the underlying list from ProtoModel -/// \param s is the stream to write to -void FuncProto::saveEffectXml(ostream &s) const +/// \param encoder is the stream encoder +void FuncProto::encodeEffect(Encoder &encoder) const { if (effectlist.empty()) return; @@ -3283,55 +3303,51 @@ void FuncProto::saveEffectXml(ostream &s) const retAddr = &curRecord; } if (!unaffectedList.empty()) { - s << " \n"; + encoder.openElement(ELEM_UNAFFECTED); for(int4 i=0;isaveXml(s); - s << '\n'; + unaffectedList[i]->encode(encoder); } - s << " \n"; + encoder.closeElement(ELEM_UNAFFECTED); } if (!killedByCallList.empty()) { - s << " \n"; + encoder.openElement(ELEM_KILLEDBYCALL); for(int4 i=0;isaveXml(s); - s << '\n'; + killedByCallList[i]->encode(encoder); } - s << " \n"; + encoder.closeElement(ELEM_KILLEDBYCALL); } if (retAddr != (const EffectRecord *)0) { - s << " \n "; - retAddr->saveXml(s); - s << "\n \n"; + encoder.openElement(ELEM_RETURNADDRESS); + retAddr->encode(encoder); + encoder.closeElement(ELEM_RETURNADDRESS); } } -/// If the -likelytrash- list is not empty it overrides the underlying ProtoModel's list. -/// Write any VarnodeData that does not appear in the ProtoModel to the XML stream. -/// \param s is the stream to write to -void FuncProto::saveLikelyTrashXml(ostream &s) const +/// If the \b likelytrash list is not empty it overrides the underlying ProtoModel's list. +/// Encode any VarnodeData that does not appear in the ProtoModel to the stream. +/// \param encoder is the stream encoder +void FuncProto::encodeLikelyTrash(Encoder &encoder) const { if (likelytrash.empty()) return; vector::const_iterator iter1,iter2; iter1 = model->trashBegin(); iter2 = model->trashEnd(); - s << " \n"; + encoder.openElement(ELEM_LIKELYTRASH); for(vector::const_iterator iter=likelytrash.begin();iter!=likelytrash.end();++iter) { const VarnodeData &cur(*iter); if (binary_search(iter1,iter2,cur)) continue; // Already exists in ProtoModel - s << " saveXmlAttributes(s,cur.offset,cur.size); - s << "/>\n"; + encoder.openElement(ELEM_ADDR); + cur.space->encodeAttributes(encoder,cur.offset,cur.size); + encoder.closeElement(ELEM_ADDR); } - s << " \n"; + encoder.closeElement(ELEM_LIKELYTRASH); } -/// EffectRecords read into \e effectlist by restoreXml() override the list from ProtoModel. +/// EffectRecords read into \e effectlist by decode() override the list from ProtoModel. /// If this list is not empty, set up \e effectlist as a complete override containing /// all EffectRecords from ProtoModel plus all the overrides. -void FuncProto::restoreEffectXml(void) +void FuncProto::decodeEffect(void) { if (effectlist.empty()) return; @@ -3360,10 +3376,10 @@ void FuncProto::restoreEffectXml(void) sort(effectlist.begin(),effectlist.end(),EffectRecord::compareByAddress); } -/// VarnodeData read into \e likelytrash by restoreXml() are additional registers over +/// VarnodeData read into \e likelytrash by decode() are additional registers over /// what is already in ProtoModel. Make \e likelytrash in \b this a complete list by /// merging in everything from ProtoModel. -void FuncProto::restoreLikelyTrashXml(void) +void FuncProto::decodeLikelyTrash(void) { if (likelytrash.empty()) return; @@ -3407,7 +3423,7 @@ void FuncProto::paramShift(int4 paramshift) nmlist.push_back(""); typelist.push_back(extra); } - + if (isInputLocked()) { // Copy in the original parameter types int4 num = numParams(); for(int4 i=0;i &namelist,const vectorclearOutput(); flags &= ~((uint4)voidinputlock); setDotdotdot(dtdtdt); - + vector pieces; // Calculate what memory locations hold each type @@ -4214,7 +4230,7 @@ bool FuncProto::isCompatible(const FuncProto &op2) const // the prototype hasn't been marked as varargs if (isInputLocked()) return false; } - else + else return false; } @@ -4258,63 +4274,63 @@ void FuncProto::printRaw(const string &funcname,ostream &s) const s << ") extrapop=" << dec << extrapop; } -/// \brief Save \b this to an XML stream as a \ tag. +/// \brief Encode \b this to a stream as a \ element. /// /// Save everything under the control of this prototype, which /// may \e not include input parameters, as these are typically /// controlled by the function's symbol table scope. -/// \param s is the output stream -void FuncProto::saveXml(ostream &s) const +/// \param encoder is the stream encoder +void FuncProto::encode(Encoder &encoder) const { - s << " getName()); + encoder.openElement(ELEM_PROTOTYPE); + encoder.writeString(ATTRIB_MODEL, model->getName()); if (extrapop == ProtoModel::extrapop_unknown) - a_v(s,"extrapop","unknown"); + encoder.writeString(ATTRIB_EXTRAPOP, "unknown"); else - a_v_i(s,"extrapop",extrapop); + encoder.writeSignedInteger(ATTRIB_EXTRAPOP, extrapop); if (isDotdotdot()) - a_v_b(s,"dotdotdot",true); + encoder.writeBool(ATTRIB_DOTDOTDOT, true); if (isModelLocked()) - a_v_b(s,"modellock",true); + encoder.writeBool(ATTRIB_MODELLOCK, true); if ((flags&voidinputlock)!=0) - a_v_b(s,"voidlock",true); + encoder.writeBool(ATTRIB_VOIDLOCK, true); if (isInline()) - a_v_b(s,"inline",true); + encoder.writeBool(ATTRIB_INLINE, true); if (isNoReturn()) - a_v_b(s,"noreturn",true); + encoder.writeBool(ATTRIB_NORETURN, true); if (hasCustomStorage()) - a_v_b(s,"custom",true); + encoder.writeBool(ATTRIB_CUSTOM, true); if (isConstructor()) - a_v_b(s,"constructor",true); + encoder.writeBool(ATTRIB_CONSTRUCTOR, true); if (isDestructor()) - a_v_b(s,"destructor",true); - s << ">\n"; + encoder.writeBool(ATTRIB_DESTRUCTOR, true); ProtoParameter *outparam = store->getOutput(); - s << " isTypeLocked()) - a_v_b(s,"typelock",true); - s << ">\n "; - outparam->getAddress().saveXml(s,outparam->getSize()); - outparam->getType()->saveXml(s); - s << " \n"; - saveEffectXml(s); - saveLikelyTrashXml(s); + encoder.writeBool(ATTRIB_TYPELOCK, true); + outparam->getAddress().encode(encoder,outparam->getSize()); + outparam->getType()->encode(encoder); + encoder.closeElement(ELEM_RETURNSYM); + encodeEffect(encoder); + encodeLikelyTrash(encoder); if (injectid >= 0) { Architecture *glb = model->getArch(); - s << " " << glb->pcodeinjectlib->getCallFixupName(injectid) << "\n"; + encoder.openElement(ELEM_INJECT); + encoder.writeString(ATTRIB_CONTENT, glb->pcodeinjectlib->getCallFixupName(injectid)); + encoder.closeElement(ELEM_INJECT); } - store->saveXml(s); // Store any internally backed prototyped symbols - s << " \n"; + store->encode(encoder); // Store any internally backed prototyped symbols + encoder.closeElement(ELEM_PROTOTYPE); } -/// \brief Restore \b this from an XML stream +/// \brief Restore \b this from a \ element in the given stream /// /// The backing store for the parameters must already be established using either /// setStore() or setInternal(). -/// \param el is the \ XML element +/// \param decoder is the given stream decoder /// \param glb is the Architecture owning the prototype -void FuncProto::restoreXml(const Element *el,Architecture *glb) +void FuncProto::decode(Decoder &decoder,Architecture *glb) { // Model must be set first @@ -4324,13 +4340,14 @@ void FuncProto::restoreXml(const Element *el,Architecture *glb) bool seenextrapop = false; bool seenunknownmod = false; int4 readextrapop; - int4 num = el->getNumAttributes(); flags = 0; injectid = -1; - for(int4 i=0;igetAttributeName(i) ); - if (attrname == "model") { - const string &modelname( el->getAttributeValue(i) ); + uint4 elemId = decoder.openElement(ELEM_PROTOTYPE); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_MODEL) { + string modelname = decoder.readString(); if ((modelname == "default")||(modelname.size()==0)) mod = glb->defaultfp; // Get default model else if (modelname == "unknown") { @@ -4340,9 +4357,9 @@ void FuncProto::restoreXml(const Element *el,Architecture *glb) else mod = glb->getModel(modelname); } - else if (attrname == "extrapop") { + else if (attribId == ATTRIB_EXTRAPOP) { seenextrapop = true; - const string &expopval( el->getAttributeValue(i) ); + string expopval = decoder.readString(); if (expopval == "unknown") readextrapop = ProtoModel::extrapop_unknown; else { @@ -4351,36 +4368,36 @@ void FuncProto::restoreXml(const Element *el,Architecture *glb) i1 >> readextrapop; } } - else if (attrname == "modellock") { - if (xml_readbool(el->getAttributeValue(i))) + else if (attribId == ATTRIB_MODELLOCK) { + if (decoder.readBool()) flags |= modellock; } - else if (attrname == "dotdotdot") { - if (xml_readbool(el->getAttributeValue(i))) + else if (attribId == ATTRIB_DOTDOTDOT) { + if (decoder.readBool()) flags |= dotdotdot; } - else if (attrname == "voidlock") { - if (xml_readbool(el->getAttributeValue(i))) + else if (attribId == ATTRIB_VOIDLOCK) { + if (decoder.readBool()) flags |= voidinputlock; } - else if (attrname == "inline") { - if (xml_readbool(el->getAttributeValue(i))) + else if (attribId == ATTRIB_INLINE) { + if (decoder.readBool()) flags |= is_inline; } - else if (attrname == "noreturn") { - if (xml_readbool(el->getAttributeValue(i))) + else if (attribId == ATTRIB_NORETURN) { + if (decoder.readBool()) flags |= no_return; } - else if (attrname == "custom") { - if (xml_readbool(el->getAttributeValue(i))) + else if (attribId == ATTRIB_CUSTOM) { + if (decoder.readBool()) flags |= custom_storage; } - else if (attrname == "constructor") { - if (xml_readbool(el->getAttributeValue(i))) + else if (attribId == ATTRIB_CONSTRUCTOR) { + if (decoder.readBool()) flags |= is_constructor; } - else if (attrname == "destructor") { - if (xml_readbool(el->getAttributeValue(i))) + else if (attribId == ATTRIB_DESTRUCTOR) { + if (decoder.readBool()) flags |= is_destructor; } } @@ -4391,40 +4408,30 @@ void FuncProto::restoreXml(const Element *el,Architecture *glb) if (seenunknownmod) flags |= unknown_model; - const List &list(el->getChildren()); - List::const_iterator iter = list.begin(); - - const Element *subel = (const Element *)0; - if (iter != list.end()) { - subel = *iter; - ++iter; - } - if (subel != (const Element *)0) { + uint4 subId = decoder.peekElement(); + if (subId != 0) { ParameterPieces outpieces; bool outputlock = false; - if (subel->getName() == "returnsym") { - num = subel->getNumAttributes(); - for(int4 i=0;igetAttributeName(i) ); - if (attrname == "typelock") - outputlock = xml_readbool(subel->getAttributeValue(i)); + if (subId == ELEM_RETURNSYM) { + decoder.openElement(); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_TYPELOCK) + outputlock = decoder.readBool(); } - const List &list2(subel->getChildren()); - List::const_iterator riter = list2.begin(); - int4 tmpsize; - outpieces.addr = Address::restoreXml(*riter,glb,tmpsize); - ++riter; - outpieces.type = glb->types->restoreXmlType(*riter); + outpieces.addr = Address::decode(decoder,glb,tmpsize); + outpieces.type = glb->types->decodeType(decoder); outpieces.flags = 0; + decoder.closeElement(subId); } - else if (subel->getName() == "addr") { // Old-style specification of return (supported partially for backward compat) + else if (subId == ELEM_ADDR) { // Old-style specification of return (supported partially for backward compat) int4 tmpsize; - outpieces.addr = Address::restoreXml(subel,glb,tmpsize); - outpieces.type = glb->types->restoreXmlType(*iter); + outpieces.addr = Address::decode(decoder,glb,tmpsize); + outpieces.type = glb->types->decodeType(decoder); outpieces.flags = 0; - ++iter; } else throw LowlevelError("Missing tag"); @@ -4438,53 +4445,55 @@ void FuncProto::restoreXml(const Element *el,Architecture *glb) if (((flags&voidinputlock)!=0)||(isOutputLocked())) flags |= modellock; - for(;iter!=list.end();++iter) { - if ((*iter)->getName() == "unaffected") { - const List &list2((*iter)->getChildren()); - List::const_iterator iter2 = list2.begin(); - while(iter2 != list2.end()) { + for(;;) { + subId = decoder.peekElement(); + if (subId == 0) break; + if (subId == ELEM_UNAFFECTED) { + decoder.openElement(); + while(decoder.peekElement() != 0) { effectlist.emplace_back(); - effectlist.back().restoreXml(EffectRecord::unaffected,*iter2,glb); - ++iter2; + effectlist.back().decode(EffectRecord::unaffected,decoder,glb); } + decoder.closeElement(subId); } - else if ((*iter)->getName() == "killedbycall") { - const List &list2((*iter)->getChildren()); - List::const_iterator iter2 = list2.begin(); - while(iter2 != list2.end()) { + else if (subId == ELEM_KILLEDBYCALL) { + decoder.openElement(); + while(decoder.peekElement() != 0) { effectlist.emplace_back(); - effectlist.back().restoreXml(EffectRecord::killedbycall,*iter2,glb); - ++iter2; + effectlist.back().decode(EffectRecord::killedbycall,decoder,glb); } + decoder.closeElement(subId); } - else if ((*iter)->getName() == "returnaddress") { - const List &list2((*iter)->getChildren()); - List::const_iterator iter2 = list2.begin(); - while(iter2 != list2.end()) { + else if (subId == ELEM_RETURNADDRESS) { + decoder.openElement(); + while(decoder.peekElement() != 0) { effectlist.emplace_back(); - effectlist.back().restoreXml(EffectRecord::return_address,*iter2,glb); - ++iter2; + effectlist.back().decode(EffectRecord::return_address,decoder,glb); } + decoder.closeElement(subId); } - else if ((*iter)->getName() == "likelytrash") { - const List &list2((*iter)->getChildren()); - List::const_iterator iter2 = list2.begin(); - while(iter2 != list2.end()) { + else if (subId == ELEM_LIKELYTRASH) { + decoder.openElement(); + while(decoder.peekElement() != 0) { likelytrash.emplace_back(); - likelytrash.back().restoreXml(*iter2,glb); - ++iter2; + likelytrash.back().decode(decoder,glb); } + decoder.closeElement(subId); } - else if ((*iter)->getName() == "inject") { - injectid = glb->pcodeinjectlib->getPayloadId(InjectPayload::CALLFIXUP_TYPE,(*iter)->getContent()); + else if (subId == ELEM_INJECT) { + decoder.openElement(); + string injectString = decoder.readString(ATTRIB_CONTENT); + injectid = glb->pcodeinjectlib->getPayloadId(InjectPayload::CALLFIXUP_TYPE,injectString); flags |= is_inline; + decoder.closeElement(subId); } - else if ((*iter)->getName() == "internallist") { - store->restoreXml(*iter,model); + else if (subId == ELEM_INTERNALLIST) { + store->decode(decoder,model); } } - restoreEffectXml(); - restoreLikelyTrashXml(); + decoder.closeElement(elemId); + decodeEffect(); + decodeLikelyTrash(); if (!isModelLocked()) { if (isInputLocked()) flags |= modellock; @@ -4527,7 +4536,7 @@ void FuncCallSpecs::resolveSpacebaseRelative(Funcdata &data,Varnode *phvn) return; } } - + if (isInputLocked()) { // The prototype is locked and had stack parameters, we grab the relative offset from this // rather than from a placeholder @@ -4744,7 +4753,7 @@ bool FuncCallSpecs::transferLockedInput(vector &newinput) for(int4 i=0;i 0) + if (reuse > 0) newinput.push_back(op->getIn(reuse)); else { if (stackref == (Varnode *)0) @@ -5197,7 +5206,7 @@ void FuncCallSpecs::checkInputTrialUse(Funcdata &data,AliasChecker &aliascheck) int4 expop = 0; if (hasModel()) { callee_pop = (getModelExtraPop() == ProtoModel::extrapop_unknown); - if (callee_pop) { + if (callee_pop) { expop = getExtraPop(); // Tried to use getEffectiveExtraPop at one point, but it is too unreliable if ((expop==ProtoModel::extrapop_unknown)||(expop <=4)) @@ -5295,7 +5304,7 @@ void FuncCallSpecs::buildInputFromTrials(Funcdata &data) bool isspacebase; Varnode *vn; vector newparam; - + newparam.push_back(op->getIn(0)); // Preserve the fspec parameter for(int4 i=0;i +extern ElementId ELEM_INTERNALLIST; ///< Marshaling element \ +extern ElementId ELEM_KILLEDBYCALL; ///< Marshaling element \ +extern ElementId ELEM_LIKELYTRASH; ///< Marshaling element \ +extern ElementId ELEM_LOCALRANGE; ///< Marshaling element \ +extern ElementId ELEM_MODEL; ///< Marshaling element \ +extern ElementId ELEM_PARAM; ///< Marshaling element \ +extern ElementId ELEM_PARAMRANGE; ///< Marshaling element \ +extern ElementId ELEM_PENTRY; ///< Marshaling element \ +extern ElementId ELEM_PROTOTYPE; ///< Marshaling element \ +extern ElementId ELEM_RESOLVEPROTOTYPE; ///< Marshaling element \ +extern ElementId ELEM_RETPARAM; ///< Marshaling element \ +extern ElementId ELEM_RETURNSYM; ///< Marshaling element \ +extern ElementId ELEM_UNAFFECTED; ///< Marshaling element \ + /// \brief Exception thrown when a prototype can't be modeled properly struct ParamUnassignedError : public LowlevelError { ParamUnassignedError(const string &s) : LowlevelError(s) {} ///< Constructor @@ -85,7 +117,7 @@ private: /// \brief Is the logical value left-justified within its container bool isLeftJustified(void) const { return (((flags&force_left_justify)!=0)||(!spaceid->isBigEndian())); } public: - ParamEntry(int4 grp) { group=grp; } ///< Constructor for use with restoreXml + ParamEntry(int4 grp) { group=grp; } ///< Constructor for use with decode 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. @@ -102,13 +134,13 @@ public: bool intersects(const Address &addr,int4 sz) const; ///< Does \b this intersect the given range in some way int4 justifiedContain(const Address &addr,int4 sz) const; ///< Calculate endian aware containment bool getContainer(const Address &addr,int4 sz,VarnodeData &res) const; - bool contains(const ParamEntry &op2) const; ///< Does \this contain the given entry (as a subpiece) + bool contains(const ParamEntry &op2) const; ///< Does \b this contain the given entry (as a subpiece) OpCode assumedExtension(const Address &addr,int4 sz,VarnodeData &res) const; int4 getSlot(const Address &addr,int4 skip) const; AddrSpace *getSpace(void) const { return spaceid; } ///< Get the address space containing \b this entry uintb getBase(void) const { return addressbase; } ///< Get the starting offset of \b this entry Address getAddrBySlot(int4 &slot,int4 sz) const; - void restoreXml(const Element *el,const AddrSpaceManager *manage,bool normalstack,bool grouped,list &curList); + void decode(Decoder &decoder,const AddrSpaceManager *manage,bool normalstack,bool grouped,list &curList); bool isParamCheckHigh(void) const { return ((flags & extracheck_high)!=0); } ///< Return \b true if there is a high overlap bool isParamCheckLow(void) const { return ((flags & extracheck_low)!=0); } ///< Return \b true if there is a low overlap static void orderWithinGroup(const ParamEntry &entry1,const ParamEntry &entry2); ///< Enforce ParamEntry group ordering rules @@ -302,11 +334,11 @@ public: class FspecSpace : public AddrSpace { public: FspecSpace(AddrSpaceManager *m,const Translate *t,int4 ind); ///< Constructor - virtual void saveXmlAttributes(ostream &s,uintb offset) const; - virtual void saveXmlAttributes(ostream &s,uintb offset,int4 size) const; + virtual void encodeAttributes(Encoder &encoder,uintb offset) const; + virtual void encodeAttributes(Encoder &encoder,uintb offset,int4 size) const; virtual void printRaw(ostream &s,uintb offset) const; virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el); + virtual void decode(Decoder &decoder); static const string NAME; ///< Reserved name for the fspec space }; @@ -342,7 +374,7 @@ private: VarnodeData range; ///< The memory range affected uint4 type; ///< The type of effect public: - EffectRecord(void) {} ///< Constructor for use with restoreXml() + EffectRecord(void) {} ///< Constructor for use with decode() EffectRecord(const EffectRecord &op2) { range = op2.range; type = op2.type; } ///< Copy constructor EffectRecord(const Address &addr,int4 size); ///< Construct a memory range with an unknown effect EffectRecord(const ParamEntry &entry,uint4 t); ///< Construct an effect on a parameter storage location @@ -352,8 +384,8 @@ public: int4 getSize(void) const { return range.size; } ///< Get the size of the affected range bool operator==(const EffectRecord &op2) const; ///< Equality operator bool operator!=(const EffectRecord &op2) const; ///< Inequality operator - void saveXml(ostream &s) const; ///< Save the record to an XML stream - void restoreXml(uint4 grouptype,const Element *el,const AddrSpaceManager *manage); ///< Restore the record from an XML stream + void encode(Encoder &encoder) const; ///< Encode the record to a stream + void decode(uint4 grouptype,Decoder &decoder,const AddrSpaceManager *manage); ///< Decode the record from a stream static bool compareByAddress(const EffectRecord &op1,const EffectRecord &op2); }; @@ -496,13 +528,13 @@ public: /// \return the maximum number of passes across all parameters in \b this model virtual int4 getMaxDelay(void) const=0; - /// \brief Restore the model from an XML stream + /// \brief Restore the model from an \ or \ element in the stream /// - /// \param el is the root \ or \ element + /// \param decoder is the stream decoder /// \param manage is used to resolve references to address spaces /// \param effectlist is a container collecting EffectRecords across all parameters /// \param normalstack is \b true if parameters are pushed on the stack in the normal order - virtual void restoreXml(const Element *el,const AddrSpaceManager *manage,vector &effectlist,bool normalstack)=0; + virtual void decode(Decoder &decoder,const AddrSpaceManager *manage,vector &effectlist,bool normalstack)=0; virtual ParamList *clone(void) const=0; ///< Clone this parameter list model }; @@ -539,12 +571,12 @@ protected: void calcDelay(void); ///< Calculate the maximum heritage delay for any potential parameter in this list void addResolverRange(AddrSpace *spc,uintb first,uintb last,ParamEntry *paramEntry,int4 position); void populateResolver(void); ///< Build the ParamEntry resolver maps - void parsePentry(const Element *el,const AddrSpaceManager *manage,vector &effectlist, + void parsePentry(Decoder &decoder,const AddrSpaceManager *manage,vector &effectlist, int4 groupid,bool normalstack,bool autokill,bool splitFloat,bool grouped); - void parseGroup(const Element *el,const AddrSpaceManager *manage,vector &effectlist, + void parseGroup(Decoder &decoder,const AddrSpaceManager *manage,vector &effectlist, int4 groupid,bool normalstack,bool autokill,bool splitFloat); public: - ParamListStandard(void) {} ///< Construct for use with restoreXml() + ParamListStandard(void) {} ///< Construct for use with decode() ParamListStandard(const ParamListStandard &op2); ///< Copy constructor virtual ~ParamListStandard(void); const list &getEntry(void) const { return entry; } ///< Get the list of parameter entries @@ -562,7 +594,7 @@ public: virtual AddrSpace *getSpacebase(void) const { return spacebase; } virtual void getRangeList(AddrSpace *spc,RangeList &res) const; virtual int4 getMaxDelay(void) const { return maxdelay; } - virtual void restoreXml(const Element *el,const AddrSpaceManager *manage,vector &effectlist,bool normalstack); + virtual void decode(Decoder &decoder,const AddrSpaceManager *manage,vector &effectlist,bool normalstack); virtual ParamList *clone(void) const; }; @@ -593,7 +625,7 @@ public: /// conventions. The assignMap() method may make less sense in this scenario. class ParamListRegister : public ParamListStandard { public: - ParamListRegister(void) : ParamListStandard() {} ///< Constructor for use with restoreXml() + ParamListRegister(void) : ParamListStandard() {} ///< Constructor for use with decode() ParamListRegister(const ParamListRegister &op2) : ParamListStandard(op2) {} ///< Copy constructor virtual uint4 getType(void) const { return p_register; } virtual void fillinMap(ParamActive *active) const; @@ -610,11 +642,11 @@ public: /// to inform the input model. class ParamListStandardOut : public ParamListRegisterOut { public: - ParamListStandardOut(void) : ParamListRegisterOut() {} ///< Constructor for use with restoreXml() + ParamListStandardOut(void) : ParamListRegisterOut() {} ///< Constructor for use with decode() ParamListStandardOut(const ParamListStandardOut &op2) : ParamListRegisterOut(op2) {} ///< Copy constructor virtual uint4 getType(void) const { return p_standard_out; } virtual void assignMap(const vector &proto,TypeFactory &typefactory,vector &res) const; - virtual void restoreXml(const Element *el,const AddrSpaceManager *manage,vector &effectlist,bool normalstack); + virtual void decode(Decoder &decoder,const AddrSpaceManager *manage,vector &effectlist,bool normalstack); virtual ParamList *clone(void) const; }; @@ -628,7 +660,7 @@ public: /// need to be invoked. class ParamListMerged : public ParamListStandard { public: - ParamListMerged(void) : ParamListStandard() {} ///< Constructor for use with restoreXml + ParamListMerged(void) : ParamListStandard() {} ///< Constructor for use with decode ParamListMerged(const ParamListMerged &op2) : ParamListStandard(op2) {} ///< Copy constructor void foldIn(const ParamListStandard &op2); ///< Add another model to the union void finalize(void) { populateResolver(); } ///< Fold-ins are finished, finalize \b this @@ -686,7 +718,7 @@ public: enum { extrapop_unknown = 0x8000 ///< Reserved extrapop value meaning the function's \e extrapop is unknown }; - ProtoModel(Architecture *g); ///< Constructor for use with restoreXml() + ProtoModel(Architecture *g); ///< Constructor for use with decode() ProtoModel(const string &nm,const ProtoModel &op2); ///< Copy constructor changing the name virtual ~ProtoModel(void); ///< Destructor const string &getName(void) const { return name; } ///< Get the name of the prototype model @@ -909,7 +941,7 @@ public: int4 getMaxOutputDelay(void) const { return output->getMaxDelay(); } virtual bool isMerged(void) const { return false; } ///< Is \b this a merged prototype model - virtual void restoreXml(const Element *el); ///< Restore \b this model from an XML stream + virtual void decode(Decoder &decoder); ///< Restore \b this model from a stream static uint4 lookupEffect(const vector &efflist,const Address &addr,int4 size); static int4 lookupRecord(const vector &efflist,int4 listSize,const Address &addr,int4 size); }; @@ -969,7 +1001,7 @@ public: void foldIn(ProtoModel *model); ///< Fold-in an additional prototype model ProtoModel *selectModel(ParamActive *active) const; ///< Select the best model given a set of trials virtual bool isMerged(void) const { return true; } - virtual void restoreXml(const Element *el); + virtual void decode(Decoder &decoder); }; class Symbol; @@ -1116,18 +1148,19 @@ public: virtual ProtoParameter *getOutput(void)=0; ///< Get the return-value description virtual ProtoStore *clone(void) const=0; ///< Clone the entire collection of parameter descriptions - /// \brief Save any parameters that are not backed by symbols to an XML stream + /// \brief Encode any parameters that are not backed by symbols to a stream /// /// Symbols are stored elsewhere, so symbol backed parameters are not serialized. - /// If there are any internal parameters an \ tag is emitted. - /// \param s is the output stream - virtual void saveXml(ostream &s) const=0; + /// If there are any internal parameters an \ element is emitted. + /// \param encoder is the stream encoder + virtual void encode(Encoder &encoder) const=0; - /// \brief Restore any internal parameter descriptions from an XML stream + /// \brief Restore any internal parameter descriptions from a stream /// - /// \param el is a root \ element containing \ and \ sub-tags. + /// Parse an \ element containing \ and \ child elements. + /// \param decoder is the stream decoder /// \param model is prototype model for determining storage for unassigned parameters - virtual void restoreXml(const Element *el,ProtoModel *model)=0; + virtual void decode(Decoder &decoder,ProtoModel *model)=0; }; /// \brief A parameter with a formal backing Symbol @@ -1183,8 +1216,8 @@ public: virtual void clearOutput(void); virtual ProtoParameter *getOutput(void); virtual ProtoStore *clone(void) const; - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el,ProtoModel *model); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,ProtoModel *model); }; /// \brief A collection of parameter descriptions without backing symbols @@ -1207,8 +1240,8 @@ public: virtual void clearOutput(void); virtual ProtoParameter *getOutput(void); virtual ProtoStore *clone(void) const; - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el,ProtoModel *model); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,ProtoModel *model); }; /// \brief Raw components of a function prototype (obtained from parsing source code) @@ -1258,10 +1291,10 @@ class FuncProto { int4 injectid; ///< (If non-negative) id of p-code snippet that should replace this function int4 returnBytesConsumed; ///< Number of bytes of return value that are consumed by callers (0 = all bytes) void updateThisPointer(void); ///< Make sure any "this" parameter is properly marked - void saveEffectXml(ostream &s) const; ///< Save any overriding EffectRecords to XML stream - void saveLikelyTrashXml(ostream &s) const; ///< Save any overriding likelytrash registers to XML stream - void restoreEffectXml(void); ///< Merge in any EffectRecord overrides - void restoreLikelyTrashXml(void); ///< Merge in any \e likelytrash overrides + void encodeEffect(Encoder &encoder) const; ///< Encode any overriding EffectRecords to stream + void encodeLikelyTrash(Encoder &encoder) const; ///< Encode any overriding likelytrash registers to stream + void decodeEffect(void); ///< Merge in any EffectRecord overrides + void decodeLikelyTrash(void); ///< Merge in any \e likelytrash overrides protected: void paramShift(int4 paramshift); ///< Add parameters to the front of the input parameter list bool isParamshiftApplied(void) const { return ((flags¶mshift_applied)!=0); } ///< Has a parameter shift been applied @@ -1502,8 +1535,8 @@ public: /// \return the active set of flags for \b this prototype uint4 getComparableFlags(void) const { return (flags & (dotdotdot | is_constructor | is_destructor | has_thisptr )); } - void saveXml(ostream &s) const; - void restoreXml(const Element *el,Architecture *glb); + void encode(Encoder &encoder) const; + void decode(Decoder &decoder,Architecture *glb); }; class Funcdata; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc index fd2f814f68..c266c34071 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc @@ -14,7 +14,14 @@ * limitations under the License. */ #include "funcdata.hh" -//#include + +AttributeId ATTRIB_NOCODE = AttributeId("nocode",70); + +ElementId ELEM_AST = ElementId("ast",89); +ElementId ELEM_FUNCTION = ElementId("function",90); +ElementId ELEM_HIGHLIST = ElementId("highlist",91); +ElementId ELEM_JUMPTABLELIST = ElementId("jumptablelist",92); +ElementId ELEM_VARNODES = ElementId("varnodes",93); /// \param nm is the (base) name of the function /// \param scope is Symbol scope associated with the function @@ -42,7 +49,7 @@ Funcdata::Funcdata(const string &nm,Scope *scope,const Address &addr,FunctionSym size = sz; AddrSpace *stackid = glb->getStackSpace(); if (nm.size()==0) - localmap = (ScopeLocal *)0; // Filled in by restoreXml + localmap = (ScopeLocal *)0; // Filled in by decode else { uint8 id; if (sym != (FunctionSymbol *)0) @@ -542,66 +549,65 @@ void Funcdata::printLocalRange(ostream &s) const } } -/// This parses a \ tag and builds a JumpTable object for -/// each \ sub-tag. -/// \param el is the root \ tag -void Funcdata::restoreXmlJumpTable(const Element *el) +/// Parse a \ element and build a JumpTable object for +/// each \ child element. +/// \param decoder is the stream decoder +void Funcdata::decodeJumpTable(Decoder &decoder) { - const List &list( el->getChildren() ); - List::const_iterator iter; - for(iter=list.begin();iter!=list.end();++iter) { + uint4 elemId = decoder.openElement(ELEM_JUMPTABLELIST); + while(decoder.peekElement() != 0) { JumpTable *jt = new JumpTable(glb); - jt->restoreXml(*iter); + jt->decode(decoder); jumpvec.push_back(jt); } + decoder.closeElement(elemId); } -/// A \ tag is written with \ sub-tags describing +/// A \ element is written with \ children describing /// each jump-table associated with the control-flow of \b this function. -/// \param s is the output stream -void Funcdata::saveXmlJumpTable(ostream &s) const +/// \param encoder is the stream encoder +void Funcdata::encodeJumpTable(Encoder &encoder) const { if (jumpvec.empty()) return; vector::const_iterator iter; - s << "\n"; + encoder.openElement(ELEM_JUMPTABLELIST); for(iter=jumpvec.begin();iter!=jumpvec.end();++iter) - (*iter)->saveXml(s); - s << "\n"; + (*iter)->encode(encoder); + encoder.closeElement(ELEM_JUMPTABLELIST); } -/// \brief Save XML descriptions for a set of Varnodes to stream +/// \brief Encode descriptions for a set of Varnodes to a stream /// -/// This is an internal function for the function's save to XML system. -/// Individual XML tags are written in sequence for Varnodes in a given set. +/// This is an internal function for the function's marshaling system. +/// Individual elements are written in sequence for Varnodes in a given set. /// The set is bounded by iterators using the 'loc' ordering. -/// \param s is the output stream +/// \param encoder is the stream encoder /// \param iter is the beginning of the set /// \param enditer is the end of the set -void Funcdata::saveVarnodeXml(ostream &s,VarnodeLocSet::const_iterator iter,VarnodeLocSet::const_iterator enditer) +void Funcdata::encodeVarnode(Encoder &encoder,VarnodeLocSet::const_iterator iter,VarnodeLocSet::const_iterator enditer) { Varnode *vn; while(iter!=enditer) { vn = *iter++; - vn->saveXml(s); - s << '\n'; + vn->encode(encoder); } } -/// This produces a single \ tag, with a \ sub-tag for each +/// This produces a single \ element, with a \ child for each /// high-level variable (HighVariable) currently associated with \b this function. -/// \param s is the output stream -void Funcdata::saveXmlHigh(ostream &s) const +/// \param encoder is the stream encoder +void Funcdata::encodeHigh(Encoder &encoder) const { Varnode *vn; HighVariable *high; if (!isHighOn()) return; - s << ""; + encoder.openElement(ELEM_HIGHLIST); VarnodeLocSet::const_iterator iter; for(iter=beginLoc();iter!=endLoc();++iter) { vn = *iter; @@ -609,104 +615,98 @@ void Funcdata::saveXmlHigh(ostream &s) const high = vn->getHigh(); if (high->isMark()) continue; high->setMark(); - high->saveXml(s); + high->encode(encoder); } for(iter=beginLoc();iter!=endLoc();++iter) { vn = *iter; if (!vn->isAnnotation()) vn->getHigh()->clearMark(); } - - s << "\n"; + encoder.closeElement(ELEM_HIGHLIST); } -/// A single \ tag is produced with children describing Varnodes, PcodeOps, and +/// A single \ element is produced with children describing Varnodes, PcodeOps, and /// basic blocks making up \b this function's current syntax tree. -/// \param s is the output stream -void Funcdata::saveXmlTree(ostream &s) const +/// \param encoder is the stream encoder +void Funcdata::encodeTree(Encoder &encoder) const { - s << "\n"; - s << "\n"; + encoder.openElement(ELEM_AST); + encoder.openElement(ELEM_VARNODES); for(int4 i=0;inumSpaces();++i) { AddrSpace *base = glb->getSpace(i); if (base == (AddrSpace *)0 || base->getType()==IPTR_IOP) continue; VarnodeLocSet::const_iterator iter = vbank.beginLoc(base); VarnodeLocSet::const_iterator enditer = vbank.endLoc(base); - saveVarnodeXml(s,iter,enditer); + encodeVarnode(encoder,iter,enditer); } - s << "\n"; + encoder.closeElement(ELEM_VARNODES); list::iterator oiter,endoiter; PcodeOp *op; BlockBasic *bs; for(int4 i=0;igetIndex()); - s << ">\n"; - bs->saveXmlBody(s); + encoder.openElement(ELEM_BLOCK); + encoder.writeSignedInteger(ATTRIB_INDEX, bs->getIndex()); + bs->encodeBody(encoder); oiter = bs->beginOp(); endoiter = bs->endOp(); while(oiter != endoiter) { op = *oiter++; - op->saveXml(s); - s << '\n'; + op->encode(encoder); } - s << "\n"; + encoder.closeElement(ELEM_BLOCK); } for(int4 i=0;isizeIn() == 0) continue; - s << "getIndex()); - s << ">\n"; - bs->saveXmlEdges(s); - s << "\n"; + encoder.openElement(ELEM_BLOCKEDGE); + encoder.writeSignedInteger(ATTRIB_INDEX, bs->getIndex()); + bs->encodeEdges(encoder); + encoder.closeElement(ELEM_BLOCKEDGE); } - s << "\n"; + encoder.closeElement(ELEM_AST); } -/// An XML description of \b this function is written to the stream, +/// A description of \b this function is written to the stream, /// including name, address, prototype, symbol, jump-table, and override information. /// If indicated by the caller, a description of the entire PcodeOp and Varnode /// tree is also emitted. -/// \param s is the output stream +/// \param encoder is the stream encoder /// \param id is the unique id associated with the function symbol /// \param savetree is \b true if the p-code tree should be emitted -void Funcdata::saveXml(ostream &s,uint8 id,bool savetree) const +void Funcdata::encode(Encoder &encoder,uint8 id,bool savetree) const { - s << "\n"; - baseaddr.saveXml(s); - s << '\n'; + encoder.writeBool(ATTRIB_NOCODE, true); + baseaddr.encode(encoder); if (!hasNoCode()) { - localmap->saveXmlRecursive(s,false); // Save scope and all subscopes + localmap->encodeRecursive(encoder,false); // Save scope and all subscopes } if (savetree) { - saveXmlTree(s); - saveXmlHigh(s); + encodeTree(encoder); + encodeHigh(encoder); } - saveXmlJumpTable(s); - funcp.saveXml(s); // Must be saved after database - localoverride.saveXml(s,glb); - s << "\n"; + encodeJumpTable(encoder); + funcp.encode(encoder); // Must be saved after database + localoverride.encode(encoder,glb); + encoder.closeElement(ELEM_FUNCTION); } -/// From an XML \ tag, recover the name, address, prototype, symbol, +/// Parse a \ element, recovering the name, address, prototype, symbol, /// jump-table, and override information for \b this function. -/// \param el is the root \ tag +/// \param decoder is the stream decoder /// \return the symbol id associated with the function -uint8 Funcdata::restoreXml(const Element *el) +uint8 Funcdata::decode(Decoder &decoder) { // clear(); // Shouldn't be needed @@ -714,22 +714,20 @@ uint8 Funcdata::restoreXml(const Element *el) size = -1; uint8 id = 0; AddrSpace *stackid = glb->getStackSpace(); - for(int4 i=0;igetNumAttributes();++i) { - const string &attrName(el->getAttributeName(i)); - if (attrName == "name") - name = el->getAttributeValue(i); - else if (attrName == "size") { - istringstream s( el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> size; + uint4 elemId = decoder.openElement(ELEM_FUNCTION); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_NAME) + name = decoder.readString(); + else if (attribId == ATTRIB_SIZE) { + size = decoder.readSignedInteger(); } - else if (attrName == "id") { - istringstream s( el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> id; + else if (attribId == ATTRIB_ID) { + id = decoder.readUnsignedInteger(); } - else if (attrName == "nocode") { - if (xml_readbool(el->getAttributeValue(i))) + else if (attribId == ATTRIB_NOCODE) { + if (decoder.readBool()) flags |= no_code; } } @@ -737,27 +735,20 @@ uint8 Funcdata::restoreXml(const Element *el) throw LowlevelError("Missing function name"); if (size == -1) throw LowlevelError("Missing function size"); - const List &list( el->getChildren() ); - List::const_iterator iter = list.begin(); - baseaddr = Address::restoreXml( *iter, glb ); - ++iter; - for(;iter!=list.end();++iter) { - if ((*iter)->getName() == "localdb") { + baseaddr = Address::decode( decoder, glb ); + for(;;) { + uint4 subId = decoder.peekElement(); + if (subId == 0) break; + if (subId == ELEM_LOCALDB) { if (localmap != (ScopeLocal *)0) throw LowlevelError("Pre-existing local scope when restoring: "+name); ScopeLocal *newMap = new ScopeLocal(id,stackid,this,glb); - glb->symboltab->restoreXmlScope(*iter,newMap); // May delete newMap and throw + glb->symboltab->decodeScope(decoder,newMap); // May delete newMap and throw localmap = newMap; } - // else if ((*iter)->getName() == "scope") { - // const Element *scopeel = *iter; - // ScopeInternal *subscope = new ScopeInternal("",glb); - // subscope->restrictScope(this); - // glb->symboltab->restore_nonglobal_xml(scopeel,subscope); - // } - else if ((*iter)->getName() == "override") - localoverride.restoreXml(*iter,glb); - else if ((*iter)->getName() == "prototype") { + else if (subId == ELEM_OVERRIDE) + localoverride.decode(decoder,glb); + else if (subId == ELEM_PROTOTYPE) { if (localmap == (ScopeLocal *)0) { // If we haven't seen a tag yet, assume we have a default local scope ScopeLocal *newMap = new ScopeLocal(id,stackid,this,glb); @@ -766,11 +757,12 @@ uint8 Funcdata::restoreXml(const Element *el) localmap = newMap; } funcp.setScope(localmap,baseaddr+ -1); // localmap built earlier - funcp.restoreXml(*iter,glb); + funcp.decode(decoder,glb); } - else if ((*iter)->getName() == "jumptablelist") - restoreXmlJumpTable(*iter); + else if (subId == ELEM_JUMPTABLELIST) + decodeJumpTable(decoder); } + decoder.closeElement(elemId); if (localmap == (ScopeLocal *)0) { // Seen neither or // This is a function shell, so we provide default locals ScopeLocal *newMap = new ScopeLocal(id,stackid,this,glb); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh index f7945d2f93..612f93eafe 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh @@ -28,6 +28,14 @@ class FlowInfo; +extern AttributeId ATTRIB_NOCODE; ///< Marshaling attribute "nocode" + +extern ElementId ELEM_AST; ///< Marshaling element \ +extern ElementId ELEM_FUNCTION; ///< Marshaling element \ +extern ElementId ELEM_HIGHLIST; ///< Marshaling element \ +extern ElementId ELEM_JUMPTABLELIST; ///< Marshaling element \ +extern ElementId ELEM_VARNODES; ///< Marshaling element \ + /// \brief Container for data structures associated with a single function /// /// This class holds the primary data structures for decompiling a function. In particular it holds @@ -120,7 +128,7 @@ class Funcdata { void nodeSplitRawDuplicate(BlockBasic *b,BlockBasic *bprime); void nodeSplitInputPatch(BlockBasic *b,BlockBasic *bprime,int4 inedge); static bool descendantsOutside(Varnode *vn); - static void saveVarnodeXml(ostream &s,VarnodeLocSet::const_iterator iter,VarnodeLocSet::const_iterator enditer); + static void encodeVarnode(Encoder &encoder,VarnodeLocSet::const_iterator iter,VarnodeLocSet::const_iterator enditer); static bool checkIndirectUse(Varnode *vn); static PcodeOp *findPrimaryBranch(PcodeOpTree::const_iterator iter,PcodeOpTree::const_iterator enditer, bool findbranch,bool findcall,bool findreturn); @@ -177,12 +185,12 @@ public: void printVarnodeTree(ostream &s) const; ///< Print a description of all Varnodes to a stream void printBlockTree(ostream &s) const; ///< Print a description of control-flow structuring to a stream void printLocalRange(ostream &s) const; ///< Print description of memory ranges associated with local scopes - void saveXml(ostream &s,uint8 id,bool savetree) const; ///< Emit an XML description of \b this function to stream - uint8 restoreXml(const Element *el); ///< Restore the state of \b this function from an XML description - void saveXmlJumpTable(ostream &s) const; ///< Emit an XML description of jump-tables to stream - void restoreXmlJumpTable(const Element *el); ///< Restore jump-tables from an XML description - void saveXmlTree(ostream &s) const; ///< Save an XML description of the p-code tree to stream - void saveXmlHigh(ostream &s) const; ///< Save an XML description of all HighVariables to stream + void encode(Encoder &encoder,uint8 id,bool savetree) const; ///< Encode a description of \b this function to stream + uint8 decode(Decoder &decoder); ///< Restore the state of \b this function from an XML description + void encodeJumpTable(Encoder &encoder) const; ///< Encode a description of jump-tables to stream + void decodeJumpTable(Decoder &decoder); ///< Decode jump-tables from a stream + void encodeTree(Encoder &encoder) const; ///< Encode a description of the p-code tree to stream + void encodeHigh(Encoder &encoder) const; ///< Encode a description of all HighVariables to stream Override &getOverride(void) { return localoverride; } ///< Get the Override object for \b this function diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc index b72a8093db..9353ae8f45 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc @@ -139,22 +139,23 @@ void ArchitectureGhidra::readStringStream(istream &s,string &res) } /// The method expects to see protocol markers indicating a string from the client, -/// otherwise it throws and exception. The string is read in and then parsed as XML. +/// otherwise it throws and exception. The string is read into the given stream decoder. /// \param s is the input stream from the client. -/// \return the XML document -Document *ArchitectureGhidra::readXMLStream(istream &s) +/// \param decoder is the given stream decoder that will hold the result +/// \return \b true if a response was received +bool ArchitectureGhidra::readStream(istream &s,Decoder &decoder) { int4 type = readToAnyBurst(s); if (type==14) { - Document *doc = xml_tree(s); + decoder.ingestStream(s); type = readToAnyBurst(s); if (type!=15) throw JavaError("alignment","Expecting XML string end"); - return doc; + return true; } if ((type&1)==1) - return (Document *)0; + return false; throw JavaError("alignment","Expecting string or end of query response"); } @@ -231,17 +232,19 @@ void ArchitectureGhidra::readResponseEnd(istream &s) } /// Read up to the beginning of a query response, check for an -/// exception record, otherwise read in a string as an XML document. +/// exception record, otherwise pass back an element for decoding. /// \param s is the input stream from the client -/// \return the XML document -Document *ArchitectureGhidra::readXMLAll(istream &s) +/// \param decoder is the stream decoder that will hold the result +/// \return \b true if we received a valid response +bool ArchitectureGhidra::readAll(istream &s,Decoder &decoder) { readToResponse(s); - Document *doc = readXMLStream(s); - if (doc != (Document *)0) + if (readStream(s,decoder)) { readResponseEnd(s); - return doc; + return true; + } + return false; } /// Read up to the beginning of a query response, check for an @@ -339,8 +342,10 @@ void ArchitectureGhidra::buildTypegrp(DocumentStorage &store) { const Element *el = store.getTag("coretypes"); types = new TypeFactoryGhidra(this); - if (el != (const Element *)0) - types->restoreXmlCoreTypes(el); + if (el != (const Element *)0) { + XmlDecode decoder(el); + types->decodeCoreTypes(decoder); + } else { // Put in the core types types->setCoreType("void",1,TYPE_VOID,false); @@ -398,11 +403,12 @@ void ArchitectureGhidra::resolveArchitecture(void) } /// Ask the Ghidra client if it knows about a specific processor register. -/// The client responds with a \ XML element describing the storage +/// The client responds with a \ element describing the storage /// location of the register. /// \param regname is the name to query for -/// \return the storage address as XML or NULL if the register is unknown -Document *ArchitectureGhidra::getRegister(const string ®name) +/// \param decoder is the stream decoder that will hold the result +/// \return \b true if the query completed successfully +bool ArchitectureGhidra::getRegister(const string ®name,Decoder &decoder) { sout.write("\000\000\001\004",4); @@ -411,7 +417,7 @@ Document *ArchitectureGhidra::getRegister(const string ®name) sout.write("\000\000\001\005",4); sout.flush(); - return readXMLAll(sin); + return readAll(sin,decoder); } /// Given a storage location and size, ask the Ghidra client if it knows of @@ -426,7 +432,8 @@ string ArchitectureGhidra::getRegisterName(const VarnodeData &vndata) writeStringStream(sout,"getRegisterName"); sout.write("\000\000\001\016",4); // Beginning of string header Address addr(vndata.space,vndata.offset); - addr.saveXml(sout,vndata.size); + encoder.clear(); + addr.encode(encoder,vndata.size); sout.write("\000\000\001\017",4); sout.write("\000\000\001\005",4); sout.flush(); @@ -438,24 +445,26 @@ string ArchitectureGhidra::getRegisterName(const VarnodeData &vndata) return res; } -/// The Ghidra client will return a description of registers that have +/// The Ghidra client will pass back a description of registers that have /// known values at the given address. The response is generally a /// \ which contains \ children which contains /// a storage location and value. /// \param addr is the given address -/// \return the response Document -Document *ArchitectureGhidra::getTrackedRegisters(const Address &addr) +/// \param decoder is the stream decoder which will hold the result +/// \return \b true if the query completed successfully +bool ArchitectureGhidra::getTrackedRegisters(const Address &addr,Decoder &decoder) { sout.write("\000\000\001\004",4); writeStringStream(sout,"getTrackedRegisters"); sout.write("\000\000\001\016",4); // Beginning of string header - addr.saveXml(sout); + encoder.clear(); + addr.encode(encoder); sout.write("\000\000\001\017",4); sout.write("\000\000\001\005",4); sout.flush(); - return readXMLAll(sin); + return readAll(sin,decoder); } /// The first operand to a CALLOTHER op indicates the specific user-defined op. @@ -491,7 +500,8 @@ uint1 *ArchitectureGhidra::getPcodePacked(const Address &addr) sout.write("\000\000\001\004",4); writeStringStream(sout,"getPacked"); sout.write("\000\000\001\016",4); // Beginning of string header - addr.saveXml(sout); + encoder.clear(); + addr.encode(encoder); sout.write("\000\000\001\017",4); sout.write("\000\000\001\005",4); sout.flush(); @@ -499,54 +509,59 @@ uint1 *ArchitectureGhidra::getPcodePacked(const Address &addr) return readPackedAll(sin); } -/// The Ghidra client will return a \ tag, \ tag, or some -/// other related Symbol information. If there no symbol at the address -/// the client should return a \ tag describing the size of the +/// The Ghidra client will pass back a \ element, \ element, or some +/// other related Symbol information, in the given stream decoder. If there is no symbol at the address +/// the client will return a \ element describing the size of the /// memory region that is free of symbols. /// \param addr is the given address -/// \return the symbol document -Document *ArchitectureGhidra::getMappedSymbolsXML(const Address &addr) +/// \param decoder is the given stream decoder that will hold the result +/// \return \b true if the query completes successfully +bool ArchitectureGhidra::getMappedSymbolsXML(const Address &addr,Decoder &decoder) { sout.write("\000\000\001\004",4); writeStringStream(sout,"getMappedSymbolsXML"); - sout.write("\000\000\001\016",4); // Beginning of string header - addr.saveXml(sout); + sout.write("\000\000\001\016",4); // Beginning of string + encoder.clear(); + addr.encode(encoder); sout.write("\000\000\001\017",4); sout.write("\000\000\001\005",4); sout.flush(); - return readXMLAll(sin); + return readAll(sin,decoder); } /// This asks the Ghidra client to resolve an \e external \e reference. /// This is an address for which the client holds a reference to a function /// that is elsewhere in memory or not in memory at all. The client -/// should unravel the reference from the given address and return either -/// a \ tag describing the referred to function symbol or -/// a \ tag if the reference can't be resolved +/// should unravel the reference from the given address and pass back either +/// a \ element describing the referred to function symbol or +/// a \ element if the reference can't be resolved. /// \param addr is the given address -/// \return a description of the referred to function -Document *ArchitectureGhidra::getExternalRefXML(const Address &addr) +/// \param decoder is the stream decoder that will hold the result +/// \return \b true if the query completes successfully +bool ArchitectureGhidra::getExternalRefXML(const Address &addr,Decoder &decoder) { sout.write("\000\000\001\004",4); writeStringStream(sout,"getExternalRefXML"); sout.write("\000\000\001\016",4); // Beginning of string header - addr.saveXml(sout); + encoder.clear(); + addr.encode(encoder); sout.write("\000\000\001\017",4); sout.write("\000\000\001\005",4); sout.flush(); - return readXMLAll(sin); + return readAll(sin,decoder); } /// Ask the Ghidra client to list all namespace elements between the global root -/// and the namespace of the given id. The client should return a \ tag with -/// a \ child for each namespace in the path. +/// and the namespace of the given id. The client will pass back a \ element with +/// a \ child for each namespace in the path, in the given stream decoder /// \param id is the given id of the namespace to resolve -/// \return the XML document -Document *ArchitectureGhidra::getNamespacePath(uint8 id) +/// \param decoder is the given stream decoder that will hold the result +/// \return \b true if the query completed successfully +bool ArchitectureGhidra::getNamespacePath(uint8 id,Decoder &decoder) { sout.write("\000\000\001\004",4); @@ -557,7 +572,7 @@ Document *ArchitectureGhidra::getNamespacePath(uint8 id) sout.write("\000\000\001\005",4); sout.flush(); - return readXMLAll(sin); + return readAll(sin,decoder); } bool ArchitectureGhidra::isNameUsed(const string &nm,uint8 startId,uint8 stopId) @@ -593,7 +608,8 @@ string ArchitectureGhidra::getCodeLabel(const Address &addr) sout.write("\000\000\001\004",4); writeStringStream(sout,"getSymbol"); sout.write("\000\000\001\016",4); // Beginning of string header - addr.saveXml(sout); + encoder.clear(); + addr.encode(encoder); sout.write("\000\000\001\017",4); sout.write("\000\000\001\005",4); sout.flush(); @@ -605,12 +621,13 @@ string ArchitectureGhidra::getCodeLabel(const Address &addr) return res; } -/// The Ghidra client should respond with a \ tag giving details +/// The Ghidra client will pass back a \ element giving details /// about the data-type. /// \param name is the name of the data-type /// \param id is a unique id associated with the data-type, pass 0 if unknown -/// \return the data-type XML element or NULL -Document *ArchitectureGhidra::getType(const string &name,uint8 id) +/// \param decoder is the stream decoder that will hold the result +/// \return \b true if the query completed successfully +bool ArchitectureGhidra::getType(const string &name,uint8 id,Decoder &decoder) { sout.write("\000\000\001\004",4); @@ -622,23 +639,25 @@ Document *ArchitectureGhidra::getType(const string &name,uint8 id) sout.write("\000\000\001\005",4); sout.flush(); - return readXMLAll(sin); + return readAll(sin,decoder); } /// Ask Ghidra client for all comments associated with one function. /// The caller must provide the sub-set of properties (Comment::comment_type) for -/// the query to match. The client will return a \ tag with -/// a \ tag child for each comment found. +/// the query to match. A \ element with \ element child for each comment found +/// will be passed back in the given stream decoder. /// \param fad is the address of the function to query /// \param flags specifies the properties the query will match (must be non-zero) -/// \return an XML document describing each comment -Document *ArchitectureGhidra::getComments(const Address &fad,uint4 flags) +/// \param decoder is the given stream decoder that will hold the result +/// \return \b true if the query completed successfully +bool ArchitectureGhidra::getComments(const Address &fad,uint4 flags,Decoder &decoder) { sout.write("\000\000\001\004",4); writeStringStream(sout,"getComments"); sout.write("\000\000\001\016",4); // Beginning of string header - fad.saveXml(sout); + encoder.clear(); + fad.encode(encoder); sout.write("\000\000\001\017",4); sout.write("\000\000\001\016",4); // Beginning of string header sout << dec << flags; @@ -646,7 +665,7 @@ Document *ArchitectureGhidra::getComments(const Address &fad,uint4 flags) sout.write("\000\000\001\005",4); sout.flush(); - return readXMLAll(sin); + return readAll(sin,decoder); } /// The Ghidra client is queried for a range of bytes, which are returned @@ -661,7 +680,8 @@ void ArchitectureGhidra::getBytes(uint1 *buf,int4 size,const Address &inaddr) sout.write("\000\000\001\004",4); writeStringStream(sout,"getBytes"); sout.write("\000\000\001\016",4); // Beginning of string header - inaddr.saveXml(sout,size); + encoder.clear(); + inaddr.encode(encoder,size); sout.write("\000\000\001\017",4); sout.write("\000\000\001\005",4); sout.flush(); @@ -708,7 +728,8 @@ void ArchitectureGhidra::getStringData(vector &buffer,const Address &addr sout.write("\000\000\001\004",4); writeStringStream(sout,"getString"); sout.write("\000\000\001\016",4); // Beginning of string header - addr.saveXml(sout,maxBytes); + encoder.clear(); + addr.encode(encoder,maxBytes); sout.write("\000\000\001\017",4); writeStringStream(sout,ct->getName()); sout.write("\000\000\001\016",4); // Beginning of string header @@ -753,14 +774,14 @@ void ArchitectureGhidra::getStringData(vector &buffer,const Address &addr /// - CALLMECHANISM_TYPE /// - EXECUTABLEPCODE_TYPE /// -/// This and additional context is provided to the Ghidra client which returns -/// an XML document describing the p-code. The document will be an \ tag -/// containing individual \ tags corresponding to individual p-code ops. +/// This and additional context is provided to the Ghidra client which passes back +/// an \ element containing individual \ tags corresponding to individual p-code ops. /// \param name is the name of the injection /// \param type is the type of injection /// \param con is the context object -/// \return an XML document describing the p-code ops to inject -Document *ArchitectureGhidra::getPcodeInject(const string &name,int4 type,const InjectContext &con) +/// \param decoder is the stream decoder which will hold the result +/// \return \b true if the query completed successfully +bool ArchitectureGhidra::getPcodeInject(const string &name,int4 type,const InjectContext &con,Decoder &decoder) { sout.write("\000\000\001\004",4); @@ -774,21 +795,22 @@ Document *ArchitectureGhidra::getPcodeInject(const string &name,int4 type,const writeStringStream(sout,"getXPcode"); writeStringStream(sout,name); sout.write("\000\000\001\016",4); - con.saveXml(sout); + encoder.clear(); + con.encode(encoder); sout.write("\000\000\001\017",4); sout.write("\000\000\001\005",4); sout.flush(); - return readXMLAll(sin); + return readAll(sin,decoder); } /// The Ghidra client is provided a sequence of 1 or more integer values -/// extracted from a CPOOLREF op. It returns an XML document describing -/// the constant pool record referenced by the integer(s) or will throw -/// an exception if record isn't properly referenced. +/// extracted from a CPOOLREF op. A description of the constant pool record referenced by the integer(s) +/// is passed back in the given stream decoder, or an exception is thrown if the record isn't properly referenced. /// \param refs is an array of 1 or more integer values referencing a constant pool record -/// \return a description of the record as a \ XML document. -Document *ArchitectureGhidra::getCPoolRef(const vector &refs) +/// \param decoder is the given stream decoder that will hold the result +/// \return \b true if the query completed successfully +bool ArchitectureGhidra::getCPoolRef(const vector &refs,Decoder &decoder) { sout.write("\000\000\001\004",4); @@ -802,7 +824,7 @@ Document *ArchitectureGhidra::getCPoolRef(const vector &refs) sout.write("\000\000\001\005",4); sout.flush(); - return readXMLAll(sin); + return readAll(sin,decoder); } // Document *ArchitectureGhidra::getScopeProperties(Scope *newscope) @@ -839,7 +861,7 @@ void ArchitectureGhidra::printMessage(const string &message) const /// \param o is the output stream to the Ghidra client ArchitectureGhidra::ArchitectureGhidra(const string &pspec,const string &cspec,const string &tspec, const string &corespec,istream &i,ostream &o) - : Architecture(), sin(i), sout(o) + : Architecture(), sin(i), sout(o), encoder(sout) { print->setXML(true); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.hh index 0953288662..d557707a1a 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.hh @@ -60,6 +60,7 @@ struct JavaError : public LowlevelError { class ArchitectureGhidra : public Architecture { istream &sin; ///< Input stream for interfacing with Ghidra ostream &sout; ///< Output stream for interfacing with Ghidra + XmlEncode encoder; ///< Encoder used to write to Ghidra mutable string warnings; ///< Warnings accumulated by the decompiler string pspecxml; ///< XML pspec passed from Ghidra string cspecxml; ///< XML cspec passed from Ghidra @@ -86,21 +87,21 @@ public: istream &i,ostream &o); const string &getWarnings(void) const { return warnings; } ///< Get warnings produced by the last decompilation void clearWarnings(void) { warnings.clear(); } ///< Clear warnings - Document *getRegister(const string ®name); ///< Retrieve a register description given a name + bool getRegister(const string ®name,Decoder &decoder); ///< Retrieve a register description given a name string getRegisterName(const VarnodeData &vndata); ///< Retrieve a register name given its storage location - Document *getTrackedRegisters(const Address &addr); ///< Retrieve \e tracked register values at the given address + bool getTrackedRegisters(const Address &addr,Decoder &decoder); ///< Retrieve \e tracked register values at the given address string getUserOpName(int4 index); ///< Get the name of a user-defined p-code op uint1 *getPcodePacked(const Address &addr); ///< Get p-code for a single instruction - Document *getMappedSymbolsXML(const Address &addr); ///< Get symbols associated with the given address - Document *getExternalRefXML(const Address &addr); ///< Retrieve a description of an external function - Document *getNamespacePath(uint8 id); ///< Get a description of a namespace path + bool getMappedSymbolsXML(const Address &addr,Decoder &decoder); ///< Get symbols associated with the given address + bool getExternalRefXML(const Address &addr,Decoder &decoder); ///< Retrieve a description of an external function + bool getNamespacePath(uint8 id,Decoder &decoder); ///< Get a description of a namespace path bool isNameUsed(const string &nm,uint8 startId,uint8 stopId); ///< Is given name used along namespace path string getCodeLabel(const Address &addr); ///< Retrieve a label at the given address - Document *getType(const string &name,uint8 id); ///< Retrieve a data-type description for the given name and id - Document *getComments(const Address &fad,uint4 flags); ///< Retrieve comments for a particular function + bool getType(const string &name,uint8 id,Decoder &decoder); ///< Retrieve a data-type description for the given name and id + bool getComments(const Address &fad,uint4 flags,Decoder &decoder); ///< Retrieve comments for a particular function void getBytes(uint1 *buf,int4 size,const Address &inaddr); ///< Retrieve bytes in the LoadImage at the given address - Document *getPcodeInject(const string &name,int4 type,const InjectContext &con); - Document *getCPoolRef(const vector &refs); ///< Resolve a constant pool reference + bool getPcodeInject(const string &name,int4 type,const InjectContext &con,Decoder &decoder); + bool getCPoolRef(const vector &refs,Decoder &decoder); ///< Resolve a constant pool reference // Document *getScopeProperties(Scope *newscope); /// \brief Toggle whether the data-flow and control-flow is emitted as part of the main decompile action @@ -138,8 +139,8 @@ public: static void writeStringStream(ostream &s,const string &msg); ///< Send a string to the client static void readToResponse(istream &s); ///< Read the query response protocol marker static void readResponseEnd(istream &s); ///< Read the ending query response protocol marker - static Document *readXMLAll(istream &s); ///< Read a whole response as an XML document - static Document *readXMLStream(istream &s); ///< Receive an XML document from the client + static bool readAll(istream &s,Decoder &decoder); ///< Read a whole response as an XML document + static bool readStream(istream &s,Decoder &decoder); ///< Receive an XML document from the client static uint1 *readPackedStream(istream &s); ///< Read packed p-code op information static uint1 *readPackedAll(istream &s); ///< Read a whole response as packed p-code op information static void passJavaException(ostream &s,const string &tp,const string &msg); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_context.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_context.cc index 596afd6405..57704c8107 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_context.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_context.cc @@ -19,11 +19,24 @@ const TrackedSet &ContextGhidra::getTrackedSet(const Address &addr) const { cache.clear(); + XmlDecode decoder; + ((ArchitectureGhidra *)glb)->getTrackedRegisters(addr,decoder); - Document *doc = ((ArchitectureGhidra *)glb)->getTrackedRegisters(addr); - Element *root = doc->getRoot(); - - restoreTracked(root,glb,cache); - delete doc; + uint4 elemId = decoder.openElement(ELEM_TRACKED_POINTSET); + decodeTracked(decoder,glb,cache); + decoder.closeElement(elemId); return cache; } + +void ContextGhidra::decode(Decoder &decoder,const AddrSpaceManager *manage) + +{ + decoder.skipElement(); // Ignore details handled by ghidra +} + +void ContextGhidra::decodeFromSpec(Decoder &decoder,const AddrSpaceManager *manage) + +{ + decoder.skipElement(); // Ignore details handled by ghidra +} + diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_context.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_context.hh index 63fea30044..6c4d45126a 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_context.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_context.hh @@ -51,8 +51,8 @@ public: virtual const TrackedSet &getTrackedSet(const Address &addr) const; // Ignored routines (taken care of by GHIDRA) - virtual void restoreXml(const Element *el,const AddrSpaceManager *manage) {} - virtual void restoreFromSpec(const Element *el,const AddrSpaceManager *manage) {} + virtual void decode(Decoder &decoder,const AddrSpaceManager *manage); + virtual void decodeFromSpec(Decoder &decoder,const AddrSpaceManager *manage); // Unimplemented routines (should never be called) virtual int getContextSize(void) const { @@ -63,8 +63,8 @@ public: throw LowlevelError("getContext should not be called for GHIDRA"); } virtual void registerVariable(const string &nm,int4 sbit,int4 ebit) { throw LowlevelError("registerVariable should not be called for GHIDRA"); } - virtual void saveXml(ostream &s) const { - throw LowlevelError("context::saveXml should not be called for GHIDRA"); } + virtual void encode(Encoder &encoder) const { + throw LowlevelError("context::encode should not be called for GHIDRA"); } virtual TrackedSet &createSet(const Address &addr1,const Address &addr2) { throw LowlevelError("createSet should not be called for GHIDRA"); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.cc index 272e4c1566..4290fdd452 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.cc @@ -274,12 +274,9 @@ void DecompileAt::loadParameters(void) { GhidraCommand::loadParameters(); - Document *doc; - doc = ArchitectureGhidra::readXMLStream(sin); // Read XML of address directly from in stream - addr = Address::restoreXml(doc->getRoot(),ghidra); // Parse XML for functions address - addr.toPhysical(); // Only for backward compatibility - // with SLED - delete doc; + XmlDecode decoder; + ArchitectureGhidra::readStream(sin,decoder); // Read encoded address directly from in stream + addr = Address::decode(decoder,ghidra); // Decode for functions address } void DecompileAt::rawAction(void) @@ -305,25 +302,18 @@ void DecompileAt::rawAction(void) sout.write("\000\000\001\016",4); // Write output XML directly to outstream if (fd->isProcComplete()) { - //bool v1 = ghidra->getSendParamMeasures(); - //sout << "value: " << ghidra->getSendParamMeasures() << "\n"; - //bool v2 = (ghidra->allacts.getCurrentName() == "paramid"); - //sout << "value: " << (ghidra->allacts.getCurrentName() == "paramid") << "\n"; - //bool v3 = v1 && v2; - sout << "\n"; - //sout << (v1?"1":"0") << "(" << (int4)v1 << ")\n" << (v2?"1":"0") << "\n" << (v3?"1":"0") << "\n"; - + XmlEncode encoder(sout); if (ghidra->getSendParamMeasures() && (ghidra->allacts.getCurrentName() == "paramid")) { ParamIDAnalysis pidanalysis( fd, true ); // Only send back final prototype - pidanalysis.saveXml( sout, true ); + pidanalysis.encode( encoder, true ); } else { if (ghidra->getSendParamMeasures()) { ParamIDAnalysis pidanalysis( fd, false ); - pidanalysis.saveXml( sout, true ); + pidanalysis.encode( encoder, true ); } - fd->saveXml(sout,0,ghidra->getSendSyntaxTree()); + fd->encode(encoder,0,ghidra->getSendSyntaxTree()); if (ghidra->getSendCCode()&& (ghidra->allacts.getCurrentName() == "decompile")) ghidra->print->docFunction(fd); @@ -337,10 +327,10 @@ void StructureGraph::loadParameters(void) { GhidraCommand::loadParameters(); - Document *doc; - doc = ArchitectureGhidra::readXMLStream(sin); - ingraph.restoreXml(doc->getRoot(),ghidra); - delete doc; + + XmlDecode decoder; + ArchitectureGhidra::readStream(sin,decoder); + ingraph.decode(decoder,ghidra); } void StructureGraph::rawAction(void) @@ -358,7 +348,8 @@ void StructureGraph::rawAction(void) resultgraph.orderBlocks(); sout.write("\000\000\001\016",4); - resultgraph.saveXml(sout); + XmlEncode encoder(sout); + resultgraph.encode(encoder); sout.write("\000\000\001\017",4); ingraph.clear(); } @@ -413,28 +404,12 @@ void SetAction::sendResult(void) GhidraCommand::sendResult(); } -SetOptions::SetOptions(void) : GhidraCommand() - -{ - doc = (Document *)0; -} - -SetOptions::~SetOptions(void) - -{ - if (doc != (Document *)0) - delete doc; -} - void SetOptions::loadParameters(void) { GhidraCommand::loadParameters(); - if (doc != (Document *)0) { - delete doc; - doc = (Document *)0; - } - doc = ArchitectureGhidra::readXMLStream(sin); + decoder.clear(); + ArchitectureGhidra::readStream(sin,decoder); } void SetOptions::rawAction(void) @@ -443,9 +418,8 @@ void SetOptions::rawAction(void) res = false; ghidra->resetDefaults(); - ghidra->options->restoreXml(doc->getRoot()); - delete doc; - doc = (Document *)0; + ghidra->options->decode(decoder); + decoder.clear(); res = true; } @@ -514,6 +488,8 @@ int main(int argc,char **argv) { signal(SIGSEGV, &ArchitectureGhidra::segvHandler); // Exit on SEGV errors + AttributeId::initialize(); + ElementId::initialize(); CapabilityPoint::initializeAll(); int4 status = 0; while(status == 0) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.hh index 9cb928c917..6a813b926b 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_process.hh @@ -220,12 +220,10 @@ public: /// The command returns a single character message, 't' or 'f', indicating whether the /// configuration succeeded. class SetOptions : public GhidraCommand { - Document *doc; ///< The XML option document + XmlDecode decoder; ///< The XML option document virtual void loadParameters(void); virtual void sendResult(void); public: - SetOptions(void); - virtual ~SetOptions(void); bool res; ///< Set to \b true if the option change succeeded virtual void rawAction(void); }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_translate.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_translate.cc index c9041db3f9..c2e4b96b4c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_translate.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_translate.cc @@ -36,7 +36,8 @@ void GhidraTranslate::initialize(DocumentStorage &store) const Element *el = store.getTag("sleigh"); if (el == (const Element *)0) throw LowlevelError("Could not find ghidra sleigh tag"); - restoreXml(el); + XmlDecode decoder(el); + decode(decoder); } const VarnodeData &GhidraTranslate::getRegister(const string &nm) const @@ -45,9 +46,10 @@ const VarnodeData &GhidraTranslate::getRegister(const string &nm) const map::const_iterator iter = nm2addr.find(nm); if (iter != nm2addr.end()) return (*iter).second; - Document *doc; + XmlDecode decoder; try { - doc = glb->getRegister(nm); // Ask Ghidra client about the register + if (!glb->getRegister(nm,decoder)) // Ask Ghidra client about the register + throw LowlevelError("No register named "+nm); } catch(XmlError &err) { ostringstream errmsg; @@ -55,16 +57,13 @@ const VarnodeData &GhidraTranslate::getRegister(const string &nm) const errmsg << " -- " << err.explain; throw LowlevelError(errmsg.str()); } - if (doc == (Document *)0) - throw LowlevelError("No register named "+nm); Address regaddr; int4 regsize; - regaddr = Address::restoreXml( doc->getRoot(), this, regsize); + regaddr = Address::decode( decoder, this, regsize); VarnodeData vndata; vndata.space = regaddr.getSpace(); vndata.offset = regaddr.getOffset(); vndata.size = regsize; - delete doc; return cacheRegister(nm,vndata); } @@ -142,33 +141,23 @@ int4 GhidraTranslate::oneInstruction(PcodeEmit &emit,const Address &baseaddr) co return offset; } -/// The Ghidra client passes descriptions of address spaces and other -/// information that needs to be cached by the decompiler -/// \param el is the element of the initialization tag -void GhidraTranslate::restoreXml(const Element *el) +/// Parse the \ element passed back by the Ghidra client, describing address spaces +/// and other information that needs to be cached by the decompiler. +/// \param decoder is the stream decoder +void GhidraTranslate::decode(Decoder &decoder) { - setBigEndian(xml_readbool(el->getAttributeValue("bigendian"))); - { - istringstream s(el->getAttributeValue("uniqbase")); - s.unsetf(ios::dec | ios::hex | ios::oct); - uintm ubase; - s >> ubase; - setUniqueBase(ubase); - } - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - restoreXmlSpaces(*iter,this); - ++iter; - while(iter != list.end()) { - const Element *subel = *iter; - if (subel->getName() == "truncate_space") { - TruncationTag tag; - tag.restoreXml(subel); - truncateSpace(tag); - } - ++iter; + uint4 elemId = decoder.openElement(ELEM_SLEIGH); + setBigEndian(decoder.readBool(ATTRIB_BIGENDIAN)); + setUniqueBase(decoder.readUnsignedInteger(ATTRIB_UNIQBASE)); + decodeSpaces(decoder,this); + for(;;) { + uint4 subId = decoder.peekElement(); + if (subId != ELEM_TRUNCATE_SPACE) break; + TruncationTag tag; + tag.decode(decoder); + truncateSpace(tag); } + decoder.closeElement(elemId); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_translate.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_translate.hh index 85a51a28ea..207f2f375f 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_translate.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_translate.hh @@ -36,7 +36,7 @@ class GhidraTranslate : public Translate { mutable map nm2addr; ///< Mapping from register name to Varnode mutable map addr2nm; ///< Mapping rom Varnode to register name const VarnodeData &cacheRegister(const string &nm,const VarnodeData &data) const; - void restoreXml(const Element *el); ///< Initialize \b this Translate from XML + void decode(Decoder &decoder); ///< Initialize \b this Translate from a stream public: GhidraTranslate(ArchitectureGhidra *g) { glb = g; } ///< Constructor diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/globalcontext.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/globalcontext.cc index 970eed9c33..67e694d344 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/globalcontext.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/globalcontext.cc @@ -15,6 +15,14 @@ */ #include "globalcontext.hh" +ElementId ELEM_CONTEXT_DATA = ElementId("context_data",94); +ElementId ELEM_CONTEXT_POINTS = ElementId("context_points",95); +ElementId ELEM_CONTEXT_POINTSET = ElementId("context_pointset",96); +ElementId ELEM_CONTEXT_SET = ElementId("context_set",97); +ElementId ELEM_SET = ElementId("set",98); +ElementId ELEM_TRACKED_POINTSET = ElementId("tracked_pointset",99); +ElementId ELEM_TRACKED_SET = ElementId("tracked_set",100); + /// Bits within the whole context blob are labeled starting with 0 as the most significant bit /// in the first word in the sequence. The new context value must be contained within a single /// word. @@ -30,76 +38,64 @@ ContextBitRange::ContextBitRange(int4 sbit,int4 ebit) mask = (~((uintm)0))>>(startbit+shift); } -/// The register storage and value are serialized as a \ tag. -/// \param s is the output stream -void TrackedContext::saveXml(ostream &s) const +/// The register storage and value are encoded as a \ element. +/// \param encoder is the stream encoder +void TrackedContext::encode(Encoder &encoder) const { - s << "saveXmlAttributes(s,loc.offset,loc.size); - a_v_u(s,"val",val); - s << "/>\n"; + encoder.openElement(ELEM_SET); + loc.space->encodeAttributes(encoder,loc.offset,loc.size); + encoder.writeUnsignedInteger(ATTRIB_VAL, val); + encoder.closeElement(ELEM_SET); } -/// Read a \ tag to fill in the storage and value details -/// \param el is the root \ tag +/// Parse a \ element to fill in the storage and value details. +/// \param decoder is the stream decoder /// \param manage is the manager used to decode address references -void TrackedContext::restoreXml(const Element *el,const AddrSpaceManager *manage) +void TrackedContext::decode(Decoder &decoder,const AddrSpaceManager *manage) { - int4 size; - Address addr = Address::restoreXml(el,manage,size); - - istringstream s(el->getAttributeValue("val")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> val; + uint4 elemId = decoder.openElement(ELEM_SET); + loc.decodeFromAttributes(decoder, manage); - loc.space = addr.getSpace(); - loc.offset = addr.getOffset(); - loc.size = size; + val = decoder.readUnsignedInteger(ATTRIB_VAL); + decoder.closeElement(elemId); } -/// \brief Save all tracked register values for a specific address to an XML stream +/// \brief Encode all tracked register values for a specific address to a stream /// /// Encode all the tracked register values associated with a specific target address /// as a \ tag. -/// \param s is the output stream +/// \param encoder is the stream encoder /// \param addr is the specific address we have tracked values for /// \param vec is the list of tracked values -void ContextDatabase::saveTracked(ostream &s,const Address &addr, - const TrackedSet &vec) +void ContextDatabase::encodeTracked(Encoder &encoder,const Address &addr,const TrackedSet &vec) + { if (vec.empty()) return; - s << "saveXmlAttributes(s,addr.getOffset() ); - s << ">\n"; + encoder.openElement(ELEM_TRACKED_POINTSET); + addr.getSpace()->encodeAttributes(encoder,addr.getOffset() ); for(int4 i=0;i\n"; + encoder.closeElement(ELEM_TRACKED_POINTSET); } -/// \brief Restore a sequence of tracked register values from an XML stream +/// \brief Restore a sequence of tracked register values from the given stream decoder /// -/// Given a root \ tag, decode each child in turn populating a list of +/// Parse a \ element, decoding each child in turn to populate a list of /// TrackedContext objects. -/// \param el is the root tag +/// \param decoder is the given stream decoder /// \param manage is used to resolve address space references /// \param vec is the container that will hold the new TrackedContext objects -void ContextDatabase::restoreTracked(const Element *el,const AddrSpaceManager *manage, +void ContextDatabase::decodeTracked(Decoder &decoder,const AddrSpaceManager *manage, TrackedSet &vec) { vec.clear(); // Clear out any old stuff - const List &list(el->getChildren()); - List::const_iterator iter = list.begin(); - - while(iter != list.end()) { - const Element *subel = *iter; + while(decoder.peekElement() != 0) { vec.emplace_back(); - vec.back().restoreXml(subel,manage); - ++iter; + vec.back().decode(decoder,manage); } } @@ -314,54 +310,47 @@ ContextInternal::FreeArray &ContextInternal::FreeArray::operator=(const FreeArra return *this; } -/// \brief Write out a single context block as an XML tag +/// \brief Encode a single context block to a stream /// /// The blob is broken up into individual values and written out as a series -/// of \ tags within a parent \ tag. -/// \param s is the output stream +/// of \ elements within a parent \ element. +/// \param encoder is the stream encoder /// \param addr is the address of the split point where the blob is valid /// \param vec is the array of words holding the blob values -void ContextInternal::saveContext(ostream &s,const Address &addr, - const uintm *vec) const +void ContextInternal::encodeContext(Encoder &encoder,const Address &addr,const uintm *vec) const { - s << "saveXmlAttributes(s,addr.getOffset() ); - s << ">\n"; + encoder.openElement(ELEM_CONTEXT_POINTSET); + addr.getSpace()->encodeAttributes(encoder,addr.getOffset() ); map::const_iterator iter; for(iter=variables.begin();iter!=variables.end();++iter) { uintm val = (*iter).second.getValue(vec); - s << " \n"; + encoder.openElement(ELEM_SET); + encoder.writeString(ATTRIB_NAME, (*iter).first); + encoder.writeUnsignedInteger(ATTRIB_VAL, val); + encoder.closeElement(ELEM_SET); } - s << "\n"; + encoder.closeElement(ELEM_CONTEXT_POINTSET); } -/// \brief Restore a context blob for given address range from an XML tag +/// \brief Restore a context blob for given address range from a stream decoder /// -/// The tag can be either \ or \. In either case, +/// Parse either a \ or \ element. In either case, /// children are parsed to get context variable values. Then a context blob is /// reconstructed from the values. The new blob is added to the interval map based /// on the address range. If the start address is invalid, the default value of /// the context variables are painted. The second address can be invalid, if /// only a split point is known. -/// \param el is the root XML tag +/// \param decoder is the stream decoder /// \param addr1 is the starting address of the given range /// \param addr2 is the ending address of the given range -void ContextInternal::restoreContext(const Element *el,const Address &addr1,const Address &addr2) +void ContextInternal::decodeContext(Decoder &decoder,const Address &addr1,const Address &addr2) { - const List &list(el->getChildren()); - List::const_iterator iter = list.begin(); - - while(iter != list.end()) { - const Element *subel = *iter; - istringstream s(subel->getAttributeValue("val")); - s.unsetf(ios::dec | ios::hex | ios::oct); - uintm val; - s >> val; - ContextBitRange &var(getVariable(subel->getAttributeValue("name"))); + for(;;) { + uint4 subId = decoder.openElement(); + if (subId != ELEM_SET) break; + uintm val = decoder.readUnsignedInteger(ATTRIB_VAL); + ContextBitRange &var(getVariable(decoder.readString(ATTRIB_NAME))); vector vec; if (addr1.isInvalid()) { // Invalid addr1, indicates we should set default value uintm *defaultBuffer = getDefaultValue(); @@ -373,7 +362,7 @@ void ContextInternal::restoreContext(const Element *el,const Address &addr1,cons getRegionForSet(vec,addr1,addr2,var.getWord(),var.getMask()<\n"; + + encoder.openElement(ELEM_CONTEXT_POINTS); partmap::const_iterator fiter,fenditer; fiter = database.begin(); fenditer = database.end(); for(;fiter!=fenditer;++fiter) // Save context at each changepoint - saveContext(s,(*fiter).first,(*fiter).second.array); + encodeContext(encoder,(*fiter).first,(*fiter).second.array); partmap::const_iterator titer,tenditer; titer = trackbase.begin(); tenditer = trackbase.end(); for(;titer!=tenditer;++titer) - saveTracked(s,(*titer).first,(*titer).second); + encodeTracked(encoder,(*titer).first,(*titer).second); - s << "\n"; + encoder.closeElement(ELEM_CONTEXT_POINTS); } -void ContextInternal::restoreXml(const Element *el,const AddrSpaceManager *manage) +void ContextInternal::decode(Decoder &decoder,const AddrSpaceManager *manage) { - const List &list(el->getChildren()); - List::const_iterator iter = list.begin(); - - while(iter != list.end()) { - const Element *subel = *iter; - if (subel->getName() == "context_pointset") { - if (subel->getNumAttributes()==0) { - restoreContext(subel,Address(),Address()); // Restore the default value + uint4 elemId = decoder.openElement(ELEM_CONTEXT_POINTS); + for(;;) { + uint4 subId = decoder.openElement(); + if (subId == 0) break; + if (subId == ELEM_CONTEXT_POINTSET) { + uint4 attribId = decoder.getNextAttributeId(); + decoder.rewindAttributes(); + if (attribId==0) { + decodeContext(decoder,Address(),Address()); // Restore the default value } else { - Address addr = Address::restoreXml(subel,manage); - restoreContext(subel,addr,Address()); + VarnodeData vData; + vData.decodeFromAttributes(decoder, manage); + decodeContext(decoder,vData.getAddr(),Address()); } } - else if (subel->getName() == "tracked_pointset") { - Address addr = Address::restoreXml(subel,manage); - restoreTracked(subel,manage,trackbase.split(addr) ); + else if (subId == ELEM_TRACKED_POINTSET) { + VarnodeData vData; + vData.decodeFromAttributes(decoder, manage); + decodeTracked(decoder,manage,trackbase.split(vData.getAddr()) ); } else - throw LowlevelError("Bad tag: "+subel->getName()); - ++iter; + throw LowlevelError("Bad tag"); + decoder.closeElement(subId); } + decoder.closeElement(elemId); } -void ContextInternal::restoreFromSpec(const Element *el,const AddrSpaceManager *manage) +void ContextInternal::decodeFromSpec(Decoder &decoder,const AddrSpaceManager *manage) { - const List &list(el->getChildren()); - List::const_iterator iter = list.begin(); - - while(iter != list.end()) { - const Element *subel = *iter; - if (subel->getName() == "context_set") { - Range range; - range.restoreXml(subel,manage); // There MUST be a range - Address addr1,addr2; - addr1 = range.getFirstAddr(); - addr2 = range.getLastAddrOpen(manage); - restoreContext(subel,addr1,addr2); + uint4 elemId = decoder.openElement(ELEM_CONTEXT_DATA); + for(;;) { + uint4 subId = decoder.openElement(); + if (subId == 0) break; + Range range; + range.decodeFromAttributes(decoder, manage); // There MUST be a range + Address addr1 = range.getFirstAddr(); + Address addr2 = range.getLastAddrOpen(manage); + if (subId == ELEM_CONTEXT_SET) { + decodeContext(decoder,addr1,addr2); } - else if (subel->getName() == "tracked_set") { - Range range; - range.restoreXml(subel,manage); // There MUST be a range - Address addr1,addr2; - addr1 = range.getFirstAddr(); - addr2 = range.getLastAddrOpen(manage); - restoreTracked(subel,manage,createSet(addr1,addr2)); + else if (subId == ELEM_TRACKED_SET) { + decodeTracked(decoder,manage,createSet(addr1,addr2)); } else - throw LowlevelError("Bad tag: "+subel->getName()); - ++iter; + throw LowlevelError("Bad tag"); + decoder.closeElement(subId); } + decoder.closeElement(elemId); } /// \param db is the context database that will be encapsulated diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/globalcontext.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/globalcontext.hh index 86dcccba46..e104a408f0 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/globalcontext.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/globalcontext.hh @@ -22,6 +22,14 @@ #include "pcoderaw.hh" #include "partmap.hh" +extern ElementId ELEM_CONTEXT_DATA; ///< Marshaling element \ +extern ElementId ELEM_CONTEXT_POINTS; ///< Marshaling element \ +extern ElementId ELEM_CONTEXT_POINTSET; ///< Marshaling element \ +extern ElementId ELEM_CONTEXT_SET; ///< Marshaling element \ +extern ElementId ELEM_SET; ///< Marshaling element \ +extern ElementId ELEM_TRACKED_POINTSET; ///< Marshaling element \ +extern ElementId ELEM_TRACKED_SET; ///< Marshaling element \ + /// \brief Description of a context variable within the disassembly context \e blob /// /// Disassembly context is stored as individual (integer) values packed into a sequence of words. This class @@ -34,7 +42,7 @@ class ContextBitRange { int4 shift; ///< Right-shift amount to apply when unpacking this value from its word uintm mask; ///< Mask to apply (after shifting) when unpacking this value from its word public: - ContextBitRange(void) { } ///< Constructor for use with restoreXml() + ContextBitRange(void) { } ///< Construct an undefined bit range ContextBitRange(int4 sbit,int4 ebit); ///< Construct a context value given an absolute bit range int4 getShift(void) const { return shift; } ///< Return the shift-amount for \b this value uintm getMask(void) const { return mask; } ///< Return the mask for \b this value @@ -68,8 +76,8 @@ public: struct TrackedContext { VarnodeData loc; ///< Storage details of the register being tracked uintb val; ///< The value of the register - void restoreXml(const Element *el,const AddrSpaceManager *manage); ///< Restore \b this from an XML stream - void saveXml(ostream &s) const; ///< Save \b this to an XML stream + void decode(Decoder &decoder,const AddrSpaceManager *manage); ///< Decode \b this from a stream + void encode(Encoder &encoder) const; ///< Encode \b this to a stream }; typedef vector TrackedSet; ///< A set of tracked registers and their values (at one code point) @@ -107,8 +115,8 @@ typedef vector TrackedSet; ///< A set of tracked registers and /// a list of TrackedContext objects. class ContextDatabase { protected: - static void saveTracked(ostream &s,const Address &addr,const TrackedSet &vec); - static void restoreTracked(const Element *el,const AddrSpaceManager *manage,TrackedSet &vec); + static void encodeTracked(Encoder &encoder,const Address &addr,const TrackedSet &vec); + static void decodeTracked(Decoder &decoder,const AddrSpaceManager *manage,TrackedSet &vec); /// \brief Retrieve the context variable description object by name /// @@ -218,24 +226,24 @@ public: /// \return the empty set of tracked register values virtual TrackedSet &createSet(const Address &addr1,const Address &addr2)=0; - /// \brief Serialize the entire database to an XML stream + /// \brief Encode the entire database to a stream /// - /// \param s is the output stream - virtual void saveXml(ostream &s) const=0; + /// \param encoder is the stream encoder + virtual void encode(Encoder &encoder) const=0; - /// \brief Restore the state of \b this database object from a serialized XML stream + /// \brief Restore the state of \b this database object from the given stream decoder /// - /// \param el is the root element of the XML describing the database state + /// \param decoder is the given stream decoder /// \param manage is used to resolve address space references - virtual void restoreXml(const Element *el,const AddrSpaceManager *manage)=0; + virtual void decode(Decoder &decoder,const AddrSpaceManager *manage)=0; - /// \brief Add initial context state from XML tags in compiler/processor specifications + /// \brief Add initial context state from elements in the compiler/processor specifications /// - /// The database can be configured with a consistent initial state by providing - /// \ tags in either the compiler or processor specification file for the architecture - /// \param el is a \ tag + /// Parse a \ element from the given stream decoder from either the compiler + /// or processor specification file for the architecture, initializing this database. + /// \param decoder is the given stream decoder /// \param manage is used to resolve address space references - virtual void restoreFromSpec(const Element *el,const AddrSpaceManager *manage)=0; + virtual void decodeFromSpec(Decoder &decoder,const AddrSpaceManager *manage)=0; void setVariableDefault(const string &nm,uintm val); ///< Provide a default value for a context variable uintm getDefaultValue(const string &nm) const; ///< Retrieve the default value for a context variable @@ -274,8 +282,8 @@ class ContextInternal : public ContextDatabase { map variables; ///< Map from context variable name to description object partmap database; ///< Partition map of context blobs (FreeArray) partmap trackbase; ///< Partition map of tracked register sets - void saveContext(ostream &s,const Address &addr,const uintm *vec) const; - void restoreContext(const Element *el,const Address &addr1,const Address &addr2); + void encodeContext(Encoder &encoder,const Address &addr,const uintm *vec) const; + void decodeContext(Decoder &decoder,const Address &addr1,const Address &addr2); virtual ContextBitRange &getVariable(const string &nm); virtual const ContextBitRange &getVariable(const string &nm) const; virtual void getRegionForSet(vector &res,const Address &addr1, @@ -296,9 +304,9 @@ public: virtual const TrackedSet &getTrackedSet(const Address &addr) const { return trackbase.getValue(addr); } virtual TrackedSet &createSet(const Address &addr1,const Address &addr2); - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el,const AddrSpaceManager *manage); - virtual void restoreFromSpec(const Element *el,const AddrSpaceManager *manage); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,const AddrSpaceManager *manage); + virtual void decodeFromSpec(Decoder &decoder,const AddrSpaceManager *manage); }; /// \brief A helper class for caching the active context blob to minimize database lookups diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc index f2994e1fcb..65bbc74458 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc @@ -314,7 +314,7 @@ void IfcOption::execute(istream &s) } try { - string res = dcp->conf->options->set(optname,p1,p2,p3); + string res = dcp->conf->options->set(ElementId::find(optname),p1,p2,p3); *status->optr << res << endl; } catch(ParseError &err) { @@ -2690,7 +2690,8 @@ void IfcCallGraphDump::execute(istream &s) if (!os) throw IfaceExecutionError("Unable to open file "+name); - dcp->cgraph->saveXml(os); + XmlEncode encoder(os); + dcp->cgraph->encode(encoder); os.close(); *status->optr << "Successfully saved callgraph to " << name << endl; } @@ -2723,7 +2724,8 @@ void IfcCallGraphLoad::execute(istream &s) Document *doc = store.parseDocument(is); dcp->allocateCallGraph(); - dcp->cgraph->restoreXml(doc->getRoot()); + XmlDecode decoder(doc->getRoot()); + dcp->cgraph->decoder(decoder); *status->optr << "Successfully read in callgraph" << endl; Scope *gscope = dcp->conf->symboltab->getGlobalScope(); @@ -3014,7 +3016,8 @@ void IfcStructureBlocks::execute(istream &s) try { BlockGraph ingraph; - ingraph.restoreXml(doc->getRoot(),dcp->conf); + XmlDecode decoder(doc->getRoot()); + ingraph.decode(decoder,dcp->conf); BlockGraph resultgraph; vector rootlist; @@ -3030,7 +3033,8 @@ void IfcStructureBlocks::execute(istream &s) sout.open(outfile.c_str()); if (!sout) throw IfaceExecutionError("Unable to open output file: "+outfile); - resultgraph.saveXml(sout); + XmlEncode encoder(sout); + resultgraph.encode(encoder); sout.close(); } catch(LowlevelError &err) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/inject_ghidra.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/inject_ghidra.cc index 5cd5f1baca..24b2471532 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/inject_ghidra.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/inject_ghidra.cc @@ -15,42 +15,43 @@ */ #include "inject_ghidra.hh" -void InjectContextGhidra::saveXml(ostream &s) const +void InjectContextGhidra::encode(Encoder &encoder) const { - s << "\n"; - baseaddr.saveXml(s); - calladdr.saveXml(s); + encoder.openElement(ELEM_CONTEXT); + baseaddr.encode(encoder); + calladdr.encode(encoder); if (!inputlist.empty()) { - s << "\n"; + encoder.openElement(ELEM_INPUT); for(int4 i=0;isaveXmlAttributes(s,vn.offset,vn.size); - s << "/>\n"; + encoder.openElement(ELEM_ADDR); + vn.space->encodeAttributes(encoder,vn.offset,vn.size); + encoder.closeElement(ELEM_ADDR); } - s << "\n"; + encoder.closeElement(ELEM_INPUT); } if (!output.empty()) { - s << "\n"; + encoder.openElement(ELEM_OUTPUT); for(int4 i=0;isaveXmlAttributes(s,vn.offset,vn.size); - s << "/>\n"; + encoder.openElement(ELEM_ADDR); + vn.space->encodeAttributes(encoder,vn.offset,vn.size); + encoder.closeElement(ELEM_ADDR); } - s << "\n"; + encoder.closeElement(ELEM_OUTPUT); } - s << "\n"; + encoder.closeElement(ELEM_CONTEXT); } void InjectPayloadGhidra::inject(InjectContext &con,PcodeEmit &emit) const { - Document *doc; ArchitectureGhidra *ghidra = (ArchitectureGhidra *)con.glb; + XmlDecode decoder; try { - doc = ghidra->getPcodeInject(name,type,con); + if (!ghidra->getPcodeInject(name,type,con,decoder)) + throw LowlevelError("Could not retrieve pcode snippet: "+name); } catch(JavaError &err) { throw LowlevelError("Error getting pcode snippet: " + err.explain); @@ -58,15 +59,19 @@ void InjectPayloadGhidra::inject(InjectContext &con,PcodeEmit &emit) const catch(XmlError &err) { throw LowlevelError("Error in pcode snippet xml: "+err.explain); } - if (doc == (Document *)0) { - throw LowlevelError("Could not retrieve pcode snippet: "+name); - } - const Element *el = doc->getRoot(); - const List &list(el->getChildren()); - List::const_iterator iter; - for(iter=list.begin();iter!=list.end();++iter) - emit.restoreXmlOp(*iter,ghidra->translate); - delete doc; + uint4 elemId = decoder.openElement(); + while(decoder.peekElement() != 0) + emit.decodeOp(decoder,ghidra->translate); + decoder.closeElement(elemId); +} + +void InjectPayloadGhidra::decode(Decoder &decoder) + +{ + // Restore a raw tag. Used for uponentry, uponreturn + uint4 elemId = decoder.openElement(ELEM_PCODE); + decodePayloadAttributes(decoder); + decoder.closeElementSkipping(elemId); } void InjectPayloadGhidra::printTemplate(ostream &s) const @@ -80,10 +85,12 @@ InjectCallfixupGhidra::InjectCallfixupGhidra(const string &src,const string &nm) { } -void InjectCallfixupGhidra::restoreXml(const Element *el) +void InjectCallfixupGhidra::decode(Decoder &decoder) { - name = el->getAttributeValue("name"); + uint4 elemId = decoder.openElement(ELEM_CALLFIXUP); + name = decoder.readString(ATTRIB_NAME); + decoder.closeElementSkipping(elemId); // Skip processing the body, let ghidra handle this } InjectCallotherGhidra::InjectCallotherGhidra(const string &src,const string &nm) @@ -91,16 +98,18 @@ InjectCallotherGhidra::InjectCallotherGhidra(const string &src,const string &nm) { } -void InjectCallotherGhidra::restoreXml(const Element *el) +void InjectCallotherGhidra::decode(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - name = el->getAttributeValue("targetop"); - iter = list.begin(); - if ((iter == list.end()) || ((*iter)->getName() != "pcode")) + uint4 elemId = decoder.openElement(ELEM_CALLOTHERFIXUP); + name = decoder.readString(ATTRIB_TARGETOP); + uint4 subId = decoder.openElement(); + if (subId != ELEM_PCODE) throw LowlevelError(" does not contain a tag"); - InjectPayload::restoreXml(*iter); + decodePayloadAttributes(decoder); + decodePayloadParams(decoder); + decoder.closeElementSkipping(subId); // Skip processing the body, let ghidra handle this + decoder.closeElement(elemId); } ExecutablePcodeGhidra::ExecutablePcodeGhidra(Architecture *g,const string &src,const string &nm) @@ -111,10 +120,11 @@ ExecutablePcodeGhidra::ExecutablePcodeGhidra(Architecture *g,const string &src,c void ExecutablePcodeGhidra::inject(InjectContext &con,PcodeEmit &emit) const { - Document *doc; ArchitectureGhidra *ghidra = (ArchitectureGhidra *)con.glb; + XmlDecode decoder; try { - doc = ghidra->getPcodeInject(name,type,con); + if (!ghidra->getPcodeInject(name,type,con,decoder)) + throw LowlevelError("Could not retrieve pcode snippet: "+name); } catch(JavaError &err) { throw LowlevelError("Error getting pcode snippet: " + err.explain); @@ -122,22 +132,22 @@ void ExecutablePcodeGhidra::inject(InjectContext &con,PcodeEmit &emit) const catch(XmlError &err) { throw LowlevelError("Error in pcode snippet xml: "+err.explain); } - if (doc == (Document *)0) { - throw LowlevelError("Could not retrieve pcode snippet: "+name); - } - const Element *el = doc->getRoot(); - const List &list(el->getChildren()); - List::const_iterator iter; - for(iter=list.begin();iter!=list.end();++iter) - emit.restoreXmlOp(*iter,ghidra->translate); - delete doc; + uint4 elemId = decoder.openElement(); + while(decoder.peekElement() != 0) + emit.decodeOp(decoder,ghidra->translate); + decoder.closeElement(elemId); } -void ExecutablePcodeGhidra::restoreXml(const Element *el) +void ExecutablePcodeGhidra::decode(Decoder &decoder) { - InjectPayload::restoreXml(el); // Read parameters - // But ignore rest of body + uint4 elemId = decoder.openElement(); + if (elemId != ELEM_CASE_PCODE && elemId != ELEM_ADDR_PCODE && + elemId != ELEM_DEFAULT_PCODE && elemId != ELEM_SIZE_PCODE) + throw XmlError("Expecting , , , or "); + decodePayloadAttributes(decoder); + decodePayloadParams(decoder); // Parse the parameters + decoder.closeElementSkipping(elemId); // But skip rest of body } void ExecutablePcodeGhidra::printTemplate(ostream &s) const diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/inject_ghidra.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/inject_ghidra.hh index 90900d6730..c0678039c7 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/inject_ghidra.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/inject_ghidra.hh @@ -28,7 +28,7 @@ /// that can then be forwarded to the Ghidra client. class InjectContextGhidra : public InjectContext { public: - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; }; /// \brief An injection payload that uses a Ghidra client to generate the p-code ops @@ -41,7 +41,7 @@ class InjectPayloadGhidra : public InjectPayload { public: InjectPayloadGhidra(const string &src,const string &nm,int4 tp) : InjectPayload(nm,tp) { source = src; } ///< Constructor virtual void inject(InjectContext &context,PcodeEmit &emit) const; - virtual void restoreXml(const Element *el) {} + virtual void decode(Decoder &decoder); virtual void printTemplate(ostream &s) const; virtual string getSource(void) const { return source; } }; @@ -50,14 +50,14 @@ public: class InjectCallfixupGhidra : public InjectPayloadGhidra { public: InjectCallfixupGhidra(const string &src,const string &nm); ///< Constructor - virtual void restoreXml(const Element *el); + virtual void decode(Decoder &decoder); }; /// \brief A callother-fixup injection that uses a Ghidra client to generate the p-code ops class InjectCallotherGhidra : public InjectPayloadGhidra { public: InjectCallotherGhidra(const string &src,const string &nm); ///< Constructor - virtual void restoreXml(const Element *el); + virtual void decode(Decoder &decoder); }; /// \brief A \e p-code \e script that uses a Ghidra client to generate the p-code ops @@ -69,7 +69,7 @@ class ExecutablePcodeGhidra : public ExecutablePcode { public: ExecutablePcodeGhidra(Architecture *g,const string &src,const string &nm); ///< Constructor virtual void inject(InjectContext &context,PcodeEmit &emit) const; - virtual void restoreXml(const Element *el); + virtual void decode(Decoder &decoder); virtual void printTemplate(ostream &s) const; }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.cc index e4e34b029b..80d19fff50 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.cc @@ -61,22 +61,31 @@ void InjectPayloadSleigh::inject(InjectContext &context,PcodeEmit &emit) const con.cacher.emit(con.baseaddr,&emit); } -void InjectPayloadSleigh::restoreXml(const Element *el) +/// The content is read as raw p-code source +/// \param decoder is the XML stream decoder +void InjectPayloadSleigh::decodeBody(Decoder &decoder) { - InjectPayload::restoreXml(el); - const List &list(el->getChildren()); - List::const_iterator iter; - for(iter=list.begin();iter!=list.end();++iter) { - const Element *subel = *iter; - if (subel->getName() == "body") { - parsestring = subel->getContent(); - } + uint4 elemId = decoder.openElement(); // Tag may not be present + if (elemId == ELEM_BODY) { + parsestring = decoder.readString(ATTRIB_CONTENT); + decoder.closeElement(elemId); } if (parsestring.size() == 0 && (!dynamic)) throw LowlevelError("Missing subtag in : "+getSource()); } +void InjectPayloadSleigh::decode(Decoder &decoder) + +{ + // Restore a raw tag. Used for uponentry, uponreturn + uint4 elemId = decoder.openElement(ELEM_PCODE); + decodePayloadAttributes(decoder); + decodePayloadParams(decoder); + decodeBody(decoder); + decoder.closeElement(elemId); +} + void InjectPayloadSleigh::printTemplate(ostream &s) const { @@ -138,23 +147,27 @@ InjectPayloadCallfixup::InjectPayloadCallfixup(const string &sourceName) { } -void InjectPayloadCallfixup::restoreXml(const Element *el) +void InjectPayloadCallfixup::decode(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - name = el->getAttributeValue("name"); + uint4 elemId = decoder.openElement(ELEM_CALLFIXUP); + name = decoder.readString(ATTRIB_NAME); bool pcodeSubtag = false; - for(iter=list.begin();iter!=list.end();++iter) { - const Element *subel = *iter; - if (subel->getName() == "pcode") { - InjectPayloadSleigh::restoreXml(subel); + for(;;) { + uint4 subId = decoder.openElement(); + if (subId == 0) break; + if (subId == ELEM_PCODE) { + decodePayloadAttributes(decoder); + decodePayloadParams(decoder); + decodeBody(decoder); pcodeSubtag = true; } - else if (subel->getName() == "target") - targetSymbolNames.push_back(subel->getAttributeValue("name")); + else if (subId == ELEM_TARGET) + targetSymbolNames.push_back(decoder.readString(ATTRIB_NAME)); + decoder.closeElement(subId); } + decoder.closeElement(elemId); if (!pcodeSubtag) throw LowlevelError(" is missing subtag: "+name); } @@ -164,16 +177,19 @@ InjectPayloadCallother::InjectPayloadCallother(const string &sourceName) { } -void InjectPayloadCallother::restoreXml(const Element *el) +void InjectPayloadCallother::decode(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - name = el->getAttributeValue("targetop"); - iter = list.begin(); - if ((iter == list.end()) || ((*iter)->getName() != "pcode")) + uint4 elemId = decoder.openElement(ELEM_CALLOTHERFIXUP); + name = decoder.readString(ATTRIB_TARGETOP); + uint4 subId = decoder.openElement(); + if (subId != ELEM_PCODE) throw LowlevelError(" does not contain a tag"); - InjectPayloadSleigh::restoreXml(*iter); + decodePayloadAttributes(decoder); + decodePayloadParams(decoder); + decodeBody(decoder); + decoder.closeElement(subId); + decoder.closeElement(elemId); } ExecutablePcodeSleigh::ExecutablePcodeSleigh(Architecture *g,const string &src,const string &nm) @@ -211,22 +227,18 @@ void ExecutablePcodeSleigh::inject(InjectContext &context,PcodeEmit &emit) const con.cacher.emit(con.baseaddr,&emit); } -void ExecutablePcodeSleigh::restoreXml(const Element *el) +void ExecutablePcodeSleigh::decode(Decoder &decoder) { - InjectPayload::restoreXml(el); - const List &list(el->getChildren()); - List::const_iterator iter; - bool hasbody = false; - for (iter = list.begin(); iter != list.end(); ++iter) { - const Element *subel = *iter; - if (subel->getName() == "body") { - hasbody = true; - parsestring = subel->getContent(); - } - } - if (!hasbody) - throw LowlevelError("Missing subtag in : " + getSource()); + uint4 elemId = decoder.openElement(); + if (elemId != ELEM_CASE_PCODE && elemId != ELEM_ADDR_PCODE && elemId != ELEM_DEFAULT_PCODE && elemId != ELEM_SIZE_PCODE) + throw XmlError("Expecting , , , or "); + decodePayloadAttributes(decoder); + decodePayloadParams(decoder); + uint4 subId = decoder.openElement(ELEM_BODY); + parsestring = decoder.readString(ATTRIB_CONTENT); + decoder.closeElement(subId); + decoder.closeElement(elemId); } void ExecutablePcodeSleigh::printTemplate(ostream &s) const @@ -243,16 +255,12 @@ InjectPayloadDynamic::~InjectPayloadDynamic(void) delete (*iter).second; } -void InjectPayloadDynamic::restoreEntry(const Element *el) +void InjectPayloadDynamic::decodeEntry(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - - iter = list.begin(); - Address addr = Address::restoreXml(*iter,glb); - ++iter; - istringstream s((*iter)->getContent()); + Address addr = Address::decode(decoder,glb); + uint4 subId = decoder.openElement(ELEM_PAYLOAD); + istringstream s(decoder.readString(ATTRIB_CONTENT)); try { Document *doc = xml_tree(s); map::iterator iter = addrMap.find(addr); @@ -263,6 +271,7 @@ void InjectPayloadDynamic::restoreEntry(const Element *el) catch(XmlError &err) { throw LowlevelError("Error in dynamic payload XML"); } + decoder.closeElement(subId); } void InjectPayloadDynamic::inject(InjectContext &context,PcodeEmit &emit) const @@ -272,10 +281,11 @@ void InjectPayloadDynamic::inject(InjectContext &context,PcodeEmit &emit) const if (eiter == addrMap.end()) throw LowlevelError("Missing dynamic inject"); const Element *el = (*eiter).second->getRoot(); - const List &list(el->getChildren()); - List::const_iterator iter; - for(iter=list.begin();iter!=list.end();++iter) - emit.restoreXmlOp(*iter,glb->translate); + XmlDecode decoder(el); + uint4 rootId = decoder.openElement(ELEM_INST); + while(decoder.peekElement() != 0) + emit.decodeOp(decoder,glb->translate); + decoder.closeElement(rootId); } PcodeInjectLibrarySleigh::PcodeInjectLibrarySleigh(Architecture *g) @@ -402,26 +412,24 @@ void PcodeInjectLibrarySleigh::registerInject(int4 injectid) } } -void PcodeInjectLibrarySleigh::restoreDebug(const Element *el) +void PcodeInjectLibrarySleigh::decodeDebug(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - - for(iter=list.begin();iter!=list.end();++iter) { - const Element *subel = *iter; - const string &name( subel->getAttributeValue("name") ); - istringstream s( subel->getAttributeValue("type") ); - int4 type = -1; - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> type; + uint4 elemId = decoder.openElement(ELEM_INJECTDEBUG); + for(;;) { + uint4 subId = decoder.openElement(); + if (subId != ELEM_INJECT) break; + string name = decoder.readString(ATTRIB_NAME); + int4 type = decoder.readSignedInteger(ATTRIB_TYPE); int4 id = getPayloadId(type,name); InjectPayloadDynamic *payload = dynamic_cast(getPayload(id)); if (payload == (InjectPayloadDynamic *)0) { payload = forceDebugDynamic(id); } - payload->restoreEntry(subel); + payload->decodeEntry(decoder); + decoder.closeElement(subId); } + decoder.closeElement(elemId); } const vector &PcodeInjectLibrarySleigh::getBehaviors(void) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.hh index 7d8776c125..be86fbcf6e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.hh @@ -25,7 +25,7 @@ public: ParserContext *pos; InjectContextSleigh(void) { pos = (ParserContext *)0; } virtual ~InjectContextSleigh(void); - virtual void saveXml(ostream &s) const {} // We don't need this functionality for sleigh + virtual void encode(Encoder &encoder) const {} // We don't need this functionality for sleigh }; class InjectPayloadSleigh : public InjectPayload { @@ -33,11 +33,13 @@ class InjectPayloadSleigh : public InjectPayload { ConstructTpl *tpl; string parsestring; string source; +protected: + void decodeBody(Decoder &decoder); ///< Parse the tag public: InjectPayloadSleigh(const string &src,const string &nm,int4 tp); virtual ~InjectPayloadSleigh(void); virtual void inject(InjectContext &context,PcodeEmit &emit) const; - virtual void restoreXml(const Element *el); + virtual void decode(Decoder &decoder); virtual void printTemplate(ostream &s) const; virtual string getSource(void) const { return source; } @@ -52,13 +54,13 @@ class InjectPayloadCallfixup : public InjectPayloadSleigh { vector targetSymbolNames; public: InjectPayloadCallfixup(const string &sourceName); - virtual void restoreXml(const Element *el); + virtual void decode(Decoder &decoder); }; class InjectPayloadCallother : public InjectPayloadSleigh { public: InjectPayloadCallother(const string &sourceName); - virtual void restoreXml(const Element *el); + virtual void decode(Decoder &decoder); }; class ExecutablePcodeSleigh : public ExecutablePcode { @@ -70,7 +72,7 @@ protected: ExecutablePcodeSleigh(Architecture *g,const string &src,const string &nm); virtual ~ExecutablePcodeSleigh(void); virtual void inject(InjectContext &context,PcodeEmit &emit) const; - virtual void restoreXml(const Element *el); + virtual void decode(Decoder &decoder); virtual void printTemplate(ostream &s) const; }; @@ -80,8 +82,9 @@ class InjectPayloadDynamic : public InjectPayload { public: InjectPayloadDynamic(Architecture *g,const string &nm,int4 tp) : InjectPayload(nm,tp) { glb = g; dynamic = true; } virtual ~InjectPayloadDynamic(void); - void restoreEntry(const Element *el); + void decodeEntry(Decoder &decoder); virtual void inject(InjectContext &context,PcodeEmit &emit) const; + virtual void decode(Decoder &decoder) { throw LowlevelError("decode not supported for InjectPayloadDynamic"); } virtual void printTemplate(ostream &s) const { s << "dynamic"; } virtual string getSource(void) const { return "dynamic"; } }; @@ -98,7 +101,7 @@ protected: virtual void registerInject(int4 injectid); public: PcodeInjectLibrarySleigh(Architecture *g); - virtual void restoreDebug(const Element *el); + virtual void decodeDebug(Decoder &decoder); virtual int4 manualCallFixup(const string &name,const string &snippetstring); virtual int4 manualCallOtherFixup(const string &name,const string &outname,const vector &inname, const string &snippet); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc index 8f9b784f5d..0b5151f2bf 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc @@ -17,32 +17,38 @@ #include "emulate.hh" #include "flow.hh" -/// \param s is the XML stream to write to -void LoadTable::saveXml(ostream &s) const +AttributeId ATTRIB_LABEL = AttributeId("label",71); +AttributeId ATTRIB_NUM = AttributeId("num",72); + +ElementId ELEM_BASICOVERRIDE = ElementId("basicoverride",101); +ElementId ELEM_DEST = ElementId("dest",102); +ElementId ELEM_JUMPTABLE = ElementId("jumptable",103); +ElementId ELEM_LOADTABLE = ElementId("loadtable",104); +ElementId ELEM_NORMADDR = ElementId("normaddr",105); +ElementId ELEM_NORMHASH = ElementId("normhash",106); +ElementId ELEM_STARTVAL = ElementId("startval",107); + +/// \param encoder is the stream encoder +void LoadTable::encode(Encoder &encoder) const { - s << "\n "; - addr.saveXml(s); - s << "\n"; + encoder.openElement(ELEM_LOADTABLE); + encoder.writeSignedInteger(ATTRIB_SIZE, size); + encoder.writeSignedInteger(ATTRIB_NUM, num); + addr.encode(encoder); + encoder.closeElement(ELEM_LOADTABLE); } -/// \param el is the root \ tag +/// \param decoder is the stream decoder /// \param glb is the architecture for resolving address space tags -void LoadTable::restoreXml(const Element *el,Architecture *glb) +void LoadTable::decode(Decoder &decoder,Architecture *glb) { - istringstream s1(el->getAttributeValue("size")); - s1.unsetf(ios::dec | ios::hex | ios::oct); - s1 >> size; - istringstream s2(el->getAttributeValue("num")); - s2.unsetf(ios::dec | ios::hex | ios::oct); - s2 >> num; - const List &list( el->getChildren() ); - List::const_iterator iter = list.begin(); - addr = Address::restoreXml( *iter, glb); + uint4 elemId = decoder.openElement(ELEM_LOADTABLE); + size = decoder.readSignedInteger(ATTRIB_SIZE); + num = decoder.readSignedInteger(ATTRIB_NUM); + addr = Address::decode( decoder, glb); + decoder.closeElement(elemId); } /// We assume the list of LoadTable entries is sorted and perform an in-place @@ -1899,55 +1905,61 @@ void JumpBasicOverride::clear(void) istrivial = false; } -void JumpBasicOverride::saveXml(ostream &s) const +void JumpBasicOverride::encode(Encoder &encoder) const { set
::const_iterator iter; - s << "\n"; + encoder.openElement(ELEM_BASICOVERRIDE); for(iter=adset.begin();iter!=adset.end();++iter) { - s << " saveXmlAttributes(s,off); - s << "/>\n"; + spc->encodeAttributes(encoder,off); + encoder.closeElement(ELEM_DEST); } if (hash != 0) { - s << " saveXmlAttributes(s,normaddress.getOffset()); - s << "/>\n"; - s << " 0x" << hex << hash << "\n"; + encoder.openElement(ELEM_NORMADDR); + normaddress.getSpace()->encodeAttributes(encoder,normaddress.getOffset()); + encoder.closeElement(ELEM_NORMADDR); + encoder.openElement(ELEM_NORMHASH); + encoder.writeUnsignedInteger(ATTRIB_CONTENT, hash); + encoder.closeElement(ELEM_NORMHASH); } if (startingvalue != 0) { - s << " 0x" << hex << startingvalue << "\n"; + encoder.openElement(ELEM_STARTVAL); + encoder.writeUnsignedInteger(ATTRIB_CONTENT, startingvalue); + encoder.closeElement(ELEM_STARTVAL); } - s << "\n"; + encoder.closeElement(ELEM_BASICOVERRIDE); } -void JumpBasicOverride::restoreXml(const Element *el,Architecture *glb) +void JumpBasicOverride::decode(Decoder &decoder,Architecture *glb) { - const List &list( el->getChildren() ); - List::const_iterator iter = list.begin(); - while(iter != list.end()) { - const Element *subel = *iter; - ++iter; - if (subel->getName() == "dest") { - adset.insert( Address::restoreXml(subel,glb) ); + uint4 elemId = decoder.openElement(ELEM_BASICOVERRIDE); + for(;;) { + uint4 subId = decoder.openElement(); + if (subId == 0) break; + if (subId == ELEM_DEST) { + VarnodeData vData; + vData.decodeFromAttributes(decoder, glb); + adset.insert( vData.getAddr() ); } - else if (subel->getName() == "normaddr") - normaddress = Address::restoreXml(subel,glb); - else if (subel->getName() == "normhash") { - istringstream s1(subel->getContent()); - s1.unsetf(ios::dec | ios::hex | ios::oct); - s1 >> hash; + else if (subId == ELEM_NORMADDR) { + VarnodeData vData; + vData.decodeFromAttributes(decoder, glb); + normaddress = vData.getAddr(); } - else if (subel->getName() == "startval") { - istringstream s2(subel->getContent()); - s2.unsetf(ios::dec | ios::hex | ios::oct); - s2 >> startingvalue; + else if (subId == ELEM_NORMHASH) { + hash = decoder.readUnsignedInteger(ATTRIB_CONTENT); } + else if (subId == ELEM_STARTVAL) { + startingvalue = decoder.readUnsignedInteger(ATTRIB_CONTENT); + } + decoder.closeElement(subId); } + decoder.closeElement(elemId); if (adset.empty()) throw LowlevelError("Empty jumptable override"); } @@ -2594,83 +2606,81 @@ void JumpTable::clear(void) // -opaddress- -maxtablesize- -maxaddsub- -maxleftright- -maxext- -collectloads- are permanent } -/// The recovered addresses and case labels are saved to the XML stream. -/// If override information is present, this is also incorporated into the tag. -/// \param s is the stream to write to -void JumpTable::saveXml(ostream &s) const +/// The recovered addresses and case labels are encode to the stream. +/// If override information is present, this is also incorporated into the element. +/// \param encoder is the stream encoder +void JumpTable::encode(Encoder &encoder) const { if (!isRecovered()) throw LowlevelError("Trying to save unrecovered jumptable"); - s << "\n"; - opaddress.saveXml(s); - s << '\n'; + encoder.openElement(ELEM_JUMPTABLE); + opaddress.encode(encoder); for(int4 i=0;isaveXmlAttributes(s,off); + spc->encodeAttributes(encoder,off); if (i\n"; + encoder.closeElement(ELEM_DEST); } if (!loadpoints.empty()) { for(int4 i=0;iisOverride())) - jmodel->saveXml(s); - s << "\n"; + jmodel->encode(encoder); + encoder.closeElement(ELEM_JUMPTABLE); } -/// Restore the addresses, \e case labels, and any override information from the tag. +/// Parse addresses, \e case labels, and any override information from a \ element. /// Other parts of the model and jump-table will still need to be recovered. -/// \param el is the root \ tag to restore from -void JumpTable::restoreXml(const Element *el) +/// \param decoder is the stream decoder +void JumpTable::decode(Decoder &decoder) { - const List &list( el->getChildren() ); - List::const_iterator iter = list.begin(); - opaddress = Address::restoreXml( *iter, glb); + uint4 elemId = decoder.openElement(ELEM_JUMPTABLE); + opaddress = Address::decode( decoder, glb); bool missedlabel = false; - ++iter; - while(iter != list.end()) { - const Element *subel = *iter; - if (subel->getName() == "dest") { - addresstable.push_back( Address::restoreXml( subel, glb) ); - int4 maxnum = subel->getNumAttributes(); - int4 i; - for(i=0;igetAttributeName(i) == "label") break; + for(;;) { + uint4 subId = decoder.peekElement(); + if (subId == 0) break; + if (subId == ELEM_DEST) { + decoder.openElement(); + bool foundlabel = false; + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_LABEL) { + if (missedlabel) + throw LowlevelError("Jumptable entries are missing labels"); + uintb lab = decoder.readUnsignedInteger(); + label.push_back(lab); + foundlabel = true; + break; + } } - if (igetAttributeValue(i)); - s1.unsetf(ios::dec | ios::hex | ios::oct); - uintb lab; - s1 >> lab; - label.push_back(lab); - } - else // No label attribute + if (!foundlabel) // No label attribute missedlabel = true; // No following entries are allowed to have a label attribute + addresstable.push_back( Address::decode( decoder, glb) ); } - else if (subel->getName() == "loadtable") { + else if (subId == ELEM_LOADTABLE) { loadpoints.emplace_back(); - loadpoints.back().restoreXml(subel,glb); + loadpoints.back().decode(decoder,glb); } - else if (subel->getName() == "basicoverride") { + else if (subId == ELEM_BASICOVERRIDE) { if (jmodel != (JumpModel *)0) throw LowlevelError("Duplicate jumptable override specs"); jmodel = new JumpBasicOverride(this); - jmodel->restoreXml(subel,glb); + jmodel->decode(decoder,glb); } - ++iter; } + decoder.closeElement(elemId); if (label.size()!=0) { while(label.size() < addresstable.size()) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh index f7c7216212..4ab0d990fe 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh @@ -24,6 +24,17 @@ class EmulateFunction; +extern AttributeId ATTRIB_LABEL; ///< Marshaling attribute "label" +extern AttributeId ATTRIB_NUM; ///< Marshaling attribute "num" + +extern ElementId ELEM_BASICOVERRIDE; ///< Marshaling element \ +extern ElementId ELEM_DEST; ///< Marshaling element \ +extern ElementId ELEM_JUMPTABLE; ///< Marshaling element \ +extern ElementId ELEM_LOADTABLE; ///< Marshaling element \ +extern ElementId ELEM_NORMADDR; ///< Marshaling element \ +extern ElementId ELEM_NORMHASH; ///< Marshaling element \ +extern ElementId ELEM_STARTVAL; ///< Marshaling element \ + /// \brief Exception thrown for a thunk mechanism that looks like a jump-table struct JumptableThunkError : public LowlevelError { JumptableThunkError(const string &s) : LowlevelError(s) {} ///< Construct with an explanatory string @@ -44,12 +55,12 @@ class LoadTable { int4 size; ///< Size of table entry int4 num; ///< Number of entries in table; public: - LoadTable(void) {} // Constructor for use with restoreXml + LoadTable(void) {} // Constructor for use with decode LoadTable(const Address &ad,int4 sz) { addr = ad, size = sz; num = 1; } ///< Constructor for a single entry table LoadTable(const Address &ad,int4 sz,int4 nm) { addr = ad; size = sz; num = nm; } ///< Construct a full table bool operator<(const LoadTable &op2) const { return (addr < op2.addr); } ///< Compare \b this with another table by address - void saveXml(ostream &s) const; ///< Save a description of \b this as an \ XML tag - void restoreXml(const Element *el,Architecture *glb); ///< Read in \b this table from a \ XML description + void encode(Encoder &encoder) const; ///< Encode a description of \b this as an \ element + void decode(Decoder &decoder,Architecture *glb); ///< Decode \b this table from a \ element static void collapseTable(vector &table); ///< Collapse a sequence of table descriptions }; @@ -308,9 +319,9 @@ public: virtual bool sanityCheck(Funcdata *fd,PcodeOp *indop,vector
&addresstable)=0; virtual JumpModel *clone(JumpTable *jt) const=0; ///< Clone \b this model - virtual void clear(void) {} ///< Clear any non-permanent aspects of the model - virtual void saveXml(ostream &s) const {} ///< Save this model as an XML tag - virtual void restoreXml(const Element *el,Architecture *glb) {} ///< Restore \b this model from an XML tag + virtual void clear(void) {} ///< Clear any non-permanent aspects of the model + virtual void encode(Encoder &encoder) const {} ///< Encode this model to a stream + virtual void decode(Decoder &decoder,Architecture *glb) {} ///< Decode \b this model from a stream }; /// \brief A trivial jump-table model, where the BRANCHIND input Varnode is the switch variable @@ -451,8 +462,8 @@ public: virtual bool sanityCheck(Funcdata *fd,PcodeOp *indop,vector
&addresstable) { return true; } virtual JumpModel *clone(JumpTable *jt) const; virtual void clear(void); - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el,Architecture *glb); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,Architecture *glb); }; class JumpAssistOp; @@ -563,9 +574,9 @@ public: bool recoverLabels(Funcdata *fd); ///< Recover the case labels for \b this jump-table bool checkForMultistage(Funcdata *fd); ///< Check if this jump-table requires an additional recovery stage void clear(void); ///< Clear instance specific data for \b this jump-table - void saveXml(ostream &s) const; ///< Save \b this jump-table as a \ XML tag - void restoreXml(const Element *el); ///< Recover \b this jump-table from a \ XML tag -}; + void encode(Encoder &encoder) const; ///< Encode \b this jump-table as a \ element + void decode(Decoder &decoder); ///< Decode \b this jump-table from a \ element +}; /// \param op2 is the other IndexPair to compare with \b this /// \return \b true if \b this is ordered before the other IndexPair diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/libdecomp.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/libdecomp.cc index cbe30249e4..b60a349fe7 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/libdecomp.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/libdecomp.cc @@ -18,6 +18,8 @@ void startDecompilerLibrary(const char *sleighhome) { + AttributeId::initialize(); + ElementId::initialize(); CapabilityPoint::initializeAll(); ArchitectureCapability::sortCapabilities(); @@ -28,6 +30,8 @@ void startDecompilerLibrary(const char *sleighhome) void startDecompilerLibrary(const vector &extrapaths) { + AttributeId::initialize(); + ElementId::initialize(); CapabilityPoint::initializeAll(); ArchitectureCapability::sortCapabilities(); @@ -38,6 +42,8 @@ void startDecompilerLibrary(const vector &extrapaths) void startDecompilerLibrary(const char *sleighhome,const vector &extrapaths) { + AttributeId::initialize(); + ElementId::initialize(); CapabilityPoint::initializeAll(); ArchitectureCapability::sortCapabilities(); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/loadimage_xml.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/loadimage_xml.cc index 076ba0fdd5..1fbfd4b0e4 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/loadimage_xml.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/loadimage_xml.cc @@ -16,6 +16,11 @@ #include "loadimage_xml.hh" #include "translate.hh" +AttributeId ATTRIB_ARCH = AttributeId("arch",73); + +ElementId ELEM_BINARYIMAGE = ElementId("binaryimage",108); +ElementId ELEM_BYTECHUNK = ElementId("bytechunk",109); + /// \param f is the (path to the) underlying XML file /// \param el is the parsed form of the file LoadImageXml::LoadImageXml(const string &f,const Element *el) : LoadImage(f) @@ -30,37 +35,42 @@ LoadImageXml::LoadImageXml(const string &f,const Element *el) : LoadImage(f) archtype = el->getAttributeValue("arch"); } -/// Write out the byte chunks and symbols as XML tags -/// \param s is the output stream -void LoadImageXml::saveXml(ostream &s) const +/// Encode the byte chunks and symbols as elements +/// \param encoder is the stream encoder +void LoadImageXml::encode(Encoder &encoder) const { - s << "\n"; + encoder.openElement(ELEM_BINARYIMAGE); + encoder.writeString(ATTRIB_ARCH, archtype); map >::const_iterator iter1; for(iter1=chunk.begin();iter1!=chunk.end();++iter1) { const vector &vec((*iter1).second); if (vec.size() == 0) continue; - s << " saveXmlAttributes(s,(*iter1).first.getOffset()); + encoder.openElement(ELEM_BYTECHUNK); + (*iter1).first.getSpace()->encodeAttributes(encoder,(*iter1).first.getOffset()); if (readonlyset.find((*iter1).first) != readonlyset.end()) - s << " readonly=\"true\""; - s << ">\n " << setfill('0'); + encoder.writeBool(ATTRIB_READONLY, "true"); + ostringstream s; + s << '\n' << setfill('0'); for(int4 i=0;i\n"; + s << '\n'; + encoder.writeString(ATTRIB_CONTENT, s.str()); + encoder.closeElement(ELEM_BYTECHUNK); } map::const_iterator iter2; for(iter2=addrtosymbol.begin();iter2!=addrtosymbol.end();++iter2) { - s << " saveXmlAttributes(s,(*iter2).first.getOffset()); - s << " name=\"" << (*iter2).second << "\"/>\n"; + encoder.openElement(ELEM_SYMBOL); + (*iter2).first.getSpace()->encodeAttributes(encoder,(*iter2).first.getOffset()); + encoder.writeString(ATTRIB_NAME, (*iter2).second); + encoder.closeElement(ELEM_SYMBOL); } - s << "\n"; + encoder.closeElement(ELEM_BINARYIMAGE); } /// \param m is for looking up address space @@ -71,35 +81,40 @@ void LoadImageXml::open(const AddrSpaceManager *m) uint4 sz; // unused size // Read parsed xml file - const List &list(rootel->getChildren()); - List::const_iterator iter; - iter = list.begin(); - while(iter != list.end()) { - Element *subel = *iter++; - if (subel->getName()=="symbol") { + XmlDecode decoder(rootel); + uint4 elemId = decoder.openElement(ELEM_BINARYIMAGE); + for(;;) { + uint4 subId = decoder.openElement(); + if (subId == 0) break; + if (subId==ELEM_SYMBOL) { AddrSpace *base = (AddrSpace *)0; - base = manage->getSpaceByName(subel->getAttributeValue("space")); + string spaceName = decoder.readString(ATTRIB_SPACE); + base = manage->getSpaceByName(spaceName); if (base == (AddrSpace *)0) - throw LowlevelError("Unknown space name: "+subel->getAttributeValue("space")); - Address addr(base,base->restoreXmlAttributes(subel,sz)); - const string &nm(subel->getAttributeValue("name")); + throw LowlevelError("Unknown space name: "+spaceName); + Address addr(base,base->decodeAttributes(decoder,sz)); + string nm = decoder.readString(ATTRIB_NAME); addrtosymbol[addr] = nm; } - else if (subel->getName() == "bytechunk") { + else if (subId == ELEM_BYTECHUNK) { AddrSpace *base = (AddrSpace *)0; - base = manage->getSpaceByName(subel->getAttributeValue("space")); + string spaceName = decoder.readString(ATTRIB_SPACE); + base = manage->getSpaceByName(spaceName); if (base == (AddrSpace *)0) - throw LowlevelError("Unknown space name: "+subel->getAttributeValue("space")); - Address addr(base,base->restoreXmlAttributes(subel,sz)); + throw LowlevelError("Unknown space name: "+spaceName); + Address addr(base,base->decodeAttributes(decoder,sz)); map >::iterator chnkiter; vector &vec( chunk[addr] ); vec.clear(); - for(int4 i=0;igetNumAttributes();++i) { - if (subel->getAttributeName(i) == "readonly") - if (xml_readbool(subel->getAttributeValue(i))) + decoder.rewindAttributes(); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_READONLY) + if (decoder.readBool()) readonlyset.insert(addr); } - istringstream is(subel->getContent()); + istringstream is(decoder.readString(ATTRIB_CONTENT)); int4 val; char c1,c2; is >> ws; @@ -126,8 +141,10 @@ void LoadImageXml::open(const AddrSpaceManager *m) } } else - throw LowlevelError("Unknown LoadImageXml tag: "+subel->getName()); + throw LowlevelError("Unknown LoadImageXml tag"); + decoder.closeElement(subId); } + decoder.closeElement(elemId); pad(); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/loadimage_xml.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/loadimage_xml.hh index df13955964..018cc06bb1 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/loadimage_xml.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/loadimage_xml.hh @@ -21,6 +21,11 @@ #include "loadimage.hh" +extern AttributeId ATTRIB_ARCH; ///< Marshaling attribute "arch" + +extern ElementId ELEM_BINARYIMAGE; ///< Marshaling element \ +extern ElementId ELEM_BYTECHUNK; ///< Marshaling element \ + /// \brief Implementation of the LoadImage interface using underlying data stored in an XML format /// /// The image data is stored in an XML file in a \ file. @@ -38,7 +43,7 @@ public: LoadImageXml(const string &f,const Element *el); ///< Constructor void open(const AddrSpaceManager *m); ///< Read XML tags into the containers void clear(void); ///< Clear out all the caches - void saveXml(ostream &s) const; ///< Save the image back out to an XML stream + void encode(Encoder &encoder) const; ///< Encode the image to a stream virtual ~LoadImageXml(void) { clear(); } virtual void loadFill(uint1 *ptr,int4 size,const Address &addr); virtual void openSymbols(void) const; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc new file mode 100644 index 0000000000..0616ede2be --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc @@ -0,0 +1,473 @@ +/* ### + * 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. + */ +#include "marshal.hh" +#include + +unordered_map AttributeId::lookupAttributeId; + +/// Access static vector of AttributeId objects that are registered during static initialization +/// The list itself is created once on the first call to this method. +/// \return a reference to the vector +vector &AttributeId::getList(void) + +{ + static vector thelist; + return thelist; +} + +/// This constructor should only be invoked for static objects. It registers the attribute for inclusion +/// in the global hashtable. +/// \param nm is the name of the attribute +/// \param i is an id to associate with the attribute +AttributeId::AttributeId(const string &nm,uint4 i) + : name(nm) +{ + id = i; + getList().push_back(this); +} + +/// Fill the hashtable mapping attribute names to their id, from registered attribute objects +void AttributeId::initialize(void) + +{ + vector &thelist(getList()); + for(int4 i=0;iname) != lookupAttributeId.end()) + throw XmlError(attrib->name + " attribute registered more than once"); +#endif + lookupAttributeId[attrib->name] = attrib->id; + } + thelist.clear(); + thelist.shrink_to_fit(); +} + +unordered_map ElementId::lookupElementId; + +/// Access static vector of ElementId objects that are registered during static initialization +/// The list itself is created once on the first call to this method. +/// \return a reference to the vector +vector &ElementId::getList(void) + +{ + static vector thelist; + return thelist; +} + +/// This constructor should only be invoked for static objects. It registers the element for inclusion +/// in the global hashtable. +/// \param nm is the name of the element +/// \param i is an id to associate with the element +ElementId::ElementId(const string &nm,uint4 i) + : name(nm) +{ + id = i; + getList().push_back(this); +} + +/// Fill the hashtable mapping element names to their id, from registered element objects +void ElementId::initialize(void) + +{ + vector &thelist(getList()); + for(int4 i=0;iname) != lookupElementId.end()) + throw XmlError(elem->name + " element registered more than once"); +#endif + lookupElementId[elem->name] = elem->id; + } + thelist.clear(); + thelist.shrink_to_fit(); +} + +XmlDecode::~XmlDecode(void) + +{ + if (document != (Document *)0) + delete document; +} + +void XmlDecode::clear(void) + +{ + if (document != (Document *)0) + delete document; + document = (Document *)0; + rootElement = (const Element *)0; + attributeIndex = -1; +} + +void XmlDecode::ingestStream(istream &s) + +{ + document = xml_tree(s); + rootElement = document->getRoot(); +} + +uint4 XmlDecode::peekElement(void) + +{ + const Element *el; + if (elStack.empty()) { + if (rootElement == (const Element *)0) + return 0; + el = rootElement; + } + else { + el = elStack.back(); + List::const_iterator iter = iterStack.back(); + if (iter == el->getChildren().end()) + return 0; + el = *iter; + } + return ElementId::find(el->getName()); +} + +uint4 XmlDecode::openElement(void) + +{ + const Element *el; + if (elStack.empty()) { + if (rootElement == (const Element *)0) + return 0; // Document already traversed + el = rootElement; + rootElement = (const Element *)0; // Only open once + } + else { + el = elStack.back(); + List::const_iterator iter = iterStack.back(); + if (iter == el->getChildren().end()) + return 0; // Element already fully traversed + el = *iter; + iterStack.back() = ++iter; + } + elStack.push_back(el); + iterStack.push_back(el->getChildren().begin()); + attributeIndex = -1; + return ElementId::find(el->getName()); +} + +uint4 XmlDecode::openElement(const ElementId &elemId) + +{ + const Element *el; + if (elStack.empty()) { + if (rootElement == (const Element *)0) + throw XmlError("Expecting <" + elemId.getName() + "> but reached end of document"); + el = rootElement; + rootElement = (const Element *)0; // Only open document once + } + else { + el = elStack.back(); + List::const_iterator iter = iterStack.back(); + if (iter != el->getChildren().end()) { + el = *iter; + iterStack.back() = ++iter; + } + else + throw XmlError("Expecting <" + elemId.getName() + "> but no remaining children in current element"); + } + if (el->getName() != elemId.getName()) + throw XmlError("Expecting <" + elemId.getName() + "> but got <" + el->getName() + ">"); + elStack.push_back(el); + iterStack.push_back(el->getChildren().begin()); + attributeIndex = -1; + return elemId.getId(); +} + +void XmlDecode::closeElement(uint4 id) + +{ +#ifdef CPUI_DEBUG + const Element *el = elStack.back(); + if (iterStack.back() != el->getChildren().end()) + throw XmlError("Closing element <" + el->getName() + "> with additional children"); + if (ElementId::find(el->getName()) != id) + throw XmlError("Trying to close <" + el->getName() + "> with mismatching id"); +#endif + elStack.pop_back(); + iterStack.pop_back(); + attributeIndex = 1000; // Cannot read any additional attributes +} + +void XmlDecode::closeElementSkipping(uint4 id) + +{ +#ifdef CPUI_DEBUG + const Element *el = elStack.back(); + if (ElementId::find(el->getName()) != id) + throw XmlError("Trying to close <" + el->getName() + "> with mismatching id"); +#endif + elStack.pop_back(); + iterStack.pop_back(); + attributeIndex = 1000; // We could check that id matches current element +} + +void XmlDecode::rewindAttributes(void) + +{ + attributeIndex = -1; +} + +uint4 XmlDecode::getNextAttributeId(void) + +{ + const Element *el = elStack.back(); + int4 nextIndex = attributeIndex + 1; + if (nextIndex < el->getNumAttributes()) { + attributeIndex = nextIndex; + return AttributeId::find(el->getAttributeName(attributeIndex)); + } + return 0; +} + +/// \brief Find the attribute index, within the given element, for the given name +/// +/// Run through the attributes of the element until we find the one matching the name, +/// or throw an exception otherwise. +/// \param el is the given element to search +/// \param attribName is the attribute name to search for +/// \return the matching attribute index +int4 XmlDecode::findMatchingAttribute(const Element *el,const string &attribName) + +{ + for(int4 i=0;igetNumAttributes();++i) { + if (el->getAttributeName(i) == attribName) + return i; + } + throw XmlError("Attribute missing: " + attribName); +} + +bool XmlDecode::readBool(void) + +{ + const Element *el = elStack.back(); + return xml_readbool(el->getAttributeValue(attributeIndex)); +} + +bool XmlDecode::readBool(const AttributeId &attribId) + +{ + const Element *el = elStack.back(); + if (attribId == ATTRIB_CONTENT) + return xml_readbool(el->getContent()); + int4 index = findMatchingAttribute(el, attribId.getName()); + return xml_readbool(el->getAttributeValue(index)); +} + +intb XmlDecode::readSignedInteger(void) + +{ + const Element *el = elStack.back(); + intb res = 0; + istringstream s2(el->getAttributeValue(attributeIndex)); + s2.unsetf(ios::dec | ios::hex | ios::oct); + s2 >> res; + return res; +} + +intb XmlDecode::readSignedInteger(const AttributeId &attribId) + +{ + const Element *el = elStack.back(); + intb res = 0; + if (attribId == ATTRIB_CONTENT) { + istringstream s(el->getContent()); + s.unsetf(ios::dec | ios::hex | ios::oct); + s >> res; + } + else { + int4 index = findMatchingAttribute(el, attribId.getName()); + istringstream s(el->getAttributeValue(index)); + s.unsetf(ios::dec | ios::hex | ios::oct); + s >> res; + } + return res; +} + +uintb XmlDecode::readUnsignedInteger(void) + +{ + const Element *el = elStack.back(); + uintb res = 0; + istringstream s2(el->getAttributeValue(attributeIndex)); + s2.unsetf(ios::dec | ios::hex | ios::oct); + s2 >> res; + return res; +} + +uintb XmlDecode::readUnsignedInteger(const AttributeId &attribId) + +{ + const Element *el = elStack.back(); + uintb res = 0; + if (attribId == ATTRIB_CONTENT) { + istringstream s(el->getContent()); + s.unsetf(ios::dec | ios::hex | ios::oct); + s >> res; + } + else { + int4 index = findMatchingAttribute(el, attribId.getName()); + istringstream s(el->getAttributeValue(index)); + s.unsetf(ios::dec | ios::hex | ios::oct); + s >> res; + } + return res; +} + +string XmlDecode::readString(void) + +{ + const Element *el = elStack.back(); + return el->getAttributeValue(attributeIndex); +} + +string XmlDecode::readString(const AttributeId &attribId) + +{ + const Element *el = elStack.back(); + if (attribId == ATTRIB_CONTENT) + return el->getContent(); + int4 index = findMatchingAttribute(el, attribId.getName()); + return el->getAttributeValue(index); +} + +void XmlEncode::openElement(const ElementId &elemId) + +{ + if (elementTagIsOpen) + outStream << '>'; + else + elementTagIsOpen = true; + outStream << '<' << elemId.getName(); +} + +void XmlEncode::closeElement(const ElementId &elemId) + +{ + if (elementTagIsOpen) { + outStream << "/>"; + elementTagIsOpen = false; + } + else { + outStream << "'; + } +} + +void XmlEncode::writeBool(const AttributeId &attribId,bool val) + +{ + if (attribId == ATTRIB_CONTENT) { // Special id indicating, text value + if (elementTagIsOpen) { + outStream << '>'; + elementTagIsOpen = false; + } + if (val) + outStream << "true"; + else + outStream << "false"; + return; + } + a_v_b(outStream, attribId.getName(), val); +} + +void XmlEncode::writeSignedInteger(const AttributeId &attribId,intb val) + +{ + if (attribId == ATTRIB_CONTENT) { // Special id indicating, text value + if (elementTagIsOpen) { + outStream << '>'; + elementTagIsOpen = false; + } + outStream << dec << val; + return; + } + a_v_i(outStream, attribId.getName(), val); +} + +void XmlEncode::writeUnsignedInteger(const AttributeId &attribId,uintb val) + +{ + if (attribId == ATTRIB_CONTENT) { // Special id indicating, text value + if (elementTagIsOpen) { + outStream << '>'; + elementTagIsOpen = false; + } + outStream << hex << "0x" << val; + return; + } + a_v_u(outStream, attribId.getName(), val); +} + +void XmlEncode::writeString(const AttributeId &attribId,const string &val) + +{ + if (attribId == ATTRIB_CONTENT) { // Special id indicating, text value + if (elementTagIsOpen) { + outStream << '>'; + elementTagIsOpen = false; + } + xml_escape(outStream, val.c_str()); + return; + } + a_v(outStream,attribId.getName(),val); +} + +// Common attributes. Attributes with multiple uses +AttributeId ATTRIB_CONTENT = AttributeId("XMLcontent",1); +AttributeId ATTRIB_ALIGN = AttributeId("align",2); +AttributeId ATTRIB_BIGENDIAN = AttributeId("bigendian",3); +AttributeId ATTRIB_CONSTRUCTOR = AttributeId("constructor",4); +AttributeId ATTRIB_DESTRUCTOR = AttributeId("destructor",5); +AttributeId ATTRIB_EXTRAPOP = AttributeId("extrapop",6); +AttributeId ATTRIB_FORMAT = AttributeId("format",7); +AttributeId ATTRIB_HIDDENRETPARM = AttributeId("hiddenretparm",8); +AttributeId ATTRIB_ID = AttributeId("id",9); +AttributeId ATTRIB_INDEX = AttributeId("index",10); +AttributeId ATTRIB_INDIRECTSTORAGE = AttributeId("indirectstorage",11); +AttributeId ATTRIB_METATYPE = AttributeId("metatype",12); +AttributeId ATTRIB_MODEL = AttributeId("model",13); +AttributeId ATTRIB_NAME = AttributeId("name",14); +AttributeId ATTRIB_NAMELOCK = AttributeId("namelock",15); +AttributeId ATTRIB_OFFSET = AttributeId("offset",16); +AttributeId ATTRIB_READONLY = AttributeId("readonly",17); +AttributeId ATTRIB_REF = AttributeId("ref",18); +AttributeId ATTRIB_SIZE = AttributeId("size",19); +AttributeId ATTRIB_SPACE = AttributeId("space",20); +AttributeId ATTRIB_THISPTR = AttributeId("thisptr",21); +AttributeId ATTRIB_TYPE = AttributeId("type",22); +AttributeId ATTRIB_TYPELOCK = AttributeId("typelock",23); +AttributeId ATTRIB_VAL = AttributeId("val",24); +AttributeId ATTRIB_VALUE = AttributeId("value",25); +AttributeId ATTRIB_WORDSIZE = AttributeId("wordsize",26); + +AttributeId ATTRIB_UNKNOWN = AttributeId("XMLunknown",136); // Number serves as next open index + +ElementId ELEM_DATA = ElementId("data",1); +ElementId ELEM_INPUT = ElementId("input",2); +ElementId ELEM_OFF = ElementId("off",3); +ElementId ELEM_OUTPUT = ElementId("output",4); +ElementId ELEM_RETURNADDRESS = ElementId("returnaddress",5); +ElementId ELEM_SYMBOL = ElementId("symbol",6); +ElementId ELEM_TARGET = ElementId("target",7); +ElementId ELEM_VAL = ElementId("val",8); +ElementId ELEM_VALUE = ElementId("value",9); +ElementId ELEM_VOID = ElementId("void",10); + +ElementId ELEM_UNKNOWN = ElementId("XMLunknown",208); // Number serves as next open index diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.hh new file mode 100644 index 0000000000..11c7548e17 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.hh @@ -0,0 +1,409 @@ +/* ### + * 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. + */ +#ifndef __CPUI_MARSHAL__ +#define __CPUI_MARSHAL__ + +#include "xml.hh" +#include + +using namespace std; + +/// \brief An annotation for a data element to being transferred to/from a stream +/// +/// This class parallels the XML concept of an \b attribute on an element. An AttributeId describes +/// a particular piece of data associated with an ElementId. The defining characteristic of the AttributeId is +/// its name. Internally this name is associated with an integer id. The name (and id) uniquely determine +/// the data being labeled, within the context of a specific ElementId. Within this context, an AttributeId labels either +/// - An unsigned integer +/// - A signed integer +/// - A boolean value +/// - A string +/// +/// The same AttributeId can be used to label a different type of data when associated with a different ElementId. +class AttributeId { + static unordered_map lookupAttributeId; ///< A map of AttributeId names to their associated id + static vector &getList(void); ///< Retrieve the list of static AttributeId + string name; ///< The name of the attribute + uint4 id; ///< The (internal) id of the attribute +public: + AttributeId(const string &nm,uint4 i); ///< Construct given a name and id + const string &getName(void) const { return name; } ///< Get the attribute's name + uint4 getId(void) const { return id; } ///< Get the attribute's id + bool operator==(const AttributeId &op2) const { return (id == op2.id); } ///< Test equality with another AttributeId + static uint4 find(const string &nm); ///< Find the id associated with a specific attribute name + static void initialize(void); ///< Populate a hashtable with all AttributeId objects + friend bool operator==(uint4 id,const AttributeId &op2) { return (id == op2.id); } ///< Test equality of a raw integer id with an AttributeId + friend bool operator==(const AttributeId &op1,uint4 id) { return (op1.id == id); } ///< Test equality of an AttributeId with a raw integer id +}; + +/// \brief An annotation for a specific collection of hierarchical data +/// +/// This class parallels the XML concept of an \b element. An ElementId describes a collection of data, where each +/// piece is annotated by a specific AttributeId. In addition, each ElementId can contain zero or more \e child +/// ElementId objects, forming a hierarchy of annotated data. Each ElementId has a name, which is unique at least +/// within the context of its parent ElementId. Internally this name is associated with an integer id. A special +/// AttributeId ATTRIB_CONTENT is used to label the XML element's text content, which is traditionally not labeled +/// as an attribute. +class ElementId { + static unordered_map lookupElementId; ///< A map of ElementId names to their associated id + static vector &getList(void); ///< Retrieve the list of static ElementId + string name; ///< The name of the element + uint4 id; ///< The (internal) id of the attribute +public: + ElementId(const string &nm,uint4 i); ///< Construct given a name and id + const string &getName(void) const { return name; } ///< Get the element's name + uint4 getId(void) const { return id; } ///< Get the element's id + bool operator==(const ElementId &op2) const { return (id == op2.id); } ///< Test equality with another ElementId + static uint4 find(const string &nm); ///< Find the id associated with a specific element name + static void initialize(void); ///< Populate a hashtable with all ElementId objects + friend bool operator==(uint4 id,const ElementId &op2) { return (id == op2.id); } ///< Test equality of a raw integer id with an ElementId + friend bool operator==(const ElementId &op1,uint4 id) { return (op1.id == id); } ///< Test equality of an ElementId with a raw integer id + friend bool operator!=(uint4 id,const ElementId &op2) { return (id != op2.id); } ///< Test inequality of a raw integer id with an ElementId + friend bool operator!=(const ElementId &op1,uint4 id) { return (op1.id != id); } ///< Test inequality of an ElementId with a raw integer id +}; + +/// \brief A class for reading structured data from a stream +/// +/// All data is loosely structured as with an XML document. A document contains a nested set +/// of \b elements, with labels corresponding to the ElementId class. A single element can hold +/// zero or more attributes and zero or more child elements. An attribute holds a primitive +/// data element (bool, integer, string) and is labeled by an AttributeId. The document is traversed +/// using a sequence of openElement() and closeElement() calls, intermixed with read*() calls to extract +/// the data. The elements are traversed in a depth first order. Attributes within an element can +/// be traversed in order using repeated calls to the getNextAttributeId() method, followed by a calls to +/// one of the read*(void) methods to extract the data. Alternately a read*(AttributeId) call can be used +/// to extract data for an attribute known to be in the element. There is a special content attribute +/// whose data can be extracted using a read*(AttributeId) call that is passed the special ATTRIB_CONTENT id. +/// This attribute will not be traversed by getNextAttribute(). +class Decoder { +public: + virtual ~Decoder(void) {} ///< Destructor + + /// \brief Clear any current decoding state + /// + /// Allows the same decoder to be reused. Object is ready for new call to ingestStream. + virtual void clear(void)=0; + + /// \brief Prepare to decode a given stream + /// + /// Called once before any decoding. Currently this is assumed to make an internal copy of the stream data, + /// i.e. the input stream is cleared before any decoding takes place. + /// \param s is the given input stream to be decode + /// \return \b true if the stream was fully ingested + virtual void ingestStream(istream &s)=0; + + /// \brief Peek at the next child element of the current parent, without traversing in (opening) it. + /// + /// The element id is returned, which can be compared to ElementId labels. + /// If there are no remaining child elements to traverse, 0 is returned. + /// \return the element id or 0 + virtual uint4 peekElement(void)=0; + + /// \brief Open (traverse into) the next child element of the current parent. + /// + /// The child becomes the current parent. The list of attributes is initialized for use with getNextAttributeId. + /// \return the id of the child element + virtual uint4 openElement(void)=0; + + /// \brief Open (traverse into) the next child element, which must be of a specific type + /// + /// The child becomes the current parent, and its attributes are initialized for use with getNextAttributeId. + /// The child must match the given element id or an exception is thrown. + /// \param elemId is the given element id to match + /// \return the id of the child element + virtual uint4 openElement(const ElementId &elemId)=0; + + /// \brief Close the current element + /// + /// The data for the current element is considered fully processed. If the element has additional children, + /// an exception is thrown. The stream must indicate the end of the element in some way. + /// \param id is the id of the element to close (which must be the current element) + virtual void closeElement(uint4 id)=0; + + /// \brief Close the current element, skipping any child elements that have not yet been parsed + /// + /// This closes the given element, which must be current. If there are child elements that have not been + /// parsed, this is not considered an error, and they are skipped over in the parse. + /// \param id is the id of the element to close (which must be the current element) + virtual void closeElementSkipping(uint4 id)=0; + + /// \brief Get the next attribute id for the current element + /// + /// Attributes are automatically set up for traversal using this method, when the element is opened. + /// If all attributes have been traversed (or there are no attributes), 0 is returned. + /// \return the id of the next attribute or 0 + virtual uint4 getNextAttributeId(void)=0; + + /// \brief Reset attribute traversal for the current element + /// + /// Attributes for a single element can be traversed more than once using the getNextAttributeId method. + virtual void rewindAttributes(void)=0; + + /// \brief Parse the current attribute as a boolean value + /// + /// The last attribute, as returned by getNextAttributeId, is treated as a boolean, and its value is returned. + /// \return the boolean value associated with the current attribute. + virtual bool readBool(void)=0; + + /// \brief Find and parse a specific attribute in the current element as a boolean value + /// + /// The set of attributes for the current element is searched for a match to the given attribute id. + /// This attribute is then parsed as a boolean and its value returned. + /// If there is no attribute matching the id, an exception is thrown. + /// Parsing via getNextAttributeId is reset. + /// \param attribId is the specific attribute id to match + /// \return the boolean value + virtual bool readBool(const AttributeId &attribId)=0; + + /// \brief Parse the current attribute as a signed integer value + /// + /// The last attribute, as returned by getNextAttributeId, is treated as a signed integer, and its value is returned. + /// \return the signed integer value associated with the current attribute. + virtual intb readSignedInteger(void)=0; + + /// \brief Find and parse a specific attribute in the current element as a signed integer + /// + /// The set of attributes for the current element is searched for a match to the given attribute id. + /// This attribute is then parsed as a signed integer and its value returned. + /// If there is no attribute matching the id, an exception is thrown. + /// Parsing via getNextAttributeId is reset. + /// \param attribId is the specific attribute id to match + /// \return the signed integer value + virtual intb readSignedInteger(const AttributeId &attribId)=0; + + /// \brief Parse the current attribute as an unsigned integer value + /// + /// The last attribute, as returned by getNextAttributeId, is treated as an unsigned integer, and its value is returned. + /// \return the unsigned integer value associated with the current attribute. + virtual uintb readUnsignedInteger(void)=0; + + /// \brief Find and parse a specific attribute in the current element as an unsigned integer + /// + /// The set of attributes for the current element is searched for a match to the given attribute id. + /// This attribute is then parsed as an unsigned integer and its value returned. + /// If there is no attribute matching the id, an exception is thrown. + /// Parsing via getNextAttributeId is reset. + /// \param attribId is the specific attribute id to match + /// \return the unsigned integer value + virtual uintb readUnsignedInteger(const AttributeId &attribId)=0; + + /// \brief Parse the current attribute as a string + /// + /// The last attribute, as returned by getNextAttributeId, is returned as a string. + /// \return the string associated with the current attribute. + virtual string readString(void)=0; + + /// \brief Find the specific attribute in the current element and return it as a string + /// + /// The set of attributes for the current element is searched for a match to the given attribute id. + /// This attribute is then returned as a string. If there is no attribute matching the id, and exception is thrown. + /// Parse via getNextAttributeId is reset. + /// \param attribId is the specific attribute id to match + /// \return the string associated with the attribute + virtual string readString(const AttributeId &attribId)=0; + + /// \brief Skip parsing of the next element + /// + /// The element skipped is the one that would be opened by the next call to openElement. + void skipElement(void) { + uint4 elemId = openElement(); + closeElementSkipping(elemId); + } +}; + +/// \brief A class for writing structured data to a stream +/// +/// The resulting encoded data is structured similarly to an XML document. The document contains a nested set +/// of \b elements, with labels corresponding to the ElementId class. A single element can hold +/// zero or more attributes and zero or more child elements. An \b attribute holds a primitive +/// data element (bool, integer, string) and is labeled by an AttributeId. The document is written +/// using a sequence of openElement() and closeElement() calls, intermixed with write*() calls to encode +/// the data primitives. All primitives written using a write*() call are associated with current open element, +/// and all write*() calls for one element must come before opening any child element. +/// The traditional XML element text content can be written using the special ATTRIB_CONTENT AttributeId, which +/// must be the last write*() call associated with the specific element. +class Encoder { +public: + virtual ~Encoder(void) {} ///< Destructor + + /// \brief Clear any state associated with the encoder + /// + /// The encoder should be ready to write a new document after this call. + virtual void clear(void)=0; + + /// \brief Begin a new element in the encoding + /// + /// The element will have the given ElementId annotation and becomes the \e current element. + /// \param elemId is the given ElementId annotation + virtual void openElement(const ElementId &elemId)=0; + + /// \brief End the current element in the encoding + /// + /// The current element must match the given annotation or an exception is thrown. + /// \param elemId is the given (expected) annotation for the current element + virtual void closeElement(const ElementId &elemId)=0; + + /// \brief Write an annotated boolean value into the encoding + /// + /// The boolean data is associated with the given AttributeId annotation and the current open element. + /// \param attribId is the given AttributeId annotation + /// \param val is boolean value to encode + virtual void writeBool(const AttributeId &attribId,bool val)=0; + + /// \brief Write an annotated signed integer value into the encoding + /// + /// The integer is associated with the given AttributeId annotation and the current open element. + /// \param attribId is the given AttributeId annotation + /// \param val is the signed integer value to encode + virtual void writeSignedInteger(const AttributeId &attribId,intb val)=0; + + /// \brief Write an annotated unsigned integer value into the encoding + /// + /// The integer is associated with the given AttributeId annotation and the current open element. + /// \param attribId is the given AttributeId annotation + /// \param val is the unsigned integer value to encode + virtual void writeUnsignedInteger(const AttributeId &attribId,uintb val)=0; + + /// \brief Write an annotated string into the encoding + /// + /// The string is associated with the given AttributeId annotation and the current open element. + /// \param attribId is the given AttributeId annotation + /// \param val is the string to encode + virtual void writeString(const AttributeId &attribId,const string &val)=0; +}; + +/// \brief An XML based decoder +/// +/// The underlying transfer encoding is an XML document. The decoder can either be initialized with an +/// existing Element as the root of the data to transfer, or the ingestStream() method can be invoked +/// to read the XML document from an input stream, in which case the decoder manages the Document object. +class XmlDecode : public Decoder { + Document *document; ///< An ingested XML document, owned by \b this decoder + const Element *rootElement; ///< The root XML element to be decoded + vector elStack; ///< Stack of currently \e open elements + vector iterStack; ///< Index of next child for each \e open element + int4 attributeIndex; ///< Position of \e current attribute to parse (in \e current element) + int4 findMatchingAttribute(const Element *el,const string &attribName); +public: + XmlDecode(const Element *root) { document = (Document *)0; rootElement = root; attributeIndex = -1; } ///< Constructor with preparsed root + XmlDecode(void) { document = (Document *)0; rootElement = (const Element *)0; attributeIndex = -1; } ///< Constructor for use with ingestStream + virtual ~XmlDecode(void); + virtual void clear(void); + virtual void ingestStream(istream &s); + virtual uint4 peekElement(void); + virtual uint4 openElement(void); + virtual uint4 openElement(const ElementId &elemId); + virtual void closeElement(uint4 id); + virtual void closeElementSkipping(uint4 id); + virtual void rewindAttributes(void); + virtual uint4 getNextAttributeId(void); + virtual bool readBool(void); + virtual bool readBool(const AttributeId &attribId); + virtual intb readSignedInteger(void); + virtual intb readSignedInteger(const AttributeId &attribId); + virtual uintb readUnsignedInteger(void); + virtual uintb readUnsignedInteger(const AttributeId &attribId); + virtual string readString(void); + virtual string readString(const AttributeId &attribId); +}; + +/// \brief An XML based encoder +/// +/// The underlying transfer encoding is an XML document. The encoder is initialized with a stream which will +/// receive the XML document as calls are made on the encoder. +class XmlEncode : public Encoder { + friend class XmlDecode; + ostream &outStream; ///< The stream receiving the encoded data + bool elementTagIsOpen; ///< If \b true, new attributes can be written to the current element +public: + XmlEncode(ostream &s) : outStream(s) { elementTagIsOpen = false; } ///< Construct from a stream + virtual void clear(void) { elementTagIsOpen = false; } + virtual void openElement(const ElementId &elemId); + virtual void closeElement(const ElementId &elemId); + virtual void writeBool(const AttributeId &attribId,bool val); + virtual void writeSignedInteger(const AttributeId &attribId,intb val); + virtual void writeUnsignedInteger(const AttributeId &attribId,uintb val); + virtual void writeString(const AttributeId &attribId,const string &val); +}; + +extern ElementId ELEM_UNKNOWN; ///< Special element to represent an element with an unrecognized name +extern AttributeId ATTRIB_UNKNOWN; ///< Special attribute to represent an attribute with an unrecognized name +extern AttributeId ATTRIB_CONTENT; ///< Special attribute for XML text content of an element + +/// The name is looked up in the global list of all attributes. If the attribute is not in the list, a special +/// placeholder attribute, ATTRIB_UNKNOWN, is returned as a placeholder for attributes with unrecognized names. +/// \param nm is the name of the attribute +/// \return the associated id +inline uint4 AttributeId::find(const string &nm) + +{ + unordered_map::const_iterator iter = lookupAttributeId.find(nm); + if (iter != lookupAttributeId.end()) + return (*iter).second; + return ATTRIB_UNKNOWN.id; +} + +/// The name is looked up in the global list of all elements. If the element is not in the list, a special +/// placeholder element, ELEM_UNKNOWN, is returned as a placeholder for elements with unrecognized names. +/// \param nm is the name of the element +/// \return the associated id +inline uint4 ElementId::find(const string &nm) + +{ + unordered_map::const_iterator iter = lookupElementId.find(nm); + if (iter != lookupElementId.end()) + return (*iter).second; + return ELEM_UNKNOWN.id; +} + +extern AttributeId ATTRIB_ALIGN; ///< Marshaling attribute "align" +extern AttributeId ATTRIB_BIGENDIAN; ///< Marshaling attribute "bigendian" +extern AttributeId ATTRIB_CONSTRUCTOR; ///< Marshaling attribute "constructor" +extern AttributeId ATTRIB_DESTRUCTOR; ///< Marshaling attribute "destructor" +extern AttributeId ATTRIB_EXTRAPOP; ///< Marshaling attribute "extrapop" +extern AttributeId ATTRIB_FORMAT; ///< Marshaling attribute "format" +extern AttributeId ATTRIB_HIDDENRETPARM; ///< Marshaling attribute "hiddenretparm" +extern AttributeId ATTRIB_ID; ///< Marshaling attribute "id" +extern AttributeId ATTRIB_INDEX; ///< Marshaling attribute "index" +extern AttributeId ATTRIB_INDIRECTSTORAGE; ///< Marshaling attribute "indirectstorage" +extern AttributeId ATTRIB_METATYPE; ///< Marshaling attribute "metatype" +extern AttributeId ATTRIB_MODEL; ///< Marshaling attribute "model" +extern AttributeId ATTRIB_NAME; ///< Marshaling attribute "name" +extern AttributeId ATTRIB_NAMELOCK; ///< Marshaling attribute "namelock" +extern AttributeId ATTRIB_OFFSET; ///< Marshaling attribute "offset" +extern AttributeId ATTRIB_READONLY; ///< Marshaling attribute "readonly" +extern AttributeId ATTRIB_REF; ///< Marshaling attribute "ref" +extern AttributeId ATTRIB_SIZE; ///< Marshaling attribute "size" +extern AttributeId ATTRIB_SPACE; ///< Marshaling attribute "space" +extern AttributeId ATTRIB_THISPTR; ///< Marshaling attribute "thisptr" +extern AttributeId ATTRIB_TYPE; ///< Marshaling attribute "type" +extern AttributeId ATTRIB_TYPELOCK; ///< Marshaling attribute "typelock" +extern AttributeId ATTRIB_VAL; ///< Marshaling attribute "val" +extern AttributeId ATTRIB_VALUE; ///< Marshaling attribute "value" +extern AttributeId ATTRIB_WORDSIZE; ///< Marshaling attribute "wordsize" + +extern ElementId ELEM_DATA; ///< Marshaling element \ +extern ElementId ELEM_INPUT; ///< Marshaling element \ +extern ElementId ELEM_OFF; ///< Marshaling element \ +extern ElementId ELEM_OUTPUT; ///< Marshaling element \ +extern ElementId ELEM_RETURNADDRESS; ///< Marshaling element \ +extern ElementId ELEM_SYMBOL; ///< Marshaling element \ +extern ElementId ELEM_TARGET; ///< Marshaling element \ +extern ElementId ELEM_VAL; ///< Marshaling element \ +extern ElementId ELEM_VALUE; ///< Marshaling element \ +extern ElementId ELEM_VOID; ///< Marshaling element \ + +#endif diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc index bd359393ea..755704dec6 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc @@ -16,6 +16,8 @@ #include "op.hh" #include "funcdata.hh" +ElementId ELEM_IOP = ElementId("iop",110); + const string IopSpace::NAME = "iop"; /// Constructor for the \b iop space. @@ -56,13 +58,13 @@ void IopSpace::printRaw(ostream &s,uintb offset) const void IopSpace::saveXml(ostream &s) const { - throw LowlevelError("Should never save iop space to XML"); + throw LowlevelError("Should never encode iop space to stream"); } -void IopSpace::restoreXml(const Element *el) +void IopSpace::decode(Decoder &decoder) { - throw LowlevelError("Should never restore iop space from XML"); + throw LowlevelError("Should never decode iop space from stream"); } /// Construct a completely unattached PcodeOp. Space is reserved for input and output Varnodes @@ -385,50 +387,62 @@ void PcodeOp::printDebug(ostream &s) const printRaw(s); } -/// Write a description including: the opcode name, the sequence number, and separate xml tags +/// Encode a description including: the opcode name, the sequence number, and separate elements /// providing a reference number for each input and output Varnode -/// \param s is the stream to write to -void PcodeOp::saveXml(ostream &s) const +/// \param encoder is the stream encoder +void PcodeOp::encode(Encoder &encoder) const { - s << "\n"; - start.saveXml(s); - s << '\n'; - if (output==(Varnode *)0) - s << "\n"; - else - s << "getCreateIndex() << "\"/>\n"; + encoder.openElement(ELEM_OP); + encoder.writeSignedInteger(ATTRIB_CODE, (int4)code()); + start.encode(encoder); + if (output==(Varnode *)0) { + encoder.openElement(ELEM_VOID); + encoder.closeElement(ELEM_VOID); + } + else { + encoder.openElement(ELEM_ADDR); + encoder.writeUnsignedInteger(ATTRIB_REF, output->getCreateIndex()); + encoder.closeElement(ELEM_ADDR); + } for(int4 i=0;i\n"; + if (vn == (const Varnode *)0) { + encoder.openElement(ELEM_VOID); + encoder.closeElement(ELEM_VOID); + } else if (vn->getSpace()->getType()==IPTR_IOP) { if ((i==1)&&(code()==CPUI_INDIRECT)) { PcodeOp *indop = PcodeOp::getOpFromConst(vn->getAddr()); - s << "getSeqNum().getTime()); - s << "/>\n"; + encoder.openElement(ELEM_IOP); + encoder.writeUnsignedInteger(ATTRIB_VALUE, indop->getSeqNum().getTime()); + encoder.closeElement(ELEM_IOP); + } + else { + encoder.openElement(ELEM_VOID); + encoder.closeElement(ELEM_VOID); } - else - s << "\n"; } else if (vn->getSpace()->getType()==IPTR_CONSTANT) { if ((i==0)&&((code()==CPUI_STORE)||(code()==CPUI_LOAD))) { AddrSpace *spc = vn->getSpaceFromConst(); - s << "getName()); - s << "/>\n"; + encoder.openElement(ELEM_SPACEID); + encoder.writeString(ATTRIB_NAME, spc->getName()); + encoder.closeElement(ELEM_SPACEID); + } + else { + encoder.openElement(ELEM_ADDR); + encoder.writeUnsignedInteger(ATTRIB_REF, vn->getCreateIndex()); + encoder.closeElement(ELEM_ADDR); } - else - s << "getCreateIndex() << "\"/>\n"; } else { - s << "getCreateIndex() << "\"/>\n"; + encoder.openElement(ELEM_ADDR); + encoder.writeUnsignedInteger(ATTRIB_REF, vn->getCreateIndex()); + encoder.closeElement(ELEM_ADDR); } } - s << "\n"; + encoder.closeElement(ELEM_OP); } /// Assuming all the inputs to this op are constants, compute the constant result of evaluating diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh index e2d234767f..c0f93456c4 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh @@ -20,6 +20,8 @@ #include "typeop.hh" +extern ElementId ELEM_IOP; ///< Marshaling element \ + /// \brief Space for storing internal PcodeOp pointers as addresses /// /// It is convenient and efficient to replace the formally encoded @@ -32,11 +34,11 @@ class IopSpace : public AddrSpace { public: IopSpace(AddrSpaceManager *m,const Translate *t,int4 ind); - virtual void saveXmlAttributes(ostream &s,uintb offset) const { s << " space=\"iop\""; } - virtual void saveXmlAttributes(ostream &s,uintb offset,int4 size) const { s << " space=\"iop\""; } + virtual void encodeAttributes(Encoder &encoder,uintb offset) const { encoder.writeString(ATTRIB_SPACE, "iop"); } + virtual void encodeAttributes(Encoder &encoder,uintb offset,int4 size) const { encoder.writeString(ATTRIB_SPACE, "iop"); } virtual void printRaw(ostream &s,uintb offset) const; virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el); + virtual void decode(Decoder &decoder); static const string NAME; ///< Reserved name for the iop space }; @@ -226,7 +228,7 @@ public: void printRaw(ostream &s) const { opcode->printRaw(s,this); } ///< Print raw info about this op to stream const string &getOpName(void) const { return opcode->getName(); } ///< Return the name of this op void printDebug(ostream &s) const; ///< Print debug description of this op to stream - void saveXml(ostream &s) const; ///< Write an XML description of this op to stream + void encode(Encoder &encoder) const; ///< Encode a description of \b this op to stream /// \brief Retrieve the PcodeOp encoded as the address \e addr static PcodeOp *getOpFromConst(const Address &addr) { return (PcodeOp *)(uintp)addr.getOffset(); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc index 12dd1874e8..b6c2417719 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc @@ -18,6 +18,44 @@ #include "flow.hh" #include "printc.hh" +ElementId ELEM_ALIASBLOCK = ElementId("aliasblock",111); +ElementId ELEM_ALLOWCONTEXTSET = ElementId("allowcontextset",112); +ElementId ELEM_ANALYZEFORLOOPS = ElementId("analyzeforloops",113); +ElementId ELEM_COMMENTHEADER = ElementId("commentheader",114); +ElementId ELEM_COMMENTINDENT = ElementId("commentindent",115); +ElementId ELEM_COMMENTINSTRUCTION = ElementId("commentinstruction",116); +ElementId ELEM_COMMENTSTYLE = ElementId("commentstyle",117); +ElementId ELEM_CONVENTIONPRINTING = ElementId("conventionprinting",118); +ElementId ELEM_CURRENTACTION = ElementId("currentaction",119); +ElementId ELEM_DEFAULTPROTOTYPE = ElementId("defaultprototype",120); +ElementId ELEM_ERRORREINTERPRETED = ElementId("errorreinterpreted",121); +ElementId ELEM_ERRORTOOMANYINSTRUCTIONS = ElementId("errortoomanyinstructions",122); +ElementId ELEM_ERRORUNIMPLEMENTED = ElementId("errorunimplemented",123); +ElementId ELEM_EXTRAPOP = ElementId("extrapop",124); +ElementId ELEM_IGNOREUNIMPLEMENTED = ElementId("ignoreunimplemented",125); +ElementId ELEM_INDENTINCREMENT = ElementId("indentincrement",126); +ElementId ELEM_INFERCONSTPTR = ElementId("inferconstptr",127); +ElementId ELEM_INLINE = ElementId("inline",128); +ElementId ELEM_INPLACEOPS = ElementId("inplaceops",129); +ElementId ELEM_INTEGERFORMAT = ElementId("integerformat",130); +ElementId ELEM_JUMPLOAD = ElementId("jumpload",131); +ElementId ELEM_MAXINSTRUCTION = ElementId("maxinstruction",132); +ElementId ELEM_MAXLINEWIDTH = ElementId("maxlinewidth",133); +ElementId ELEM_NAMESPACESTRATEGY = ElementId("namespacestrategy",134); +ElementId ELEM_NOCASTPRINTING = ElementId("nocastprinting",135); +ElementId ELEM_NORETURN = ElementId("noreturn",136); +ElementId ELEM_NULLPRINTING = ElementId("nullprinting",137); +ElementId ELEM_OPTIONSLIST = ElementId("optionslist",138); +ElementId ELEM_PARAM1 = ElementId("param1",139); +ElementId ELEM_PARAM2 = ElementId("param2",140); +ElementId ELEM_PARAM3 = ElementId("param3",141); +ElementId ELEM_PROTOEVAL = ElementId("protoeval",142); +ElementId ELEM_SETACTION = ElementId("setaction",143); +ElementId ELEM_SETLANGUAGE = ElementId("setlanguage",144); +ElementId ELEM_STRUCTALIGN = ElementId("structalign",145); +ElementId ELEM_TOGGLERULE = ElementId("togglerule",146); +ElementId ELEM_WARNING = ElementId("warning",147); + /// If the parameter is "on" return \b true, if "off" return \b false. /// Any other value causes an exception. /// \param p is the parameter @@ -40,7 +78,8 @@ bool ArchOption::onOrOff(const string &p) void OptionDatabase::registerOption(ArchOption *option) { - optionmap[option->getName()] = option; + uint4 id = ElementId::find(option->getName()); // Option name must match a known element name + optionmap[id] = option; } /// Register all possible ArchOption objects with this database and set-up the parsing map. @@ -88,69 +127,67 @@ OptionDatabase::OptionDatabase(Architecture *g) OptionDatabase::~OptionDatabase(void) { - map::iterator iter; + map::iterator iter; for(iter=optionmap.begin();iter!=optionmap.end();++iter) delete (*iter).second; } -/// Perform an \e option \e command directly, given its name and optional parameters -/// \param nm is the registered name of the option +/// Perform an \e option \e command directly, given its id and optional parameters +/// \param nameId is the id of the option /// \param p1 is the first optional parameter /// \param p2 is the second optional parameter /// \param p3 is the third optional parameter /// \return the confirmation/failure method after trying to apply the option -string OptionDatabase::set(const string &nm,const string &p1,const string &p2,const string &p3) +string OptionDatabase::set(uint4 nameId,const string &p1,const string &p2,const string &p3) { - map::const_iterator iter; - iter = optionmap.find(nm); + map::const_iterator iter; + iter = optionmap.find(nameId); if (iter == optionmap.end()) - throw ParseError("Unknown option: "+nm); + throw ParseError("Unknown option"); ArchOption *opt = (*iter).second; return opt->apply(glb,p1,p2,p3); } -/// Unwrap the name and optional parameters and call method set() -/// \param el is the command XML tag -void OptionDatabase::parseOne(const Element *el) +/// Scan the name and optional parameters and call method set() +/// \param decoder is the stream decoder +void OptionDatabase::decodeOne(Decoder &decoder) { - const string &optname( el->getName() ); - const List &list(el->getChildren()); - List::const_iterator iter; - string p1,p2,p3; - iter = list.begin(); - if (iter != list.end()) { - p1 = (*iter)->getContent(); - ++iter; - if (iter != list.end()) { - p2 = (*iter)->getContent(); - ++iter; - if (iter != list.end()) { - p3 = (*iter)->getContent(); - ++iter; - if (iter != list.end()) - throw LowlevelError("Too many parameters to option: "+optname); + uint4 elemId = decoder.openElement(); + uint4 subId = decoder.openElement(); + if (subId == ELEM_PARAM1) { + p1 = decoder.readString(ATTRIB_CONTENT); + decoder.closeElement(subId); + subId = decoder.openElement(); + if (subId == ELEM_PARAM2) { + p2 = decoder.readString(ATTRIB_CONTENT); + decoder.closeElement(subId); + subId = decoder.openElement(); + if (subId == ELEM_PARAM3) { + p3 = decoder.readString(ATTRIB_CONTENT); + decoder.closeElement(subId); } } } - else - p1 = el->getContent(); // If no children, content is param 1 - set(optname,p1,p2,p3); + else if (subId == 0) + p1 = decoder.readString(ATTRIB_CONTENT); // If no children, content is param 1 + decoder.closeElement(elemId); + set(elemId,p1,p2,p3); } -/// Parse the \ tag, treating each sub-tag as an \e option \e command. -/// \param el is the \ tag -void OptionDatabase::restoreXml(const Element *el) +/// Parse an \ element, treating each child as an \e option \e command. +/// \param decoder is the stream decoder +void OptionDatabase::decode(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; + uint4 elemId = decoder.openElement(ELEM_OPTIONSLIST); - for(iter=list.begin();iter!=list.end();++iter) - parseOne(*iter); + while(decoder.peekElement() != 0) + decodeOne(decoder); + decoder.closeElement(elemId); } /// \class OptionExtraPop diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/options.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/options.hh index b18e0a1b46..474ee70715 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/options.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/options.hh @@ -20,10 +20,48 @@ #define __ARCH_OPTIONS__ #include "error.hh" -#include "xml.hh" +#include "marshal.hh" class Architecture; +extern ElementId ELEM_ALIASBLOCK; ///< Marshaling element \ +extern ElementId ELEM_ALLOWCONTEXTSET; ///< Marshaling element \ +extern ElementId ELEM_ANALYZEFORLOOPS; ///< Marshaling element \ +extern ElementId ELEM_COMMENTHEADER; ///< Marshaling element \ +extern ElementId ELEM_COMMENTINDENT; ///< Marshaling element \ +extern ElementId ELEM_COMMENTINSTRUCTION; ///< Marshaling element \ +extern ElementId ELEM_COMMENTSTYLE; ///< Marshaling element \ +extern ElementId ELEM_CONVENTIONPRINTING; ///< Marshaling element \ +extern ElementId ELEM_CURRENTACTION; ///< Marshaling element \ +extern ElementId ELEM_DEFAULTPROTOTYPE; ///< Marshaling element \ +extern ElementId ELEM_ERRORREINTERPRETED; ///< Marshaling element \ +extern ElementId ELEM_ERRORTOOMANYINSTRUCTIONS; ///< Marshaling element \ +extern ElementId ELEM_ERRORUNIMPLEMENTED; ///< Marshaling element \ +extern ElementId ELEM_EXTRAPOP; ///< Marshaling element \ +extern ElementId ELEM_IGNOREUNIMPLEMENTED; ///< Marshaling element \ +extern ElementId ELEM_INDENTINCREMENT; ///< Marshaling element \ +extern ElementId ELEM_INFERCONSTPTR; ///< Marshaling element \ +extern ElementId ELEM_INLINE; ///< Marshaling element \ +extern ElementId ELEM_INPLACEOPS; ///< Marshaling element \ +extern ElementId ELEM_INTEGERFORMAT; ///< Marshaling element \ +extern ElementId ELEM_JUMPLOAD; ///< Marshaling element \ +extern ElementId ELEM_MAXINSTRUCTION; ///< Marshaling element \ +extern ElementId ELEM_MAXLINEWIDTH; ///< Marshaling element \ +extern ElementId ELEM_NAMESPACESTRATEGY; ///< Marshaling element \ +extern ElementId ELEM_NOCASTPRINTING; ///< Marshaling element \ +extern ElementId ELEM_NORETURN; ///< Marshaling element \ +extern ElementId ELEM_NULLPRINTING; ///< Marshaling element \ +extern ElementId ELEM_OPTIONSLIST; ///< Marshaling element \ +extern ElementId ELEM_PARAM1; ///< Marshaling element \ +extern ElementId ELEM_PARAM2; ///< Marshaling element \ +extern ElementId ELEM_PARAM3; ///< Marshaling element \ +extern ElementId ELEM_PROTOEVAL; ///< Marshaling element \ +extern ElementId ELEM_SETACTION; ///< Marshaling element \ +extern ElementId ELEM_SETLANGUAGE; ///< Marshaling element \ +extern ElementId ELEM_STRUCTALIGN; ///< Marshaling element \ +extern ElementId ELEM_TOGGLERULE; ///< Marshaling element \ +extern ElementId ELEM_WARNING; ///< Marshaling element \ + /// \brief Base class for options classes that affect the configuration of the Architecture object /// /// Each class instance affects configuration through its apply() method, which is handed the @@ -56,20 +94,20 @@ public: /// An \b option \b command is a specific request by a user to change the configuration options /// for an Architecture. This class takes care of dispatching the command to the proper ArchOption /// derived class, which does the work of actually modifying the configuration. The command is issued -/// either through the set() method directly, or via an XML tag handed to the restoreXml() method. -/// The restoreXml() method expects an \ tag with one or more sub-tags. The sub-tag names -/// match the registered name of the option and have up to three child tags, \, \ and \, +/// either through the set() method directly, or via an element handed to the decode() method. +/// The decode() method expects an \ element with one or more children. The child names +/// match the registered name of the option and have up to three child elements, \, \ and \, /// whose content is provided as the optional parameters to command. class OptionDatabase { Architecture *glb; ///< The Architecture affected by the contained ArchOption - map optionmap; ///< A map from option name to registered ArchOption instance + map optionmap; ///< A map from option id to registered ArchOption instance void registerOption(ArchOption *option); ///< Map from ArchOption name to its class instance public: OptionDatabase(Architecture *g); ///< Construct given the owning Architecture ~OptionDatabase(void); ///< Destructor - string set(const string &nm,const string &p1="",const string &p2="",const string &p3=""); ///< Issue an option command - void parseOne(const Element *el); ///< Unwrap and execute a single option XML tag - void restoreXml(const Element *el); ///< Execute a series of \e option \e commands passed by XML + string set(uint4 nameId,const string &p1="",const string &p2="",const string &p3=""); ///< Issue an option command + void decodeOne(Decoder &decoder); ///< Parse and execute a single option element + void decode(Decoder &decoder); ///< Execute a series of \e option \e commands parsed from a stream }; class OptionExtraPop : public ArchOption { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/override.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/override.cc index a998ba2817..f677330aa9 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/override.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/override.cc @@ -16,6 +16,14 @@ #include "override.hh" #include "funcdata.hh" +ElementId ELEM_DEADCODEDELAY = ElementId("deadcodedelay",148); +ElementId ELEM_FLOW = ElementId("flow",149); +ElementId ELEM_FORCEGOTO = ElementId("forcegoto",150); +ElementId ELEM_INDIRECTOVERRIDE = ElementId("indirectoverride",151); +ElementId ELEM_MULTISTAGEJUMP = ElementId("multistagejump",152); +ElementId ELEM_OVERRIDE = ElementId("override",153); +ElementId ELEM_PROTOOVERRIDE = ElementId("protooverride",154); + void Override::clear(void) { @@ -276,141 +284,118 @@ void Override::generateOverrideMessages(vector &messagelist,Architecture } } -/// \brief Write the override commands to an XML stream +/// \brief Encode the override commands to a stream /// -/// All the commands are written as sub-tags of a root \ tag. -/// \param s is the output stream +/// All the commands are written as children of a root \ element. +/// \param encoder is the stream encoder /// \param glb is the Architecture -void Override::saveXml(ostream &s,Architecture *glb) const +void Override::encode(Encoder &encoder,Architecture *glb) const { if (forcegoto.empty() && deadcodedelay.empty() && indirectover.empty() && protoover.empty() && multistagejump.empty() && flowoverride.empty()) return; - s << "\n"; + encoder.openElement(ELEM_OVERRIDE); map::const_iterator iter; for(iter=forcegoto.begin();iter!=forcegoto.end();++iter) { - s << ""; - (*iter).first.saveXml(s); - (*iter).second.saveXml(s); - s << "\n"; + encoder.openElement(ELEM_FORCEGOTO); + (*iter).first.encode(encoder); + (*iter).second.encode(encoder); + encoder.closeElement(ELEM_FORCEGOTO); } for(int4 i=0;igetSpace(i); - s << "getName()); - a_v_i(s,"delay",deadcodedelay[i]); - s << "/>\n"; + encoder.openElement(ELEM_DEADCODEDELAY); + encoder.writeString(ATTRIB_SPACE, spc->getName()); + encoder.writeSignedInteger(ATTRIB_DELAY, deadcodedelay[i]); + encoder.closeElement(ELEM_DEADCODEDELAY); } for(iter=indirectover.begin();iter!=indirectover.end();++iter) { - s << ""; - (*iter).first.saveXml(s); - (*iter).second.saveXml(s); - s << "\n"; + encoder.openElement(ELEM_INDIRECTOVERRIDE); + (*iter).first.encode(encoder); + (*iter).second.encode(encoder); + encoder.closeElement(ELEM_INDIRECTOVERRIDE); } map::const_iterator fiter; for(fiter=protoover.begin();fiter!=protoover.end();++fiter) { - s << ""; - (*fiter).first.saveXml(s); - (*fiter).second->saveXml(s); - s << "\n"; + encoder.openElement(ELEM_PROTOOVERRIDE); + (*fiter).first.encode(encoder); + (*fiter).second->encode(encoder); + encoder.closeElement(ELEM_PROTOOVERRIDE); } for(int4 i=0;i"; - multistagejump[i].saveXml(s); - s << ""; + encoder.openElement(ELEM_MULTISTAGEJUMP); + multistagejump[i].encode(encoder); + encoder.closeElement(ELEM_MULTISTAGEJUMP); } map::const_iterator titer; for(titer=flowoverride.begin();titer!=flowoverride.end();++titer) { - s << ""; - (*titer).first.saveXml(s); - s << "\n"; + encoder.openElement(ELEM_FLOW); + encoder.writeString(ATTRIB_TYPE, typeToString( (*titer).second )); + (*titer).first.encode(encoder); + encoder.closeElement(ELEM_FLOW); } - - s << "\n"; - + encoder.closeElement(ELEM_OVERRIDE); } -/// \brief Read in override commands from XML +/// \brief Parse and \ element containing override commands /// -/// \param el is the root \ element +/// \param decoder is the stream decoder /// \param glb is the Architecture -void Override::restoreXml(const Element *el,Architecture *glb) +void Override::decode(Decoder &decoder,Architecture *glb) { - const List &list(el->getChildren()); - List::const_iterator iter; - - for(iter=list.begin();iter!=list.end();++iter) { - const Element *subel = *iter; - - if (subel->getName() == "indirectoverride") { - const List &list2(subel->getChildren()); - List::const_iterator iter2 = list2.begin(); - Address callpoint = Address::restoreXml(*iter2,glb); - ++iter2; - Address directcall = Address::restoreXml(*iter2,glb); + uint4 elemId = decoder.openElement(ELEM_OVERRIDE); + for(;;) { + uint4 subId = decoder.openElement(); + if (subId == 0) break; + if (subId == ELEM_INDIRECTOVERRIDE) { + Address callpoint = Address::decode(decoder,glb); + Address directcall = Address::decode(decoder,glb); insertIndirectOverride(callpoint,directcall); } - else if (subel->getName() == "protooverride") { - const List &list2(subel->getChildren()); - List::const_iterator iter2 = list2.begin(); - Address callpoint = Address::restoreXml(*iter2,glb); - ++iter2; + else if (subId == ELEM_PROTOOVERRIDE) { + Address callpoint = Address::decode(decoder,glb); FuncProto *fp = new FuncProto(); fp->setInternal(glb->defaultfp,glb->types->getTypeVoid()); - fp->restoreXml(*iter2,glb); + fp->decode(decoder,glb); insertProtoOverride(callpoint,fp); } - else if (subel->getName() == "forcegoto") { - const List &list2(subel->getChildren()); - List::const_iterator iter2 = list2.begin(); - Address targetpc = Address::restoreXml(*iter2,glb); - ++iter2; - Address destpc = Address::restoreXml(*iter2,glb); + else if (subId == ELEM_FORCEGOTO) { + Address targetpc = Address::decode(decoder,glb); + Address destpc = Address::decode(decoder,glb); insertForceGoto(targetpc,destpc); } - else if (subel->getName() == "deadcodedelay") { - int4 delay = -1; - istringstream s(subel->getAttributeValue("delay")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> delay; - AddrSpace *spc = glb->getSpaceByName( subel->getAttributeValue("space")); + else if (subId == ELEM_DEADCODEDELAY) { + int4 delay = decoder.readSignedInteger(ATTRIB_DELAY); + AddrSpace *spc = glb->getSpaceByName( decoder.readString(ATTRIB_SPACE)); if ((spc == (AddrSpace *)0)||(delay < 0)) throw LowlevelError("Bad deadcodedelay tag"); insertDeadcodeDelay(spc,delay); } - else if (subel->getName() == "multistagejump") { - const Element *tmpel = subel->getChildren().front(); - Address callpoint = Address::restoreXml(tmpel,glb); + else if (subId == ELEM_MULTISTAGEJUMP) { + Address callpoint = Address::decode(decoder,glb); insertMultistageJump(callpoint); } - else if (subel->getName() == "multistagejump") { - const Element *tmpel = subel->getChildren().front(); - Address callpoint = Address::restoreXml(tmpel,glb); - insertMultistageJump(callpoint); - } - else if (subel->getName() == "flow") { - uint4 type = stringToType(subel->getAttributeValue("type")); - const Element *tmpel = subel->getChildren().front(); - Address addr = Address::restoreXml(tmpel,glb); + else if (subId == ELEM_FLOW) { + uint4 type = stringToType(decoder.readString(ATTRIB_TYPE)); + Address addr = Address::decode(decoder,glb); if ((type == Override::NONE)||(addr.isInvalid())) throw LowlevelError("Bad flowoverride tag"); insertFlowOverride(addr,type); } + decoder.closeElement(subId); } - + decoder.closeElement(elemId); } /// \param tp is the override type diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/override.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/override.hh index 2b7195d443..1a76e46e1d 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/override.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/override.hh @@ -23,6 +23,14 @@ class FuncCallSpecs; // Forward declaration +extern ElementId ELEM_DEADCODEDELAY; ///< Marshaling element \ +extern ElementId ELEM_FLOW; ///< Marshaling element \ +extern ElementId ELEM_FORCEGOTO; ///< Marshaling element \ +extern ElementId ELEM_INDIRECTOVERRIDE; ///< Marshaling element \ +extern ElementId ELEM_MULTISTAGEJUMP; ///< Marshaling element \ +extern ElementId ELEM_OVERRIDE; ///< Marshaling element \ +extern ElementId ELEM_PROTOOVERRIDE; ///< Marshaling element \ + /// \brief A container of commands that override the decompiler's default behavior for a single function /// /// Information about a particular function that can be overridden includes: @@ -75,8 +83,8 @@ public: uint4 getFlowOverride(const Address &addr) const; void printRaw(ostream &s,Architecture *glb) const; void generateOverrideMessages(vector &messagelist,Architecture *glb) const; - void saveXml(ostream &s,Architecture *glb) const; - void restoreXml(const Element *el,Architecture *glb); + void encode(Encoder &encoder,Architecture *glb) const; + void decode(Decoder &decoder,Architecture *glb); static string typeToString(uint4 tp); ///< Convert a flow override type to a string static uint4 stringToType(const string &nm); ///< Convert a string to a flow override type }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/paramid.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/paramid.cc index 9aab194b65..05a1900c6c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/paramid.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/paramid.cc @@ -15,6 +15,10 @@ */ #include "paramid.hh" +ElementId ELEM_PARAMMEASURES = ElementId("parammeasures",155); +ElementId ELEM_PROTO = ElementId("proto",156); +ElementId ELEM_RANK = ElementId("rank",157); + // NOTES FROM 20121206 W/Decompiler-Man // direct reads is for all opcodes, with special for these: // BRANCH is direct read on input0. No direct write. @@ -152,19 +156,20 @@ void ParamMeasure::calculateRank(bool best,Varnode *basevn,PcodeOp *ignoreop) walkbackward(state, ignoreop, basevn); } -void ParamMeasure::saveXml( ostream &s,string tag,bool moredetail ) const +void ParamMeasure::encode( Encoder &encoder,ElementId &tag,bool moredetail ) const { - s << "<" + tag +">\nsaveXmlAttributes( s, vndata.offset, vndata.size ); - s << "/>\n"; - vntype->saveXml(s); + encoder.openElement(tag); + encoder.openElement(ELEM_ADDR); + vndata.space->encodeAttributes( encoder, vndata.offset, vndata.size ); + encoder.closeElement(ELEM_ADDR); + vntype->encode(encoder); if( moredetail ) { - s << ""; + encoder.openElement(ELEM_RANK); + encoder.writeSignedInteger(ATTRIB_VAL, rank); + encoder.closeElement(ELEM_RANK); } - s << "\n"; + encoder.closeElement(tag); } void ParamMeasure::savePretty( ostream &s,bool moredetail ) const @@ -227,35 +232,31 @@ ParamIDAnalysis::ParamIDAnalysis( Funcdata *fd_in, bool justproto ) } } -void ParamIDAnalysis::saveXml( ostream &s,bool moredetail ) const +void ParamIDAnalysis::encode( Encoder &encoder,bool moredetail ) const { - s << "getName() ); - s << ">\n "; - fd->getAddress().saveXml( s ); - s << "\n getName()); + fd->getAddress().encode( encoder ); + encoder.openElement(ELEM_PROTO); - a_v(s,"model", fd->getFuncProto().getModelName()); + encoder.writeString(ATTRIB_MODEL, fd->getFuncProto().getModelName()); int4 extrapop = fd->getFuncProto().getExtraPop(); if (extrapop == ProtoModel::extrapop_unknown) - a_v(s,"extrapop","unknown"); + encoder.writeString(ATTRIB_EXTRAPOP, "unknown"); else - a_v_i(s,"extrapop",extrapop); - s << "/>\n"; + encoder.writeSignedInteger(ATTRIB_EXTRAPOP, extrapop); + encoder.closeElement(ELEM_PROTO); list::const_iterator pm_iter; for( pm_iter = InputParamMeasures.begin(); pm_iter != InputParamMeasures.end(); ++pm_iter) { const ParamMeasure &pm( *pm_iter ); - s << " "; - pm.saveXml(s,"input",moredetail); + pm.encode(encoder,ELEM_INPUT,moredetail); } for( pm_iter = OutputParamMeasures.begin(); pm_iter != OutputParamMeasures.end() ; ++pm_iter) { const ParamMeasure &pm( *pm_iter ); - s << " "; - pm.saveXml( s, "output", moredetail ); + pm.encode( encoder, ELEM_OUTPUT, moredetail ); } - s << ""; - s << "\n"; + encoder.closeElement(ELEM_PARAMMEASURES); } void ParamIDAnalysis::savePretty( ostream &s,bool moredetail ) const diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/paramid.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/paramid.hh index 9e112bdc5e..7eb7d78c97 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/paramid.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/paramid.hh @@ -18,6 +18,10 @@ #include "funcdata.hh" +extern ElementId ELEM_PARAMMEASURES; ///< Marshaling element \ +extern ElementId ELEM_PROTO; ///< Marshaling element \ +extern ElementId ELEM_RANK; ///< Marshaling element \ + class ParamMeasure { public: enum ParamIDIO { @@ -56,7 +60,7 @@ public: ParamMeasure( const Address &addr, int4 sz, Datatype *dt, ParamIDIO io_in) { vndata.space=addr.getSpace(); vndata.offset=addr.getOffset(); vndata.size = sz; vntype=dt; io = io_in; rank=WORSTRANK; } void calculateRank(bool best,Varnode *basevn,PcodeOp *ignoreop); - void saveXml( ostream &s,string tag,bool moredetail ) const; + void encode( Encoder &encoder,ElementId &tag,bool moredetail ) const; void savePretty( ostream &s,bool moredetail ) const; int4 getMeasure(void) const { return (int4) rank; } }; @@ -68,7 +72,7 @@ class ParamIDAnalysis list OutputParamMeasures; public: ParamIDAnalysis( Funcdata *fd_in, bool justproto ); - void saveXml( ostream &s, bool moredetail ) const; + void encode( Encoder &encoder, bool moredetail ) const; void savePretty( ostream &s, bool moredetail ) const; }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeinject.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeinject.cc index 4b3af74df3..d12c32679b 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeinject.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeinject.cc @@ -16,26 +16,47 @@ #include "pcodeinject.hh" #include "architecture.hh" -/// \brief Read in an \ or \ XML tag describing an injection parameter +AttributeId ATTRIB_DYNAMIC = AttributeId("dynamic",74); +AttributeId ATTRIB_INCIDENTALCOPY = AttributeId("incidentalcopy",75); +AttributeId ATTRIB_INJECT = AttributeId("inject",76); +AttributeId ATTRIB_PARAMSHIFT = AttributeId("paramshift",77); +AttributeId ATTRIB_TARGETOP = AttributeId("targetop",78); + +ElementId ELEM_ADDR_PCODE = ElementId("addr_pcode",158); +ElementId ELEM_BODY = ElementId("body",159); +ElementId ELEM_CALLFIXUP = ElementId("callfixup",160); +ElementId ELEM_CALLOTHERFIXUP = ElementId("callotherfixup",161); +ElementId ELEM_CASE_PCODE = ElementId("case_pcode",162); +ElementId ELEM_CONTEXT = ElementId("context",163); +ElementId ELEM_DEFAULT_PCODE = ElementId("default_pcode",164); +ElementId ELEM_INJECT = ElementId("inject",165); +ElementId ELEM_INJECTDEBUG = ElementId("injectdebug",166); +ElementId ELEM_INST = ElementId("inst",167); +ElementId ELEM_PAYLOAD = ElementId("payload",168); +ElementId ELEM_PCODE = ElementId("pcode",169); +ElementId ELEM_SIZE_PCODE = ElementId("size_pcode",170); + +/// \brief Parse an \ or \ element describing an injection parameter /// -/// \param el is the XML element +/// \param decoder is the stream decoder /// \param name is used to pass back the parameter name /// \param size is used to pass back the parameter size -void InjectPayload::readParameter(const Element *el,string &name,uint4 &size) +void InjectPayload::decodeParameter(Decoder &decoder,string &name,uint4 &size) { name = ""; size = 0; - int4 num = el->getNumAttributes(); - for(int4 i=0;igetAttributeName(i) == "name") - name = el->getAttributeValue(i); - else if (el->getAttributeName(i) == "size") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> size; + uint4 elemId = decoder.openElement(); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_NAME) + name = decoder.readString(); + else if (attribId == ATTRIB_SIZE) { + size = decoder.readUnsignedInteger(); } } + decoder.closeElement(elemId); if (name.size()==0) throw LowlevelError("Missing inject parameter name"); } @@ -55,44 +76,55 @@ void InjectPayload::orderParameters(void) } } -/// The base class version of this method restores from a \ tag. -/// Derived classes may restore from a parent tag and then invoke the -/// base class method. -/// \param el is the XML element -void InjectPayload::restoreXml(const Element *el) +/// The \ element must be current and already opened. +/// \param decoder is the stream decoder +void InjectPayload::decodePayloadAttributes(Decoder &decoder) { paramshift = 0; dynamic = false; - int4 num = el->getNumAttributes(); - for(int4 i=0;igetAttributeName(i)); - if (elname == "paramshift") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> paramshift; + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_PARAMSHIFT) { + paramshift = decoder.readSignedInteger(); + } + else if (attribId == ATTRIB_DYNAMIC) + dynamic = decoder.readBool(); + else if (attribId == ATTRIB_INCIDENTALCOPY) + incidentalCopy = decoder.readBool(); + else if (attribId == ATTRIB_INJECT) { + string uponType = decoder.readString(); + if (uponType == "uponentry") + name = name + "@@inject_uponentry"; + else + name = name + "@@inject_uponreturn"; } - else if (elname == "dynamic") - dynamic = xml_readbool(el->getAttributeValue(i)); - else if (elname == "incidentalcopy") - incidentalCopy = xml_readbool(el->getAttributeValue(i)); } - const List &list(el->getChildren()); - List::const_iterator iter; - for(iter=list.begin();iter!=list.end();++iter) { - const Element *subel = *iter; - if (subel->getName() == "input") { +} + +/// Elements are processed until the first child that isn't an \ or \ tag +/// is encountered. The \ element must be current and already opened. +/// \param decoder is the stream decoder +void InjectPayload::decodePayloadParams(Decoder &decoder) + +{ + for(;;) { + uint4 subId = decoder.peekElement(); + if (subId == ELEM_INPUT) { string paramName; uint4 size; - readParameter(subel,paramName,size); + decodeParameter(decoder,paramName,size); inputlist.push_back(InjectParameter(paramName,size)); } - else if (subel->getName() == "output") { + else if (subId == ELEM_OUTPUT) { string paramName; uint4 size; - readParameter(subel,paramName,size); + decodeParameter(decoder,paramName,size); output.push_back(InjectParameter(paramName,size)); } + else + break; } orderParameters(); } @@ -305,21 +337,21 @@ string PcodeInjectLibrary::getCallMechanismName(int4 injectid) const return callMechTarget[injectid]; } -/// \brief Read in and register an injection payload from an XML stream +/// \brief Parse and register an injection payload from a stream element /// -/// The root XML element describing the payload is given (\, \ -/// \, etc.), the InjectPayload is allocated and then -/// initialized using the element. Then the InjectPayload is finalized with the library. -/// \param src is a string describing the source of the payload being restored +/// The element is one of: \, \ \, etc. +/// The InjectPayload is allocated and then initialized using the element. +/// Then the InjectPayload is finalized with the library. +/// \param src is a string describing the source of the payload being decoded /// \param nm is the name of the payload /// \param tp is the type of the payload (CALLFIXUP_TYPE, EXECUTABLEPCODE_TYPE, etc.) -/// \param el is the given XML element +/// \param decoder is the stream decoder /// \return the id of the newly registered payload -int4 PcodeInjectLibrary::restoreXmlInject(const string &src,const string &nm,int4 tp,const Element *el) +int4 PcodeInjectLibrary::decodeInject(const string &src,const string &nm,int4 tp,Decoder &decoder) { int4 injectid = allocateInject(src, nm, tp); - getPayload(injectid)->restoreXml(el); + getPayload(injectid)->decode(decoder); registerInject(injectid); return injectid; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeinject.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeinject.hh index af14ad02d6..86821b222e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeinject.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeinject.hh @@ -23,6 +23,26 @@ class Architecture; +extern AttributeId ATTRIB_DYNAMIC; ///< Marshaling attribute "dynamic" +extern AttributeId ATTRIB_INCIDENTALCOPY; ///< Marshaling attribute "incidentalcopy" +extern AttributeId ATTRIB_INJECT; ///< Marshaling attribute "inject" +extern AttributeId ATTRIB_PARAMSHIFT; ///< Marshaling attribute "paramshift" +extern AttributeId ATTRIB_TARGETOP; ///< Marshaling attribute "targetop" + +extern ElementId ELEM_ADDR_PCODE; ///< Marshaling element \ +extern ElementId ELEM_BODY; ///< Marshaling element \ +extern ElementId ELEM_CALLFIXUP; ///< Marshaling element \ +extern ElementId ELEM_CALLOTHERFIXUP; ///< Marshaling element \ +extern ElementId ELEM_CASE_PCODE; ///< Marshaling element \ +extern ElementId ELEM_CONTEXT; ///< Marshaling element \ +extern ElementId ELEM_DEFAULT_PCODE; ///< Marshaling element \ +extern ElementId ELEM_INJECT; ///< Marshaling element \ +extern ElementId ELEM_INJECTDEBUG; ///< Marshaling element \ +extern ElementId ELEM_INST; ///< Marshaling element \ +extern ElementId ELEM_PAYLOAD; ///< Marshaling element \ +extern ElementId ELEM_PCODE; ///< Marshaling element \ +extern ElementId ELEM_SIZE_PCODE; ///< Marshaling element \ + /// \brief An input or output parameter to a p-code injection payload /// /// Within the chunk of p-code being injected, this is a placeholder for Varnodes @@ -64,10 +84,10 @@ public: virtual ~InjectContext(void) {} ///< Destructor virtual void clear(void) { inputlist.clear(); output.clear(); } ///< Release resources (from last injection) - /// \brief Save \b this context to an XML stream as a \ tag + /// \brief Encode \b this context to a stream as a \ element /// - /// \param s is the output stream - virtual void saveXml(ostream &s) const=0; + /// \param encoder is the stream encoder + virtual void encode(Encoder &encoder) const=0; }; /// \brief An active container for a set of p-code operations that can be injected into data-flow @@ -91,10 +111,12 @@ protected: int4 paramshift; ///< Number of parameters shifted in the original call vector inputlist; ///< List of input parameters to this payload vector output; ///< List of output parameters - static void readParameter(const Element *el,string &name,uint4 &size); + static void decodeParameter(Decoder &decoder,string &name,uint4 &size); void orderParameters(void); ///< Assign an index to parameters + void decodePayloadAttributes(Decoder &decoder); ///< Parse the attributes of the current \ tag + void decodePayloadParams(Decoder &decoder); ///< Parse any \ or \ children of current \ tag public: - InjectPayload(const string &nm,int4 tp) { name=nm; type=tp; paramshift=0; dynamic = false; incidentalCopy = false; } ///< Construct for use with restoreXml + InjectPayload(const string &nm,int4 tp) { name=nm; type=tp; paramshift=0; dynamic = false; incidentalCopy = false; } ///< Construct for use with decode int4 getParamShift(void) const { return paramshift; } ///< Get the number of parameters shifted bool isDynamic(void) const { return dynamic; } ///< Return \b true if p-code in the injection is generated dynamically bool isIncidentalCopy(void) const { return incidentalCopy; } ///< Return \b true if any injected COPY is considered \e incidental @@ -115,7 +137,7 @@ public: /// \param emit is the provovided PcodeEmit object virtual void inject(InjectContext &context,PcodeEmit &emit) const=0; - virtual void restoreXml(const Element *el); ///< Restore \b this payload from an XML stream + virtual void decode(Decoder &decoder)=0; ///< Decode \b this payload from a stream virtual void printTemplate(ostream &s) const=0; ///< Print the p-code ops of the injection to a stream (for debugging) string getName(void) const { return name; } ///< Return the name of the injection int4 getType(void) const { return type; } ///< Return the type of injection (CALLFIXUP_TYPE, CALLOTHERFIXUP_TYPE, etc.) @@ -150,7 +172,7 @@ public: /// \brief A collection of p-code injection payloads /// /// This is a container of InjectPayload objects that can be applied for a -/// specific Architecture. Payloads can be read in via XML (restoreXmlInject()) and manually +/// specific Architecture. Payloads can be read in via stream (decodeInject()) and manually /// via manualCallFixup() and manualCallOtherFixup(). Each payload is assigned an integer \e id /// when it is read in, and getPayload() fetches the payload during analysis. The library /// also associates the formal names of payloads with the id. Payloads of different types, @@ -203,15 +225,15 @@ public: string getCallFixupName(int4 injectid) const; ///< Get the call-fixup name associated with an id string getCallOtherTarget(int4 injectid) const; ///< Get the callother-fixup name associated with an id string getCallMechanismName(int4 injectid) const; ///< Get the call mechanism name associated with an id - int4 restoreXmlInject(const string &src,const string &nm,int4 tp,const Element *el); + int4 decodeInject(const string &src,const string &suffix,int4 tp,Decoder &decoder); - /// \brief A method for reading in p-code generated externally for use in debugging + /// \brief A method for parsing p-code generated externally for use in debugging /// /// Instantiate a special InjectPayloadDynamic object initialized with an - /// \ tag. Within the library, this replaces the original InjectPayload, + /// \ element. Within the library, this replaces the original InjectPayload, /// allowing its p-code to be \e replayed for debugging purposes. - /// \param el is the \ element - virtual void restoreDebug(const Element *el) {} + /// \param decoder is the stream decoder + virtual void decodeDebug(Decoder &decoder) {} /// \brief Manually add a call-fixup payload given a compilable snippet of p-code \e source /// diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeparse.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeparse.cc index 8a02942b63..1b3236d101 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeparse.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeparse.cc @@ -2904,6 +2904,9 @@ int4 PcodeLexer::moveState(void) switch(curstate) { case start: switch(curchar) { + case '#': + curstate = comment; + return start; case '|': if (lookahead1 == '|') { starttoken(); @@ -3118,17 +3121,14 @@ int4 PcodeLexer::moveState(void) advancetoken(); curstate = start; return identifier; - break; case special3: advancetoken(); curstate = special32; return start; - break; case special32: advancetoken(); curstate = start; return identifier; - break; case comment: if (curchar == '\n') curstate = start; @@ -3136,28 +3136,25 @@ int4 PcodeLexer::moveState(void) curstate = endstream; return endstream; } - break; + return start; case identifier: advancetoken(); if (isIdent(lookahead1)) return start; curstate = start; return identifier; - break; case hexstring: advancetoken(); if (isHex(lookahead1)) return start; curstate = start; return hexstring; - break; case decstring: advancetoken(); if (isDec(lookahead1)) return start; curstate = start; return decstring; - break; default: curstate = endstream; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeparse.y b/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeparse.y index b376fb6c75..454d7c3877 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeparse.y +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeparse.y @@ -303,6 +303,9 @@ int4 PcodeLexer::moveState(void) switch(curstate) { case start: switch(curchar) { + case '#': + curstate = comment; + return start; case '|': if (lookahead1 == '|') { starttoken(); @@ -517,17 +520,14 @@ int4 PcodeLexer::moveState(void) advancetoken(); curstate = start; return identifier; - break; case special3: advancetoken(); curstate = special32; return start; - break; case special32: advancetoken(); curstate = start; return identifier; - break; case comment: if (curchar == '\n') curstate = start; @@ -535,28 +535,25 @@ int4 PcodeLexer::moveState(void) curstate = endstream; return endstream; } - break; + return start; case identifier: advancetoken(); if (isIdent(lookahead1)) return start; curstate = start; return identifier; - break; case hexstring: advancetoken(); if (isHex(lookahead1)) return start; curstate = start; return hexstring; - break; case decstring: advancetoken(); if (isDec(lookahead1)) return start; curstate = start; return decstring; - break; default: curstate = endstream; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/pcoderaw.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/pcoderaw.cc index 1e9cc222a7..d9d9266b0f 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/pcoderaw.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/pcoderaw.cc @@ -16,28 +16,43 @@ #include "pcoderaw.hh" #include "translate.hh" -/// Build this VarnodeData from an \b \ tag -/// \param el is the parsed tag +/// Build this VarnodeData from an \, \, or \ element. +/// \param decoder is the stream decoder /// \param manage is the address space manager -void VarnodeData::restoreXml(const Element *el,const AddrSpaceManager *manage) +void VarnodeData::decode(Decoder &decoder,const AddrSpaceManager *manage) + +{ + uint4 elemId = decoder.openElement(); + decodeFromAttributes(decoder,manage); + decoder.closeElement(elemId); +} + +/// Collect attributes for the VarnodeData possibly from amidst other attributes +/// \param decoder is the stream decoder +/// \param manage is the address space manager +void VarnodeData::decodeFromAttributes(Decoder &decoder,const AddrSpaceManager *manage) { space = (AddrSpace *)0; size = 0; - int4 num = el->getNumAttributes(); - for(int4 i=0;igetAttributeName(i)=="space") { - space = manage->getSpaceByName(el->getAttributeValue(i)); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) + break; // Its possible to have no attributes in an tag + if (attribId == ATTRIB_SPACE) { + string nm = decoder.readString(); + space = manage->getSpaceByName(nm); if (space == (AddrSpace *)0) - throw LowlevelError("Unknown space name: "+el->getAttributeValue(i)); - offset = space->restoreXmlAttributes(el,size); - return; + throw LowlevelError("Unknown space name: "+nm); + decoder.rewindAttributes(); + offset = space->decodeAttributes(decoder,size); + break; } - else if (el->getAttributeName(i)=="name") { + else if (attribId == ATTRIB_NAME) { const Translate *trans = manage->getDefaultCodeSpace()->getTrans(); - const VarnodeData &point(trans->getRegister(el->getAttributeValue(i))); + const VarnodeData &point(trans->getRegister(decoder.readString())); *this = point; - return; + break; } } } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/pcoderaw.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/pcoderaw.hh index 10385c2351..d254993924 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/pcoderaw.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/pcoderaw.hh @@ -44,8 +44,11 @@ struct VarnodeData { /// Treat \b this as a constant and recover encoded address space AddrSpace *getSpaceFromConst(void) const; - /// Recover this object from an XML tag - void restoreXml(const Element *el,const AddrSpaceManager *manage); + /// Recover this object from a stream + void decode(Decoder &decoder,const AddrSpaceManager *manage); + + /// Recover \b this object from attributes of the current open element + void decodeFromAttributes(Decoder &decoder,const AddrSpaceManager *manage); /// Does \b this container another given VarnodeData bool contains(const VarnodeData &op2) const; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/prefersplit.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/prefersplit.cc index 788afa8547..aa20a71f18 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/prefersplit.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/prefersplit.cc @@ -16,6 +16,8 @@ #include "prefersplit.hh" #include "funcdata.hh" +ElementId ELEM_PREFERSPLIT = ElementId("prefersplit",171); + bool PreferSplitRecord::operator<(const PreferSplitRecord &op2) const { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/prefersplit.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/prefersplit.hh index ec06bdfd17..9654ceedd1 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/prefersplit.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/prefersplit.hh @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +19,8 @@ #include "varnode.hh" class Funcdata; // Forward declaration +extern ElementId ELEM_PREFERSPLIT; ///< Marshaling element \ + struct PreferSplitRecord { VarnodeData storage; int4 splitoffset; // Number of initial bytes (in address order) to split into first piece diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/raw_arch.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/raw_arch.cc index bd5c9f14c4..b3d440bd7a 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/raw_arch.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/raw_arch.cc @@ -15,6 +15,8 @@ */ #include "raw_arch.hh" +ElementId ELEM_RAW_SAVEFILE = ElementId("raw_savefile",172); + // Constructing this object registers the capability RawBinaryArchitectureCapability RawBinaryArchitectureCapability::rawBinaryArchitectureCapability; @@ -81,16 +83,15 @@ RawBinaryArchitecture::RawBinaryArchitecture(const string &fname,const string &t adjustvma = 0; } -void RawBinaryArchitecture::saveXml(ostream &s) const +void RawBinaryArchitecture::encode(Encoder &encoder) const { - s << "\n"; - types->saveXmlCoreTypes(s); - SleighArchitecture::saveXml(s); - s << "\n"; + encoder.openElement(ELEM_RAW_SAVEFILE); + encodeHeader(encoder); + encoder.writeUnsignedInteger(ATTRIB_ADJUSTVMA, adjustvma); + types->encodeCoreTypes(encoder); + SleighArchitecture::encode(encoder); + encoder.closeElement(ELEM_RAW_SAVEFILE); } void RawBinaryArchitecture::restoreXml(DocumentStorage &store) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/raw_arch.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/raw_arch.hh index 7457a63035..2245840a0f 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/raw_arch.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/raw_arch.hh @@ -18,6 +18,8 @@ #include "sleigh_arch.hh" #include "loadimage.hh" +extern ElementId ELEM_RAW_SAVEFILE; ///< Marshaling element \ + /// \brief Extension point for building an Architecture that reads in raw images class RawBinaryArchitectureCapability : public ArchitectureCapability { static RawBinaryArchitectureCapability rawBinaryArchitectureCapability; ///< The singleton instance @@ -38,7 +40,7 @@ class RawBinaryArchitecture : public SleighArchitecture { virtual void resolveArchitecture(void); virtual void postSpecFile(void); public: - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; virtual void restoreXml(DocumentStorage &store); RawBinaryArchitecture(const string &fname,const string &targ,ostream *estream); ///< Constructor virtual ~RawBinaryArchitecture(void) {} diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc index 6b8edd53e2..83e7787333 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc @@ -16,56 +16,81 @@ #include "sleigh_arch.hh" #include "inject_sleigh.hh" +AttributeId ATTRIB_DEPRECATED = AttributeId("deprecated",79); +AttributeId ATTRIB_ENDIAN = AttributeId("endian",80); +AttributeId ATTRIB_PROCESSOR = AttributeId("processor",81); +AttributeId ATTRIB_PROCESSORSPEC = AttributeId("processorspec",82); +AttributeId ATTRIB_SLAFILE = AttributeId("slafile",83); +AttributeId ATTRIB_SPEC = AttributeId("spec",84); +AttributeId ATTRIB_TARGET = AttributeId("target",85); +AttributeId ATTRIB_VARIANT = AttributeId("variant",86); +AttributeId ATTRIB_VERSION = AttributeId("version",87); + +ElementId ELEM_COMPILER = ElementId("compiler",173); +ElementId ELEM_DESCRIPTION = ElementId("description",174); +ElementId ELEM_LANGUAGE = ElementId("language",175); +ElementId ELEM_LANGUAGE_DEFINITIONS = ElementId("language_definitions",176); + map SleighArchitecture::translators; vector SleighArchitecture::description; FileManage SleighArchitecture::specpaths; // Global specfile manager -/// Read file attributes from an XML \ tag -/// \param el is the XML element -void CompilerTag::restoreXml(const Element *el) +/// Parse file attributes from a \ element +/// \param decoder is the stream decoder +void CompilerTag::decode(Decoder &decoder) { - name = el->getAttributeValue("name"); - spec = el->getAttributeValue("spec"); - id = el->getAttributeValue("id"); + uint4 elemId = decoder.openElement(ELEM_COMPILER); + name = decoder.readString(ATTRIB_NAME); + spec = decoder.readString(ATTRIB_SPEC); + id = decoder.readString(ATTRIB_ID); + decoder.closeElement(elemId); } -/// Parse an ldefs \ tag -/// \param el is the XML element -void LanguageDescription::restoreXml(const Element *el) +/// Parse an ldefs \ element +/// \param decoder is the stream decoder +void LanguageDescription::decode(Decoder &decoder) { - processor = el->getAttributeValue("processor"); - isbigendian = (el->getAttributeValue("endian")=="big"); - istringstream s1(el->getAttributeValue("size")); - s1.unsetf(ios::dec | ios::hex | ios::oct); - s1 >> size; - variant = el->getAttributeValue("variant"); - version = el->getAttributeValue("version"); - slafile = el->getAttributeValue("slafile"); - processorspec = el->getAttributeValue("processorspec"); - id = el->getAttributeValue("id"); + uint4 elemId = decoder.openElement(ELEM_LANGUAGE); + processor = decoder.readString(ATTRIB_PROCESSOR); + isbigendian = (decoder.readString(ATTRIB_ENDIAN)=="big"); + size = decoder.readSignedInteger(ATTRIB_SIZE); + variant = decoder.readString(ATTRIB_VARIANT); + version = decoder.readString(ATTRIB_VERSION); + slafile = decoder.readString(ATTRIB_SLAFILE); + processorspec = decoder.readString(ATTRIB_PROCESSORSPEC); + id = decoder.readString(ATTRIB_ID); deprecated = false; - for(int4 i=0;igetNumAttributes();++i) { - if (el->getAttributeName(i)=="deprecated") - deprecated = xml_readbool(el->getAttributeValue(i)); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId==ATTRIB_DEPRECATED) + deprecated = decoder.readBool(); } - const List &sublist(el->getChildren()); - List::const_iterator subiter; - for(subiter=sublist.begin();subiter!=sublist.end();++subiter) { - const Element *subel = *subiter; - if (subel->getName() == "description") - description = subel->getContent(); - else if (subel->getName() == "compiler") { + for(;;) { + uint4 subId = decoder.peekElement(); + if (subId == 0) break; + if (subId == ELEM_DESCRIPTION) { + decoder.openElement(); + description = decoder.readString(ATTRIB_CONTENT); + decoder.closeElement(subId); + } + else if (subId == ELEM_COMPILER) { compilers.emplace_back(); - compilers.back().restoreXml(subel); + compilers.back().decode(decoder); } - else if (subel->getName() == "truncate_space") { + else if (subId == ELEM_TRUNCATE_SPACE) { truncations.emplace_back(); - truncations.back().restoreXml(subel); + truncations.back().decode(decoder); + } + else { // Ignore other child elements + decoder.openElement(); + decoder.closeElementSkipping(subId); } } + decoder.closeElement(elemId); } /// Pick out the CompilerTag associated with the desired \e compiler \e id string @@ -97,25 +122,29 @@ void SleighArchitecture::loadLanguageDescription(const string &specfile,ostream ifstream s(specfile.c_str()); if (!s) return; - Document *doc; - Element *el; + XmlDecode decoder; try { - doc = xml_tree(s); + decoder.ingestStream(s); } catch(XmlError &err) { errs << "WARNING: Unable to parse sleigh specfile: " << specfile; return; } - el = doc->getRoot(); - const List &list(el->getChildren()); - List::const_iterator iter; - for(iter=list.begin();iter!=list.end();++iter) { - if ((*iter)->getName() != "language") continue; - description.emplace_back(); - description.back().restoreXml( *iter ); + uint4 elemId = decoder.openElement(ELEM_LANGUAGE_DEFINITIONS); + for(;;) { + uint4 subId = decoder.peekElement(); + if (subId == 0) break; + if (subId == ELEM_LANGUAGE) { + description.emplace_back(); + description.back().decode( decoder ); + } + else { + decoder.openElement(); + decoder.closeElementSkipping(subId); + } } - delete doc; + decoder.closeElement(elemId); } SleighArchitecture::~SleighArchitecture(void) @@ -307,12 +336,12 @@ void SleighArchitecture::collectSpecFiles(ostream &errs) loadLanguageDescription(*iter,errs); } -/// \param s is the XML output stream -void SleighArchitecture::saveXmlHeader(ostream &s) const +/// \param encoder is the stream encoder +void SleighArchitecture::encodeHeader(Encoder &encoder) const { - a_v(s,"name",filename); - a_v(s,"target",target); + encoder.writeString(ATTRIB_NAME, filename); + encoder.writeString(ATTRIB_TARGET, target); } /// \param el is the root XML element @@ -457,6 +486,19 @@ void SleighArchitecture::scanForSleighDirectories(const string &rootpath) specpaths.addDir2Path(languagesubdirs[i]); } +/// Parse all .ldef files and a return the list of all LanguageDescription objects +/// If there are any parse errors in the .ldef files, an exception is thrown +/// \return the list of LanguageDescription objects +const vector &SleighArchitecture::getDescriptions(void) + +{ + ostringstream s; + collectSpecFiles(s); + if (!s.str().empty()) + throw LowlevelError(s.str()); + return description; +} + void SleighArchitecture::shutdown(void) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.hh index 84b55fd54b..6bb57b81a3 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.hh @@ -23,6 +23,21 @@ #include "architecture.hh" #include "sleigh.hh" +extern AttributeId ATTRIB_DEPRECATED; ///< Marshaling attribute "deprecated" +extern AttributeId ATTRIB_ENDIAN; ///< Marshaling attribute "endian" +extern AttributeId ATTRIB_PROCESSOR; ///< Marshaling attribute "processor" +extern AttributeId ATTRIB_PROCESSORSPEC; ///< Marshaling attribute "processorspec" +extern AttributeId ATTRIB_SLAFILE; ///< Marshaling attribute "slafile" +extern AttributeId ATTRIB_SPEC; ///< Marshaling attribute "spec" +extern AttributeId ATTRIB_TARGET; ///< Marshaling attribute "target" +extern AttributeId ATTRIB_VARIANT; ///< Marshaling attribute "variant" +extern AttributeId ATTRIB_VERSION; ///< Marshaling attribute "version" + +extern ElementId ELEM_COMPILER; ///< Marshaling element \ +extern ElementId ELEM_DESCRIPTION; ///< Marshaling element \ +extern ElementId ELEM_LANGUAGE; ///< Marshaling element \ +extern ElementId ELEM_LANGUAGE_DEFINITIONS; ///< Marshaling element \ + /// \brief Contents of a \ tag in a .ldefs file /// /// This class describes a compiler specification file as referenced by the Sleigh language subsystem. @@ -32,7 +47,7 @@ class CompilerTag { string id; ///< Unique id for this compiler public: CompilerTag(void) {} ///< Constructor - void restoreXml(const Element *el); ///< Restore the record from an XML stream + void decode(Decoder &decoder); ///< Restore the record from an XML stream const string &getName(void) const { return name; } ///< Get the human readable name of the spec const string &getSpec(void) const { return spec; } ///< Get the file-name const string &getId(void) const { return id; } ///< Get the string used as part of \e language \e id @@ -61,7 +76,7 @@ class LanguageDescription { vector truncations; ///< Address space truncations required by this processor public: LanguageDescription(void) {} ///< Constructor - void restoreXml(const Element *el); ///< Read the XML tag from stream + void decode(Decoder &decoder); ///< Parse \b this description from a stream const string &getProcessor(void) const { return processor; } ///< Get the name of the processor bool isBigEndian(void) const { return isbigendian; } ///< Return \b true if the processor is big-endian int4 getSize(void) const { return size; } ///< Get the size of the address bus @@ -73,6 +88,8 @@ public: const string &getDescription(void) const { return description; } ///< Get a description of the processor bool isDeprecated(void) const { return deprecated; } ///< Return \b true if this specification is deprecated const CompilerTag &getCompiler(const string &nm) const; ///< Get compiler specification of the given name + int4 numCompilers(void) const { return compilers.size(); } ///< Get the number of compiler records + const CompilerTag &getCompiler(int4 i) const { return compilers[i]; } ///< Get the i-th compiler record int4 numTruncations(void) const { return truncations.size(); } ///< Get the number of truncation records const TruncationTag &getTruncation(int4 i) const { return truncations[i]; } ///< Get the i-th truncation record }; @@ -107,18 +124,19 @@ public: SleighArchitecture(const string &fname,const string &targ,ostream *estream); ///< Construct given executable file const string &getFilename(void) const { return filename; } ///< Get the executable filename const string &getTarget(void) const { return target; } ///< Get the \e language \e id of the active processor - void saveXmlHeader(ostream &s) const; ///< Write out (as XML) basic attributes of the active executable - void restoreXmlHeader(const Element *el); ///< Restore from XML basic attributes of an executable + void encodeHeader(Encoder &encoder) const; ///< Encode basic attributes of the active executable + void restoreXmlHeader(const Element *el); ///< Restore from basic attributes of an executable virtual void printMessage(const string &message) const { *errorstream << message << endl; } virtual ~SleighArchitecture(void); virtual string getDescription(void) const; - + static string normalizeProcessor(const string &nm); ///< Try to recover a \e language \e id processor field static string normalizeEndian(const string &nm); ///< Try to recover a \e language \e id endianess field static string normalizeSize(const string &nm); ///< Try to recover a \e language \e id size field static string normalizeArchitecture(const string &nm); ///< Try to recover a \e language \e id string static void scanForSleighDirectories(const string &rootpath); - static void shutdown(void); ///< Shutdown this SleighArchitecture and free all resources. + static const vector &getDescriptions(void); ///< Get list of all known language descriptions + static void shutdown(void); ///< Shutdown all Translate objects and free global resources. static FileManage specpaths; ///< Known directories that contain .ldefs files. }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/sleighbase.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/sleighbase.cc index 0af4b793d3..51fb8203af 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/sleighbase.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/sleighbase.cc @@ -268,7 +268,8 @@ void SleighBase::restoreXml(const Element *el) } indexer.restoreXml(*iter); iter++; - restoreXmlSpaces(*iter,this); + XmlDecode decoder(*iter); + decodeSpaces(decoder,this); iter++; symtab.restoreXml(*iter,this); root = (SubtableSymbol *)symtab.getGlobalScope()->findSymbol("instruction"); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/sleighbase.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/sleighbase.hh index 2cfe1f751d..560c5a203c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/sleighbase.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/sleighbase.hh @@ -33,19 +33,19 @@ /// the source file index. class SourceFileIndexer { public: - SourceFileIndexer() {leastUnusedIndex = 0;} - ~SourceFileIndexer(void) { } - ///Returns the index of the file. If the file is not in the index it is added. - int4 index(const string filename); - int4 getIndex(const string); ///< get the index of a file. Error if the file is not in the index. - string getFilename(int4); ///< get the filename corresponding to an index - void restoreXml(const Element *el); ///< read a stored index mapping from an XML file - void saveXml(ostream&) const; ///< save the index mapping to an XML file + SourceFileIndexer() {leastUnusedIndex = 0;} + ~SourceFileIndexer(void) { } + ///Returns the index of the file. If the file is not in the index it is added. + int4 index(const string filename); + int4 getIndex(const string); ///< get the index of a file. Error if the file is not in the index. + string getFilename(int4); ///< get the filename corresponding to an index + void restoreXml(const Element *el); ///< read a stored index mapping from an XML file + void saveXml(ostream&) const; ///< save the index mapping to an XML file private: - int4 leastUnusedIndex; ///< one-up count for assigning indices to files - map indexToFile; ///< map from indices to files - map fileToIndex; ///< map from files to indices + int4 leastUnusedIndex; ///< one-up count for assigning indices to files + map indexToFile; ///< map from indices to files + map fileToIndex; ///< map from files to indices }; /// \brief Common core of classes that read or write SLEIGH specification files natively. diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/space.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/space.cc index dc0ec5c4ac..e3fd106702 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/space.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/space.cc @@ -16,6 +16,21 @@ #include "space.hh" #include "translate.hh" +AttributeId ATTRIB_BASE = AttributeId("base",88); +AttributeId ATTRIB_DEADCODEDELAY = AttributeId("deadcodedelay",89); +AttributeId ATTRIB_DELAY = AttributeId("delay", 90); +AttributeId ATTRIB_LOGICALSIZE = AttributeId("logicalsize",91); +AttributeId ATTRIB_PHYSICAL = AttributeId("physical",92); +AttributeId ATTRIB_PIECE1 = AttributeId("piece1",93); // piece attributes must have sequential ids +AttributeId ATTRIB_PIECE2 = AttributeId("piece2",94); +AttributeId ATTRIB_PIECE3 = AttributeId("piece3",95); +AttributeId ATTRIB_PIECE4 = AttributeId("piece4",96); +AttributeId ATTRIB_PIECE5 = AttributeId("piece5",97); +AttributeId ATTRIB_PIECE6 = AttributeId("piece6",98); +AttributeId ATTRIB_PIECE7 = AttributeId("piece7",99); +AttributeId ATTRIB_PIECE8 = AttributeId("piece8",100); +AttributeId ATTRIB_PIECE9 = AttributeId("piece9",101); + /// Calculate \e highest based on \e addressSize, and \e wordsize. /// This also calculates the default pointerLowerBound void AddrSpace::calcScaleMask(void) @@ -111,58 +126,51 @@ void AddrSpace::truncateSpace(uint4 newsize) calcScaleMask(); } -/// Write the main XML attributes for an address within this space +/// Write the main attributes for an address within \b this space. /// The caller provides only the \e offset, and this routine fills /// in other details pertaining to this particular space. -/// \param s is the stream to write to +/// \param encoder is the stream encoder /// \param offset is the offset of the address -void AddrSpace::saveXmlAttributes(ostream &s,uintb offset) const +void AddrSpace::encodeAttributes(Encoder &encoder,uintb offset) const { - a_v(s,"space",getName()); // Just append the proper attributes - s << ' ' << "offset=\""; - printOffset(s,offset); - s << "\""; + encoder.writeString(ATTRIB_SPACE,getName()); + encoder.writeUnsignedInteger(ATTRIB_OFFSET, offset); } -/// Write the main XML attributes of an address with this space +/// Write the main attributes of an address with \b this space /// and a size. The caller provides the \e offset and \e size, /// and other details about this particular space are filled in. -/// \param s is the stream to write to +/// \param encoder is the stream encoder /// \param offset is the offset of the address /// \param size is the size of the memory location -void AddrSpace::saveXmlAttributes(ostream &s,uintb offset,int4 size) const +void AddrSpace::encodeAttributes(Encoder &encoder,uintb offset,int4 size) const { - a_v(s,"space",getName()); // Just append the proper attributes - s << ' ' << "offset=\""; - printOffset(s,offset); - s << "\""; - a_v_i(s,"size",size); + encoder.writeString(ATTRIB_SPACE, getName()); + encoder.writeUnsignedInteger(ATTRIB_OFFSET, offset); + encoder.writeSignedInteger(ATTRIB_SIZE, size); } -/// For an XML tag describing an address in this space, this routine -/// recovers the offset and possibly the size described by the tag -/// \param el is the XML address tag +/// For an open element describing an address in \b this space, this routine +/// recovers the offset and possibly the size described by the element +/// \param decoder is the stream decoder /// \param size is a reference where the recovered size should be stored /// \return the recovered offset -uintb AddrSpace::restoreXmlAttributes(const Element *el,uint4 &size) const +uintb AddrSpace::decodeAttributes(Decoder &decoder,uint4 &size) const { uintb offset; - int4 num = el->getNumAttributes(); bool foundoffset = false; - for(int4 i=0;igetAttributeName(i)=="offset") { + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_OFFSET) { foundoffset = true; - istringstream s1(el->getAttributeValue(i)); - s1.unsetf(ios::dec | ios::hex | ios::oct); - s1 >> offset; + offset = decoder.readUnsignedInteger(); } - else if (el->getAttributeName(i)=="size") { - istringstream s2(el->getAttributeValue(i)); - s2.unsetf(ios::dec | ios::hex | ios::oct); - s2 >> size; + else if (attribId == ATTRIB_SIZE) { + size = decoder.readUnsignedInteger(); } } if (!foundoffset) @@ -281,7 +289,7 @@ uintb AddrSpace::read(const string &s,int4 &size) const } /// Write a tag fully describing the details of this space -/// suitable for later recovery via restoreXml. +/// suitable for later recovery via decode. /// \param s is the stream being written void AddrSpace::saveXml(ostream &s) const @@ -291,56 +299,36 @@ void AddrSpace::saveXml(ostream &s) const s << "/>\n"; } -/// Walk a parsed XML tag and recover all the properties defining +/// Walk attributes of the current element and recover all the properties defining /// this space. The processor translator, \e trans, and the /// \e type must already be filled in. -/// \param el is the parsed XML tag -void AddrSpace::restoreXml(const Element *el) +/// \param decoder is the stream decoder +void AddrSpace::decodeBasicAttributes(Decoder &decoder) { - int4 numAttribs = el->getNumAttributes(); deadcodedelay = -1; - for (int4 i=0; i < numAttribs; i++) { - string attrName = el->getAttributeName(i); - string attrValue = el->getAttributeValue(i); - - if (attrName == "name") { - name = attrValue; + for (;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_NAME) { + name = decoder.readString(); } - if (attrName == "index") - { - istringstream s1(attrValue); - s1.unsetf(ios::dec | ios::hex | ios::oct); - s1 >> index; - } - if (attrName == "size") - { - istringstream s1(attrValue); - s1.unsetf(ios::dec | ios::hex | ios::oct); - s1 >> addressSize; - } - if (attrName == "wordsize") - { - istringstream s1(attrValue); - s1.unsetf(ios::dec | ios::hex | ios::oct); - s1 >> wordsize; - } - if (attrName == "bigendian") { - if (xml_readbool(attrValue)) + if (attribId == ATTRIB_INDEX) + index = decoder.readSignedInteger(); + else if (attribId == ATTRIB_SIZE) + addressSize = decoder.readUnsignedInteger(); + else if (attribId == ATTRIB_WORDSIZE) + wordsize = decoder.readUnsignedInteger(); + else if (attribId == ATTRIB_BIGENDIAN) { + if (decoder.readBool()) flags |= big_endian; } - if (attrName == "delay") { - istringstream s1(attrValue); - s1.unsetf(ios::dec | ios::hex | ios::oct); - s1 >> delay; - } - if (attrName == "deadcodedelay") { - istringstream s1(attrValue); - s1.unsetf(ios::dec | ios::hex | ios::oct); - s1 >> deadcodedelay; - } - if (attrName == "physical") { - if (xml_readbool(attrValue)) + else if (attribId == ATTRIB_DELAY) + delay = decoder.readSignedInteger(); + else if (attribId == ATTRIB_DEADCODEDELAY) + deadcodedelay = decoder.readSignedInteger(); + else if (attribId == ATTRIB_PHYSICAL) { + if (decoder.readBool()) flags |= hasphysical; } @@ -350,6 +338,14 @@ void AddrSpace::restoreXml(const Element *el) calcScaleMask(); } +void AddrSpace::decode(Decoder &decoder) + +{ + uint4 elemId = decoder.openElement(); // Multiple tags: , , + decodeBasicAttributes(decoder); + decoder.closeElement(elemId); +} + const string ConstantSpace::NAME = "const"; const int4 ConstantSpace::INDEX = 0; @@ -384,11 +380,11 @@ void ConstantSpace::saveXml(ostream &s) const } /// As the ConstantSpace is never saved, it should never get -/// restored either. -void ConstantSpace::restoreXml(const Element *el) +/// decoded either. +void ConstantSpace::decode(Decoder &decoder) { - throw LowlevelError("Should never restore the constant space from XML"); + throw LowlevelError("Should never decode the constant space"); } const string OtherSpace::NAME = "OTHER"; @@ -475,87 +471,72 @@ JoinSpace::JoinSpace(AddrSpaceManager *m,const Translate *t,int4 ind) clearFlags(heritaged); // This space is never heritaged, but does dead-code analysis } -/// Save a join address to the stream as XML. This method in the interface only -/// outputs XML attributes for a single tag, so we are forced to encode what should probably -/// be recursive tags into an attribute -/// \param s is the stream being written to +/// Encode a \e join address to the stream. This method in the interface only +/// outputs attributes for a single element, so we are forced to encode what should probably +/// be recursive elements into an attribute. +/// \param encoder is the stream encoder /// \param offset is the offset within the address space to encode -void JoinSpace::saveXmlAttributes(ostream &s,uintb offset) const +void JoinSpace::encodeAttributes(Encoder &encoder,uintb offset) const { + static AttributeId *pieceArray[] = { &ATTRIB_PIECE1, &ATTRIB_PIECE2, &ATTRIB_PIECE3, &ATTRIB_PIECE4, + &ATTRIB_PIECE5, &ATTRIB_PIECE6, &ATTRIB_PIECE7, &ATTRIB_PIECE8, &ATTRIB_PIECE9 }; JoinRecord *rec = getManager()->findJoin(offset); // Record must already exist - a_v(s,"space",getName()); + encoder.writeString(ATTRIB_SPACE, getName()); int4 num = rec->numPieces(); + if (num >= 8) + throw LowlevelError("Cannot encode more than 8 pieces"); for(int4 i=0;igetPiece(i) ); ostringstream t; - t << " piece" << dec << (i+1) << "=\""; + AttributeId *attribId = pieceArray[i]; t << vdata.space->getName() << ":0x"; - t << hex << vdata.offset << ':' << dec << vdata.size << '\"'; - s << t.str(); + t << hex << vdata.offset << ':' << dec << vdata.size; + encoder.writeString(*attribId, t.str()); } if (num == 1) - a_v_i(s,"logicalsize",rec->getUnified().size); - + encoder.writeSignedInteger(ATTRIB_LOGICALSIZE, rec->getUnified().size); } -/// Save a join address to the stream as XML. This method in the interface only -/// outputs XML attributes for a single tag, so we are forced to encode what should probably -/// be recursive tags into an attribute -/// \param s is the stream being written to +/// Encode a \e join address to the stream. This method in the interface only +/// outputs attributes for a single element, so we are forced to encode what should probably +/// be recursive elements into an attribute. +/// \param encoder is the stream encoder /// \param offset is the offset within the address space to encode /// \param size is the size of the memory location being encoded -void JoinSpace::saveXmlAttributes(ostream &s,uintb offset,int4 size) const +void JoinSpace::encodeAttributes(Encoder &encoder,uintb offset,int4 size) const { - JoinRecord *rec = getManager()->findJoin(offset); // Record must already exist - a_v(s,"space",getName()); - int4 num = rec->numPieces(); - int4 count = 0; - for(int4 i=0;igetPiece(i) ); - ostringstream t; - t << " piece" << dec << (i+1) << "=\""; - t << vdata.space->getName() << ":0x"; - t << hex << vdata.offset << ':' << dec << vdata.size << '\"'; - count += vdata.size; - s << t.str(); - } - if (num == 1) - a_v_i(s,"logicalsize",rec->getUnified().size); - if ((count != size)&&(num>1)) - throw LowlevelError("size attribute in join tag does not match size of pieces"); + encodeAttributes(encoder,offset); // Ignore size } -/// Restore a join address from an XML tag. Pieces of the join are encoded as a sequence -/// of tag attributes. The Translate::findAddJoin method is used to construct a logical +/// Parse a join address the current element. Pieces of the join are encoded as a sequence +/// of attributes. The Translate::findAddJoin method is used to construct a logical /// address within the join space. -/// \param el is the parsed XML element to extract the address from +/// \param decoder is the stream decoder /// \param size is a reference to be filled in as the size encoded by the tag /// \return the offset of the final address encoded by the tag -uintb JoinSpace::restoreXmlAttributes(const Element *el,uint4 &size) const +uintb JoinSpace::decodeAttributes(Decoder &decoder,uint4 &size) const { vector pieces; - int4 numAttribs = el->getNumAttributes(); uint4 sizesum = 0; uint4 logicalsize = 0; - for(int4 i=0;igetAttributeName(i); - if (0!=attrName.compare(0,5,"piece")) { - if (attrName == "logicalsize") { - istringstream s3(el->getAttributeValue(i)); - s3.unsetf(ios::dec | ios::hex | ios::oct); - s3 >> logicalsize; - } + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_LOGICALSIZE) { + logicalsize = decoder.readUnsignedInteger(); continue; } - int4 pos = (int4)(attrName[5] - '1'); + if (attribId < ATTRIB_PIECE1.getId() || attribId > ATTRIB_PIECE9.getId()) + continue; + int4 pos = (int4)(attribId - ATTRIB_PIECE1.getId()); while(pieces.size() <= pos) pieces.emplace_back(); VarnodeData &vdat( pieces[pos] ); - string attrVal = el->getAttributeValue(i); + string attrVal = decoder.readString(); string::size_type offpos = attrVal.find(':'); if (offpos == string::npos) { const Translate *tr = getTrans(); @@ -644,10 +625,10 @@ void JoinSpace::saveXml(ostream &s) const throw LowlevelError("Should never save join space to XML"); } -void JoinSpace::restoreXml(const Element *el) +void JoinSpace::decode(Decoder &decoder) { - throw LowlevelError("Should never restore join space from XML"); + throw LowlevelError("Should never decode join space"); } /// \param m is the address space manager @@ -669,18 +650,18 @@ void OverlaySpace::saveXml(ostream &s) const s << "/>\n"; } -void OverlaySpace::restoreXml(const Element *el) +void OverlaySpace::decode(Decoder &decoder) { - name = el->getAttributeValue("name"); - istringstream s1(el->getAttributeValue("index")); - s1.unsetf(ios::dec | ios::hex | ios::oct); - s1 >> index; + uint4 elemId = decoder.openElement(ELEM_SPACE_OVERLAY); + name = decoder.readString(ATTRIB_NAME); + index = decoder.readSignedInteger(ATTRIB_INDEX); - string basename = el->getAttributeValue("base"); + string basename = decoder.readString(ATTRIB_BASE); baseSpace = getManager()->getSpaceByName(basename); if (baseSpace == (AddrSpace *)0) throw LowlevelError("Base space does not exist for overlay space: "+name); + decoder.closeElement(elemId); addressSize = baseSpace->getAddrSize(); wordsize = baseSpace->getWordSize(); delay = baseSpace->getDelay(); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/space.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/space.hh index 2188f8c31d..f5e61cf060 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/space.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/space.hh @@ -20,7 +20,7 @@ #define __CPUI_SPACE__ #include "error.hh" -#include "xml.hh" +#include "marshal.hh" /// \brief Fundemental address space types /// @@ -40,6 +40,21 @@ class AddrSpaceManager; struct VarnodeData; class Translate; +extern AttributeId ATTRIB_BASE; ///< Marshaling attribute "base" +extern AttributeId ATTRIB_DEADCODEDELAY; ///< Marshaling attribute "deadcodedelay" +extern AttributeId ATTRIB_DELAY; ///< Marshaling attribute "delay" +extern AttributeId ATTRIB_LOGICALSIZE; ///< Marshaling attribute "logicalsize" +extern AttributeId ATTRIB_PHYSICAL; ///< Marshaling attribute "physical" +extern AttributeId ATTRIB_PIECE1; ///< Marshaling attribute "piece1" +extern AttributeId ATTRIB_PIECE2; ///< Marshaling attribute "piece2" +extern AttributeId ATTRIB_PIECE3; ///< Marshaling attribute "piece3" +extern AttributeId ATTRIB_PIECE4; ///< Marshaling attribute "piece4" +extern AttributeId ATTRIB_PIECE5; ///< Marshaling attribute "piece5" +extern AttributeId ATTRIB_PIECE6; ///< Marshaling attribute "piece6" +extern AttributeId ATTRIB_PIECE7; ///< Marshaling attribute "piece7" +extern AttributeId ATTRIB_PIECE8; ///< Marshaling attribute "piece8" +extern AttributeId ATTRIB_PIECE9; ///< Marshaling attribute "piece9" + /// \brief A region where processor data is stored /// /// An AddrSpace (Address Space) is an arbitrary sequence of @@ -108,10 +123,11 @@ protected: void setFlags(uint4 fl); ///< Set a cached attribute void clearFlags(uint4 fl); ///< Clear a cached attribute void saveBasicAttributes(ostream &s) const; ///< Write the XML attributes of this space + void decodeBasicAttributes(Decoder &decoder); ///< Read attributes for \b this space from an open XML element void truncateSpace(uint4 newsize); public: AddrSpace(AddrSpaceManager *m,const Translate *t,spacetype tp,const string &nm,uint4 size,uint4 ws,int4 ind,uint4 fl,int4 dl); - AddrSpace(AddrSpaceManager *m,const Translate *t,spacetype tp); ///< For use with restoreXml + AddrSpace(AddrSpaceManager *m,const Translate *t,spacetype tp); ///< For use with decode virtual ~AddrSpace(void) {} ///< The address space destructor const string &getName(void) const; ///< Get the name AddrSpaceManager *getManager(void) const; ///< Get the space manager @@ -145,13 +161,13 @@ public: virtual const VarnodeData &getSpacebaseFull(int4 i) const; ///< Return original spacebase register before truncation virtual bool stackGrowsNegative(void) const; ///< Return \b true if a stack in this space grows negative virtual AddrSpace *getContain(void) const; ///< Return this space's containing space (if any) - virtual void saveXmlAttributes(ostream &s,uintb offset) const; ///< Save an address as XML - virtual void saveXmlAttributes(ostream &s,uintb offset,int4 size) const; ///< Save an address and size as XML - virtual uintb restoreXmlAttributes(const Element *el,uint4 &size) const; ///< Recover an offset and size + virtual void encodeAttributes(Encoder &encoder,uintb offset) const; ///< Encode address attributes to a stream + virtual void encodeAttributes(Encoder &encoder,uintb offset,int4 size) const; ///< Encode an address and size attributes to a stream + virtual uintb decodeAttributes(Decoder &decoder,uint4 &size) const; ///< Recover an offset and size virtual void printRaw(ostream &s,uintb offset) const; ///< Write an address in this space to a stream virtual uintb read(const string &s,int4 &size) const; ///< Read in an address (and possible size) from a string virtual void saveXml(ostream &s) const; ///< Write the details of this space as XML - virtual void restoreXml(const Element *el); ///< Recover the details of this space from XML + virtual void decode(Decoder &decoder); ///< Recover the details of this space from XML static uintb addressToByte(uintb val,uint4 ws); ///< Scale from addressable units to byte units static uintb byteToAddress(uintb val,uint4 ws); ///< Scale from byte units to addressable units @@ -177,7 +193,7 @@ public: ConstantSpace(AddrSpaceManager *m,const Translate *t); ///< Only constructor virtual void printRaw(ostream &s,uintb offset) const; virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el); + virtual void decode(Decoder &decoder); static const string NAME; ///< Reserved name for the address space static const int4 INDEX; ///< Reserved index for constant space }; @@ -186,7 +202,7 @@ public: class OtherSpace : public AddrSpace { public: OtherSpace(AddrSpaceManager *m, const Translate *t, int4 ind); ///< Constructor - OtherSpace(AddrSpaceManager *m, const Translate *t); ///< For use with restoreXml + OtherSpace(AddrSpaceManager *m, const Translate *t); ///< For use with decode virtual void printRaw(ostream &s, uintb offset) const; virtual void saveXml(ostream &s) const; static const string NAME; ///< Reserved name for the address space @@ -205,7 +221,7 @@ public: class UniqueSpace : public AddrSpace { public: UniqueSpace(AddrSpaceManager *m,const Translate *t,int4 ind,uint4 fl); ///< Constructor - UniqueSpace(AddrSpaceManager *m,const Translate *t); ///< For use with restoreXml + UniqueSpace(AddrSpaceManager *m,const Translate *t); ///< For use with decode virtual void saveXml(ostream &s) const; static const string NAME; ///< Reserved name for the unique space static const uint4 SIZE; ///< Fixed size (in bytes) for unique space offsets @@ -222,13 +238,13 @@ public: class JoinSpace : public AddrSpace { public: JoinSpace(AddrSpaceManager *m,const Translate *t,int4 ind); - virtual void saveXmlAttributes(ostream &s,uintb offset) const; - virtual void saveXmlAttributes(ostream &s,uintb offset,int4 size) const; - virtual uintb restoreXmlAttributes(const Element *el,uint4 &size) const; + virtual void encodeAttributes(Encoder &encoder,uintb offset) const; + virtual void encodeAttributes(Encoder &encoder,uintb offset,int4 size) const; + virtual uintb decodeAttributes(Decoder &decoder,uint4 &size) const; virtual void printRaw(ostream &s,uintb offset) const; virtual uintb read(const string &s,int4 &size) const; virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el); + virtual void decode(Decoder &decoder); static const string NAME; ///< Reserved name for the join space }; @@ -246,7 +262,7 @@ public: OverlaySpace(AddrSpaceManager *m,const Translate *t); ///< Constructor virtual AddrSpace *getContain(void) const { return baseSpace; } virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el); + virtual void decode(Decoder &decoder); }; /// An internal method for derived classes to set space attributes diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/stringmanage.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/stringmanage.cc index d698b6530f..6ee92eb432 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/stringmanage.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/stringmanage.cc @@ -16,6 +16,12 @@ #include "stringmanage.hh" #include "architecture.hh" +AttributeId ATTRIB_TRUNC = AttributeId("trunc",102); + +ElementId ELEM_BYTES = ElementId("bytes",177); +ElementId ELEM_STRING = ElementId("string",178); +ElementId ELEM_STRINGMANAGE = ElementId("stringmanage",179); + /// \param max is the maximum number of characters to allow before truncating string StringManager::StringManager(int4 max) @@ -83,46 +89,49 @@ bool StringManager::isString(const Address &addr,Datatype *charType) return !buffer.empty(); } -/// Write \ tag, with \ sub-tags. -/// \param s is the stream to write to -void StringManager::saveXml(ostream &s) const +/// Encode \ element, with \ children. +/// \param encoder is the stream encoder +void StringManager::encode(Encoder &encoder) const { - s << "\n"; + encoder.openElement(ELEM_STRINGMANAGE); map::const_iterator iter1; for(iter1=stringMap.begin();iter1!=stringMap.end();++iter1) { - s << "\n"; - (*iter1).first.saveXml(s); + encoder.openElement(ELEM_STRING); + (*iter1).first.encode(encoder); const StringData &stringData( (*iter1).second ); - s << " \n" << setfill('0'); + encoder.openElement(ELEM_BYTES); + encoder.writeBool(ATTRIB_TRUNC, stringData.isTruncated); + ostringstream s; + s << '\n' << setfill('0'); for(int4 i=0;i\n"; + s << '\n'; + encoder.writeString(ATTRIB_CONTENT, s.str()); + encoder.closeElement(ELEM_BYTES); } - s << "\n"; + encoder.closeElement(ELEM_STRINGMANAGE); } -/// Read \ tag, with \ sub-tags. -/// \param el is the root tag element +/// Parse a \ element, with \ children. +/// \param decoder is the stream decoder /// \param m is the manager for looking up AddressSpaces -void StringManager::restoreXml(const Element *el, const AddrSpaceManager *m) +void StringManager::decode(Decoder &decoder, const AddrSpaceManager *m) { - const List &list(el->getChildren()); - List::const_iterator iter1; - for (iter1 = list.begin(); iter1 != list.end(); ++iter1) { - List::const_iterator iter2 = (*iter1)->getChildren().begin(); - Address addr = Address::restoreXml(*iter2, m); - ++iter2; + uint4 elemId = decoder.openElement(ELEM_STRINGMANAGE); + for (;;) { + uint4 subId = decoder.openElement(); + if (subId != ELEM_STRING) break; + Address addr = Address::decode(decoder, m); StringData &stringData(stringMap[addr]); - stringData.isTruncated = xml_readbool((*iter2)->getAttributeValue("trunc")); - istringstream is((*iter2)->getContent()); + uint4 subId2 = decoder.openElement(ELEM_BYTES); + stringData.isTruncated = decoder.readBool(ATTRIB_TRUNC); + istringstream is(decoder.readString(ATTRIB_CONTENT)); int4 val; char c1, c2; is >> ws; @@ -147,7 +156,10 @@ void StringManager::restoreXml(const Element *el, const AddrSpaceManager *m) c1 = is.get(); c2 = is.get(); } + decoder.closeElement(subId2); + decoder.closeElement(subId); } + decoder.closeElement(elemId); } /// \param buffer is the byte buffer diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/stringmanage.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/stringmanage.hh index 64f091d234..39276ef4e2 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/stringmanage.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/stringmanage.hh @@ -23,6 +23,12 @@ class Architecture; +extern AttributeId ATTRIB_TRUNC; ///< Marshaling attribute "trunc" + +extern ElementId ELEM_BYTES; ///< Marshaling element \ +extern ElementId ELEM_STRING; ///< Marshaling element \ +extern ElementId ELEM_STRINGMANAGE; ///< Marshaling element \ + /// \brief Storage for decoding and storing strings associated with an address /// /// Looks at data in the loadimage to determine if it represents a "string". @@ -56,8 +62,8 @@ public: /// \return the byte array of UTF8 data virtual const vector &getStringData(const Address &addr,Datatype *charType,bool &isTrunc)=0; - void saveXml(ostream &s) const; ///< Save cached strings to a stream as XML - void restoreXml(const Element *el,const AddrSpaceManager *m); ///< Restore string cache from XML + void encode(Encoder &encoder) const; ///< Encode cached strings to a stream + void decode(Decoder &decoder,const AddrSpaceManager *m); ///< Restore string cache from a stream static bool hasCharTerminator(const uint1 *buffer,int4 size,int4 charsize); ///< Check for a unicode string terminator static int4 readUtf16(const uint1 *buf,bool bigend); ///< Read a UTF16 code point from a byte array diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/transform.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/transform.cc index c60d99bdb7..0b9f726744 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/transform.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/transform.cc @@ -16,6 +16,8 @@ #include "transform.hh" #include "funcdata.hh" +AttributeId ATTRIB_VECTOR_LANE_SIZES = AttributeId("vector_lane_sizes",103); + /// \param op2 is the lane description to copy from LaneDescription::LaneDescription(const LaneDescription &op2) @@ -277,24 +279,32 @@ void LanedRegister::LanedIterator::normalize(void) size = -1; // Indicate ending iterator } -/// Read XML of the form \ -/// \param el is the particular \e register tag +/// Parse any vector lane sizes. +/// \param decoder is the stream decoder /// \param manage is used to map register names to storage info /// \return \b true if the XML description provides lane sizes -bool LanedRegister::restoreXml(const Element *el,const AddrSpaceManager *manage) +bool LanedRegister::decode(Decoder &decoder,const AddrSpaceManager *manage) { + uint4 elemId = decoder.openElement(ELEM_REGISTER); string laneSizes; - for(int4 i=0;igetNumAttributes();++i) { - if (el->getAttributeName(i) == "vector_lane_sizes") { - laneSizes = el->getAttributeValue(i); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_VECTOR_LANE_SIZES) { + laneSizes = decoder.readString(); break; } } - if (laneSizes.empty()) return false; + if (laneSizes.empty()) { + decoder.closeElement(elemId); + return false; + } + decoder.rewindAttributes(); VarnodeData storage; storage.space = (AddrSpace *)0; - storage.restoreXml(el, manage); + storage.decodeFromAttributes(decoder, manage); + decoder.closeElement(elemId); wholeSize = storage.size; sizeBitMask = 0; string::size_type pos = 0; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/transform.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/transform.hh index c90131af7d..413eabf2b7 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/transform.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/transform.hh @@ -22,6 +22,8 @@ class Funcdata; // Forward declaration class TransformOp; +extern AttributeId ATTRIB_VECTOR_LANE_SIZES; ///< Marshaling attribute "vector_lane_sizes" + /// \brief Placeholder node for Varnode that will exist after a transform is applied to a function class TransformVar { friend class TransformManager; @@ -107,9 +109,9 @@ private: int4 wholeSize; ///< Size of the whole register uint4 sizeBitMask; ///< A 1-bit for every permissible lane size public: - LanedRegister(void) { wholeSize = 0; sizeBitMask = 0; } ///< Constructor for use with restoreXml + LanedRegister(void) { wholeSize = 0; sizeBitMask = 0; } ///< Constructor for use with decode LanedRegister(int4 sz,uint4 mask) { wholeSize = sz; sizeBitMask = mask; } ///< Constructor - bool restoreXml(const Element *el,const AddrSpaceManager *manage); ///< Restore object from XML stream + bool decode(Decoder &decoder,const AddrSpaceManager *manage); ///< Parse \ elements for lane sizes int4 getWholeSize(void) const { return wholeSize; } ///< Get the size in bytes of the whole laned register uint4 getSizeBitMask(void) const { return sizeBitMask; } ///< Get the bit mask of possible lane sizes void addLaneSize(int4 size) { sizeBitMask |= ((uint4)1 << size); } ///< Add a new \e size to the allowed list diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/translate.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/translate.cc index ceeda78f9b..6d97814bbf 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/translate.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/translate.cc @@ -15,15 +15,31 @@ */ #include "translate.hh" -/// Read a \ XML tag to configure \b this object -/// \param el is the XML element -void TruncationTag::restoreXml(const Element *el) +AttributeId ATTRIB_CODE = AttributeId("code",104); +AttributeId ATTRIB_CONTAIN = AttributeId("contain",105); +AttributeId ATTRIB_DEFAULTSPACE = AttributeId("defaultspace",106); +AttributeId ATTRIB_UNIQBASE = AttributeId("uniqbase",107); + +ElementId ELEM_OP = ElementId("op",180); +ElementId ELEM_SLEIGH = ElementId("sleigh",181); +ElementId ELEM_SPACE = ElementId("space",182); +ElementId ELEM_SPACEID = ElementId("spaceid",183); +ElementId ELEM_SPACES = ElementId("spaces",184); +ElementId ELEM_SPACE_BASE = ElementId("space_base",185); +ElementId ELEM_SPACE_OTHER = ElementId("space_other",186); +ElementId ELEM_SPACE_OVERLAY = ElementId("space_overlay",187); +ElementId ELEM_SPACE_UNIQUE = ElementId("space_unique",188); +ElementId ELEM_TRUNCATE_SPACE = ElementId("truncate_space",189); + +/// Parse a \ element to configure \b this object +/// \param decoder is the stream decoder +void TruncationTag::decode(Decoder &decoder) { - spaceName = el->getAttributeValue("space"); - istringstream s(el->getAttributeValue("size")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> size; + uint4 elemId = decoder.openElement(ELEM_TRUNCATE_SPACE); + spaceName = decoder.readString(ATTRIB_SPACE); + size = decoder.readUnsignedInteger(ATTRIB_SIZE); + decoder.closeElement(elemId); } /// Construct a virtual space. This is usually used for the stack @@ -45,7 +61,7 @@ SpacebaseSpace::SpacebaseSpace(AddrSpaceManager *m,const Translate *t,const stri } /// This is a partial constructor, which must be followed up -/// with restoreXml in order to fillin the rest of the spaces +/// with decode in order to fillin the rest of the spaces /// attributes /// \param m is the associated address space manager /// \param t is the associated processor translator @@ -111,11 +127,13 @@ void SpacebaseSpace::saveXml(ostream &s) const s << "/>\n"; } -void SpacebaseSpace::restoreXml(const Element *el) +void SpacebaseSpace::decode(Decoder &decoder) { - AddrSpace::restoreXml(el); // Restore basic attributes - contain = getManager()->getSpaceByName(el->getAttributeValue("contain")); + uint4 elemId = decoder.openElement(ELEM_SPACE_BASE); + decodeBasicAttributes(decoder); + contain = getManager()->getSpaceByName(decoder.readString(ATTRIB_CONTAIN)); + decoder.closeElement(elemId); } /// The \e join space range maps to the underlying pieces in a natural endian aware way. @@ -191,55 +209,53 @@ AddrSpaceManager::AddrSpaceManager(void) /// The initialization of address spaces is the same across all /// variants of the Translate object. This routine initializes -/// a single address space from a parsed XML tag. It knows +/// a single address space from a decoder element. It knows /// which class derived from AddrSpace to instantiate based on -/// the tag name. -/// \param el is the parsed XML tag +/// the ElementId. +/// \param decoder is the stream decoder /// \param trans is the translator object to be associated with the new space /// \return a pointer to the initialized AddrSpace -AddrSpace *AddrSpaceManager::restoreXmlSpace(const Element *el,const Translate *trans) +AddrSpace *AddrSpaceManager::decodeSpace(Decoder &decoder,const Translate *trans) { + uint4 elemId = decoder.peekElement(); AddrSpace *res; - const string &tp(el->getName()); - if (tp == "space_base") + if (elemId == ELEM_SPACE_BASE) res = new SpacebaseSpace(this,trans); - else if (tp == "space_unique") + else if (elemId == ELEM_SPACE_UNIQUE) res = new UniqueSpace(this,trans); - else if (tp == "space_other") + else if (elemId == ELEM_SPACE_OTHER) res = new OtherSpace(this,trans); - else if (tp == "space_overlay") + else if (elemId == ELEM_SPACE_OVERLAY) res = new OverlaySpace(this,trans); else res = new AddrSpace(this,trans,IPTR_PROCESSOR); - res->restoreXml(el); + res->decode(decoder); return res; } /// This routine initializes (almost) all the address spaces used -/// for a particular processor by using a \b \ tag, -/// which contains subtags for the specific address spaces. +/// for a particular processor by using a \b \ element, +/// which contains child elements for the specific address spaces. /// This also instantiates the builtin \e constant space. It /// should probably also instantiate the \b iop, \b fspec, and \b join /// spaces, but this is currently done by the Architecture class. -/// \param el is the parsed \b \ tag +/// \param decoder is the stream decoder /// \param trans is the processor translator to be associated with the spaces -void AddrSpaceManager::restoreXmlSpaces(const Element *el,const Translate *trans) +void AddrSpaceManager::decodeSpaces(Decoder &decoder,const Translate *trans) { // The first space should always be the constant space insertSpace(new ConstantSpace(this,trans)); - string defname(el->getAttributeValue("defaultspace")); - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - while(iter!=list.end()) { - AddrSpace *spc = restoreXmlSpace(*iter,trans); + uint4 elemId = decoder.openElement(ELEM_SPACES); + string defname = decoder.readString(ATTRIB_DEFAULTSPACE); + while(decoder.peekElement() != 0) { + AddrSpace *spc = decodeSpace(decoder,trans); insertSpace(spc); - ++iter; } + decoder.closeElement(elemId); AddrSpace *spc = getSpaceByName(defname); if (spc == (AddrSpace *)0) throw LowlevelError("Bad 'defaultspace' attribute: "+defname); @@ -887,44 +903,48 @@ const FloatFormat *Translate::getFloatFormat(int4 size) const return (const FloatFormat *)0; } -/// A convenience method for passing around pcode operations via -/// XML. A single pcode operation is parsed from an XML tag and +/// A convenience method for passing around pcode operations via stream. +/// A single pcode operation is parsed from an \ element and /// returned to the application via the PcodeEmit::dump method. -/// \param el is the pcode operation XML tag +/// \param decoder is the stream decoder /// \param manage is the AddrSpace manager object of the associated processor -void PcodeEmit::restoreXmlOp(const Element *el,const AddrSpaceManager *manage) +void PcodeEmit::decodeOp(Decoder &decoder,const AddrSpaceManager *manage) -{ // Read a raw pcode op from DOM (and dump it) +{ int4 opcode; VarnodeData outvar; VarnodeData invar[30]; VarnodeData *outptr; - istringstream i(el->getAttributeValue("code")); - i >> opcode; - const List &list(el->getChildren()); - List::const_iterator iter = list.begin(); - Address pc = Address::restoreXml(*iter,manage); - ++iter; - if ((*iter)->getName() == "void") + uint4 elemId = decoder.openElement(ELEM_OP); + opcode = decoder.readSignedInteger(ATTRIB_CODE); + Address pc = Address::decode(decoder,manage); + uint4 subId = decoder.peekElement(); + if (subId == ELEM_VOID) { + decoder.openElement(); + decoder.closeElement(subId); outptr = (VarnodeData *)0; + } else { - outvar.restoreXml(*iter,manage); + outvar.decode(decoder,manage); outptr = &outvar; } - ++iter; int4 isize = 0; - while(iter != list.end() && isize < 30) { - if ((*iter)->getName() == "spaceid") { + while(isize < 30) { + subId = decoder.peekElement(); + if (subId == 0) break; + if (subId == ELEM_SPACEID) { + decoder.openElement(); invar[isize].space = manage->getConstantSpace(); - invar[isize].offset = (uintb)(uintp)manage->getSpaceByName( (*iter)->getAttributeValue("name") ); + invar[isize].offset = (uintb)(uintp)manage->getSpaceByName( decoder.readString(ATTRIB_NAME) ); invar[isize].size = sizeof(void *); + decoder.closeElement(subId); } else - invar[isize].restoreXml(*iter,manage); + invar[isize].decode(decoder,manage); isize += 1; - ++iter; } + decoder.closeElement(elemId); dump(pc,(OpCode)opcode,outptr,invar,isize); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/translate.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/translate.hh index 7bc942af79..4b68058966 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/translate.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/translate.hh @@ -24,6 +24,22 @@ #include "pcoderaw.hh" #include "float.hh" +extern AttributeId ATTRIB_CODE; ///< Marshaling attribute "code" +extern AttributeId ATTRIB_CONTAIN; ///< Marshaling attribute "contain" +extern AttributeId ATTRIB_DEFAULTSPACE; ///< Marshaling attribute "defaultspace" +extern AttributeId ATTRIB_UNIQBASE; ///< Marshaling attribute "uniqbase" + +extern ElementId ELEM_OP; ///< Marshaling element \ +extern ElementId ELEM_SLEIGH; ///< Marshaling element \ +extern ElementId ELEM_SPACE; ///< Marshaling element \ +extern ElementId ELEM_SPACEID; ///< Marshaling element \ +extern ElementId ELEM_SPACES; ///< Marshaling element \ +extern ElementId ELEM_SPACE_BASE; ///< Marshaling element \ +extern ElementId ELEM_SPACE_OTHER; ///< Marshaling element \ +extern ElementId ELEM_SPACE_OVERLAY; ///< Marshaling element \ +extern ElementId ELEM_SPACE_UNIQUE; ///< Marshaling element \ +extern ElementId ELEM_TRUNCATE_SPACE; ///< Marshaling element \ + // Some errors specific to the translation unit /// \brief Exception for encountering unimplemented pcode @@ -64,7 +80,7 @@ class TruncationTag { string spaceName; ///< Name of space to be truncated uint4 size; ///< Size truncated addresses into the space public: - void restoreXml(const Element *el); ///< Restore \b this from XML + void decode(Decoder &decoder); ///< Restore \b this from a stream const string &getName(void) const { return spaceName; } ///< Get name of address space being truncated uint4 getSize(void) const { return size; } ///< Size (of pointers) for new truncated space }; @@ -91,8 +107,8 @@ public: /// \param isize is the number of input varnodes virtual void dump(const Address &addr,OpCode opc,VarnodeData *outvar,VarnodeData *vars,int4 isize)=0; - /// Emit pcode directly from an XML tag - void restoreXmlOp(const Element *el,const AddrSpaceManager *trans); + /// Emit pcode directly from an \ element + void decodeOp(Decoder &decoder,const AddrSpaceManager *trans); enum { // Tags for packed pcode format unimpl_tag = 0x20, @@ -177,14 +193,14 @@ class SpacebaseSpace : public AddrSpace { void setBaseRegister(const VarnodeData &data,int4 origSize,bool stackGrowth); ///< Set the base register at time space is created public: SpacebaseSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind,int4 sz,AddrSpace *base,int4 dl); - SpacebaseSpace(AddrSpaceManager *m,const Translate *t); ///< For use with restoreXml + SpacebaseSpace(AddrSpaceManager *m,const Translate *t); ///< For use with decode virtual int4 numSpacebase(void) const; virtual const VarnodeData &getSpacebase(int4 i) const; virtual const VarnodeData &getSpacebaseFull(int4 i) const; virtual bool stackGrowsNegative(void) const { return isNegativeStack; } virtual AddrSpace *getContain(void) const { return contain; } ///< Return containing space virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el); + virtual void decode(Decoder &decoder); }; /// \brief A record describing how logical values are split @@ -232,8 +248,8 @@ class AddrSpaceManager { set splitset; ///< Different splits that have been defined in join space vector splitlist; ///< JoinRecords indexed by join address protected: - AddrSpace *restoreXmlSpace(const Element *el,const Translate *trans); ///< Add a space to the model based an on XML tag - void restoreXmlSpaces(const Element *el,const Translate *trans); ///< Restore address spaces in the model from an XML tag + AddrSpace *decodeSpace(Decoder &decoder,const Translate *trans); ///< Add a space to the model based an on XML tag + void decodeSpaces(Decoder &decoder,const Translate *trans); ///< Restore address spaces in the model from an XML tag void setDefaultCodeSpace(int4 index); ///< Set the default address space (for code) void setDefaultDataSpace(int4 index); ///< Set the default address space for data void setReverseJustified(AddrSpace *spc); ///< Set reverse justified property on this space diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc index e4ad058a1f..552535978f 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc @@ -23,6 +23,34 @@ sub_metatype Datatype::base2sub[14] = { SUB_UINT_PLAIN, SUB_INT_PLAIN, SUB_UNKNOWN, SUB_SPACEBASE, SUB_VOID }; +AttributeId ATTRIB_ALIGNMENT = AttributeId("alignment",108); +AttributeId ATTRIB_ARRAYSIZE = AttributeId("arraysize",109); +AttributeId ATTRIB_CHAR = AttributeId("char",110); +AttributeId ATTRIB_CORE = AttributeId("core",111); +AttributeId ATTRIB_ENUM = AttributeId("enum",112); +AttributeId ATTRIB_ENUMSIGNED = AttributeId("enumsigned",113); +AttributeId ATTRIB_ENUMSIZE = AttributeId("enumsize",114); +AttributeId ATTRIB_INTSIZE = AttributeId("intsize",115); +AttributeId ATTRIB_LONGSIZE = AttributeId("longsize",116); +AttributeId ATTRIB_OPAQUESTRING = AttributeId("opaquestring",117); +AttributeId ATTRIB_SIGNED = AttributeId("signed",118); +AttributeId ATTRIB_STRUCTALIGN = AttributeId("structalign",119); +AttributeId ATTRIB_UTF = AttributeId("utf",120); +AttributeId ATTRIB_VARLENGTH = AttributeId("varlength",121); + +ElementId ELEM_CORETYPES = ElementId("coretypes",190); +ElementId ELEM_DATA_ORGANIZATION = ElementId("data_organization",191); +ElementId ELEM_DEF = ElementId("def",192); +ElementId ELEM_ENTRY = ElementId("entry",193); +ElementId ELEM_ENUM = ElementId("enum",194); +ElementId ELEM_FIELD = ElementId("field",195); +ElementId ELEM_INTEGER_SIZE = ElementId("integer_size",196); +ElementId ELEM_LONG_SIZE = ElementId("long_size",197); +ElementId ELEM_SIZE_ALIGNMENT_MAP = ElementId("size_alignment_map",198); +ElementId ELEM_TYPE = ElementId("type",199); +ElementId ELEM_TYPEGRP = ElementId("typegrp",200); +ElementId ELEM_TYPEREF = ElementId("typeref",201); + // Some default routines for displaying data /// Display an array of bytes as a hex dump at a given address. @@ -278,87 +306,86 @@ type_metatype string2metatype(const string &metastring) throw LowlevelError("Unknown metatype: "+metastring); } -/// Write out a formal description of the data-type as an XML \ tag. +/// Encode a formal description of the data-type as a \ element. /// For composite data-types, the description goes down one level, describing /// the component types only by reference. -/// \param s is the stream to write to -void Datatype::saveXml(ostream &s) const +/// \param encoder is the stream encoder +void Datatype::encode(Encoder &encoder) const { - s << ""; + encoder.openElement(ELEM_TYPE); + encodeBasic(metatype,encoder); + encoder.closeElement(ELEM_TYPE); } -/// Write out basic data-type properties (name,size,id) as XML attributes. -/// This routine presumes the initial tag is already written to the stream. -/// \param meta is the metatype to put in the XML -/// \param s is the stream to write to -void Datatype::saveXmlBasic(type_metatype meta,ostream &s) const +/// Encode basic data-type properties (name,size,id) as attributes. +/// This routine presumes the initial element is already written to the stream. +/// \param meta is the metatype attribute +/// \param encoder is the stream encoder +void Datatype::encodeBasic(type_metatype meta,Encoder &encoder) const { - a_v(s,"name",name); + encoder.writeString(ATTRIB_NAME, name); uint8 saveId; if (isVariableLength()) saveId = hashSize(id, size); else saveId = id; if (saveId != 0) { - s << " id=\"0x" << hex << saveId << '\"'; + encoder.writeUnsignedInteger(ATTRIB_ID, saveId); } - a_v_i(s,"size",size); + encoder.writeSignedInteger(ATTRIB_SIZE, size); string metastring; metatype2string(meta,metastring); - a_v(s,"metatype",metastring); + encoder.writeString(ATTRIB_METATYPE,metastring); if ((flags & coretype)!=0) - a_v_b(s,"core",true); + encoder.writeBool(ATTRIB_CORE,true); if (isVariableLength()) - a_v_b(s,"varlength",true); + encoder.writeBool(ATTRIB_VARLENGTH,true); if ((flags & opaque_string)!=0) - a_v_b(s,"opaquestring",true); + encoder.writeBool(ATTRIB_OPAQUESTRING,true); uint4 format = getDisplayFormat(); if (format != 0) - a_v(s,"format",decodeIntegerFormat(format)); + encoder.writeString(ATTRIB_FORMAT,decodeIntegerFormat(format)); } -/// Write a simple reference to \b this data-type as an XML \ tag, -/// which only encodes the name and id. -/// \param s is the stream to write to -void Datatype::saveXmlRef(ostream &s) const +/// Encode a simple reference to \b this data-type as a \ element, +/// including only the name and id. +/// \param encoder is the stream encoder +void Datatype::encodeRef(Encoder &encoder) const { // Save just a name reference if possible if ((id!=0)&&(metatype != TYPE_VOID)) { - s << ""; + encoder.closeElement(ELEM_TYPEREF); } else - saveXml(s); + encode(encoder); } -/// Called only if the \b typedefImm field is non-null. Write the data-type to the -/// stream as a simple \ tag including only the names and ids of \b this and +/// Called only if the \b typedefImm field is non-null. Encode the data-type to the +/// stream as a simple \ element including only the names and ids of \b this and /// the data-type it typedefs. -/// \param s is the output stream -void Datatype::saveXmlTypedef(ostream &s) const +/// \param encoder is the stream encoder +void Datatype::encodeTypedef(Encoder &encoder) const { - s << ""; - typedefImm->saveXmlRef(s); - s << ""; + encoder.writeString(ATTRIB_FORMAT,Datatype::decodeIntegerFormat(format)); + typedefImm->encodeRef(encoder); + encoder.closeElement(ELEM_DEF); } /// A CPUI_PTRSUB must act on a pointer data-type where the given offset addresses a component. @@ -418,44 +445,48 @@ int4 Datatype::findCompatibleResolve(Datatype *ct) const /// Restore the basic properties (name,size,id) of a data-type from an XML element /// Properties are read from the attributes of the element -/// \param el is the XML element -void Datatype::restoreXmlBasic(const Element *el) +/// \param decoder is the stream decoder +void Datatype::decodeBasic(Decoder &decoder) { - name = el->getAttributeValue("name"); - istringstream s(el->getAttributeValue("size")); - s.unsetf(ios::dec | ios::hex | ios::oct); size = -1; - s >> size; - if (size < 0) - throw LowlevelError("Bad size for type "+name); - metatype = string2metatype( el->getAttributeValue("metatype") ); - submeta = base2sub[metatype]; + metatype = TYPE_VOID; id = 0; - for(int4 i=0;igetNumAttributes();++i) { - const string &attribName( el->getAttributeName(i) ); - if (attribName == "core") { - if (xml_readbool(el->getAttributeValue(i))) + for(;;) { + uint4 attrib = decoder.getNextAttributeId(); + if (attrib == 0) break; + if (attrib == ATTRIB_NAME) { + name = decoder.readString(); + } + else if (attrib == ATTRIB_SIZE) { + size = decoder.readSignedInteger(); + } + else if (attrib == ATTRIB_METATYPE) { + metatype = string2metatype(decoder.readString()); + } + else if (attrib == ATTRIB_CORE) { + if (decoder.readBool()) flags |= coretype; } - else if (attribName == "id") { - istringstream s1(el->getAttributeValue(i)); - s1.unsetf(ios::dec | ios::hex | ios::oct); - s1 >> id; + else if (attrib == ATTRIB_ID) { + id = decoder.readUnsignedInteger(); } - else if (attribName == "varlength") { - if (xml_readbool(el->getAttributeValue(i))) + else if (attrib == ATTRIB_VARLENGTH) { + if (decoder.readBool()) flags |= variable_length; } - else if (attribName == "opaquestring") { - if (xml_readbool(el->getAttributeValue(i))) + else if (attrib == ATTRIB_OPAQUESTRING) { + if (decoder.readBool()) flags |= opaque_string; } - else if (attribName == "format") { - uint4 val = encodeIntegerFormat(el->getAttributeValue(i)); + else if (attrib == ATTRIB_FORMAT) { + uint4 val = encodeIntegerFormat(decoder.readString()); setDisplayFormat(val); } } + if (size < 0) + throw LowlevelError("Bad size for type "+name); + submeta = base2sub[metatype]; if ((id==0)&&(name.size()>0)) // If there is a type name id = hashName(name); // There must be some kind of id if (isVariableLength()) { @@ -546,74 +577,74 @@ string Datatype::decodeIntegerFormat(uint4 val) throw LowlevelError("Unrecognized integer format encoding"); } -/// Contruct from the given \ element. -/// \param el is the element +/// Construct from a \ element. +/// \param decoder is the stream decoder /// \param typegrp is the TypeFactory for parsing data-type info -TypeField::TypeField(const Element *el,TypeFactory &typegrp) +TypeField::TypeField(Decoder &decoder,TypeFactory &typegrp) { + uint4 elemId = decoder.openElement(ELEM_FIELD); ident = -1; offset = -1; - for(int4 i=0;igetNumAttributes();++i) { - const string &attribName(el->getAttributeName(i)); - if (attribName == "name") - name = el->getAttributeValue(i); - else if (attribName == "offset") { - istringstream j(el->getAttributeValue(i)); - j.unsetf(ios::dec | ios::hex | ios::oct); - j >> offset; + for(;;) { + uint4 attrib = decoder.getNextAttributeId(); + if (attrib == 0) break; + if (attrib == ATTRIB_NAME) + name = decoder.readString(); + else if (attrib == ATTRIB_OFFSET) { + offset = decoder.readSignedInteger(); } - else if (attribName == "id") { - istringstream j(el->getAttributeValue(i)); - j.unsetf(ios::dec | ios::hex | ios::oct); - j >> ident; + else if (attrib == ATTRIB_ID) { + ident = decoder.readSignedInteger(); } } - type = typegrp.restoreXmlType( *el->getChildren().begin() ); + type = typegrp.decodeType( decoder ); if (name.size()==0) throw LowlevelError("name attribute must not be empty in tag"); if (offset < 0) throw LowlevelError("offset attribute invalid for tag"); if (ident < 0) ident = offset; // By default the id is the offset + decoder.closeElement(elemId); } -/// Write out a formal description of \b this as an XML \ tag. -/// \param s is the stream to write to -void TypeField::saveXml(ostream &s) const +/// Encode a formal description of \b this as a \ element. +/// \param encoder is the stream encoder +void TypeField::encode(Encoder &encoder) const { - s << "'; - type->saveXmlRef(s); - s << "\n"; + encoder.writeSignedInteger(ATTRIB_ID, ident); + type->encodeRef(encoder); + encoder.closeElement(ELEM_FIELD); } -/// Parse a \ tag for attributes of the character data-type -/// \param el is the root XML element +/// Parse a \ element for attributes of the character data-type +/// \param decoder is the stream decoder /// \param typegrp is the factory owning \b this data-type -void TypeChar::restoreXml(const Element *el,TypeFactory &typegrp) +void TypeChar::decode(Decoder &decoder,TypeFactory &typegrp) { - restoreXmlBasic(el); +// uint4 elemId = decoder.openElement(); + decodeBasic(decoder); submeta = (metatype == TYPE_INT) ? SUB_INT_CHAR : SUB_UINT_CHAR; +// decoder.closeElement(elemId); } -void TypeChar::saveXml(ostream &s) const +void TypeChar::encode(Encoder &encoder) const { if (typedefImm != (Datatype *)0) { - saveXmlTypedef(s); + encodeTypedef(encoder); return; } - s << ""; + encoder.openElement(ELEM_TYPE); + encodeBasic(metatype,encoder); + encoder.writeBool(ATTRIB_CHAR, true); + encoder.closeElement(ELEM_TYPE); } /// Properties that specify which encoding this type uses are set based @@ -629,16 +660,18 @@ 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 +/// Parse a \ tag for properties of the data-type. +/// \param decoder is the stream decoder /// \param typegrp is the factory owning \b this data-type -void TypeUnicode::restoreXml(const Element *el,TypeFactory &typegrp) +void TypeUnicode::decode(Decoder &decoder,TypeFactory &typegrp) { - restoreXmlBasic(el); +// uint4 elemId = decoder.openElement(); + decodeBasic(decoder); // Get endianness flag from architecture, rather than specific type encoding setflags(); submeta = (metatype == TYPE_INT) ? SUB_INT_UNICODE : SUB_UINT_UNICODE; +// decoder.closeElement(elemId); } TypeUnicode::TypeUnicode(const string &nm,int4 sz,type_metatype m) @@ -648,27 +681,28 @@ TypeUnicode::TypeUnicode(const string &nm,int4 sz,type_metatype m) submeta = (m == TYPE_INT) ? SUB_INT_UNICODE : SUB_UINT_UNICODE; } -void TypeUnicode::saveXml(ostream &s) const +void TypeUnicode::encode(Encoder &encoder) const { if (typedefImm != (Datatype *)0) { - saveXmlTypedef(s); + encodeTypedef(encoder); return; } - s << ""; + encoder.openElement(ELEM_TYPE); + encodeBasic(metatype,encoder); + encoder.writeBool(ATTRIB_UTF, true); + encoder.closeElement(ELEM_TYPE); } -void TypeVoid::saveXml(ostream &s) const +void TypeVoid::encode(Encoder &encoder) const { if (typedefImm != (Datatype *)0) { - saveXmlTypedef(s); + encodeTypedef(encoder); return; } - s << ""; + encoder.openElement(ELEM_VOID); + encoder.closeElement(ELEM_VOID); } void TypePointer::printRaw(ostream &s) const @@ -717,46 +751,47 @@ int4 TypePointer::compareDependency(const Datatype &op) const return (op.getSize()-size); } -void TypePointer::saveXml(ostream &s) const +void TypePointer::encode(Encoder &encoder) const { if (typedefImm != (Datatype *)0) { - saveXmlTypedef(s); + encodeTypedef(encoder); return; } - s << "getName()); - s << '>'; - ptrto->saveXmlRef(s); - s << ""; + encoder.writeString(ATTRIB_SPACE, spaceid->getName()); + ptrto->encodeRef(encoder); + encoder.closeElement(ELEM_TYPE); } -/// Parse a \ tag with a child describing the data-type being pointed to -/// \param el is the root XML element +/// Parse a \ element with a child describing the data-type being pointed to +/// \param decoder is the stream decoder /// \param typegrp is the factory owning \b this data-type -void TypePointer::restoreXml(const Element *el,TypeFactory &typegrp) +void TypePointer::decode(Decoder &decoder,TypeFactory &typegrp) { - restoreXmlBasic(el); - for(int4 i=0;igetNumAttributes();++i) { - const string &attrName(el->getAttributeName(i)); - if (attrName == "wordsize") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> wordsize; +// uint4 elemId = decoder.openElement(); + decodeBasic(decoder);; + decoder.rewindAttributes(); + for(;;) { + uint4 attrib = decoder.getNextAttributeId(); + if (attrib == 0) break; + if (attrib == ATTRIB_WORDSIZE) { + wordsize = decoder.readUnsignedInteger(); } - else if (attrName == "space") { - spaceid = typegrp.getArch()->getSpaceByName(el->getAttributeValue(i)); + else if (attrib == ATTRIB_SPACE) { + spaceid = typegrp.getArch()->getSpaceByName(decoder.readString()); } } - ptrto = typegrp.restoreXmlType( *el->getChildren().begin() ); + ptrto = typegrp.decodeType( decoder ); calcSubmeta(); if (name.size() == 0) // Inherit only if no name flags |= ptrto->getInheritable(); +// decoder.closeElement(elemId); } /// Pointers to structures may require a specific \b submeta @@ -934,19 +969,18 @@ Datatype *TypeArray::getSubEntry(int4 off,int4 sz,int4 *newoff,int4 *el) const return arrayof; } -void TypeArray::saveXml(ostream &s) const +void TypeArray::encode(Encoder &encoder) const { if (typedefImm != (Datatype *)0) { - saveXmlTypedef(s); + encodeTypedef(encoder); return; } - s << "'; - arrayof->saveXmlRef(s); - s << ""; + encoder.openElement(ELEM_TYPE); + encodeBasic(metatype,encoder); + encoder.writeSignedInteger(ATTRIB_ARRAYSIZE, arraysize); + arrayof->encodeRef(encoder); + encoder.closeElement(ELEM_TYPE); } Datatype *TypeArray::resolveInFlow(PcodeOp *op,int4 slot) @@ -977,22 +1011,29 @@ int4 TypeArray::findCompatibleResolve(Datatype *ct) const return -1; } -/// Parse a \ tag with a child describing the array element data-type. -/// \param el is the root XML element +/// Parse a \ element with a child describing the array element data-type. +/// \param decoder is the stream decoder /// \param typegrp is the factory owning \b this data-type -void TypeArray::restoreXml(const Element *el,TypeFactory &typegrp) +void TypeArray::decode(Decoder &decoder,TypeFactory &typegrp) { - restoreXmlBasic(el); +// uint4 elemId = decoder.openElement(); + decodeBasic(decoder); arraysize = -1; - istringstream j(el->getAttributeValue("arraysize")); - j.unsetf(ios::dec | ios::hex | ios::oct); - j >> arraysize; - arrayof = typegrp.restoreXmlType(*el->getChildren().begin()); + decoder.rewindAttributes(); + for(;;) { + uint4 attrib = decoder.getNextAttributeId(); + if (attrib == 0) break; + if (attrib == ATTRIB_ARRAYSIZE) { + arraysize = decoder.readSignedInteger(); + } + } + arrayof = typegrp.decodeType(decoder); if ((arraysize<=0)||(arraysize*arrayof->getSize()!=size)) throw LowlevelError("Bad size for array of type "+arrayof->getName()); if (arraysize == 1) flags |= needs_resolution; // Array of size 1 needs special treatment +// decoder.closeElement(elemId); } TypeEnum::TypeEnum(const TypeEnum &op) : TypeBase(op) @@ -1141,50 +1182,59 @@ int4 TypeEnum::compareDependency(const Datatype &op) const return 0; } -void TypeEnum::saveXml(ostream &s) const +void TypeEnum::encode(Encoder &encoder) const { if (typedefImm != (Datatype *)0) { - saveXmlTypedef(s); + encodeTypedef(encoder); return; } - s << "\n"; + encoder.openElement(ELEM_TYPE); + encodeBasic(metatype,encoder); + encoder.writeString(ATTRIB_ENUM, "true"); map::const_iterator iter; for(iter=namemap.begin();iter!=namemap.end();++iter) { - s << "\n"; + encoder.openElement(ELEM_VAL); + encoder.writeString(ATTRIB_NAME,(*iter).second); + encoder.writeUnsignedInteger(ATTRIB_VALUE, (*iter).first); + encoder.closeElement(ELEM_VAL); } - s << ""; + encoder.closeElement(ELEM_TYPE); } -/// Parse a \ tag with children describing each specific enumeration value. -/// \param el is the root XML element +/// Parse a \ element with children describing each specific enumeration value. +/// \param decoder is the stream decoder /// \param typegrp is the factory owning \b this data-type -void TypeEnum::restoreXml(const Element *el,TypeFactory &typegrp) +void TypeEnum::decode(Decoder &decoder,TypeFactory &typegrp) { - restoreXmlBasic(el); +// uint4 elemId = decoder.openElement(); + decodeBasic(decoder); submeta = (metatype == TYPE_INT) ? SUB_INT_ENUM : SUB_UINT_ENUM; - const List &list(el->getChildren()); - List::const_iterator iter; map nmap; - for(iter=list.begin();iter!=list.end();++iter) { - uintb val; - Element *subel = *iter; - istringstream is(subel->getAttributeValue("value")); - is.unsetf(ios::dec|ios::hex|ios::oct); - intb valsign; // Value might be negative - is >> valsign; - val = (uintb)valsign & calc_mask(size); - nmap[val] = subel->getAttributeValue("name"); + for(;;) { + uint4 childId = decoder.openElement(); + if (childId == 0) break; + uintb val = 0; + string nm; + for(;;) { + uint4 attrib = decoder.getNextAttributeId(); + if (attrib == 0) break; + if (attrib == ATTRIB_VALUE) { + intb valsign = decoder.readSignedInteger(); // Value might be negative + val = (uintb)valsign & calc_mask(size); + } + else if (attrib == ATTRIB_NAME) + nm = decoder.readString(); + } + if (nm.size() == 0) + throw LowlevelError(name + ": TypeEnum field missing name attribute"); + nmap[val] = nm; + decoder.closeElement(childId); } setNameMap(nmap); +// decoder.closeElement(elemId); } TypeStruct::TypeStruct(const TypeStruct &op) @@ -1420,34 +1470,31 @@ int4 TypeStruct::compareDependency(const Datatype &op) const return 0; } -void TypeStruct::saveXml(ostream &s) const +void TypeStruct::encode(Encoder &encoder) const { if (typedefImm != (Datatype *)0) { - saveXmlTypedef(s); + encodeTypedef(encoder); return; } - s << "\n"; + encoder.openElement(ELEM_TYPE); + encodeBasic(metatype,encoder); vector::const_iterator iter; for(iter=field.begin();iter!=field.end();++iter) { - (*iter).saveXml(s); + (*iter).encode(encoder); } - s << ""; + encoder.closeElement(ELEM_TYPE); } /// Children of the structure element describe each field. -/// \param el is the root structure element +/// \param decoder is the stream decoder /// \param typegrp is the factory owning the new structure -void TypeStruct::restoreFields(const Element *el,TypeFactory &typegrp) +void TypeStruct::decodeFields(Decoder &decoder,TypeFactory &typegrp) { - const List &list(el->getChildren()); - List::const_iterator iter; int4 maxoffset = 0; - for(iter=list.begin();iter!=list.end();++iter) { - field.emplace_back(*iter,typegrp); + while(decoder.peekElement() != 0) { + field.emplace_back(decoder,typegrp); int4 trialmax = field.back().offset + field.back().type->getSize(); if (trialmax > maxoffset) maxoffset = trialmax; @@ -1457,7 +1504,7 @@ void TypeStruct::restoreFields(const Element *el,TypeFactory &typegrp) throw LowlevelError(s.str()); } } - if (size == 0) // We can restore an incomplete structure, indicated by 0 size + if (size == 0) // We can decode an incomplete structure, indicated by 0 size flags |= type_incomplete; else markComplete(); // Otherwise the structure is complete @@ -1591,23 +1638,21 @@ void TypeUnion::setFields(const vector &fd) } } -/// Children of the XML element describe each field. -/// \param el is the root union element +/// Parse children of the \ element describing each field. +/// \param decoder is the stream decoder /// \param typegrp is the factory owning the new union -void TypeUnion::restoreFields(const Element *el,TypeFactory &typegrp) +void TypeUnion::decodeFields(Decoder &decoder,TypeFactory &typegrp) { - const List &list(el->getChildren()); - List::const_iterator iter; - for(iter=list.begin();iter!=list.end();++iter) { - field.emplace_back(*iter,typegrp); + while(decoder.peekElement() != 0) { + field.emplace_back(decoder,typegrp); if (field.back().offset + field.back().type->getSize() > size) { ostringstream s; s << "Field " << field.back().name << " does not fit in union " << name; throw LowlevelError(s.str()); } } - if (size == 0) // We can restore an incomplete structure, indicated by 0 size + if (size == 0) // We can decode an incomplete structure, indicated by 0 size flags |= type_incomplete; else markComplete(); // Otherwise the union is complete @@ -1684,21 +1729,20 @@ int4 TypeUnion::compareDependency(const Datatype &op) const return 0; } -void TypeUnion::saveXml(ostream &s) const +void TypeUnion::encode(Encoder &encoder) const { if (typedefImm != (Datatype *)0) { - saveXmlTypedef(s); + encodeTypedef(encoder); return; } - s << "\n"; + encoder.openElement(ELEM_TYPE); + encodeBasic(metatype,encoder); vector::const_iterator iter; for(iter=field.begin();iter!=field.end();++iter) { - (*iter).saveXml(s); + (*iter).encode(encoder); } - s << ""; + encoder.closeElement(ELEM_TYPE); } Datatype *TypeUnion::resolveInFlow(PcodeOp *op,int4 slot) @@ -1808,41 +1852,39 @@ int4 TypeUnion::findCompatibleResolve(Datatype *ct) const return -1; } -/// Parse a \ tag with children describing the data-type being pointed to and the parent data-type. -/// \param el is the root XML element +/// Parse a \ element with children describing the data-type being pointed to +/// and the parent data-type. +/// \param decoder is the stream decoder /// \param typegrp is the factory owning \b this data-type -void TypePointerRel::restoreXml(const Element *el,TypeFactory &typegrp) +void TypePointerRel::decode(Decoder &decoder,TypeFactory &typegrp) { +// uint4 elemId = decoder.openElement(); flags |= is_ptrrel; - restoreXmlBasic(el); + decodeBasic(decoder); metatype = TYPE_PTR; // Don't use TYPE_PTRREL internally - for(int4 i=0;igetNumAttributes();++i) { - const string &attribName(el->getAttributeName(i)); - if (attribName == "wordsize") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> wordsize; + decoder.rewindAttributes(); + for(;;) { + uint4 attrib = decoder.getNextAttributeId(); + if (attrib == 0) break; + if (attrib == ATTRIB_WORDSIZE) { + wordsize = decoder.readUnsignedInteger(); } - else if (attribName == "space") { - spaceid = typegrp.getArch()->getSpaceByName(el->getAttributeValue("space")); + else if (attrib == ATTRIB_SPACE) { + spaceid = typegrp.getArch()->getSpaceByName(decoder.readString()); } } - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - ptrto = typegrp.restoreXmlType( *iter ); - ++iter; - parent = typegrp.restoreXmlType( *iter ); - ++iter; - istringstream s1((*iter)->getContent()); - s1.unsetf(ios::dec | ios::hex | ios::oct); - s1 >> offset; + ptrto = typegrp.decodeType( decoder ); + parent = typegrp.decodeType( decoder ); + uint4 subId = decoder.openElement(ELEM_OFF); + offset = decoder.readSignedInteger(ATTRIB_CONTENT); + decoder.closeElement(subId); if (offset == 0) throw new LowlevelError("For metatype=\"ptrstruct\", tag must not be zero"); submeta = (ptrto->getMetatype()==TYPE_UNKNOWN) ? SUB_PTRREL_UNK: SUB_PTRREL; if (name.size() == 0) // If the data-type is not named cacheStrippedType(typegrp); // it is considered ephemeral +// decoder.closeElement(elemId); } /// For a variable that is a relative pointer, constant offsets relative to the variable can be @@ -1903,19 +1945,19 @@ int4 TypePointerRel::compareDependency(const Datatype &op) const return (op.getSize()-size); } -void TypePointerRel::saveXml(ostream &s) const +void TypePointerRel::encode(Encoder &encoder) const { - s << "\n"; - ptrto->saveXml(s); - s << '\n'; - parent->saveXmlRef(s); - s << "\n" << dec << offset << "\n"; - s << ""; + encoder.writeSignedInteger(ATTRIB_WORDSIZE, wordsize); + ptrto->encode(encoder); + parent->encodeRef(encoder); + encoder.openElement(ELEM_OFF); + encoder.writeSignedInteger(ATTRIB_CONTENT, offset); + encoder.closeElement(ELEM_OFF); + encoder.closeElement(ELEM_TYPE); } TypePointer *TypePointerRel::downChain(uintb &off,TypePointer *&par,uintb &parOff,bool allowArrayWrap, @@ -2161,49 +2203,45 @@ int4 TypeCode::compareDependency(const Datatype &op) const return 0; } -void TypeCode::saveXml(ostream &s) const +void TypeCode::encode(Encoder &encoder) const { if (typedefImm != (Datatype *)0) { - saveXmlTypedef(s); + encodeTypedef(encoder); return; } - s << "\n"; + encoder.openElement(ELEM_TYPE); + encodeBasic(metatype,encoder); if (proto != (FuncProto *)0) - proto->saveXml(s); - s << ""; + proto->encode(encoder); + encoder.closeElement(ELEM_TYPE); } -/// \param el is the root XML element describing the code object -void TypeCode::restoreStub(const Element *el) +/// \param decoder is the stream decoder +void TypeCode::decodeStub(Decoder &decoder) { - if (!el->getChildren().empty()) { + if (decoder.peekElement() != 0) { // Traditionally a tag implies variable length, without a "varlength" attribute flags |= variable_length; } - restoreXmlBasic(el); + decodeBasic(decoder); } /// A single child element indicates a full function prototype. -/// \param el is the root XML tag describing the code object +/// \param decoder is the stream decoder /// \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) +void TypeCode::decodePrototype(Decoder &decoder,bool isConstructor,bool isDestructor,TypeFactory &typegrp) { - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - if (iter != list.end()) { + if (decoder.peekElement() != 0) { Architecture *glb = typegrp.getArch(); factory = &typegrp; proto = new FuncProto(); proto->setInternal( glb->defaultfp, typegrp.getTypeVoid() ); - proto->restoreXml(*iter,glb); + proto->decode(decoder,glb); proto->setConstructor(isConstructor); proto->setDestructor(isDestructor); } @@ -2350,34 +2388,33 @@ Address TypeSpacebase::getAddress(uintb off,int4 sz,const Address &point) const return glb->resolveConstant(spaceid,off,sz,point,fullEncoding); } -void TypeSpacebase::saveXml(ostream &s) const +void TypeSpacebase::encode(Encoder &encoder) const { if (typedefImm != (Datatype *)0) { - saveXmlTypedef(s); + encodeTypedef(encoder); return; } - s << "getName()); - s << '>'; - localframe.saveXml(s); - s << ""; + encoder.openElement(ELEM_TYPE); + encodeBasic(metatype,encoder); + encoder.writeString(ATTRIB_SPACE, spaceid->getName()); + localframe.encode(encoder); + encoder.closeElement(ELEM_TYPE); } /// Parse the \ tag. -/// \param el is the root XML element +/// \param decoder is the stream decoder /// \param typegrp is the factory owning \b this data-type -void TypeSpacebase::restoreXml(const Element *el,TypeFactory &typegrp) +void TypeSpacebase::decode(Decoder &decoder,TypeFactory &typegrp) { - restoreXmlBasic(el); - spaceid = glb->getSpaceByName(el->getAttributeValue("space")); - const List &list(el->getChildren()); - localframe = Address::restoreXml(list.front(),typegrp.getArch()); +// uint4 elemId = decoder.openElement(); + decodeBasic(decoder); + spaceid = glb->getSpaceByName(decoder.readString(ATTRIB_SPACE)); + localframe = Address::decode(decoder,typegrp.getArch()); +// decoder.closeElement(elemId); } - /// Initialize an empty container /// \param g is the owning Architecture TypeFactory::TypeFactory(Architecture *g) @@ -3289,87 +3326,82 @@ Datatype *TypeFactory::concretize(Datatype *ct) return ct; } -/// Restore a Datatype object from an XML tag description: either \, \, or \ -/// \param el is the XML element describing the data-type -/// \return the restored Datatype object -Datatype *TypeFactory::restoreXmlType(const Element *el) +/// Restore a Datatype object from an element: either \, \, or \ +/// \param decoder is the stream decoder +/// \return the decoded Datatype object +Datatype *TypeFactory::decodeType(Decoder &decoder) { Datatype *ct; - if (el->getName() == "typeref") { + uint4 elemId = decoder.peekElement(); + if (ELEM_TYPEREF == elemId) { + elemId = decoder.openElement(); uint8 newid = 0; int4 size = -1; - int4 num = el->getNumAttributes(); - for(int4 i=0;igetAttributeName(i)); - if (nm == "id") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> newid; + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_ID) { + newid = decoder.readUnsignedInteger(); } - else if (nm == "size") { // A "size" attribute indicates a "variable length" base - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> size; + else if (attribId == ATTRIB_ID) { // A "size" attribute indicates a "variable length" base + size = decoder.readSignedInteger(); } } - const string &newname( el->getAttributeValue("name")); + string newname = decoder.readString(ATTRIB_NAME); if (newid == 0) // If there was no id, use the name hash newid = Datatype::hashName(newname); ct = findById(newname,newid,size); if (ct == (Datatype *)0) throw LowlevelError("Unable to resolve type: "+newname); + decoder.closeElement(elemId); return ct; } - return restoreXmlTypeNoRef(el,false); + return decodeTypeNoRef(decoder,false); } -/// \brief Restore data-type from XML with extra "code" flags +/// \brief Restore data-type from an element and extra "code" flags /// -/// Kludge to get flags into code pointer types, when they can't come through XML -/// \param el is the XML element describing the Datatype +/// Kludge to get flags into code pointer types, when they can't come through the stream +/// \param decoder is the stream decoder /// \param isConstructor toggles "constructor" property on "function" datatypes /// \param isDestructor toggles "destructor" property on "function" datatypes -/// \return the restored Datatype object -Datatype *TypeFactory::restoreXmlTypeWithCodeFlags(const Element *el,bool isConstructor,bool isDestructor) +/// \return the decoded Datatype object +Datatype *TypeFactory::decodeTypeWithCodeFlags(Decoder &decoder,bool isConstructor,bool isDestructor) { TypePointer tp; - tp.restoreXmlBasic(el); + uint4 elemId = decoder.openElement(); + tp.decodeBasic(decoder); if (tp.getMetatype() != TYPE_PTR) - throw LowlevelError("Special type restoreXml does not see pointer"); - for(int4 i=0;igetNumAttributes();++i) - if (el->getAttributeName(i) == "wordsize") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> tp.wordsize; + throw LowlevelError("Special type decode does not see pointer"); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_WORDSIZE) { + tp.wordsize = decoder.readUnsignedInteger(); } - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - const Element *subel = *iter; - if (subel->getAttributeValue("metatype") != "code") - throw LowlevelError("Special type restoreXml does not see code"); - tp.ptrto = restoreCode(subel, isConstructor, isDestructor, false); + } + tp.ptrto = decodeCode(decoder, isConstructor, isDestructor, false); + decoder.closeElement(elemId); return findAdd(tp); } -/// All data-types, in dependency order, are written out to an XML stream -/// \param s is the output stream -void TypeFactory::saveXml(ostream &s) const +/// All data-types, in dependency order, are encoded to a stream +/// \param encoder is the stream encoder +void TypeFactory::encode(Encoder &encoder) const { vector deporder; vector::iterator iter; dependentOrder(deporder); // Put types in correct order - s << "\n"; + encoder.openElement(ELEM_TYPEGRP); + encoder.writeSignedInteger(ATTRIB_INTSIZE, sizeOfInt); + encoder.writeSignedInteger(ATTRIB_LONGSIZE, sizeOfLong); + encoder.writeSignedInteger(ATTRIB_STRUCTALIGN, align); + encoder.writeSignedInteger(ATTRIB_ENUMSIZE, enumsize); + encoder.writeBool(ATTRIB_ENUMSIGNED, (enumtype==TYPE_INT)); for(iter=deporder.begin();iter!=deporder.end();++iter) { if ((*iter)->getName().size()==0) continue; // Don't save anonymous types if ((*iter)->isCoreType()) { // If this would be saved as a coretype @@ -3378,23 +3410,21 @@ void TypeFactory::saveXml(ostream &s) const (meta != TYPE_STRUCT)&&(meta != TYPE_UNION)) continue; // Don't save it here } - s << ' '; - (*iter)->saveXml(s); - s << '\n'; + (*iter)->encode(encoder); } - s << "\n"; + encoder.closeElement(ELEM_TYPEGRP); } -/// Any data-type within this container marked as "core" will -/// be written to an XML \ stream. -/// \param s is the output stream -void TypeFactory::saveXmlCoreTypes(ostream &s) const +/// Any data-type within this container marked as \e core will +/// be encodeded as a \ element. +/// \param encoder is the stream encoder +void TypeFactory::encodeCoreTypes(Encoder &encoder) const { DatatypeSet::const_iterator iter; Datatype *ct; - s << "\n"; + encoder.openElement(ELEM_CORETYPES); for(iter=tree.begin();iter!=tree.end();++iter) { ct = *iter; if (!ct->isCoreType()) continue; @@ -3402,41 +3432,40 @@ void TypeFactory::saveXmlCoreTypes(ostream &s) const if ((meta==TYPE_PTR)||(meta==TYPE_ARRAY)|| (meta==TYPE_STRUCT)||(meta==TYPE_UNION)) continue; - s << ' '; - ct->saveXml(s); - s << '\n'; + ct->encode(encoder); } - s << "\n"; + encoder.closeElement(ELEM_CORETYPES); } /// Scan the new id and name. A subtag references the data-type being typedefed. /// Construct the new data-type based on the referenced data-type but with new name and id. -/// \param el is the \ element +/// \param decoder is the stream decoder /// \return the constructed typedef data-type -Datatype *TypeFactory::restoreTypedef(const Element *el) +Datatype *TypeFactory::decodeTypedef(Decoder &decoder) { uint8 id = 0; string nm; uint4 format = 0; // No forced display format by default - for(int4 i=0;igetNumAttributes();++i) { - const string &attribName(el->getAttributeName(i)); - if (attribName == "id") { - istringstream s1(el->getAttributeValue(i)); - s1.unsetf(ios::dec | ios::hex | ios::oct); - s1 >> id; +// uint4 elemId = decoder.openElement(); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_ID) { + id = decoder.readUnsignedInteger(); } - else if (attribName == "name") { - nm = el->getAttributeValue(i); + else if (attribId == ATTRIB_NAME) { + nm = decoder.readString(); } - else if (attribName == "format") { - format = Datatype::encodeIntegerFormat(el->getAttributeValue(i)); + else if (attribId == ATTRIB_FORMAT) { + format = Datatype::encodeIntegerFormat(decoder.readString()); } } if (id == 0) { // Its possible the typedef is a builtin id = Datatype::hashName(nm); // There must be some kind of id } - Datatype *defedType = restoreXmlType( *el->getChildren().begin() ); + Datatype *defedType = decodeType( decoder ); +// decoder.closeElement(elemId); if (defedType->isVariableLength()) id = Datatype::hashSize(id, defedType->size); if (defedType->getMetatype() == TYPE_STRUCT || defedType->getMetatype() == TYPE_UNION) { @@ -3465,14 +3494,15 @@ Datatype *TypeFactory::restoreTypedef(const Element *el) } /// 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 decoder is the stream decoder /// \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) +Datatype* TypeFactory::decodeStruct(Decoder &decoder,bool forcecore) { TypeStruct ts; - ts.restoreXmlBasic(el); +// uint4 elemId = decoder.openElement(); + ts.decodeBasic(decoder); if (forcecore) ts.flags |= Datatype::coretype; Datatype *ct = findByIdLocal(ts.name,ts.id); @@ -3481,7 +3511,7 @@ Datatype* TypeFactory::restoreStruct(const Element *el,bool forcecore) } else if (ct->getMetatype() != TYPE_STRUCT) throw LowlevelError("Trying to redefine type: " + ts.name); - ts.restoreFields(el,*this); + ts.decodeFields(decoder,*this); if (!ct->isIncomplete()) { // Structure of this name was already present if (0 != ct->compareDependency(ts)) throw LowlevelError("Redefinition of structure: " + ts.name); @@ -3490,18 +3520,20 @@ Datatype* TypeFactory::restoreStruct(const Element *el,bool forcecore) if (!setFields(ts.field,(TypeStruct*)ct,ts.size,ts.flags)) // Define structure now by copying fields throw LowlevelError("Bad structure definition"); } +// decoder.closeElement(elemId); return ct; } /// If necessary create a stub object before parsing the field descriptions, to deal with recursive definitions -/// \param el is the XML element describing the union +/// \param decoder is the stream decoder /// \param forcecore is \b true if the data-type is considered core /// \return the newly minted union data-type -Datatype* TypeFactory::restoreUnion(const Element *el,bool forcecore) +Datatype* TypeFactory::decodeUnion(Decoder &decoder,bool forcecore) { TypeUnion tu; - tu.restoreXmlBasic(el); +// uint4 elemId = decoder.openElement(); + tu.decodeBasic(decoder); if (forcecore) tu.flags |= Datatype::coretype; Datatype *ct = findByIdLocal(tu.name,tu.id); @@ -3510,7 +3542,7 @@ Datatype* TypeFactory::restoreUnion(const Element *el,bool forcecore) } else if (ct->getMetatype() != TYPE_UNION) throw LowlevelError("Trying to redefine type: " + tu.name); - tu.restoreFields(el,*this); + tu.decodeFields(decoder,*this); if (!ct->isIncomplete()) { // Structure of this name was already present if (0 != ct->compareDependency(tu)) throw LowlevelError("Redefinition of union: " + tu.name); @@ -3519,20 +3551,25 @@ Datatype* TypeFactory::restoreUnion(const Element *el,bool forcecore) if (!setFields(tu.field,(TypeUnion*)ct,tu.size,tu.flags)) // Define structure now by copying fields throw LowlevelError("Bad union definition"); } +// decoder.closeElement(elemId); 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 decoder is the stream decoder /// \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) +Datatype *TypeFactory::decodeCode(Decoder &decoder,bool isConstructor,bool isDestructor,bool forcecore) { TypeCode tc; - tc.restoreStub(el); +// uint4 elemId = decoder.openElement(); + tc.decodeStub(decoder); + if (tc.getMetatype() != TYPE_CODE) { + throw LowlevelError("Expecting metatype=\"code\""); + } if (forcecore) tc.flags |= Datatype::coretype; Datatype *ct = findByIdLocal(tc.name,tc.id); @@ -3541,7 +3578,7 @@ Datatype *TypeFactory::restoreCode(const Element *el,bool isConstructor,bool isD } else if (ct->getMetatype() != TYPE_CODE) throw LowlevelError("Trying to redefine type: " + tc.name); - tc.restorePrototype(el, isConstructor, isDestructor, *this); + tc.decodePrototype(decoder, 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); @@ -3549,34 +3586,38 @@ Datatype *TypeFactory::restoreCode(const Element *el,bool isConstructor,bool isD else { // If there was a placeholder stub setPrototype(tc.proto, (TypeCode *)ct, tc.flags); } +// decoder.closeElement(elemId); 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 +/// Restore a Datatype object from a \ element. (Don't use for \ elements) +/// The new Datatype is added to \b this container. +/// \param decoder is the stream decoder /// \param forcecore is true if the new type should be labeled as a core type /// \return the new Datatype object -Datatype *TypeFactory::restoreXmlTypeNoRef(const Element *el,bool forcecore) +Datatype *TypeFactory::decodeTypeNoRef(Decoder &decoder,bool forcecore) { string metastring; Datatype *ct; - char c = el->getName()[0]; - if (c != 't') { - if (el->getName() == "void") - return getTypeVoid(); // Automatically a coretype - if (el->getName() == "def") - return restoreTypedef(el); + uint4 elemId = decoder.openElement(); + if (elemId == ELEM_VOID) { + ct = getTypeVoid(); // Automatically a coretype + decoder.closeElement(elemId); + return ct; } - metastring = el->getAttributeValue("metatype"); - type_metatype meta = string2metatype(metastring); + if (elemId == ELEM_DEF) { + ct = decodeTypedef(decoder); + decoder.closeElement(elemId); + return ct; + } + type_metatype meta = string2metatype(decoder.readString(ATTRIB_METATYPE)); switch(meta) { case TYPE_PTR: { TypePointer tp; - tp.restoreXml(el,*this); + tp.decode(decoder,*this); if (forcecore) tp.flags |= Datatype::coretype; ct = findAdd(tp); @@ -3585,7 +3626,7 @@ Datatype *TypeFactory::restoreXmlTypeNoRef(const Element *el,bool forcecore) case TYPE_PTRREL: { TypePointerRel tp; - tp.restoreXml(el, *this); + tp.decode(decoder, *this); if (forcecore) tp.flags |= Datatype::coretype; ct = findAdd(tp); @@ -3594,169 +3635,166 @@ Datatype *TypeFactory::restoreXmlTypeNoRef(const Element *el,bool forcecore) case TYPE_ARRAY: { TypeArray ta; - ta.restoreXml(el,*this); + ta.decode(decoder,*this); if (forcecore) ta.flags |= Datatype::coretype; ct = findAdd(ta); } break; case TYPE_STRUCT: - ct = restoreStruct(el,forcecore); + ct = decodeStruct(decoder,forcecore); break; case TYPE_UNION: - ct = restoreUnion(el,forcecore); + ct = decodeUnion(decoder,forcecore); break; case TYPE_SPACEBASE: { TypeSpacebase tsb((AddrSpace *)0,Address(),glb); - tsb.restoreXml(el,*this); + tsb.decode(decoder,*this); if (forcecore) tsb.flags |= Datatype::coretype; ct = findAdd(tsb); } break; case TYPE_CODE: - ct = restoreCode(el,false, false, forcecore); + ct = decodeCode(decoder,false, false, forcecore); break; default: - for(int4 i=0;igetNumAttributes();++i) { - if ((el->getAttributeName(i) == "char") && - xml_readbool(el->getAttributeValue(i))) { - TypeChar tc(el->getAttributeValue("name")); - tc.restoreXml(el,*this); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_CHAR && decoder.readBool()) { + TypeChar tc(decoder.readString(ATTRIB_NAME)); + decoder.rewindAttributes(); + tc.decode(decoder,*this); if (forcecore) tc.flags |= Datatype::coretype; ct = findAdd(tc); + decoder.closeElement(elemId); return ct; } - else if ((el->getAttributeName(i) == "enum") && - xml_readbool(el->getAttributeValue(i))) { + else if (attribId == ATTRIB_ENUM && decoder.readBool()) { TypeEnum te(1,TYPE_INT); // size and metatype are replaced - te.restoreXml(el,*this); + decoder.rewindAttributes(); + te.decode(decoder,*this); if (forcecore) te.flags |= Datatype::coretype; ct = findAdd(te); + decoder.closeElement(elemId); return ct; } - else if ((el->getAttributeName(i) == "utf") && - xml_readbool(el->getAttributeValue(i))) { + else if (attribId == ATTRIB_UTF && decoder.readBool()) { TypeUnicode tu; - tu.restoreXml(el,*this); + decoder.rewindAttributes(); + tu.decode(decoder,*this); if (forcecore) tu.flags |= Datatype::coretype; ct = findAdd(tu); + decoder.closeElement(elemId); return ct; } } { + decoder.rewindAttributes(); TypeBase tb(0,TYPE_UNKNOWN); - tb.restoreXmlBasic(el); + tb.decodeBasic(decoder); if (forcecore) tb.flags |= Datatype::coretype; ct = findAdd(tb); } break; } + decoder.closeElement(elemId); return ct; } -/// Read data-types into this container from an XML stream -/// \param el is the root XML element -void TypeFactory::restoreXml(const Element *el) +/// Scan configuration parameters of the factory and parse elements describing data-types +/// into this container. +/// \param decoder is the stream decoder +void TypeFactory::decode(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; + uint4 elemId = decoder.openElement(ELEM_TYPEGRP); string metastring; - istringstream i3(el->getAttributeValue("intsize")); - i3.unsetf(ios::dec | ios::hex | ios::oct); - i3 >> sizeOfInt; - istringstream i4(el->getAttributeValue("longsize")); - i4.unsetf(ios::dec | ios::hex | ios::oct); - i4 >> sizeOfLong; - istringstream i(el->getAttributeValue("structalign")); - i.unsetf(ios::dec | ios::hex | ios::oct); - i >> align; - istringstream i2(el->getAttributeValue("enumsize")); - i2.unsetf(ios::dec | ios::hex | ios::oct); - i2 >> enumsize; - if (xml_readbool(el->getAttributeValue("enumsigned"))) + sizeOfInt = decoder.readSignedInteger(ATTRIB_INTSIZE); + sizeOfLong = decoder.readSignedInteger(ATTRIB_LONGSIZE); + align = decoder.readSignedInteger(ATTRIB_STRUCTALIGN); + enumsize = decoder.readSignedInteger(ATTRIB_ENUMSIZE); + if (decoder.readBool(ATTRIB_ENUMSIGNED)) enumtype = TYPE_INT; else enumtype = TYPE_UINT; - for(iter=list.begin();iter!=list.end();++iter) - restoreXmlTypeNoRef(*iter,false); + while(decoder.peekElement() != 0) + decodeTypeNoRef(decoder,false); + decoder.closeElement(elemId); } -/// Restore data-types from an XML stream into this container +/// Parse data-type elements into this container. /// This stream is presumed to contain "core" datatypes and the /// cached matrix will be populated from this set. -/// \param el is the root XML element -void TypeFactory::restoreXmlCoreTypes(const Element *el) +/// \param decoder is the stream decoder +void TypeFactory::decodeCoreTypes(Decoder &decoder) { clear(); // Make sure this routine flushes - const List &list(el->getChildren()); - List::const_iterator iter; - - for(iter=list.begin();iter!=list.end();++iter) - restoreXmlTypeNoRef(*iter,true); + uint4 elemId = decoder.openElement(ELEM_CORETYPES); + while(decoder.peekElement() != 0) + decodeTypeNoRef(decoder,true); + decoder.closeElement(elemId); cacheCoreTypes(); } /// Recover various sizes relevant to \b this container, such as /// the default size of "int" and structure alignment, by parsing -/// the \ tag. -/// \param el is the XML element -void TypeFactory::parseDataOrganization(const Element *el) +/// a \ element. +/// \param decoder is the stream decoder +void TypeFactory::decodeDataOrganization(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - - for(iter=list.begin();iter!=list.end();++iter) { - const Element *subel = *iter; - if (subel->getName() == "integer_size") { - istringstream i(subel->getAttributeValue("value")); - i.unsetf(ios::dec | ios::hex | ios::oct); - i >> sizeOfInt; + uint elemId = decoder.openElement(ELEM_DATA_ORGANIZATION); + for(;;) { + uint4 subId = decoder.openElement(); + if (subId == 0) break; + if (subId == ELEM_INTEGER_SIZE) { + sizeOfInt = decoder.readSignedInteger(ATTRIB_VALUE); } - else if (subel->getName() == "long_size") { - istringstream i(subel->getAttributeValue("value")); - i.unsetf(ios::dec | ios::hex | ios::oct); - i >> sizeOfLong; + else if (subId == ELEM_LONG_SIZE) { + sizeOfLong = decoder.readSignedInteger(ATTRIB_VALUE); } - else if (subel->getName() == "size_alignment_map") { - const List &childlist(subel->getChildren()); - List::const_iterator iter2; + else if (subId == ELEM_SIZE_ALIGNMENT_MAP) { align = 0; - for(iter2=childlist.begin();iter2!=childlist.end();++iter2) { - const Element *childel = *iter2; - int4 val; - istringstream i2(childel->getAttributeValue("alignment")); - i2.unsetf(ios::dec | ios::hex | ios::oct); - i2 >> val; + for(;;) { + uint4 mapId = decoder.openElement(); + if (mapId != ELEM_ENTRY) break; + int4 val = decoder.readSignedInteger(ATTRIB_ALIGNMENT); + decoder.closeElement(mapId); if (val > align) // Take maximum size alignment align = val; } } + else { + decoder.closeElementSkipping(subId); + continue; + } + decoder.closeElement(subId); } + decoder.closeElement(elemId); } /// Recover default enumeration properties (size and meta-type) from /// an \ XML tag. Should probably consider this deprecated. These /// values are only used by the internal C parser. /// param el is the XML element -void TypeFactory::parseEnumConfig(const Element *el) +void TypeFactory::parseEnumConfig(Decoder &decoder) { - istringstream s(el->getAttributeValue("size")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> enumsize; - if (xml_readbool(el->getAttributeValue("signed"))) + uint4 elemId = decoder.openElement(ELEM_ENUM); + enumsize = decoder.readSignedInteger(ATTRIB_SIZE); + if (decoder.readBool(ATTRIB_SIGNED)) enumtype = TYPE_INT; else enumtype = TYPE_UINT; + decoder.closeElement(elemId); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh index 41ea5a1937..8f98ab82d6 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh @@ -21,6 +21,34 @@ #include "address.hh" +extern AttributeId ATTRIB_ALIGNMENT; ///< Marshaling attribute "alignment" +extern AttributeId ATTRIB_ARRAYSIZE; ///< Marshaling attribute "arraysize" +extern AttributeId ATTRIB_CHAR; ///< Marshaling attribute "char" +extern AttributeId ATTRIB_CORE; ///< Marshaling attribute "core" +extern AttributeId ATTRIB_ENUM; ///< Marshaling attribute "enum" +extern AttributeId ATTRIB_ENUMSIGNED; ///< Marshaling attribute "enumsigned" +extern AttributeId ATTRIB_ENUMSIZE; ///< Marshaling attribute "enumsize" +extern AttributeId ATTRIB_INTSIZE; ///< Marshaling attribute "intsize" +extern AttributeId ATTRIB_LONGSIZE; ///< Marshaling attribute "longsize" +extern AttributeId ATTRIB_OPAQUESTRING; ///< Marshaling attribute "opaquestring" +extern AttributeId ATTRIB_SIGNED; ///< Marshaling attribute "signed" +extern AttributeId ATTRIB_STRUCTALIGN; ///< Marshaling attribute "structalign" +extern AttributeId ATTRIB_UTF; ///< Marshaling attribute "utf" +extern AttributeId ATTRIB_VARLENGTH; ///< Marshaling attribute "varlength" + +extern ElementId ELEM_CORETYPES; ///< Marshaling element \ +extern ElementId ELEM_DATA_ORGANIZATION; ///< Marshaling element \ +extern ElementId ELEM_DEF; ///< Marshaling element \ +extern ElementId ELEM_ENTRY; ///< Marshaling element \ +extern ElementId ELEM_ENUM; ///< Marshaling element \ +extern ElementId ELEM_FIELD; ///< Marshaling element \ +extern ElementId ELEM_INTEGER_SIZE; ///< Marshaling element \ +extern ElementId ELEM_LONG_SIZE; ///< Marshaling element \ +extern ElementId ELEM_SIZE_ALIGNMENT_MAP; ///< Marshaling element \ +extern ElementId ELEM_TYPE; ///< Marshaling element \ +extern ElementId ELEM_TYPEGRP; ///< Marshaling element \ +extern ElementId ELEM_TYPEREF; ///< Marshaling element \ + /// Print a hex dump of a data buffer to stream extern void print_data(ostream &s,uint1 *buffer,int4 size,const Address &baseaddr); //extern void print_char(ostream &s,int4 onechar); @@ -115,9 +143,9 @@ protected: uint4 flags; ///< Boolean properties of the type uint8 id; ///< A unique id for the type (or 0 if an id is not assigned) Datatype *typedefImm; ///< The immediate data-type being typedefed by \e this - void restoreXmlBasic(const Element *el); ///< Recover basic data-type properties - void saveXmlBasic(type_metatype meta,ostream &s) const; ///< Save basic data-type properties - void saveXmlTypedef(ostream &s) const; ///< Write \b this as a \e typedef tag to stream + void decodeBasic(Decoder &decoder); ///< Recover basic data-type properties + void encodeBasic(type_metatype meta,Encoder &encoder) const; ///< Encode basic data-type properties + void encodeTypedef(Encoder &encoder) const; ///< Encode \b this as a \e typedef element to a stream void markComplete(void) { flags &= ~(uint4)type_incomplete; } ///< Mark \b this data-type as completely defined void setDisplayFormat(uint4 format); ///< Set a specific display format virtual Datatype *clone(void) const=0; ///< Clone the data-type @@ -162,7 +190,7 @@ public: virtual void printNameBase(ostream &s) const { if (!name.empty()) s< 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 - void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore \b this enum data-type from an XML element + void decode(Decoder &decoder,TypeFactory &typegrp); ///< Restore \b this enum data-type from a stream public: /// Construct from another TypeEnum TypeEnum(const TypeEnum &op); @@ -370,7 +398,7 @@ public: virtual int4 compare(const Datatype &op,int4 level) const; virtual int4 compareDependency(const Datatype &op) const; virtual Datatype *clone(void) const { return new TypeEnum(*this); } - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; }; /// \brief A composite Datatype object: A \b structure with component \b fields @@ -381,7 +409,7 @@ 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 - void restoreFields(const Element *el,TypeFactory &typegrp); ///< Restore fields from XML description + void decodeFields(Decoder &decoder,TypeFactory &typegrp); ///< Restore fields from a stream int4 scoreFill(PcodeOp *op,int4 slot) const; ///< Determine best type fit for given PcodeOp use public: TypeStruct(const TypeStruct &op); ///< Construct from another TypeStruct @@ -397,7 +425,7 @@ public: virtual int4 compare(const Datatype &op,int4 level) const; // For tree structure virtual int4 compareDependency(const Datatype &op) const; // For tree structure virtual Datatype *clone(void) const { return new TypeStruct(*this); } - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot); virtual Datatype* findResolve(const PcodeOp *op,int4 slot); virtual int4 findCompatibleResolve(Datatype *ct) const; @@ -413,7 +441,7 @@ protected: friend class TypeFactory; vector field; ///< The list of fields void setFields(const vector &fd); ///< Establish fields for \b this - void restoreFields(const Element *el,TypeFactory &typegrp); ///< Restore fields from XML description + void decodeFields(Decoder &decoder,TypeFactory &typegrp); ///< Restore fields from a stream public: TypeUnion(const TypeUnion &op); ///< Construct from another TypeUnion TypeUnion(void) : Datatype(0,TYPE_UNION) { flags |= (type_incomplete | needs_resolution); } ///< Construct incomplete TypeUnion @@ -424,7 +452,7 @@ public: virtual int4 compare(const Datatype &op,int4 level) const; // For tree structure virtual int4 compareDependency(const Datatype &op) const; // For tree structure virtual Datatype *clone(void) const { return new TypeUnion(*this); } - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot); virtual Datatype* findResolve(const PcodeOp *op,int4 slot); virtual int4 findCompatibleResolve(Datatype *ct) const; @@ -442,8 +470,8 @@ 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); - void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore \b this relative pointer data-type from an XML element - /// Internal constructor for restoreXml + void decode(Decoder &decoder,TypeFactory &typegrp); ///< Restore \b this relative pointer data-type from a stream + /// Internal constructor for decode TypePointerRel(void) : TypePointer() { offset = 0; parent = (Datatype *)0; stripped = (TypePointer *)0; submeta = SUB_PTRREL; } public: /// Construct from another TypePointerRel @@ -464,7 +492,7 @@ public: virtual int4 compare(const Datatype &op,int4 level) const; virtual int4 compareDependency(const Datatype &op) const; virtual Datatype *clone(void) const { return new TypePointerRel(*this); } - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; virtual TypePointer *downChain(uintb &off,TypePointer *&par,uintb &parOff,bool allowArrayWrap,TypeFactory &typegrp); virtual bool isPtrsubMatching(uintb off) const; virtual Datatype *getStripped(void) const { return stripped; } ///< Get the plain form of the pointer @@ -486,8 +514,8 @@ protected: 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 + void decodeStub(Decoder &decoder); ///< Restore stub of data-type without the full prototype + void decodePrototype(Decoder &decoder,bool isConstructor,bool isDestructor,TypeFactory &typegrp); ///< Restore any prototype description public: TypeCode(const TypeCode &op); ///< Construct from another TypeCode TypeCode(void); ///< Construct an incomplete TypeCode @@ -499,7 +527,7 @@ public: virtual int4 compare(const Datatype &op,int4 level) const; virtual int4 compareDependency(const Datatype &op) const; virtual Datatype *clone(void) const { return new TypeCode(*this); } - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; }; /// \brief Special Datatype object used to describe pointers that index into the symbol table @@ -512,7 +540,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 - void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore \b this spacebase data-type from an XML element + void decode(Decoder &decoder,TypeFactory &typegrp); ///< Restore \b this spacebase data-type from a stream public: /// Construct from another TypeSpacebase TypeSpacebase(const TypeSpacebase &op) : Datatype(op) { @@ -529,7 +557,7 @@ public: virtual int4 compare(const Datatype &op,int4 level) const; virtual int4 compareDependency(const Datatype &op) const; // For tree structure virtual Datatype *clone(void) const { return new TypeSpacebase(*this); } - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; }; /// \brief Container class for all Datatype objects in an Architecture @@ -549,11 +577,11 @@ class TypeFactory { void insert(Datatype *newtype); ///< Insert pointer into the cross-reference sets Datatype *findAdd(Datatype &ct); ///< Find data-type in this container or add it 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 *restoreUnion(const Element *el,bool forcecore); ///< Restore a \ XML tag describing a union - 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 + Datatype *decodeTypedef(Decoder &decoder); ///< Restore a \ element describing a typedef + Datatype *decodeStruct(Decoder &decoder,bool forcecore); ///< Restore a \ element describing a structure + Datatype *decodeUnion(Decoder &decoder,bool forcecore); ///< Restore a \ element describing a union + Datatype *decodeCode(Decoder &decoder,bool isConstructor,bool isDestructor,bool forcecore); ///< Restore an element describing a code object + Datatype *decodeTypeNoRef(Decoder &decoder,bool forcecore); ///< Restore from a stream void clearCache(void); ///< Clear the common type cache TypeChar *getTypeChar(const string &n); ///< Create a default "char" type TypeUnicode *getTypeUnicode(const string &nm,int4 sz,type_metatype m); ///< Create a default "unicode" type @@ -584,8 +612,8 @@ public: const vector &vallist, const vector &assignlist, TypeEnum *te); ///< Set named values for an enumeration - Datatype *restoreXmlType(const Element *el); ///< Restore Datatype from XML - Datatype *restoreXmlTypeWithCodeFlags(const Element *el,bool isConstructor,bool isDestructor); + Datatype *decodeType(Decoder &decoder); ///< Restore Datatype from a stream + Datatype *decodeTypeWithCodeFlags(Decoder &decoder,bool isConstructor,bool isDestructor); TypeVoid *getTypeVoid(void); ///< Get the "void" data-type Datatype *getBaseNoChar(int4 s,type_metatype m); ///< Get atomic type excluding "char" Datatype *getBase(int4 s,type_metatype m); ///< Get atomic type @@ -610,12 +638,12 @@ public: void destroyType(Datatype *ct); ///< Remove a data-type from \b this Datatype *concretize(Datatype *ct); ///< Convert given data-type to concrete form void dependentOrder(vector &deporder) const; ///< Place all data-types in dependency order - void saveXml(ostream &s) const; ///< Save \b this container to stream - void saveXmlCoreTypes(ostream &s) const; ///< Save core types to stream - void restoreXml(const Element *el); ///< Restore \b this container from a stream - void restoreXmlCoreTypes(const Element *el); ///< Initialize basic type names - void parseDataOrganization(const Element *el); ///< Parse the \ tag - void parseEnumConfig(const Element *el); ///< Parse the \ tag + void encode(Encoder &encoder) const; ///< Encode \b this container to stream + void encodeCoreTypes(Encoder &encoder) const; ///< Encode core types to stream + void decode(Decoder &decoder); ///< Decode \b this from a \ element + void decodeCoreTypes(Decoder &decoder); ///< Initialize basic data-types from a stream + void decodeDataOrganization(Decoder &decoder); ///< Parse a \ element + void parseEnumConfig(Decoder &decoder); ///< Parse the \ tag void setCoreType(const string &name,int4 size,type_metatype meta,bool chartp); ///< Create a core data-type void cacheCoreTypes(void); ///< Cache common types }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/typegrp_ghidra.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/typegrp_ghidra.cc index 6202da9e35..71f1a7c6f5 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/typegrp_ghidra.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/typegrp_ghidra.cc @@ -20,16 +20,14 @@ Datatype *TypeFactoryGhidra::findById(const string &n,uint8 id,int4 sz) { Datatype *ct = TypeFactory::findById(n,id,sz); // Try internal find if (ct != (Datatype *)0) return ct; - - Document *doc; + XmlDecode decoder; try { - doc = ((ArchitectureGhidra *)glb)->getType(n,id); // See if ghidra knows about type + if (!((ArchitectureGhidra *)glb)->getType(n,id,decoder)) // See if ghidra knows about type + return (Datatype *)0; } catch(XmlError &err) { throw LowlevelError("XML error: "+err.explain); } - if (doc == (Document *)0) return (Datatype *)0; - ct = restoreXmlType(doc->getRoot()); // Parse ghidra's type - delete doc; + ct = decodeType(decoder); // Parse ghidra's type return ct; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/userop.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/userop.cc index 496a32644f..c7df676c0e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/userop.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/userop.cc @@ -16,10 +16,19 @@ #include "userop.hh" #include "funcdata.hh" -void InjectedUserOp::restoreXml(const Element *el) +AttributeId ATTRIB_FARPOINTER = AttributeId("farpointer",122); +AttributeId ATTRIB_INPUTOP = AttributeId("inputop",123); +AttributeId ATTRIB_OUTPUTOP = AttributeId("outputop",124); +AttributeId ATTRIB_USEROP = AttributeId("userop",125); + +ElementId ELEM_CONSTRESOLVE = ElementId("constresolve",202); +ElementId ELEM_JUMPASSIST = ElementId("jumpassist",203); +ElementId ELEM_SEGMENTOP = ElementId("segmentop",204); + +void InjectedUserOp::decode(Decoder &decoder) { - injectid = glb->pcodeinjectlib->restoreXmlInject("userop", name, InjectPayload::CALLOTHERFIXUP_TYPE,el); + injectid = glb->pcodeinjectlib->decodeInject("userop", "", InjectPayload::CALLOTHERFIXUP_TYPE,decoder); name = glb->pcodeinjectlib->getCallOtherTarget(injectid); UserPcodeOp *base = glb->userops.getOp(name); // This tag overrides the base functionality of a userop @@ -59,12 +68,6 @@ string VolatileReadOp::getOperatorName(const PcodeOp *op) const return appendSize(name,op->getOut()->getSize()); } -void VolatileReadOp::restoreXml(const Element *el) - -{ - name = el->getAttributeValue("inputop"); -} - string VolatileWriteOp::getOperatorName(const PcodeOp *op) const { @@ -72,49 +75,6 @@ string VolatileWriteOp::getOperatorName(const PcodeOp *op) const return appendSize(name,op->getIn(2)->getSize()); } -void VolatileWriteOp::restoreXml(const Element *el) - -{ - name = el->getAttributeValue("outputop"); -} - -/// Process either a \ or \ element. Currently -/// this only supports INT_ZEXT, INT_LEFT, and INT_AND operations -/// \param el is the root XML element -void OpFollow::restoreXml(const Element *el) - -{ - const string &name(el->getAttributeValue("code")); - if (name=="INT_ZEXT") - opc = CPUI_INT_ZEXT; - else if (name=="INT_LEFT") - opc = CPUI_INT_LEFT; - else if (name=="INT_AND") - opc = CPUI_INT_AND; - else - throw LowlevelError("Bad segment pattern opcode"); - - val = 0; - slot=0; - - for(int4 i=0;igetNumAttributes();++i) { - if (el->getAttributeName(i) == "code") continue; - else if (el->getAttributeName(i) == "value") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> val; - } - else if (el->getAttributeName(i) == "slot") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> slot; - } - else - throw LowlevelError("Bad XML tag in segment pattern: "+el->getAttributeValue(i)); - } - -} - /// \param g is the owning Architecture for this instance of the segment operation /// \param nm is the low-level name of the segment operation /// \param ind is the constant id identifying the specific CALLOTHER variant @@ -160,26 +120,29 @@ uintb SegmentOp::execute(const vector &input) const return pcodeScript->evaluate(input); } -void SegmentOp::restoreXml(const Element *el) +void SegmentOp::decode(Decoder &decoder) { - spc = glb->getSpaceByName(el->getAttributeValue("space")); + uint4 elemId = decoder.openElement(ELEM_SEGMENTOP); + spc = (AddrSpace *)0; injectId = -1; baseinsize = 0; innerinsize = 0; supportsfarpointer = false; name = "segment"; // Default name, might be overridden by userop attribute - for(int4 i=0;igetNumAttributes();++i) { - const string &nm(el->getAttributeName(i)); - if (nm == "space") continue; - else if (nm == "farpointer") + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == ATTRIB_SPACE) + spc = glb->getSpaceByName(decoder.readString()); + else if (attribId == ATTRIB_FARPOINTER) supportsfarpointer = true; - else if (nm == "userop") { // Based on existing sleigh op - name = el->getAttributeValue(i); + else if (attribId == ATTRIB_USEROP) { // Based on existing sleigh op + name = decoder.readString(); } - else - throw LowlevelError("Bad segmentop tag attribute: "+nm); } + if (spc == (AddrSpace *)0) + throw LowlevelError(" expecting space attribute"); UserPcodeOp *otherop = glb->userops.getOp(name); if (otherop == (UserPcodeOp *)0) throw LowlevelError(" unknown userop " + name); @@ -187,30 +150,27 @@ void SegmentOp::restoreXml(const Element *el) if (dynamic_cast(otherop) == (UnspecializedPcodeOp *)0) throw LowlevelError("Redefining userop "+name); - const List &list(el->getChildren()); - List::const_iterator iter; - for(iter=list.begin();iter!=list.end();++iter) { - const Element *subel = *iter; - if (subel->getName()=="constresolve") { + for(;;) { + uint4 subId = decoder.peekElement(); + if (subId == 0) break; + if (subId==ELEM_CONSTRESOLVE) { int4 sz; - const List &sublist(subel->getChildren()); - if (!sublist.empty()) { - List::const_iterator subiter = sublist.begin(); - const Element *subsubel = *subiter; - Address addr = Address::restoreXml(subsubel,glb,sz); + decoder.openElement(); + if (decoder.peekElement() != 0) { + Address addr = Address::decode(decoder,glb,sz); constresolve.space = addr.getSpace(); constresolve.offset = addr.getOffset(); constresolve.size = sz; } + decoder.closeElement(subId); } - else if (subel->getName() == "pcode") { + else if (subId == ELEM_PCODE) { string nm = name + "_pcode"; string source = "cspec"; - injectId = glb->pcodeinjectlib->restoreXmlInject(source, nm, InjectPayload::EXECUTABLEPCODE_TYPE, subel); + injectId = glb->pcodeinjectlib->decodeInject(source, nm, InjectPayload::EXECUTABLEPCODE_TYPE, decoder); } - else - throw LowlevelError("Bad segment pattern tag: "+subel->getName()); } + decoder.closeElement(elemId); if (injectId < 0) throw LowlevelError("Missing child in tag"); InjectPayload *payload = glb->pcodeinjectlib->getPayload(injectId); @@ -237,43 +197,44 @@ JumpAssistOp::JumpAssistOp(Architecture *g) calcsize = -1; } -void JumpAssistOp::restoreXml(const Element *el) +void JumpAssistOp::decode(Decoder &decoder) { - name = el->getAttributeValue("name"); + uint4 elemId = decoder.openElement(ELEM_JUMPASSIST); + name = decoder.readString(ATTRIB_NAME); index2case = -1; // Mark as not present until we see a tag index2addr = -1; defaultaddr = -1; calcsize = -1; - const List &list(el->getChildren()); - List::const_iterator iter; - for(iter=list.begin();iter!=list.end();++iter) { - const Element *subel = *iter; - if (subel->getName() == "case_pcode") { + for(;;) { + uint4 subId = decoder.peekElement(); + if (subId == 0) break; + if (subId == ELEM_CASE_PCODE) { if (index2case != -1) throw LowlevelError("Too many tags"); - index2case = glb->pcodeinjectlib->restoreXmlInject("jumpassistop", name+"_index2case", - InjectPayload::EXECUTABLEPCODE_TYPE,subel); + index2case = glb->pcodeinjectlib->decodeInject("jumpassistop", name+"_index2case", + InjectPayload::EXECUTABLEPCODE_TYPE,decoder); } - else if (subel->getName() == "addr_pcode") { + else if (subId == ELEM_ADDR_PCODE) { if (index2addr != -1) throw LowlevelError("Too many tags"); - index2addr = glb->pcodeinjectlib->restoreXmlInject("jumpassistop", name+"_index2addr", - InjectPayload::EXECUTABLEPCODE_TYPE,subel); + index2addr = glb->pcodeinjectlib->decodeInject("jumpassistop", name+"_index2addr", + InjectPayload::EXECUTABLEPCODE_TYPE,decoder); } - else if (subel->getName() == "default_pcode") { + else if (subId == ELEM_DEFAULT_PCODE) { if (defaultaddr != -1) throw LowlevelError("Too many tags"); - defaultaddr = glb->pcodeinjectlib->restoreXmlInject("jumpassistop", name+"_defaultaddr", - InjectPayload::EXECUTABLEPCODE_TYPE,subel); + defaultaddr = glb->pcodeinjectlib->decodeInject("jumpassistop", name+"_defaultaddr", + InjectPayload::EXECUTABLEPCODE_TYPE,decoder); } - else if (subel->getName() == "size_pcode") { + else if (subId == ELEM_SIZE_PCODE) { if (calcsize != -1) throw LowlevelError("Too many tags"); - calcsize = glb->pcodeinjectlib->restoreXmlInject("jumpassistop", name+"_calcsize", - InjectPayload::EXECUTABLEPCODE_TYPE,subel); + calcsize = glb->pcodeinjectlib->decodeInject("jumpassistop", name+"_calcsize", + InjectPayload::EXECUTABLEPCODE_TYPE,decoder); } } + decoder.closeElement(elemId); if (index2addr == -1) throw LowlevelError("userop: " + name + " is missing "); @@ -406,17 +367,17 @@ void UserOpManage::registerOp(UserPcodeOp *op) } } -/// Create a SegmentOp description object based on the tag details and +/// Create a SegmentOp description object based on the element and /// register it with \b this manager. -/// \param el is the root \ element +/// \param decoder is the stream decoder /// \param glb is the owning Architecture -void UserOpManage::parseSegmentOp(const Element *el,Architecture *glb) +void UserOpManage::decodeSegmentOp(Decoder &decoder,Architecture *glb) { SegmentOp *s_op; s_op = new SegmentOp(glb,"",useroplist.size()); try { - s_op->restoreXml(el); + s_op->decode(decoder); registerOp(s_op); } catch(LowlevelError &err) { delete s_op; @@ -425,28 +386,28 @@ void UserOpManage::parseSegmentOp(const Element *el,Architecture *glb) } /// Create either a VolatileReadOp or VolatileWriteOp description object based on -/// the XML details and register it with \b this manager. -/// \param el is the root \ element +/// the element and register it with \b this manager. +/// \param decoder is the stream decoder /// \param glb is the owning Architecture -void UserOpManage::parseVolatile(const Element *el,Architecture *glb) +void UserOpManage::decodeVolatile(Decoder &decoder,Architecture *glb) { - for(int4 i=0;igetNumAttributes();++i) { - if (el->getAttributeName(i)=="inputop") { - VolatileReadOp *vr_op = new VolatileReadOp(glb,"",useroplist.size()); + for(;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId==ATTRIB_INPUTOP) { + VolatileReadOp *vr_op = new VolatileReadOp(glb,decoder.readString(),useroplist.size()); try { - vr_op->restoreXml(el); registerOp(vr_op); } catch(LowlevelError &err) { delete vr_op; throw err; } } - else if (el->getAttributeName(i)=="outputop") { + else if (attribId==ATTRIB_OUTPUTOP) { // Read in the volatile output tag - VolatileWriteOp *vw_op = new VolatileWriteOp(glb,"",useroplist.size()); + VolatileWriteOp *vw_op = new VolatileWriteOp(glb,decoder.readString(),useroplist.size()); try { - vw_op->restoreXml(el); registerOp(vw_op); } catch(LowlevelError &err) { delete vw_op; @@ -456,16 +417,16 @@ void UserOpManage::parseVolatile(const Element *el,Architecture *glb) } } -/// Create an InjectedUserOp description object based on the XML description +/// Create an InjectedUserOp description object based on the element /// and register it with \b this manager. -/// \param el is the root \ element +/// \param decoder is the stream decoder /// \param glb is the owning Architecture -void UserOpManage::parseCallOtherFixup(const Element *el,Architecture *glb) +void UserOpManage::decodeCallOtherFixup(Decoder &decoder,Architecture *glb) { InjectedUserOp *op = new InjectedUserOp(glb,"",0,0); try { - op->restoreXml(el); + op->decode(decoder); registerOp(op); } catch(LowlevelError &err) { delete op; @@ -473,16 +434,16 @@ void UserOpManage::parseCallOtherFixup(const Element *el,Architecture *glb) } } -/// Create a JumpAssistOp description object based on the XML description +/// Create a JumpAssistOp description object based on the element /// and register it with \b this manager. -/// \param el is the root \ element +/// \param decoder is the stream decoder /// \param glb is the owning Architecture -void UserOpManage::parseJumpAssist(const Element *el,Architecture *glb) +void UserOpManage::decodeJumpAssist(Decoder &decoder,Architecture *glb) { JumpAssistOp *op = new JumpAssistOp(glb); try { - op->restoreXml(el); + op->decode(decoder); registerOp(op); } catch(LowlevelError &err) { delete op; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/userop.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/userop.hh index 56521513b5..8bc62223d8 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/userop.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/userop.hh @@ -21,6 +21,15 @@ #include "typeop.hh" +extern AttributeId ATTRIB_FARPOINTER; ///< Marshaling attribute "farpointer" +extern AttributeId ATTRIB_INPUTOP; ///< Marshaling attribute "inputop" +extern AttributeId ATTRIB_OUTPUTOP; ///< Marshaling attribute "outputop" +extern AttributeId ATTRIB_USEROP; ///< Marshaling attribute "userop" + +extern ElementId ELEM_CONSTRESOLVE; ///< Marshaling element \ +extern ElementId ELEM_JUMPASSIST; ///< Marshaling element \ +extern ElementId ELEM_SEGMENTOP; ///< Marshaling element \ + /// \brief The base class for a detailed definition of a user-defined p-code operation /// /// Within the raw p-code framework, the CALLOTHER opcode represents a user defined @@ -32,7 +41,7 @@ /// /// The derived classes can in principle implement any functionality, tailored to the architecture /// or program. At this base level, the only commonality is a formal \b name of the operator and -/// its CALLOTHER index. A facility for reading in implementation details is provided via restoreXml(). +/// its CALLOTHER index. A facility for reading in implementation details is provided via decode(). class UserPcodeOp { protected: string name; ///< Low-level name of p-code operator @@ -54,12 +63,11 @@ public: virtual string getOperatorName(const PcodeOp *op) const { return name; } - /// \brief Restore the detailed description from an XML stream + /// \brief Restore the detailed description from a stream element /// - /// The details of how a user defined operation behaves can be dynamically configured - /// from an XML tag. - /// \param el is the root XML element describing the op - virtual void restoreXml(const Element *el)=0; + /// The details of how a user defined operation behaves are parsed from the element. + /// \param decoder is the stream decoder + virtual void decode(Decoder &decoder)=0; }; /// \brief A user defined p-code op with no specialization @@ -71,7 +79,7 @@ class UnspecializedPcodeOp : public UserPcodeOp { public: UnspecializedPcodeOp(Architecture *g,const string &nm,int4 ind) : UserPcodeOp(g,nm,ind) {} ///< Constructor - virtual void restoreXml(const Element *el) {} + virtual void decode(Decoder &decoder) {} }; /// \brief A user defined operation that is injected with other p-code @@ -86,7 +94,7 @@ public: InjectedUserOp(Architecture *g,const string &nm,int4 ind,int4 injid) : UserPcodeOp(g,nm,ind) { injectid = injid; } ///< Constructor uint4 getInjectId(void) const { return injectid; } ///< Get the id of the injection object - virtual void restoreXml(const Element *el); + virtual void decode(Decoder &decoder); }; /// \brief A base class for operations that access volatile memory @@ -102,6 +110,7 @@ protected: public: VolatileOp(Architecture *g,const string &nm,int4 ind) : UserPcodeOp(g,nm,ind) { } ///< Constructor + virtual void decode(Decoder &decoder) {} ///< Currently volatile ops only need their name }; /// \brief An operation that reads from volatile memory @@ -114,7 +123,6 @@ public: VolatileReadOp(Architecture *g,const string &nm,int4 ind) : VolatileOp(g,nm,ind) {} ///< Constructor virtual string getOperatorName(const PcodeOp *op) const; - virtual void restoreXml(const Element *el); }; /// \brief An operation that writes to volatile memory @@ -128,7 +136,6 @@ public: VolatileWriteOp(Architecture *g,const string &nm,int4 ind) : VolatileOp(g,nm,ind) {} ///< Constructor virtual string getOperatorName(const PcodeOp *op) const; - virtual void restoreXml(const Element *el); }; /// \brief A user defined p-code op that has a dynamically defined procedure @@ -161,19 +168,6 @@ public: virtual uintb execute(const vector &input) const=0; }; -/// \brief A simple node used to dynamically define a sequence of operations -/// -/// This should be deprecated in favor of ExecutablePcode objects. This -/// class holds a single operation (within a sequence). It acts on the output -/// of the previous operation with an optional constant value as the second input. -struct OpFollow { - OpCode opc; ///< The particular p-code operation - uintb val; ///< A possible constant second input - int4 slot; ///< Slot to follow - OpFollow(void) {} ///< Construct an empty object - void restoreXml(const Element *el); ///< Restore \b this node from an XML stream -}; - /// \brief The \e segmented \e address operator /// /// This op is a placeholder for address mappings involving \b segments. @@ -213,7 +207,7 @@ public: virtual int4 getNumVariableTerms(void) const { if (baseinsize!=0) return 2; return 1; } virtual bool unify(Funcdata &data,PcodeOp *op,vector &bindlist) const; virtual uintb execute(const vector &input) const; - virtual void restoreXml(const Element *el); + virtual void decode(Decoder &decoder); }; /// \brief A user defined p-code op for assisting the recovery of jump tables. @@ -237,7 +231,7 @@ public: int4 getIndex2Addr(void) const { return index2addr; } ///< Get the injection id for \b index2addr int4 getDefaultAddr(void) const { return defaultaddr; } ///< Get the injection id for \b defaultaddr int4 getCalcSize(void) const { return calcsize; } ///< Get the injection id for \b calcsize - virtual void restoreXml(const Element *el); + virtual void decode(Decoder &decoder); }; /// \brief Manager/container for description objects (UserPcodeOp) of user defined p-code ops @@ -281,10 +275,10 @@ public: VolatileReadOp *getVolatileRead(void) const { return vol_read; } ///< Get (the) volatile read description VolatileWriteOp *getVolatileWrite(void) const { return vol_write; } ///< Get (the) volatile write description - void parseSegmentOp(const Element *el,Architecture *glb); ///< Parse a \ XML tag - void parseVolatile(const Element *el,Architecture *glb); ///< Parse a \ XML tag - void parseCallOtherFixup(const Element *el,Architecture *glb); ///< Parse a \ XML tag - void parseJumpAssist(const Element *el,Architecture *glb); ///< Parse a \ XML tag + void decodeSegmentOp(Decoder &decoder,Architecture *glb); ///< Parse a \ element + void decodeVolatile(Decoder &decoder,Architecture *glb); ///< Parse a \ element + void decodeCallOtherFixup(Decoder &decoder,Architecture *glb); ///< Parse a \ element + void decodeJumpAssist(Decoder &decoder,Architecture *glb); ///< Parse a \ element void manualCallOtherFixup(const string &useropname,const string &outname, const vector &inname,const string &snippet,Architecture *glb); }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/variable.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/variable.cc index b814f2d39c..c30cb9c2bf 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/variable.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/variable.cc @@ -17,6 +17,12 @@ #include "op.hh" #include "database.hh" +AttributeId ATTRIB_CLASS = AttributeId("class",126); +AttributeId ATTRIB_REPREF = AttributeId("repref",127); +AttributeId ATTRIB_SYMREF = AttributeId("symref",128); + +ElementId ELEM_HIGH = ElementId("high",205); + /// The new instance starts off with no associate Symbol and all properties marked as \e dirty. /// \param vn is the single Varnode member HighVariable::HighVariable(Varnode *vn) @@ -451,44 +457,42 @@ int4 HighVariable::instanceIndex(const Varnode *vn) const return -1; } -/// \param s is the output stream to write XML to -void HighVariable::saveXml(ostream &s) const +/// \param encoder is the stream encoder +void HighVariable::encode(Encoder &encoder) const { Varnode *vn = getNameRepresentative(); // Get representative varnode - s << "getName()); - a_v_u(s,"repref",vn->getCreateIndex()); + encoder.openElement(ELEM_HIGH); + encoder.writeUnsignedInteger(ATTRIB_REPREF, vn->getCreateIndex()); if (isSpacebase()||isImplied()) // This is a special variable - a_v(s,"class",string("other")); + encoder.writeString(ATTRIB_CLASS, "other"); else if (isPersist()&&isAddrTied()) // Global variable - a_v(s,"class",string("global")); + encoder.writeString(ATTRIB_CLASS, "global"); else if (isConstant()) - a_v(s,"class",string("constant")); + encoder.writeString(ATTRIB_CLASS, "constant"); else if (!isPersist() && (symbol != (Symbol *)0)) { if (symbol->getCategory() == Symbol::function_parameter) - a_v(s,"class",string("param")); + encoder.writeString(ATTRIB_CLASS, "param"); else - a_v(s,"class",string("local")); + encoder.writeString(ATTRIB_CLASS, "local"); } else { - a_v(s,"class",string("other")); + encoder.writeString(ATTRIB_CLASS, "other"); } if (isTypeLock()) - a_v_b(s,"typelock",true); + encoder.writeBool(ATTRIB_TYPELOCK, true); if (symbol != (Symbol *)0) { - a_v_u(s,"symref",symbol->getId()); + encoder.writeUnsignedInteger(ATTRIB_SYMREF, symbol->getId()); if (symboloffset >= 0) - a_v_i(s, "offset", symboloffset); + encoder.writeSignedInteger(ATTRIB_OFFSET, symboloffset); } - s << '>'; - getType()->saveXml(s); + getType()->encode(encoder); for(int4 j=0;jgetCreateIndex()); - s << "/>"; + encoder.openElement(ELEM_ADDR); + encoder.writeUnsignedInteger(ATTRIB_REF, inst[j]->getCreateIndex()); + encoder.closeElement(ELEM_ADDR); } - s << ""; + encoder.closeElement(ELEM_HIGH); } /// Given a Varnode at the root of an expression, we collect all the \e explicit HighVariables diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/variable.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/variable.hh index 98be353e1a..25f6f83619 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/variable.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/variable.hh @@ -23,6 +23,12 @@ class Symbol; +extern AttributeId ATTRIB_CLASS; ///< Marshaling attribute "class" +extern AttributeId ATTRIB_REPREF; ///< Marshaling attribute "repref" +extern AttributeId ATTRIB_SYMREF; ///< Marshaling attribute "symref" + +extern ElementId ELEM_HIGH; ///< Marshaling element \ + /// \brief A high-level variable modeled as a list of low-level variables, each written once /// /// In the Static Single Assignment (SSA) representation of a function's data-flow, the Varnode @@ -130,7 +136,7 @@ public: bool isUnattached(void) const { return inst.empty(); } ///< Return \b true if \b this has no member Varnode bool isTypeLock(void) const { updateType(); return ((flags & Varnode::typelock)!=0); } ///< Return \b true if \b this is \e typelocked bool isNameLock(void) const { updateFlags(); return ((flags & Varnode::namelock)!=0); } ///< Return \b true if \b this is \e namelocked - void saveXml(ostream &s) const; ///< Save the variable to stream as an XML \ tag + void encode(Encoder &encoder) const; ///< Encode \b this variable to stream as a \ element #ifdef MERGEMULTI_DEBUG void verifyCover(void) const; #endif diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc index 5533eccf05..94d2171940 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc @@ -16,6 +16,11 @@ #include "varmap.hh" #include "funcdata.hh" +AttributeId ATTRIB_LOCK = AttributeId("lock",129); +AttributeId ATTRIB_MAIN = AttributeId("main",130); + +ElementId ELEM_LOCALDB = ElementId("localdb",206); + /// \brief Can the given intersecting RangeHint coexist with \b this at their given offsets /// /// Determine if the data-type information in the two ranges \e line \e up @@ -364,27 +369,30 @@ void ScopeLocal::resetLocalWindow(void) glb->symboltab->setRange(this,newrange); } -void ScopeLocal::saveXml(ostream &s) const +void ScopeLocal::encode(Encoder &encoder) const { - s << "getName()); - a_v_b(s,"lock",rangeLocked); - s << ">\n"; - ScopeInternal::saveXml(s); - s << "\n"; + encoder.openElement(ELEM_LOCALDB); + encoder.writeString(ATTRIB_MAIN, space->getName()); + encoder.writeBool(ATTRIB_LOCK, rangeLocked); + ScopeInternal::encode(encoder); + encoder.closeElement(ELEM_LOCALDB); } -void ScopeLocal::restoreXml(const Element *el) +void ScopeLocal::decode(Decoder &decoder) + +{ + ScopeInternal::decode( decoder ); + collectNameRecs(); +} + +void ScopeLocal::decodeWrappingAttributes(Decoder &decoder) { rangeLocked = false; - if (xml_readbool(el->getAttributeValue("lock"))) + if (decoder.readBool(ATTRIB_LOCK)) rangeLocked = true; - space = glb->getSpaceByName(el->getAttributeValue("main")); - - ScopeInternal::restoreXml( *(el->getChildren().begin()) ); - collectNameRecs(); + space = glb->getSpaceByName(decoder.readString(ATTRIB_MAIN)); } /// The given range can no longer hold a \e mapped local variable. This indicates the range diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.hh index b8e16c2f91..d0a5564cb9 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.hh @@ -21,6 +21,11 @@ #include "database.hh" +extern AttributeId ATTRIB_LOCK; ///< Marshaling attribute "lock" +extern AttributeId ATTRIB_MAIN; ///< Marshaling attribute "main" + +extern ElementId ELEM_LOCALDB; ///< Marshaling element \ + /// \brief A symbol name recommendation with its associated storage location /// /// The name is associated with a static Address and use point in the code. Symbols @@ -224,8 +229,9 @@ public: void markNotMapped(AddrSpace *spc,uintb first,int4 sz,bool param); ///< Mark a specific address range is not mapped // Routines that are specific to one address space - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder); + virtual void decodeWrappingAttributes(Decoder &decoder); virtual string buildVariableName(const Address &addr, const Address &pc, Datatype *ct, diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.cc index 4a9b342725..bff6146f5c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.cc @@ -16,6 +16,12 @@ #include "varnode.hh" #include "funcdata.hh" +AttributeId ATTRIB_ADDRTIED = AttributeId("addrtied",131); +AttributeId ATTRIB_GRP = AttributeId("grp",132); +AttributeId ATTRIB_INPUT = AttributeId("input",133); +AttributeId ATTRIB_PERSISTS = AttributeId("persists",134); +AttributeId ATTRIB_UNAFF = AttributeId("unaff",135); + /// Compare by location then by definition. /// This is the same as the normal varnode compare, but we distinguish identical frees by their /// pointer address. Thus varsets defined with this comparison act like multisets for free varnodes @@ -863,30 +869,30 @@ int4 Varnode::termOrder(const Varnode *op) const return 0; } -/// Write an XML tag, \b \, with at least the following attributes: +/// Encode \b this as an \ element, with at least the following attributes: /// - \b space describes the AddrSpace /// - \b offset of the Varnode within the space /// - \b size of the Varnode is bytes /// -/// Additionally the tag will contain other optional attributes. -/// \param s is the stream to write the tag to -void Varnode::saveXml(ostream &s) const +/// Additionally the element will contain other optional attributes. +/// \param encoder is the stream encoder +void Varnode::encode(Encoder &encoder) const { - s << "saveXmlAttributes(s,loc.getOffset(),size); - a_v_u(s,"ref",getCreateIndex()); + encoder.openElement(ELEM_ADDR); + loc.getSpace()->encodeAttributes(encoder,loc.getOffset(),size); + encoder.writeUnsignedInteger(ATTRIB_REF, getCreateIndex()); if (mergegroup != 0) - a_v_i(s,"grp",getMergeGroup()); + encoder.writeSignedInteger(ATTRIB_GRP, getMergeGroup()); if (isPersist()) - s << " persists=\"true\""; + encoder.writeBool(ATTRIB_PERSISTS, true); if (isAddrTied()) - s << " addrtied=\"true\""; + encoder.writeBool(ATTRIB_ADDRTIED, true); if (isUnaffected()) - s << " unaff=\"true\""; + encoder.writeBool(ATTRIB_UNAFF, true); if (isInput()) - s << " input=\"true\""; - s << "/>"; + encoder.writeBool(ATTRIB_INPUT, true); + encoder.closeElement(ELEM_ADDR); } /// Invoke the printRaw method on the given Varnode pointer, but take into account that it diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.hh index 471c17e5a8..de858ba015 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.hh @@ -30,6 +30,12 @@ class Funcdata; class SymbolEntry; class ValueSet; +extern AttributeId ATTRIB_ADDRTIED; ///< Marshaling attribute "addrtied" +extern AttributeId ATTRIB_GRP; ///< Marshaling attribute "grp" +extern AttributeId ATTRIB_INPUT; ///< Marshaling attribute "input" +extern AttributeId ATTRIB_PERSISTS; ///< Marshaling attribute "persists" +extern AttributeId ATTRIB_UNAFF; ///< Marshaling attribute "unaff" + /// \brief Compare two Varnode pointers by location then definition struct VarnodeCompareLocDef { bool operator()(const Varnode *a,const Varnode *b) const; ///< Functional comparison operator @@ -315,7 +321,7 @@ public: void setLongPrint(void) { addlflags |= Varnode::longprint; } ///< Force \b this to be printed as a \e long token void setStopUpPropagation(void) { addlflags |= Varnode::stop_uppropagation; } ///< Stop up-propagation thru \b this void clearStopUpPropagation(void) { addlflags &= ~Varnode::stop_uppropagation; } ///< Stop up-propagation thru \b this - void setImpliedField(void) { addlflags |= Varnode::has_implied_field; } ///< Mark \this as having an implied field + void setImpliedField(void) { addlflags |= Varnode::has_implied_field; } ///< Mark \b this as having an implied field bool updateType(Datatype *ct,bool lock,bool override); ///< (Possibly) set the Datatype given various restrictions void setStackStore(void) { addlflags |= Varnode::stack_store; } ///< Mark as produced by explicit CPUI_STORE void setLockedInput(void) { addlflags |= Varnode::locked_input; } ///< Mark as existing input, even if unused @@ -323,10 +329,9 @@ public: void copySymbolIfValid(const Varnode *vn); ///< Copy symbol info from \b vn if constant value matches Datatype *getLocalType(bool &blockup) const; ///< Calculate type of Varnode based on local information bool copyShadow(const Varnode *op2) const; ///< Are \b this and \b op2 copied from the same source? - void saveXml(ostream &s) const; ///< Save a description of \b this as an XML tag + void encode(Encoder &encoder) const; ///< Encode a description of \b this to a stream static bool comparePointers(const Varnode *a,const Varnode *b) { return (*a < *b); } ///< Compare Varnodes as pointers static void printRaw(ostream &s,const Varnode *vn); ///< Print raw info about a Varnode to stream - // static Varnode *restoreXml(const Element *el,Funcdata &fd,bool coderef); }; /// \brief A container for Varnode objects from a specific function diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/xml_arch.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/xml_arch.cc index d6fa8bc408..c87a175c5f 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/xml_arch.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/xml_arch.cc @@ -15,6 +15,8 @@ */ #include "xml_arch.hh" +ElementId ELEM_XML_SAVEFILE = ElementId("xml_savefile",207); + // Constructing the singleton registers the capability XmlArchitectureCapability XmlArchitectureCapability::xmlArchitectureCapability; @@ -96,18 +98,17 @@ XmlArchitecture::XmlArchitecture(const string &fname,const string &targ,ostream } /// Prepend extra stuff to specify binary file and spec -/// \param s is the stream to write to -void XmlArchitecture::saveXml(ostream &s) const +/// \param encoder is the stream encoder +void XmlArchitecture::encode(Encoder &encoder) const { - s << "\n"; - ((LoadImageXml *)loader)->saveXml(s); // Save the LoadImage - types->saveXmlCoreTypes(s); - SleighArchitecture::saveXml(s); // Save the rest of the state - s << "\n"; + encoder.openElement(ELEM_XML_SAVEFILE); + encodeHeader(encoder); + encoder.writeUnsignedInteger(ATTRIB_ADJUSTVMA, adjustvma); + ((LoadImageXml *)loader)->encode(encoder); // Save the LoadImage + types->encodeCoreTypes(encoder); + SleighArchitecture::encode(encoder); // Save the rest of the state + encoder.closeElement(ELEM_XML_SAVEFILE); } void XmlArchitecture::restoreXml(DocumentStorage &store) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/xml_arch.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/xml_arch.hh index 4d404e6ad9..d395fb8a3c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/xml_arch.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/xml_arch.hh @@ -18,6 +18,8 @@ #include "sleigh_arch.hh" #include "loadimage_xml.hh" +extern ElementId ELEM_XML_SAVEFILE; ///< Marshaling element \ + /// \brief Extension for building an XML format capable Architecture class XmlArchitectureCapability : public ArchitectureCapability { static XmlArchitectureCapability xmlArchitectureCapability; ///< The singleton instance @@ -38,7 +40,7 @@ class XmlArchitecture : public SleighArchitecture { // virtual void resolveArchitecture(void); ///< Inherit SleighArchitecture's version virtual void postSpecFile(void); public: - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; virtual void restoreXml(DocumentStorage &store); XmlArchitecture(const string &fname,const string &targ,ostream *estream); ///< Constructor virtual ~XmlArchitecture(void) {} diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileDebug.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileDebug.java index 7d4eed2806..163d46653f 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileDebug.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileDebug.java @@ -343,8 +343,9 @@ public class DecompileDebug { new DataTypeDependencyOrderer(program.getDataTypeManager(), dtypes); //First output all structures as zero size so to avoid any cyclic dependencies. for (DataType dataType : TypeOrderer.getCompositeList()) { - debugStream.write( - (dtmanage.buildCompositeZeroSizePlaceholder(dataType) + "\n").toString().getBytes()); + debugStream + .write((dtmanage.buildCompositeZeroSizePlaceholder(dataType) + "\n").toString() + .getBytes()); } //Next, use the dependency stack to output types. for (DataType dataType : TypeOrderer.getDependencyList()) { @@ -553,7 +554,7 @@ public class DecompileDebug { private void dumpDatabases(OutputStream debugStream) throws IOException { Namespace scopename = null; ArrayList spaceList = orderNamespaces(); - debugStream.write("\n".getBytes()); + debugStream.write("\n".getBytes()); for (Namespace element : spaceList) { scopename = element; StringBuilder datahead = new StringBuilder(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java index 23babf97c3..8ed8d91d5d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java @@ -1427,7 +1427,6 @@ public class SleighLanguage implements Language { String tag; int delay; boolean physical; - boolean global; for (AddressSpace element : spclist) { if ((element instanceof OverlayAddressSpace)) { @@ -1445,25 +1444,21 @@ public class SleighLanguage implements Language { tag = "space"; delay = 1; physical = true; - global = true; break; case AddressSpace.TYPE_REGISTER: tag = "space"; delay = 0; physical = true; - global = false; break; case AddressSpace.TYPE_UNIQUE: tag = "space_unique"; delay = 0; physical = true; - global = false; break; case AddressSpace.TYPE_OTHER: tag = "space_other"; delay = 0; physical = true; - global = true; break; default: continue; @@ -1491,7 +1486,6 @@ public class SleighLanguage implements Language { SpecXmlUtils.encodeBooleanAttribute(resBuf, "bigendian", isBigEndian()); SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "delay", delay); SpecXmlUtils.encodeBooleanAttribute(resBuf, "physical", physical); - SpecXmlUtils.encodeBooleanAttribute(resBuf, "global", global); resBuf.append("/>\n"); }