GP-2157 Marshaling refactor. Decompiler side.

This commit is contained in:
caheckman 2022-05-17 16:15:21 -04:00
parent 672c1f11e2
commit d8c10bf229
97 changed files with 5313 additions and 3733 deletions

View file

@ -51,6 +51,7 @@ model {
source { source {
srcDir "src/decompile/cpp" srcDir "src/decompile/cpp"
include "marshal.cc"
include "space.cc" include "space.cc"
include "float.cc" include "float.cc"
include "address.cc" include "address.cc"
@ -152,6 +153,7 @@ model {
source { source {
srcDir "src/decompile/cpp" srcDir "src/decompile/cpp"
include "marshal.cc"
include "space.cc" include "space.cc"
include "float.cc" include "float.cc"
include "address.cc" include "address.cc"

View file

@ -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 # The following macros partition all the source files, there should be no overlaps
# Some core source files used in all projects # 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 # Additional core files for any projects that decompile
DECCORE=capability architecture options graph cover block cast typeop database cpool \ DECCORE=capability architecture options graph cover block cast typeop database cpool \
comment stringmanage fspec action loadimage grammar varnode op \ comment stringmanage fspec action loadimage grammar varnode op \

View file

@ -128,8 +128,6 @@ public:
virtual int4 apply(Funcdata &data)=0; 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 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 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 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 virtual Rule *getSubRule(const string &specify); ///< Retrieve a specific sub-rule by name
}; };

View file

@ -16,6 +16,17 @@
#include "address.hh" #include "address.hh"
#include "translate.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) 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); uniq = (ex == Address::m_minimal) ? 0 : ~((uintm)0);
} }
void SeqNum::saveXml(ostream &s) const void SeqNum::encode(Encoder &encoder) const
{ {
s << "<seqnum"; encoder.openElement(ELEM_SEQNUM);
pc.getSpace()->saveXmlAttributes(s,pc.getOffset()); pc.getSpace()->encodeAttributes(encoder,pc.getOffset());
a_v_u(s,"uniq",uniq); encoder.writeUnsignedInteger(ATTRIB_UNIQ, uniq);
s << "/>"; 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); uintm uniq = ~((uintm)0);
Address pc = Address::restoreXml(el,manage); // Recover address uint4 elemId = decoder.openElement(ELEM_SEQNUM);
for(int4 i=0;i<el->getNumAttributes();++i) Address pc = Address::decode(decoder,manage); // Recover address
if (el->getAttributeName(i) == "uniq") { for(;;) {
istringstream s2(el->getAttributeValue(i)); // Recover unique (if present) uint4 attribId = decoder.getNextAttributeId();
s2.unsetf(ios::dec | ios::hex | ios::oct); if (attribId == 0) break;
s2 >> uniq; if (attribId == ATTRIB_UNIQ) {
uniq = decoder.readUnsignedInteger();
break; break;
} }
}
decoder.closeElement(elemId);
return SeqNum(pc,uniq); 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 /// Return \b true if the range starting at \b this extending the given number of bytes
/// is contained by the second given range. /// is contained by the second given range.
/// \param sz is the given number of bytes in \b this 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); base->getManager()->renormalizeJoinAddress(*this,size);
} }
/// This is usually used to build an address from an \b \<addr\> /// This is usually used to decode an address from an \b \<addr\>
/// tag, but it can be used to create an address from any tag /// element, but any element can be used if it has the appropriate attributes
/// with the appropriate attributes
/// - \e space indicates the address space of the tag /// - \e space indicates the address space of the tag
/// - \e offset indicates the offset within the space /// - \e offset indicates the offset within the space
/// ///
/// or a \e name attribute can be used to recover an address /// or a \e name attribute can be used to recover an address
/// based on a register name. /// 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 /// \param manage is the address space manager for the program
/// \return the resulting Address /// \return the resulting Address
Address Address::restoreXml(const Element *el,const AddrSpaceManager *manage) Address Address::decode(Decoder &decoder,const AddrSpaceManager *manage)
{ {
VarnodeData var; VarnodeData var;
var.restoreXml(el,manage); var.decode(decoder,manage);
return Address(var.space,var.offset); return Address(var.space,var.offset);
} }
/// This is usually used to build an address from an \b \<addr\> /// This is usually used to decode an address from an \b \<addr\>
/// tag, but it can be used to create an address from any tag /// element, but any element can be used if it has the appropriate attributes
/// with the appropriate attributes
/// - \e space indicates the address space of the tag /// - \e space indicates the address space of the tag
/// - \e offset indicates the offset within the space /// - \e offset indicates the offset within the space
/// - \e size indicates the size of an address range /// - \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 /// or a \e name attribute can be used to recover an address
/// and size based on a register name. If a size is recovered /// and size based on a register name. If a size is recovered
/// it is stored in \e size reference. /// 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 manage is the address space manager for the program
/// \param size is the reference to any recovered size /// \param size is the reference to any recovered size
/// \return the resulting Address /// \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; VarnodeData var;
var.restoreXml(el,manage); var.decode(decoder,manage);
size = var.size; size = var.size;
return Address(var.space,var.offset); 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 /// Get the last address +1, updating the space, or returning
/// the extremal address if necessary /// the extremal address if necessary
/// \param manage is used to fetch the next address space /// \param manage is used to fetch the next address space
@ -259,48 +287,60 @@ void Range::printBounds(ostream &s) const
s << hex << first << '-' << last; s << hex << first << '-' << last;
} }
/// Write this object to a stream as a \<range> tag. /// Encode \b this to a stream as a \<range> element.
/// \param s is the output stream /// \param encoder is the stream encoder
void Range::saveXml(ostream &s) const void Range::encode(Encoder &encoder) const
{ {
s << "<range"; encoder.openElement(ELEM_RANGE);
a_v(s,"space",spc->getName()); encoder.writeString(ATTRIB_SPACE, spc->getName());
a_v_u(s,"first",first); encoder.writeUnsignedInteger(ATTRIB_FIRST, first);
a_v_u(s,"last",last); encoder.writeUnsignedInteger(ATTRIB_LAST, last);
s << "/>\n"; encoder.closeElement(ELEM_RANGE);
} }
/// Reconstruct this object from an XML \<range> element /// Reconstruct this object from a \<range> or \<register> element
/// \param el is the XML element /// \param decoder is the stream decoder
/// \param manage is the space manage for recovering AddrSpace objects /// \param manage is the space manager for recovering AddrSpace objects
void Range::restoreXml(const Element *el,const AddrSpaceManager *manage) void Range::decode(Decoder &decoder,const AddrSpaceManager *manage)
{
uint4 elemId = decoder.openElement();
if (elemId != ELEM_RANGE && elemId != ELEM_REGISTER)
throw XmlError("Expecting <range> or <register> element");
decodeFromAttributes(decoder,manage);
decoder.closeElement(elemId);
}
/// Reconstruct from attributes that may not be part of a \<range> 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; spc = (AddrSpace *)0;
bool seenLast = false; bool seenLast = false;
first = 0; first = 0;
last = 0; last = 0;
for(int4 i=0;i<el->getNumAttributes();++i) { for(;;) {
if (el->getAttributeName(i) == "space") { uint4 attribId = decoder.getNextAttributeId();
spc = manage->getSpaceByName(el->getAttributeValue(i)); if (attribId == 0) break;
if (attribId == ATTRIB_SPACE) {
string spcname = decoder.readString();
spc = manage->getSpaceByName(spcname);
if (spc == (AddrSpace *)0) if (spc == (AddrSpace *)0)
throw LowlevelError("Undefined space: "+el->getAttributeValue(i)); throw LowlevelError("Undefined space: "+spcname);
} }
else if (el->getAttributeName(i) == "first") { else if (attribId == ATTRIB_FIRST) {
istringstream s(el->getAttributeValue(i)); first = decoder.readUnsignedInteger();
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> first;
} }
else if (el->getAttributeName(i) == "last") { else if (attribId == ATTRIB_LAST) {
istringstream s(el->getAttributeValue(i)); last = decoder.readUnsignedInteger();
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> last;
seenLast = true; seenLast = true;
} }
else if (el->getAttributeName(i) == "name") { else if (attribId == ATTRIB_NAME) {
const Translate *trans = manage->getDefaultCodeSpace()->getTrans(); const Translate *trans = manage->getDefaultCodeSpace()->getTrans();
const VarnodeData &point(trans->getRegister(el->getAttributeValue(i))); const VarnodeData &point(trans->getRegister(decoder.readString()));
spc = point.space; spc = point.space;
first = point.offset; first = point.offset;
last = (first-1) + point.size; last = (first-1) + point.size;
@ -316,6 +356,31 @@ void Range::restoreXml(const Element *el,const AddrSpaceManager *manage)
throw LowlevelError("Illegal range tag"); throw LowlevelError("Illegal range tag");
} }
void RangeProperties::decode(Decoder &decoder)
{
uint4 elemId = decoder.openElement();
if (elemId != ELEM_RANGE && elemId != ELEM_REGISTER)
throw XmlError("Expecting <range> or <register> 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 /// Insert a new Range merging as appropriate to maintain the disjoint cover
/// \param spc is the address space containing the new range /// \param spc is the address space containing the new range
/// \param first is the offset of the first byte in 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 \<rangelist> tag /// Encode \b this as a \<rangelist> element
/// \param s is the output stream /// \param encoder is the stream encoder
void RangeList::saveXml(ostream &s) const void RangeList::encode(Encoder &encoder) const
{ {
set<Range>::const_iterator iter; set<Range>::const_iterator iter;
s << "<rangelist>\n"; encoder.openElement(ELEM_RANGELIST);
for(iter=tree.begin();iter!=tree.end();++iter) { for(iter=tree.begin();iter!=tree.end();++iter) {
(*iter).saveXml(s); (*iter).encode(encoder);
} }
s << "</rangelist>\n"; encoder.closeElement(ELEM_RANGELIST);
} }
/// Recover each individual disjoint Range for \b this RangeList as encoded /// Recover each individual disjoint Range for \b this RangeList.
/// in a \<rangelist> tag. /// \param decoder is the stream decoder
/// \param el is the XML element
/// \param manage is manager for retrieving address spaces /// \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()); uint4 elemId = decoder.openElement(ELEM_RANGELIST);
List::const_iterator iter; while(decoder.peekElement() != 0) {
for(iter=list.begin();iter!=list.end();++iter) {
const Element *subel = *iter;
Range range; Range range;
range.restoreXml(subel,manage); range.decode(decoder,manage);
tree.insert(range); tree.insert(range);
} }
decoder.closeElement(elemId);
} }
#ifdef UINTB4 #ifdef UINTB4

View file

@ -30,6 +30,17 @@
class AddrSpaceManager; 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 \<addr>
extern ElementId ELEM_RANGE; ///< Marshaling element \<range>
extern ElementId ELEM_RANGELIST; ///< Marshaling element \<rangelist>
extern ElementId ELEM_REGISTER; ///< Marshaling element \<register>
extern ElementId ELEM_SEQNUM; ///< Marshaling element \<seqnum>
extern ElementId ELEM_VARNODE; ///< Marshaling element \<varnode>
/// \brief A low-level machine address for labelling bytes and data. /// \brief A low-level machine address for labelling bytes and data.
/// ///
/// All data that can be manipulated within the processor reverse /// 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 int4 read(const string &s); ///< Read in the address from a string
AddrSpace *getSpace(void) const; ///< Get the address space AddrSpace *getSpace(void) const; ///< Get the address space
uintb getOffset(void) const; ///< Get the address offset 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 char getShortcut(void) const; ///< Get the shortcut character for the address space
Address &operator=(const Address &op2); ///< Copy an address Address &operator=(const Address &op2); ///< Copy an address
bool operator==(const Address &op2) const; ///< Compare two addresses for equality 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 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 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 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 encode(Encoder &encoder) const; ///< Encode \b this to a stream
void saveXml(ostream &s,int4 size) const; ///< Save this and a size to a stream as an XML tag void encode(Encoder &encoder,int4 size) const; ///< Encode \b this and a size to a stream
/// Restore an address from parsed XML /// 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 /// 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 /// \brief A class for uniquely labelling and comparing PcodeOps
@ -144,16 +154,18 @@ public:
return (pc < op2.pc); return (pc < op2.pc);
} }
/// Save a SeqNum to a stream as an XML tag /// Encode a SeqNum to a stream
void saveXml(ostream &s) const; void encode(Encoder &encoder) const;
/// Restore a SeqNum from parsed XML /// Decode a SeqNum from a stream
static SeqNum restoreXml(const Element *el,const AddrSpaceManager *manage); 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); friend ostream &operator<<(ostream &s,const SeqNum &sq);
}; };
class RangeProperties;
/// \brief A contiguous range of bytes in some address space /// \brief A contiguous range of bytes in some address space
class Range { class Range {
friend class RangeList; friend class RangeList;
@ -169,7 +181,8 @@ public:
/// \param l is the offset of the last byte in the range /// \param l is the offset of the last byte in the range
Range(AddrSpace *s,uintb f,uintb l) { Range(AddrSpace *s,uintb f,uintb l) {
spc = s; first = f; last = 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 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 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 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 (spc->getIndex() < op2.spc->getIndex());
return (first < op2.first); } return (first < op2.first); }
void printBounds(ostream &s) const; ///< Print \b this Range to a stream 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 encode(Encoder &encoder) const; ///< Encode \b this Range to a stream
void restoreXml(const Element *el,const AddrSpaceManager *manage); ///< Restore \b this from XML 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 \<range> 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 /// \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 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 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 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 encode(Encoder &encoder) const; ///< Encode \b this RangeList to a stream
void restoreXml(const Element *el,const AddrSpaceManager *manage); ///< Restore \b this RangeList from an XML stream void decode(Decoder &decoder,const AddrSpaceManager *manage); ///< Decode \b this RangeList from a \<rangelist> element
}; };
/// Precalculated masks indexed by size /// Precalculated masks indexed by size
@ -416,27 +445,27 @@ inline bool Address::isJoin(void) const {
return (base->getType() == IPTR_JOIN); return (base->getType() == IPTR_JOIN);
} }
/// Save an \b \<addr\> tag corresponding to this address to a /// Save an \<addr\> element corresponding to this address to a
/// stream. The exact format is determined by the address space, /// stream. The exact format is determined by the address space,
/// but this generally has a \e space and an \e offset attribute. /// but this generally has a \e space and an \e offset attribute.
/// \param s is the stream being written to /// \param encoder is the stream encoder
inline void Address::saveXml(ostream &s) const { inline void Address::encode(Encoder &encoder) const {
s << "<addr"; encoder.openElement(ELEM_ADDR);
if (base!=(AddrSpace *)0) if (base!=(AddrSpace *)0)
base->saveXmlAttributes(s,offset); base->encodeAttributes(encoder,offset);
s << "/>"; encoder.closeElement(ELEM_ADDR);
} }
/// Save an \b \<addr\> tag corresponding to this address to a /// Encode an \<addr> element corresponding to this address to a
/// stream. The tag will also include an extra \e size attribute /// stream. The tag will also include an extra \e size attribute
/// so that it can describe an entire memory range. /// 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 /// \param size is the number of bytes in the range
inline void Address::saveXml(ostream &s,int4 size) const { inline void Address::encode(Encoder &encoder,int4 size) const {
s << "<addr"; encoder.openElement(ELEM_ADDR);
if (base!=(AddrSpace *)0) if (base!=(AddrSpace *)0)
base->saveXmlAttributes(s,offset,size); base->encodeAttributes(encoder,offset,size);
s << "/>"; encoder.closeElement(ELEM_ADDR);
} }
/// \param addr is the Address to test for containment /// \param addr is the Address to test for containment

File diff suppressed because it is too large Load diff

View file

@ -61,6 +61,47 @@ public:
class Architecture; 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 \<address_shift_amount>
extern ElementId ELEM_AGGRESSIVETRIM; ///< Marshaling element \<aggressivetrim>
extern ElementId ELEM_COMPILER_SPEC; ///< Marshaling element \<compiler_spec>
extern ElementId ELEM_DATA_SPACE; ///< Marshaling element \<data_space>
extern ElementId ELEM_DEFAULT_MEMORY_BLOCKS; ///< Marshaling element \<default_memory_blocks>
extern ElementId ELEM_DEFAULT_PROTO; ///< Marshaling element \<default_proto>
extern ElementId ELEM_DEFAULT_SYMBOLS; ///< Marshaling element \<default_symbols>
extern ElementId ELEM_EVAL_CALLED_PROTOTYPE; ///< Marshaling element \<eval_called_prototype>
extern ElementId ELEM_EVAL_CURRENT_PROTOTYPE; ///< Marshaling element \<eval_current_prototype>
extern ElementId ELEM_EXPERIMENTAL_RULES; ///< Marshaling element \<experimental_rules>
extern ElementId ELEM_FLOWOVERRIDELIST; ///< Marshaling element \<flowoverridelist>
extern ElementId ELEM_FUNCPTR; ///< Marshaling element \<funcptr>
extern ElementId ELEM_GLOBAL; ///< Marshaling element \<global>
extern ElementId ELEM_INCIDENTALCOPY; ///< Marshaling element \<incidentalcopy>
extern ElementId ELEM_INFERPTRBOUNDS; ///< Marshaling element \<inferptrbounds>
extern ElementId ELEM_MODELALIAS; ///< Marshaling element \<modelalias>
extern ElementId ELEM_NOHIGHPTR; ///< Marshaling element \<nohighptr>
extern ElementId ELEM_PROCESSOR_SPEC; ///< Marshaling element \<processor_spec>
extern ElementId ELEM_PROGRAMCOUNTER; ///< Marshaling element \<programcounter>
extern ElementId ELEM_PROPERTIES; ///< Marshaling element \<properties>
extern ElementId ELEM_READONLY; ///< Marshaling element \<readonly>
extern ElementId ELEM_REGISTER_DATA; ///< Marshaling element \<register_data>
extern ElementId ELEM_RULE; ///< Marshaling element \<rule>
extern ElementId ELEM_SAVE_STATE; ///< Marshaling element \<save_state>
extern ElementId ELEM_SEGMENTED_ADDRESS; ///< Marshaling element \<segmented_address>
extern ElementId ELEM_SPACEBASE; ///< Marshaling element \<spacebase>
extern ElementId ELEM_SPECEXTENSIONS; ///< Marshaling element \<specextensions>
extern ElementId ELEM_STACKPOINTER; ///< Marshaling element \<stackpointer>
extern ElementId ELEM_VOLATILE; ///< Marshaling element \<volatile>
/// \brief Abstract extension point for building Architecture objects /// \brief Abstract extension point for building Architecture objects
/// ///
/// Decompilation hinges on initially recognizing the format of code then /// 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 setPrototype(const PrototypePieces &pieces); ///< Set the prototype for a particular function
void setPrintLanguage(const string &nm); ///< Establish a particular output language void setPrintLanguage(const string &nm); ///< Establish a particular output language
void globalify(void); ///< Mark \e all spaces as global 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 ~Architecture(void); ///< Destructor
virtual string getDescription(void) const { return archid; } ///< Get a string describing \b this architecture 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 /// Write the given message to whatever the registered error stream is
/// \param message is the error message /// \param message is the error message
virtual void printMessage(const string &message) const=0; virtual void printMessage(const string &message) const=0;
virtual void saveXml(ostream &s) const; ///< Serialize this architecture to XML virtual void encode(Encoder &encoder) const; ///< Encode \b this architecture to a stream
virtual void restoreXml(DocumentStorage &store); ///< Restore the Architecture state from an XML 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 virtual void nameFunction(const Address &addr,string &name) const; ///< Pick a default name for a function
#ifdef OPACTION_DEBUG #ifdef OPACTION_DEBUG
void setDebugStream(ostream *s) { debugstream = s; } ///< Establish the debug console stream 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 parseCompilerConfig(DocumentStorage &store); ///< Apply compiler specific configuration
void parseExtraRules(DocumentStorage &store); ///< Apply any Rule tags void parseExtraRules(DocumentStorage &store); ///< Apply any Rule tags
void parseDynamicRule(const Element *el); ///< Apply details of a dynamic Rule object void decodeDynamicRule(Decoder &decoder); ///< Apply details of a dynamic Rule object
ProtoModel *parseProto(const Element *el); ///< Build a proto-type model from an XML tag ProtoModel *decodeProto(Decoder &decoder); ///< Parse a proto-type model from a stream
void parseProtoEval(const Element *el); ///< Apply prototype evaluation configuration void decodeProtoEval(Decoder &decoder); ///< Apply prototype evaluation configuration
void parseDefaultProto(const Element *el); ///< Apply default prototype model configuration void decodeDefaultProto(Decoder &decoder); ///< Apply default prototype model configuration
void parseGlobal(const Element *el); ///< Apply global space configuration void decodeGlobal(Decoder &decoder,vector<RangeProperties> &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 addOtherSpace(void); ///< Add OTHER space and all of its overlays to the symboltab
void parseReadOnly(const Element *el); ///< Apply read-only region configuration void decodeReadOnly(Decoder &decoder); ///< Apply read-only region configuration
void parseVolatile(const Element *el); ///< Apply volatile region configuration void decodeVolatile(Decoder &decoder); ///< Apply volatile region configuration
void parseReturnAddress(const Element *el); ///< Apply return address configuration void decodeReturnAddress(Decoder &decoder); ///< Apply return address configuration
void parseIncidentalCopy(const Element *el); ///< Apply incidental copy configuration void decodeIncidentalCopy(Decoder &decoder); ///< Apply incidental copy configuration
void parseLaneSizes(const Element *el); ///< Apply lane size configuration void decodeLaneSizes(Decoder &decoder); ///< Apply lane size configuration
void parseStackPointer(const Element *el); ///< Apply stack pointer configuration void decodeStackPointer(Decoder &decoder); ///< Apply stack pointer configuration
void parseDeadcodeDelay(const Element *el); ///< Apply dead-code delay configuration void decodeDeadcodeDelay(Decoder &decoder); ///< Apply dead-code delay configuration
void parseInferPtrBounds(const Element *el); ///< Apply pointer inference bounds void decodeInferPtrBounds(Decoder &decoder); ///< Apply pointer inference bounds
void parseFuncPtrAlign(const Element *el); ///< Apply function pointer alignment configuration void decodeFuncPtrAlign(Decoder &decoder); ///< Apply function pointer alignment configuration
void parseSpacebase(const Element *el); ///< Create an additional indexed space void decodeSpacebase(Decoder &decoder); ///< Create an additional indexed space
void parseNoHighPtr(const Element *el); ///< Apply memory alias configuration void decodeNoHighPtr(Decoder &decoder); ///< Apply memory alias configuration
void parsePreferSplit(const Element *el); ///< Designate registers to be split void decodePreferSplit(Decoder &decoder); ///< Designate registers to be split
void parseAggressiveTrim(const Element *el); ///< Designate how to trim extension p-code ops void decodeAggressiveTrim(Decoder &decoder); ///< Designate how to trim extension p-code ops
}; };
/// \brief A resolver for segmented architectures /// \brief A resolver for segmented architectures

View file

@ -19,6 +19,8 @@
// Constructing this object registers capability // Constructing this object registers capability
BfdArchitectureCapability BfdArchitectureCapability::bfdArchitectureCapability; BfdArchitectureCapability BfdArchitectureCapability::bfdArchitectureCapability;
ElementId ELEM_BFD_SAVEFILE = ElementId("bfd_savefile",46);
BfdArchitectureCapability::BfdArchitectureCapability(void) BfdArchitectureCapability::BfdArchitectureCapability(void)
{ {
@ -125,16 +127,15 @@ BfdArchitecture::BfdArchitecture(const string &fname,const string &targ,ostream
adjustvma = 0; adjustvma = 0;
} }
void BfdArchitecture::saveXml(ostream &s) const void BfdArchitecture::encode(Encoder &encoder) const
{ // prepend extra stuff to specify binary file and spec { // prepend extra stuff to specify binary file and spec
s << "<bfd_savefile"; encoder.openElement(ELEM_BFD_SAVEFILE);
saveXmlHeader(s); encodeHeader(encoder);
a_v_u(s,"adjustvma",adjustvma); encoder.writeUnsignedInteger(ATTRIB_ADJUSTVMA, adjustvma);
s << ">\n"; types->encodeCoreTypes(encoder);
types->saveXmlCoreTypes(s); SleighArchitecture::encode(encoder); // Save the rest of the state
SleighArchitecture::saveXml(s); // Save the rest of the state encoder.closeElement(ELEM_BFD_SAVEFILE);
s << "</bfd_savefile>\n";
} }
void BfdArchitecture::restoreXml(DocumentStorage &store) void BfdArchitecture::restoreXml(DocumentStorage &store)

View file

@ -20,6 +20,8 @@
#include "sleigh_arch.hh" #include "sleigh_arch.hh"
#include "loadimage_bfd.hh" #include "loadimage_bfd.hh"
extern ElementId ELEM_BFD_SAVEFILE; ///< Marshaling element \<bfd_savefile>
/// \brief Extension point for building a GNU BFD capable Architecture /// \brief Extension point for building a GNU BFD capable Architecture
class BfdArchitectureCapability : public ArchitectureCapability { class BfdArchitectureCapability : public ArchitectureCapability {
static BfdArchitectureCapability bfdArchitectureCapability; ///< The singleton instance static BfdArchitectureCapability bfdArchitectureCapability; ///< The singleton instance
@ -40,7 +42,7 @@ class BfdArchitecture : public SleighArchitecture {
virtual void resolveArchitecture(void); virtual void resolveArchitecture(void);
virtual void postSpecFile(void); virtual void postSpecFile(void);
public: public:
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual void restoreXml(DocumentStorage &store); virtual void restoreXml(DocumentStorage &store);
BfdArchitecture(const string &fname,const string &targ,ostream *estream); ///< Constructor BfdArchitecture(const string &fname,const string &targ,ostream *estream); ///< Constructor
virtual ~BfdArchitecture(void) {} virtual ~BfdArchitecture(void) {}

View file

@ -17,34 +17,43 @@
#include "block.hh" #include "block.hh"
#include "funcdata.hh" #include "funcdata.hh"
/// The edge is saved assuming we already know what block we are in AttributeId ATTRIB_ALTINDEX = AttributeId("altindex",40);
/// \param s is the output stream AttributeId ATTRIB_DEPTH = AttributeId("depth",41);
void BlockEdge::saveXml(ostream &s) const 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 << "<edge"; encoder.openElement(ELEM_EDGE);
// We are not saving label currently // We are not saving label currently
a_v_i(s,"end",point->getIndex()); // Reference to other end of edge encoder.writeSignedInteger(ATTRIB_END, point->getIndex()); // Reference to other end of edge
a_v_i(s,"rev",reverse_index); // Position within other blocks edgelist encoder.writeSignedInteger(ATTRIB_REV, reverse_index); // Position within other blocks edgelist
s << "/>\n"; encoder.closeElement(ELEM_EDGE);
} }
/// \param el is the \<edge> tag /// Parse an \<edge> element
/// \param decoder is the stream decoder
/// \param resolver is used to cross-reference the edge's FlowBlock endpoints /// \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 label = 0; // Tag does not currently contain info about label
int4 endIndex; int4 endIndex = decoder.readSignedInteger(ATTRIB_END);
istringstream s(el->getAttributeValue("end"));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> endIndex;
point = resolver.findLevelBlock(endIndex); point = resolver.findLevelBlock(endIndex);
if (point == (FlowBlock *)0) if (point == (FlowBlock *)0)
throw LowlevelError("Bad serialized edge in block graph"); throw LowlevelError("Bad serialized edge in block graph");
istringstream s2(el->getAttributeValue("rev")); reverse_index = decoder.readSignedInteger(ATTRIB_REV);
s2.unsetf(ios::dec | ios::hex | ios::oct); decoder.closeElement(elemId);
s2 >> reverse_index;
} }
FlowBlock::FlowBlock(void) FlowBlock::FlowBlock(void)
@ -68,14 +77,15 @@ void FlowBlock::addInEdge(FlowBlock *b,uint4 lab)
b->outofthis.push_back(BlockEdge(this,lab,brev)); b->outofthis.push_back(BlockEdge(this,lab,brev));
} }
/// \param el is the \<edge> element /// Parse the next \<edge> element in the stream
/// \param decoder is the stream decoder
/// \param resolver is used to resolve block references /// \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(); intothis.emplace_back();
BlockEdge &inedge(intothis.back()); BlockEdge &inedge(intothis.back());
inedge.restoreXml(el,resolver); inedge.decode(decoder,resolver);
while(inedge.point->outofthis.size() <= inedge.reverse_index) while(inedge.point->outofthis.size() <= inedge.reverse_index)
inedge.point->outofthis.emplace_back(); inedge.point->outofthis.emplace_back();
BlockEdge &outedge(inedge.point->outofthis[inedge.reverse_index]); 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. /// 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 /// TODO: Fill in the remaining names and types
/// \param nm is the name string /// \param nm is the name string
/// \return the corresponding block_type /// \return the corresponding block_type
@ -1286,14 +1296,14 @@ void BlockGraph::finalizePrinting(Funcdata &data) const
(*iter)->finalizePrinting(data); (*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;i<list.size();++i) { for(int4 i=0;i<list.size();++i) {
FlowBlock *bl = list[i]; FlowBlock *bl = list[i];
s << "<bhead"; encoder.openElement(ELEM_BHEAD);
a_v_i(s,"index",bl->getIndex()); encoder.writeSignedInteger(ATTRIB_INDEX, bl->getIndex());
FlowBlock::block_type bt = bl->getType(); FlowBlock::block_type bt = bl->getType();
string nm; string nm;
if (bt == FlowBlock::t_if) { if (bt == FlowBlock::t_if) {
@ -1307,54 +1317,47 @@ void BlockGraph::saveXmlBody(ostream &s) const
} }
else else
nm = FlowBlock::typeToName(bt); nm = FlowBlock::typeToName(bt);
a_v(s,"type",nm); encoder.writeString(ATTRIB_TYPE, nm);
s << "/>\n"; encoder.closeElement(ELEM_BHEAD);
} }
for(int4 i=0;i<list.size();++i) for(int4 i=0;i<list.size();++i)
list[i]->saveXml(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); BlockMap newresolver(resolver);
FlowBlock::restoreXmlBody(iter,enditer,newresolver);
vector<FlowBlock *> tmplist; vector<FlowBlock *> tmplist;
while(iter != enditer) { for(;;) {
const Element *el = *iter; uint4 subId = decoder.peekElement();
if (el->getName() != "bhead") break; if (subId != ELEM_BHEAD) break;
++iter; decoder.openElement();
int4 newindex; int4 newindex = decoder.readSignedInteger(ATTRIB_INDEX);
istringstream s(el->getAttributeValue("index")); FlowBlock *bl = newresolver.createBlock(decoder.readString(ATTRIB_TYPE));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> newindex;
const string &nm( el->getAttributeValue("type") );
FlowBlock *bl = newresolver.createBlock(nm);
bl->index = newindex; // Need to set index here for sort bl->index = newindex; // Need to set index here for sort
tmplist.push_back(bl); tmplist.push_back(bl);
decoder.closeElement(subId);
} }
newresolver.sortList(); newresolver.sortList();
for(int4 i=0;i<tmplist.size();++i) { for(int4 i=0;i<tmplist.size();++i) {
if (iter == enditer)
throw LowlevelError("Bad BlockGraph xml");
FlowBlock *bl = tmplist[i]; FlowBlock *bl = tmplist[i];
bl->restoreXml(*iter,newresolver); bl->decode(decoder,newresolver);
addBlock(bl); addBlock(bl);
++iter;
} }
} }
/// This is currently just a wrapper around the FlowBlock::restoreXml() /// Parse a \<block> element. This is currently just a wrapper around the
/// that sets of the BlockMap resolver /// FlowBlock::decode() that sets of the BlockMap resolver
/// \param el is the root \<block> tag /// \param decoder is the stream decoder
/// \param m is the address space manager /// \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); BlockMap resolver(m);
FlowBlock::restoreXml(el,resolver); FlowBlock::decode(decoder,resolver);
// Restore goto references here // Restore goto references here
} }
@ -2353,77 +2356,70 @@ bool BlockBasic::isComplex(void) const
return false; return false;
} }
/// \param s is the output stream /// \param encoder is the stream encoder
void FlowBlock::saveXmlHeader(ostream &s) const 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 /// \param decoder is the stream decoder to pull attributes from
void FlowBlock::restoreXmlHeader(const Element *el) void FlowBlock::decodeHeader(Decoder &decoder)
{ {
istringstream s(el->getAttributeValue("index")); index = decoder.readSignedInteger(ATTRIB_INDEX);
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> index;
} }
/// Write \<edge> tags to stream /// Write \<edge> element to a stream
/// \param s is the output stream /// \param encoder is the stream encoder
void FlowBlock::saveXmlEdges(ostream &s) const void FlowBlock::encodeEdges(Encoder &encoder) const
{ {
for(int4 i=0;i<intothis.size();++i) { for(int4 i=0;i<intothis.size();++i) {
intothis[i].saveXml(s); intothis[i].encode(encoder);
} }
} }
/// \brief Restore edges from an XML stream /// \brief Restore edges from an encoded stream
/// ///
/// \param iter is an iterator to the \<edge> tags /// \param decoder is the stream decoder
/// \param enditer marks the end of the list of tags
/// \param resolver is used to recover FlowBlock cross-references /// \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) { for(;;) {
const Element *el = *iter; uint4 subId = decoder.peekElement();
if (el->getName() != "edge") if (subId != ELEM_EDGE)
return; break;
++iter; decodeNextInEdge(decoder,resolver);
restoreNextInEdge(el,resolver);
} }
} }
/// Serialize \b this and all its sub-components as an XML \<block> tag. /// Encode \b this and all its sub-components as a \<block> element.
/// \param s is the output stream /// \param encoder is the stream encoder
void FlowBlock::saveXml(ostream &s) const void FlowBlock::encode(Encoder &encoder) const
{ {
s << "<block"; encoder.openElement(ELEM_BLOCK);
saveXmlHeader(s); encodeHeader(encoder);
s << ">\n"; encodeBody(encoder);
saveXmlBody(s); encodeEdges(encoder);
saveXmlEdges(s); encoder.closeElement(ELEM_BLOCK);
s << "</block>\n";
} }
/// Recover \b this and all it sub-components from an XML \<block> tag. /// Recover \b this and all it sub-components from a \<block> element.
/// ///
/// This will construct all the sub-components using \b resolver as a factory. /// 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 /// \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); uint4 elemId = decoder.openElement(ELEM_BLOCK);
const List &list(el->getChildren()); decodeHeader(decoder);
List::const_iterator iter; decodeBody(decoder,resolver);
decodeEdges(decoder,resolver);
iter = list.begin(); decoder.closeElement(elemId);
restoreXmlBody(iter,list.end(),resolver);
restoreXmlEdges(iter,list.end(),resolver);
} }
/// If there are two branches, pick the fall-thru branch /// 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()); cover.decode(decoder, resolver.getAddressManager());
++iter;
} }
void BlockBasic::printHeader(ostream &s) const void BlockBasic::printHeader(ostream &s) const
@ -2635,12 +2630,12 @@ void BlockCopy::printTree(ostream &s,int4 level) const
copy->printTree(s,level); 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(); int4 altindex = copy->getIndex();
a_v_i(s,"altindex",altindex); encoder.writeSignedInteger(ATTRIB_ALTINDEX, altindex);
} }
void BlockGoto::markUnstructured(void) void BlockGoto::markUnstructured(void)
@ -2692,17 +2687,17 @@ FlowBlock *BlockGoto::nextFlowAfter(const FlowBlock *bl) const
return getGotoTarget()->getFrontLeaf(); return getGotoTarget()->getFrontLeaf();
} }
void BlockGoto::saveXmlBody(ostream &s) const void BlockGoto::encodeBody(Encoder &encoder) const
{ {
BlockGraph::saveXmlBody(s); BlockGraph::encodeBody(encoder);
s << "<target"; encoder.openElement(ELEM_TARGET);
const FlowBlock *leaf = gototarget->getFrontLeaf(); const FlowBlock *leaf = gototarget->getFrontLeaf();
int4 depth = gototarget->calcDepth(leaf); int4 depth = gototarget->calcDepth(leaf);
a_v_i(s,"index",leaf->getIndex()); encoder.writeSignedInteger(ATTRIB_INDEX, leaf->getIndex());
a_v_i(s,"depth",depth); encoder.writeSignedInteger(ATTRIB_DEPTH, depth);
a_v_u(s,"type",gototype); encoder.writeUnsignedInteger(ATTRIB_TYPE, gototype);
s << "/>\n"; encoder.closeElement(ELEM_TARGET);
} }
void BlockMultiGoto::scopeBreak(int4 curexit,int4 curloopexit) void BlockMultiGoto::scopeBreak(int4 curexit,int4 curloopexit)
@ -2725,18 +2720,18 @@ FlowBlock *BlockMultiGoto::nextFlowAfter(const FlowBlock *bl) const
return (FlowBlock *)0; 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;i<gotoedges.size();++i) { for(int4 i=0;i<gotoedges.size();++i) {
FlowBlock *gototarget = gotoedges[i]; FlowBlock *gototarget = gotoedges[i];
const FlowBlock *leaf = gototarget->getFrontLeaf(); const FlowBlock *leaf = gototarget->getFrontLeaf();
int4 depth = gototarget->calcDepth(leaf); int4 depth = gototarget->calcDepth(leaf);
s << "<target"; encoder.openElement(ELEM_TARGET);
a_v_i(s,"index",leaf->getIndex()); encoder.writeSignedInteger(ATTRIB_INDEX, leaf->getIndex());
a_v_i(s,"depth",depth); encoder.writeSignedInteger(ATTRIB_DEPTH, depth);
s << "/>\n"; encoder.closeElement(ELEM_TARGET);
} }
} }
@ -2846,12 +2841,12 @@ FlowBlock *BlockCondition::nextFlowAfter(const FlowBlock *bl) const
return (FlowBlock *)0; // Do not know where flow goes 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)); string nm(get_opname(opc));
a_v(s,"opcode",nm); encoder.writeString(ATTRIB_OPCODE, nm);
} }
void BlockIf::markUnstructured(void) void BlockIf::markUnstructured(void)
@ -2924,18 +2919,18 @@ FlowBlock *BlockIf::nextFlowAfter(const FlowBlock *bl) const
return getParent()->nextFlowAfter(this); 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 if (getSize() == 1) { // If this is a if GOTO block
const FlowBlock *leaf = gototarget->getFrontLeaf(); const FlowBlock *leaf = gototarget->getFrontLeaf();
int4 depth = gototarget->calcDepth(leaf); int4 depth = gototarget->calcDepth(leaf);
s << "<target"; encoder.openElement(ELEM_TARGET);
a_v_i(s,"index",leaf->getIndex()); encoder.writeSignedInteger(ATTRIB_INDEX, leaf->getIndex());
a_v_i(s,"depth",depth); encoder.writeSignedInteger(ATTRIB_DEPTH, depth);
a_v_u(s,"type",gototype); encoder.writeUnsignedInteger(ATTRIB_TYPE, gototype);
s << "/>\n"; encoder.closeElement(ELEM_TARGET);
} }
} }

View file

@ -35,6 +35,17 @@ class BlockSwitch;
class PrintLanguage; class PrintLanguage;
class BlockMap; 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 \<bhead>
extern ElementId ELEM_BLOCK; ///< Marshaling element \<block>
extern ElementId ELEM_BLOCKEDGE; ///< Marshaling element \<blockedge>
extern ElementId ELEM_EDGE; ///< Marshaling element \<edge>
/// \brief A control-flow edge between blocks (FlowBlock) /// \brief A control-flow edge between blocks (FlowBlock)
/// ///
/// The edge is owned by the source block and can have FlowBlock::edge_flags /// 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 uint4 label; ///< Label of the edge
FlowBlock *point; ///< Other end of the edge FlowBlock *point; ///< Other end of the edge
int4 reverse_index; ///< Index for edge coming other way 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 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 encode(Encoder &encoder) const; ///< Encode \b this edge to a stream
void restoreXml(const Element *el,BlockMap &resolver); ///< Restore \b this edge from an XML stream void decode(Decoder &decoder,BlockMap &resolver); ///< Restore \b this edge from a stream
}; };
/// \brief Description of a control-flow block containing PcodeOps /// \brief Description of a control-flow block containing PcodeOps
@ -119,7 +130,7 @@ private:
// the result of the condition being false // the result of the condition being false
static void replaceEdgeMap(vector<BlockEdge> &vec); ///< Update block references in edges with copy map static void replaceEdgeMap(vector<BlockEdge> &vec); ///< Update block references in edges with copy map
void addInEdge(FlowBlock *b,uint4 lab); ///< Add an edge coming into \b this 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 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 halfDeleteOutEdge(int4 slot); ///< Delete the \e out half of an edge, correcting indices
void removeInEdge(int4 slot); ///< Remove an incoming edge void removeInEdge(int4 slot); ///< Remove an incoming edge
@ -172,20 +183,19 @@ public:
virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const; virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const;
virtual void finalTransform(Funcdata &data) {} ///< Do any structure driven final transforms 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 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 encodeHeader(Encoder &encoder) const; ///< Encode basic information as attributes
virtual void restoreXmlHeader(const Element *el); ///< Restore basic information for XML attributes virtual void decodeHeader(Decoder &decoder); ///< Decode basic information from element attributes
virtual void saveXmlBody(ostream &s) const {} ///< Save detail about components to an XML stream 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 decoder is the stream decoder
/// \param enditer marks the end of the XML tags /// \param resolver is used to recover FlowBlock objects based on elment references
/// \param resolver is used to recover FlowBlock objects based on XML references virtual void decodeBody(Decoder &decoder,BlockMap &resolver) {}
virtual void restoreXmlBody(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver) {} void encodeEdges(Encoder &encoder) const; ///< Encode edge information to a stream
void saveXmlEdges(ostream &s) const; ///< Save edge information to an XML stream void decodeEdges(Decoder &decoder,BlockMap &resolver);
void restoreXmlEdges(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver); void encode(Encoder &encoder) const; ///< Encode \b this to a stream
void saveXml(ostream &s) const; ///< Write out \b this to an XML stream void decode(Decoder &decoder,BlockMap &resolver); ///< Decode \b this from a stream
void restoreXml(const Element *el,BlockMap &resolver); ///< Restore \b this from an XML stream
const FlowBlock *nextInFlow(void) const; ///< Return next block to be executed in flow 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 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 int4 getVisitCount(void) const { return visitcount; } ///< Get the count of visits
@ -299,9 +309,9 @@ public:
virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const; virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const;
virtual void finalTransform(Funcdata &data); virtual void finalTransform(Funcdata &data);
virtual void finalizePrinting(Funcdata &data) const; virtual void finalizePrinting(Funcdata &data) const;
virtual void saveXmlBody(ostream &s) const; virtual void encodeBody(Encoder &encoder) const;
virtual void restoreXmlBody(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver); virtual void decodeBody(Decoder &decoder,BlockMap &resolver);
void restoreXml(const Element *el,const AddrSpaceManager *m); ///< Restore \b this BlockGraph from an XML stream 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 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 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 void removeEdge(FlowBlock *begin,FlowBlock *end); ///< Remove an edge between component FlowBlocks
@ -383,8 +393,8 @@ public:
virtual Address getStop(void) const; virtual Address getStop(void) const;
virtual block_type getType(void) const { return t_basic; } virtual block_type getType(void) const { return t_basic; }
virtual FlowBlock *subBlock(int4 i) const { return (FlowBlock *)0; } virtual FlowBlock *subBlock(int4 i) const { return (FlowBlock *)0; }
virtual void saveXmlBody(ostream &s) const; virtual void encodeBody(Encoder &encoder) const;
virtual void restoreXmlBody(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver); virtual void decodeBody(Decoder &decoder,BlockMap &resolver);
virtual void printHeader(ostream &s) const; virtual void printHeader(ostream &s) const;
virtual void printRaw(ostream &s) const; virtual void printRaw(ostream &s) const;
virtual void emit(PrintLanguage *lng) const { lng->emitBlockBasic(this); } 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 bool negateCondition(bool toporbottom) { bool res = copy->negateCondition(true); FlowBlock::negateCondition(toporbottom); return res; }
virtual FlowBlock *getSplitPoint(void) { return copy->getSplitPoint(); } virtual FlowBlock *getSplitPoint(void) { return copy->getSplitPoint(); }
virtual bool isComplex(void) const { return copy->isComplex(); } 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 /// \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 const FlowBlock *getExitLeaf(void) const { return getBlock(0)->getExitLeaf(); }
virtual PcodeOp *lastOp(void) const { return getBlock(0)->lastOp(); } virtual PcodeOp *lastOp(void) const { return getBlock(0)->lastOp(); }
virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const; 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. /// \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 const FlowBlock *getExitLeaf(void) const { return getBlock(0)->getExitLeaf(); }
virtual PcodeOp *lastOp(void) const { return getBlock(0)->lastOp(); } virtual PcodeOp *lastOp(void) const { return getBlock(0)->lastOp(); }
virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const; 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. /// \brief A series of blocks that execute in sequence.
@ -531,7 +541,7 @@ public:
virtual PcodeOp *lastOp(void) const; virtual PcodeOp *lastOp(void) const;
virtual bool isComplex(void) const { return getBlock(0)->isComplex(); } virtual bool isComplex(void) const { return getBlock(0)->isComplex(); }
virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const; virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const;
virtual void saveXmlHeader(ostream &s) const; virtual void encodeHeader(Encoder &encoder) const;
}; };
/// \brief A basic "if" block /// \brief A basic "if" block
@ -569,7 +579,7 @@ public:
virtual const FlowBlock *getExitLeaf(void) const; virtual const FlowBlock *getExitLeaf(void) const;
virtual PcodeOp *lastOp(void) const; virtual PcodeOp *lastOp(void) const;
virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) 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. /// \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 /// list of FlowBlock objects sorted by index and then looks up the FlowBlock matching a given
/// index as edges specify them. /// index as edges specify them.
class BlockMap { 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<FlowBlock *> sortlist; ///< The list of deserialized FlowBlock objects vector<FlowBlock *> sortlist; ///< The list of deserialized FlowBlock objects
FlowBlock *resolveBlock(FlowBlock::block_type bt); ///< Construct a FlowBlock of the given type FlowBlock *resolveBlock(FlowBlock::block_type bt); ///< Construct a FlowBlock of the given type
static FlowBlock *findBlock(const vector<FlowBlock *> &list,int4 ind); ///< Locate a FlowBlock with a given index static FlowBlock *findBlock(const vector<FlowBlock *> &list,int4 ind); ///< Locate a FlowBlock with a given index

View file

@ -16,34 +16,30 @@
#include "callgraph.hh" #include "callgraph.hh"
#include "funcdata.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 << " <edge>\n"; encoder.openElement(ELEM_EDGE);
s << " "; from->getAddr().encode(encoder);
from->getAddr().saveXml(s); to->getAddr().encode(encoder);
s << "\n "; callsiteaddr.encode(encoder);
to->getAddr().saveXml(s); encoder.closeElement(ELEM_EDGE);
s << "\n ";
callsiteaddr.saveXml(s);
s << "\n </edge>\n";
} }
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(); const AddrSpaceManager *manage = graph->getArch();
Address fromaddr,toaddr,siteaddr; Address fromaddr,toaddr,siteaddr;
const List &list(el->getChildren()); fromaddr = Address::decode(decoder,manage);
List::const_iterator iter; toaddr = Address::decode(decoder,manage);
siteaddr = Address::decode(decoder,manage);
iter = list.begin(); decoder.closeElement(elemId);
fromaddr = Address::restoreXml(*iter,manage);
++iter;
toaddr = Address::restoreXml(*iter,manage);
++iter;
siteaddr = Address::restoreXml(*iter,manage);
CallGraphNode *fromnode = graph->findNode(fromaddr); CallGraphNode *fromnode = graph->findNode(fromaddr);
if (fromnode == (CallGraphNode *)0) if (fromnode == (CallGraphNode *)0)
@ -66,28 +62,29 @@ void CallGraphNode::setFuncdata(Funcdata *f)
fd = f; fd = f;
} }
void CallGraphNode::saveXml(ostream &s) const void CallGraphNode::encode(Encoder &encoder) const
{ {
s << " <node"; encoder.openElement(ELEM_NODE);
if (name.size() != 0) if (name.size() != 0)
a_v(s,"name",name); encoder.writeString(ATTRIB_NAME, name);
s << ">\n "; entryaddr.encode(encoder);
entryaddr.saveXml(s); encoder.closeElement(ELEM_NODE);
s << "\n </node>\n";
} }
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; string name;
for(int4 i=0;i<num;++i) { for(;;) {
if (el->getAttributeName(i) == "name") uint4 attribId = decoder.getNextAttributeId();
name = el->getAttributeValue(i); 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); 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<Address,CallGraphNode>::const_iterator iter; map<Address,CallGraphNode>::const_iterator iter;
s << "<callgraph>\n"; encoder.openElement(ELEM_CALLGRAPH);
for(iter=graph.begin();iter!=graph.end();++iter) for(iter=graph.begin();iter!=graph.end();++iter)
(*iter).second.saveXml(s); (*iter).second.encode(encoder);
// Dump all the "in" edges // Dump all the "in" edges
for(iter=graph.begin();iter!=graph.end();++iter) { for(iter=graph.begin();iter!=graph.end();++iter) {
const CallGraphNode &node( (*iter).second ); const CallGraphNode &node( (*iter).second );
for(uint4 i=0;i<node.inedge.size();++i) for(uint4 i=0;i<node.inedge.size();++i)
node.inedge[i].saveXml(s); node.inedge[i].encode(encoder);
} }
s << "</callgraph>\n"; encoder.closeElement(ELEM_CALLGRAPH);
} }
void CallGraph::restoreXml(const Element *el) void CallGraph::decoder(Decoder &decoder)
{ {
const List &list(el->getChildren()); uint4 elemId = decoder.openElement(ELEM_CALLGRAPH);
List::const_iterator iter; for(;;) {
uint4 subId = decoder.peekElement();
iter = list.begin(); if (subId == 0) break;
while(iter != list.end()) { if (subId == ELEM_EDGE)
const Element *subel = *iter; CallGraphEdge::decode(decoder,this);
++iter;
if (subel->getName() == "edge")
CallGraphEdge::restoreXml(subel,this);
else else
CallGraphNode::restoreXml(subel,this); CallGraphNode::decode(decoder,this);
} }
decoder.closeElement(elemId);
} }

View file

@ -24,6 +24,9 @@ class Funcdata;
class CallGraphNode; class CallGraphNode;
class CallGraph; class CallGraph;
extern ElementId ELEM_CALLGRAPH; ///< Marshaling element \<callgraph>
extern ElementId ELEM_NODE; ///< Marshaling element \<node>
class CallGraphEdge { class CallGraphEdge {
public: public:
enum { enum {
@ -41,9 +44,9 @@ private:
public: public:
CallGraphEdge(void) { flags = 0; } CallGraphEdge(void) { flags = 0; }
bool isCycle(void) const { return ((flags&1)!=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; } const Address &getCallSiteAddr(void) const { return callsiteaddr; }
static void restoreXml(const Element *el,CallGraph *graph); static void decode(Decoder &decoder,CallGraph *graph);
}; };
class CallGraphNode { class CallGraphNode {
@ -77,8 +80,8 @@ public:
const CallGraphEdge &getOutEdge(int4 i) const { return outedge[i]; } const CallGraphEdge &getOutEdge(int4 i) const { return outedge[i]; }
CallGraphNode *getOutNode(int4 i) const { return outedge[i].to; } CallGraphNode *getOutNode(int4 i) const { return outedge[i].to; }
void setFuncdata(Funcdata *f); void setFuncdata(Funcdata *f);
void saveXml(ostream &s) const; void encode(Encoder &encoder) const;
static void restoreXml(const Element *el,CallGraph *graph); static void decode(Decoder &decoder,CallGraph *graph);
}; };
struct LeafIterator { struct LeafIterator {
@ -116,8 +119,8 @@ public:
map<Address,CallGraphNode>::iterator end(void) { return graph.end(); } map<Address,CallGraphNode>::iterator end(void) { return graph.end(); }
void buildAllNodes(void); void buildAllNodes(void);
void buildEdges(Funcdata *fd); void buildEdges(Funcdata *fd);
void saveXml(ostream &s) const; void encode(Encoder &encoder) const;
void restoreXml(const Element *el); void decoder(Decoder &decoder);
}; };
#endif #endif

View file

@ -16,6 +16,10 @@
#include "comment.hh" #include "comment.hh"
#include "funcdata.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 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 fad is the Address of the function containing the comment
/// \param ad is the Address of the instruction associated with 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 \<comment> tag. /// The single comment is encoded as a \<comment> element.
/// \param s is the output stream /// \param encoder is the stream encoder
void Comment::saveXml(ostream &s) const void Comment::encode(Encoder &encoder) const
{ {
string tpname = Comment::decodeCommentType(type); string tpname = Comment::decodeCommentType(type);
s << "<comment"; encoder.openElement(ELEM_COMMENT);
a_v(s,"type",tpname); encoder.writeString(ATTRIB_TYPE, tpname);
s << ">\n"; encoder.openElement(ELEM_ADDR);
s << " <addr"; funcaddr.getSpace()->encodeAttributes(encoder,funcaddr.getOffset());
funcaddr.getSpace()->saveXmlAttributes(s,funcaddr.getOffset()); encoder.closeElement(ELEM_ADDR);
s << "/>\n"; encoder.openElement(ELEM_ADDR);
s << " <addr"; addr.getSpace()->encodeAttributes(encoder,addr.getOffset());
addr.getSpace()->saveXmlAttributes(s,addr.getOffset()); encoder.closeElement(ELEM_ADDR);
s << "/>\n"; encoder.openElement(ELEM_TEXT);
s << " <text>"; encoder.writeString(ATTRIB_CONTENT, text);
xml_escape(s,text.c_str()); encoder.closeElement(ELEM_TEXT);
s << " </text>\n"; encoder.closeElement(ELEM_COMMENT);
s << "</comment>\n";
} }
/// The comment is parsed from a \<comment> tag. /// Parse a \<comment> element from the given stream decoder
/// \param el is the \<comment> element /// \param decoder is the given stream decoder
/// \param manage is a manager for resolving address space references /// \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; emitted = false;
type = 0; type = 0;
type = Comment::encodeCommentType(el->getAttributeValue("type")); uint4 elemId = decoder.openElement(ELEM_COMMENT);
const List &list(el->getChildren()); type = Comment::encodeCommentType(decoder.readString(ATTRIB_TYPE));
List::const_iterator iter; funcaddr = Address::decode(decoder,manage);
addr = Address::decode(decoder,manage);
iter = list.begin(); uint4 subId = decoder.peekElement();
funcaddr = Address::restoreXml(*iter,manage); if (subId != 0) {
++iter; decoder.openElement();
addr = Address::restoreXml(*iter,manage); text = decoder.readString(ATTRIB_CONTENT);
++iter; decoder.closeElement(subId);
if (iter != list.end()) }
text = (*iter)->getContent(); decoder.closeElement(elemId);
} }
/// \param name is a string representation of a single comment property /// \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); return commentset.lower_bound(&testcomm);
} }
void CommentDatabaseInternal::saveXml(ostream &s) const void CommentDatabaseInternal::encode(Encoder &encoder) const
{ {
CommentSet::const_iterator iter; CommentSet::const_iterator iter;
s << "<commentdb>\n"; encoder.openElement(ELEM_COMMENTDB);
for(iter=commentset.begin();iter!=commentset.end();++iter) for(iter=commentset.begin();iter!=commentset.end();++iter)
(*iter)->saveXml(s); (*iter)->encode(encoder);
s << "</commentdb>\n"; 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()); uint4 elemId = decoder.openElement(ELEM_COMMENTDB);
List::const_iterator iter; while(decoder.peekElement() != 0) {
for(iter=list.begin();iter!=list.end();++iter) {
Comment com; Comment com;
com.restoreXml(*iter,manage); com.decode(decoder,manage);
addComment(com.getType(),com.getFuncAddr(),com.getAddr(),com.getText()); addComment(com.getType(),com.getFuncAddr(),com.getAddr(),com.getText());
} }
decoder.closeElement(elemId);
} }
/// Figure out position of given Comment and initialize its key. /// Figure out position of given Comment and initialize its key.

View file

@ -25,6 +25,10 @@ class FlowBlock;
class PcodeOp; class PcodeOp;
class Funcdata; class Funcdata;
extern ElementId ELEM_COMMENT; ///< Marshaling element \<comment>
extern ElementId ELEM_COMMENTDB; ///< Marshaling element \<commentdb>
extern ElementId ELEM_TEXT; ///< Marshaling element \<text>
/// \brief A comment attached to a specific function and code address /// \brief A comment attached to a specific function and code address
/// ///
/// Things contains the actual character data of the comment. It is /// 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 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(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 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 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 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 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 int4 getUniq(void) const { return uniq; } ///< Get the sub-sorting index
const string &getText(void) const { return text; } ///< Get the body of the comment 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 encode(Encoder &encoder) const; ///< Encode the comment to a stream
void restoreXml(const Element *el,const AddrSpaceManager *manage); ///< Restore the comment from XML 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 uint4 encodeCommentType(const string &name); ///< Convert name string to comment property
static string decodeCommentType(uint4 val); ///< Convert comment property to string static string decodeCommentType(uint4 val); ///< Convert comment property to string
}; };
@ -134,17 +138,17 @@ public:
/// \return the ending iterator /// \return the ending iterator
virtual CommentSet::const_iterator endComment(const Address &fad) const=0; 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 \<commentdb> tag, with \<comment> sub-tags for each Comment object. /// Writes a \<commentdb> element, with \<comment> children for each Comment object.
/// \param s is the output stream /// \param encoder is the stream encoder
virtual void saveXml(ostream &s) const=0; virtual void encode(Encoder &encoder) const=0;
/// \brief Restore all comments from XML /// \brief Restore all comments from a \<commentdb> element
/// ///
/// \param el is the root \<commentdb> element /// \param decoder is the stream decoder
/// \param manage is a manager for resolving address space references /// \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 void deleteComment(Comment *com);
virtual CommentSet::const_iterator beginComment(const Address &fad) const; virtual CommentSet::const_iterator beginComment(const Address &fad) const;
virtual CommentSet::const_iterator endComment(const Address &fad) const; virtual CommentSet::const_iterator endComment(const Address &fad) const;
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual void restoreXml(const Element *el,const AddrSpaceManager *manage); virtual void decode(Decoder &decoder,const AddrSpaceManager *manage);
}; };
/// \brief A class for sorting comments into and within basic blocks /// \brief A class for sorting comments into and within basic blocks

View file

@ -28,7 +28,6 @@ CommentDatabaseGhidra::CommentDatabaseGhidra(ArchitectureGhidra *g)
void CommentDatabaseGhidra::fillCache(const Address &fad) const void CommentDatabaseGhidra::fillCache(const Address &fad) const
{ {
Document *doc;
uint4 commentfilter; uint4 commentfilter;
if (cachefilled) return; // Already queried ghidra if (cachefilled) return; // Already queried ghidra
@ -41,10 +40,9 @@ void CommentDatabaseGhidra::fillCache(const Address &fad) const
iter = cache.beginComment(fad); iter = cache.beginComment(fad);
iterend = cache.endComment(fad); iterend = cache.endComment(fad);
doc = ghidra->getComments(fad,commentfilter); XmlDecode decoder;
if (doc != (Document *)0) { if (ghidra->getComments(fad,commentfilter,decoder)) {
cache.restoreXml(doc->getRoot(),ghidra); cache.decode(decoder,ghidra);
delete doc;
} }
} }

View file

@ -45,10 +45,10 @@ public:
throw LowlevelError("deleteComment unimplemented"); } throw LowlevelError("deleteComment unimplemented"); }
virtual CommentSet::const_iterator beginComment(const Address &fad) const; virtual CommentSet::const_iterator beginComment(const Address &fad) const;
virtual CommentSet::const_iterator endComment(const Address &fad) const; virtual CommentSet::const_iterator endComment(const Address &fad) const;
virtual void saveXml(ostream &s) const { virtual void encode(Encoder &encoder) const {
throw LowlevelError("commentdb::saveXml unimplemented"); } throw LowlevelError("commentdb::encode unimplemented"); }
virtual void restoreXml(const Element *el,const AddrSpaceManager *trans) { virtual void decode(Decoder &decoder,const AddrSpaceManager *trans) {
throw LowlevelError("commentdb::restoreXml unimplemented"); } throw LowlevelError("CommentDatabaseGhidra::decode unimplemented"); }
}; };
#endif #endif

View file

@ -132,7 +132,8 @@ void IfcSave::execute(istream &s)
if (!fs) if (!fs)
throw IfaceExecutionError("Unable to open file: "+savefile); throw IfaceExecutionError("Unable to open file: "+savefile);
dcp->conf->saveXml(fs); XmlEncode encoder(fs);
dcp->conf->encode(encoder);
fs.close(); fs.close();
} }

View file

@ -15,41 +15,52 @@
*/ */
#include "cpool.hh" #include "cpool.hh"
/// Save the constant pool object description as a \<cpoolrec> tag. AttributeId ATTRIB_A = AttributeId("a",45);
/// \param s is the output stream AttributeId ATTRIB_B = AttributeId("b",46);
void CPoolRecord::saveXml(ostream &s) const 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 \<cpoolrec> element.
/// \param encoder is the stream encoder
void CPoolRecord::encode(Encoder &encoder) const
{ {
s << "<cpoolrec"; encoder.openElement(ELEM_CPOOLREC);
if (tag == pointer_method) if (tag == pointer_method)
a_v(s,"tag","method"); encoder.writeString(ATTRIB_TAG, "method");
else if (tag == pointer_field) else if (tag == pointer_field)
a_v(s,"tag","field"); encoder.writeString(ATTRIB_TAG, "field");
else if (tag == instance_of) else if (tag == instance_of)
a_v(s,"tag","instanceof"); encoder.writeString(ATTRIB_TAG, "instanceof");
else if (tag == array_length) else if (tag == array_length)
a_v(s,"tag","arraylength"); encoder.writeString(ATTRIB_TAG, "arraylength");
else if (tag == check_cast) else if (tag == check_cast)
a_v(s,"tag","checkcast"); encoder.writeString(ATTRIB_TAG, "checkcast");
else if (tag == string_literal) else if (tag == string_literal)
a_v(s,"tag","string"); encoder.writeString(ATTRIB_TAG, "string");
else if (tag == class_reference) else if (tag == class_reference)
a_v(s,"tag","classref"); encoder.writeString(ATTRIB_TAG, "classref");
else else
a_v(s,"tag","primitive"); encoder.writeString(ATTRIB_TAG, "primitive");
if (isConstructor()) if (isConstructor())
a_v_b(s,"constructor",true); encoder.writeBool(ATTRIB_CONSTRUCTOR, true);
if (isDestructor()) if (isDestructor())
a_v_b(s,"destructor",true); encoder.writeBool(ATTRIB_DESTRUCTOR, true);
s << ">\n";
if (tag == primitive) { if (tag == primitive) {
s << " <value>0x"; encoder.openElement(ELEM_VALUE);
s << hex << value; encoder.writeUnsignedInteger(ATTRIB_CONTENT, value);
s << "</value>\n"; encoder.closeElement(ELEM_VALUE);
} }
if (byteData != (uint1 *)0) { if (byteData != (uint1 *)0) {
s << " <data length=\"" << dec << byteDataLen << "\">\n"; encoder.openElement(ELEM_DATA);
encoder.writeSignedInteger(ATTRIB_LENGTH, byteDataLen);
int4 wrap = 0; int4 wrap = 0;
ostringstream s;
for(int4 i=0;i<byteDataLen;++i) { for(int4 i=0;i<byteDataLen;++i) {
s << setfill('0') << setw(2) << hex << byteData[i] << ' '; s << setfill('0') << setw(2) << hex << byteData[i] << ' ';
wrap += 1; wrap += 1;
@ -58,31 +69,33 @@ void CPoolRecord::saveXml(ostream &s) const
wrap = 0; wrap = 0;
} }
} }
s << " </data>\n"; encoder.writeString(ATTRIB_CONTENT, s.str());
encoder.closeElement(ELEM_DATA);
} }
else { else {
s << " <token>"; encoder.openElement(ELEM_TOKEN);
xml_escape(s,token.c_str()); encoder.writeString(ATTRIB_CONTENT, token);
s << " </token>\n"; encoder.closeElement(ELEM_TOKEN);
} }
type->saveXml(s); type->encode(encoder);
s << "</cpoolrec>\n"; encoder.closeElement(ELEM_CPOOLREC);
} }
/// Initialize \b this CPoolRecord instance from a \<cpoolrec> tag. /// Initialize \b this CPoolRecord instance from a \<cpoolrec> element.
/// \param el is the \<cpoolrec> element /// \param decoder is the stream decoder
/// \param typegrp is the TypeFactory used to resolve data-types /// \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 tag = primitive; // Default tag
value = 0; value = 0;
flags = 0; flags = 0;
int4 num = el->getNumAttributes(); uint4 elemId = decoder.openElement(ELEM_CPOOLREC);
for(int4 i=0;i<num;++i) { for(;;) {
const string &attr(el->getAttributeName(i)); uint4 attribId = decoder.getNextAttributeId();
if (attr == "tag") { if (attribId == 0) break;
const string &tagstring(el->getAttributeValue(i)); if (attribId == ATTRIB_TAG) {
string tagstring = decoder.readString();
if (tagstring == "method") if (tagstring == "method")
tag = pointer_method; tag = pointer_method;
else if (tagstring == "field") else if (tagstring == "field")
@ -98,36 +111,27 @@ void CPoolRecord::restoreXml(const Element *el,TypeFactory &typegrp)
else if (tagstring == "classref") else if (tagstring == "classref")
tag = class_reference; tag = class_reference;
} }
else if (attr == "constructor") { else if (attribId == ATTRIB_CONSTRUCTOR) {
if (xml_readbool(el->getAttributeValue(i))) if (decoder.readBool())
flags |= CPoolRecord::is_constructor; flags |= CPoolRecord::is_constructor;
} }
else if (attr == "destructor") { else if (attribId == ATTRIB_DESTRUCTOR) {
if (xml_readbool(el->getAttributeValue(i))) if (decoder.readBool())
flags |= CPoolRecord::is_destructor; flags |= CPoolRecord::is_destructor;
} }
} }
const List &list(el->getChildren()); uint4 subId;
List::const_iterator iter;
iter = list.begin();
const Element *subel;
if (tag == primitive) { // First tag must be value if (tag == primitive) { // First tag must be value
subel = *iter; subId = decoder.openElement(ELEM_VALUE);
istringstream s1(subel->getContent()); value = decoder.readUnsignedInteger(ATTRIB_CONTENT);
s1.unsetf(ios::dec | ios::hex | ios::oct); decoder.closeElement(subId);
s1 >> value;
++iter;
} }
subel = *iter; subId = decoder.openElement();
++iter; if (subId == ELEM_TOKEN)
if (subel->getName() == "token") token = decoder.readString(ATTRIB_CONTENT);
token = subel->getContent();
else { else {
istringstream s2(subel->getAttributeValue("length")); byteDataLen = decoder.readSignedInteger(ATTRIB_LENGTH);
s2.unsetf(ios::dec | ios::hex | ios::oct); istringstream s3(decoder.readString(ATTRIB_CONTENT));
s2 >> byteDataLen;
istringstream s3(subel->getContent());
byteData = new uint1[byteDataLen]; byteData = new uint1[byteDataLen];
for(int4 i=0;i<byteDataLen;++i) { for(int4 i=0;i<byteDataLen;++i) {
uint4 val; uint4 val;
@ -135,16 +139,17 @@ void CPoolRecord::restoreXml(const Element *el,TypeFactory &typegrp)
byteData[i] = (uint1)val; byteData[i] = (uint1)val;
} }
} }
decoder.closeElement(subId);
if (tag == string_literal && (byteData == (uint1 *)0)) if (tag == string_literal && (byteData == (uint1 *)0))
throw LowlevelError("Bad constant pool record: missing <data>"); throw LowlevelError("Bad constant pool record: missing <data>");
subel = *iter;
if (flags != 0) { if (flags != 0) {
bool isConstructor = ((flags & is_constructor)!=0); bool isConstructor = ((flags & is_constructor)!=0);
bool isDestructor = ((flags & is_destructor)!=0); bool isDestructor = ((flags & is_destructor)!=0);
type = typegrp.restoreXmlTypeWithCodeFlags(subel,isConstructor,isDestructor); type = typegrp.decodeTypeWithCodeFlags(decoder,isConstructor,isDestructor);
} }
else else
type = typegrp.restoreXmlType(subel); type = typegrp.decodeType(decoder);
decoder.closeElement(elemId);
} }
void ConstantPool::putRecord(const vector<uintb> &refs,uint4 tag,const string &tok,Datatype *ct) void ConstantPool::putRecord(const vector<uintb> &refs,uint4 tag,const string &tok,Datatype *ct)
@ -156,36 +161,34 @@ void ConstantPool::putRecord(const vector<uintb> &refs,uint4 tag,const string &t
newrec->type = ct; newrec->type = ct;
} }
const CPoolRecord *ConstantPool::restoreXmlRecord(const vector<uintb> &refs,const Element *el,TypeFactory &typegrp) const CPoolRecord *ConstantPool::decodeRecord(const vector<uintb> &refs,Decoder &decoder,TypeFactory &typegrp)
{ {
CPoolRecord *newrec = createRecord(refs); CPoolRecord *newrec = createRecord(refs);
newrec->restoreXml(el,typegrp); newrec->decode(decoder,typegrp);
return newrec; return newrec;
} }
/// The reference is output as a \<ref> tag. /// The reference is encoded as a \<ref> element.
/// \param s is the output stream /// \param encoder is the stream encoder
void ConstantPoolInternal::CheapSorter::saveXml(ostream &s) const void ConstantPoolInternal::CheapSorter::encode(Encoder &encoder) const
{ {
s << "<ref"; encoder.openElement(ELEM_REF);
a_v_u(s,"a",a); encoder.writeUnsignedInteger(ATTRIB_A, a);
a_v_u(s,"b",b); encoder.writeUnsignedInteger(ATTRIB_B, b);
s << "/>\n"; encoder.closeElement(ELEM_REF);
} }
/// Restore \b this \e reference from a \<ref> XML tag /// Restore \b this \e reference from a \<ref> element
/// \param el is the XML element /// \param decoder is the stream decoder
void ConstantPoolInternal::CheapSorter::restoreXml(const Element *el) void ConstantPoolInternal::CheapSorter::decode(Decoder &decoder)
{ {
istringstream s1(el->getAttributeValue("a")); uint4 elemId = decoder.openElement(ELEM_REF);
s1.unsetf(ios::dec | ios::hex | ios::oct); a = decoder.readUnsignedInteger(ATTRIB_A);
s1 >> a; b = decoder.readUnsignedInteger(ATTRIB_B);
istringstream s2(el->getAttributeValue("b")); decoder.closeElement(elemId);
s2.unsetf(ios::dec | ios::hex | ios::oct);
s2 >> b;
} }
CPoolRecord *ConstantPoolInternal::createRecord(const vector<uintb> &refs) CPoolRecord *ConstantPoolInternal::createRecord(const vector<uintb> &refs)
@ -210,32 +213,29 @@ const CPoolRecord *ConstantPoolInternal::getRecord(const vector<uintb> &refs) co
return &(*iter).second; return &(*iter).second;
} }
void ConstantPoolInternal::saveXml(ostream &s) const void ConstantPoolInternal::encode(Encoder &encoder) const
{ {
map<CheapSorter,CPoolRecord>::const_iterator iter; map<CheapSorter,CPoolRecord>::const_iterator iter;
s << "<constantpool>\n"; encoder.openElement(ELEM_CONSTANTPOOL);
for(iter=cpoolMap.begin();iter!=cpoolMap.end();++iter) { for(iter=cpoolMap.begin();iter!=cpoolMap.end();++iter) {
(*iter).first.saveXml(s); (*iter).first.encode(encoder);
(*iter).second.saveXml(s); (*iter).second.encode(encoder);
} }
s << "</constantpool>\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()); uint4 elemId = decoder.openElement(ELEM_CONSTANTPOOL);
List::const_iterator iter; while(decoder.peekElement() != 0) {
for(iter=list.begin();iter!=list.end();++iter) {
const Element *subel = *iter;
CheapSorter sorter; CheapSorter sorter;
sorter.restoreXml(subel); sorter.decode(decoder);
vector<uintb> refs; vector<uintb> refs;
sorter.apply(refs); sorter.apply(refs);
++iter;
subel = *iter;
CPoolRecord *newrec = createRecord(refs); CPoolRecord *newrec = createRecord(refs);
newrec->restoreXml(subel,typegrp); newrec->decode(decoder,typegrp);
} }
decoder.closeElement(elemId);
} }

View file

@ -21,6 +21,16 @@
#include "type.hh" #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 \<constantpool>
extern ElementId ELEM_CPOOLREC; ///< Marshaling element \<cpoolrec>
extern ElementId ELEM_REF; ///< Marshaling element \<ref>
extern ElementId ELEM_TOKEN; ///< Marshaling element \<token>
/// \brief A description of a byte-code object referenced by a constant /// \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 /// 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 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 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 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 encode(Encoder &encoder) const; ///< Encode \b this to a stream
void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore object from XML 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 /// \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 /// \param ct is the data-type associated with the object
void putRecord(const vector<uintb> &refs,uint4 tag,const string &tok,Datatype *ct); void putRecord(const vector<uintb> &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 \<cpoolrec> element initializes the new record which is immediately associated /// A \<cpoolrec> element initializes the new record which is immediately associated
/// with the \e reference. /// with the \e reference.
/// \param refs is the \e reference (made up of 1 or more identifying integers) /// \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 /// \param typegrp is the TypeFactory used to resolve data-type references in XML
/// \return the newly allocated and initialized CPoolRecord /// \return the newly allocated and initialized CPoolRecord
const CPoolRecord *restoreXmlRecord(const vector<uintb> &refs,const Element *el,TypeFactory &typegrp); const CPoolRecord *decodeRecord(const vector<uintb> &refs,Decoder &decoder,TypeFactory &typegrp);
virtual bool empty(void) const=0; ///< Is the container empty of records virtual bool empty(void) const=0; ///< Is the container empty of records
virtual void clear(void)=0; ///< Release any (local) resources 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 \<constantpool> element is written containing \<cpoolrec> /// (If supported) A \<constantpool> element is written containing \<cpoolrec>
/// child elements for each CPoolRecord in the container. /// child elements for each CPoolRecord in the container.
/// \param s is the output stream /// \param encoder is the stream encoder
virtual void saveXml(ostream &s) const=0; 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 /// (If supported) The container is populated with CPoolRecords initialized
/// from a \<constantpool> XML tag. /// from a \<constantpool> element.
/// \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 the XML /// \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 /// \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 /// \param refs is the provided container of integers
void apply(vector<uintb> &refs) const { refs.push_back(a); refs.push_back(b); } void apply(vector<uintb> &refs) const { refs.push_back(a); refs.push_back(b); }
void saveXml(ostream &s) const; ///< Serialize the \e reference to an XML element void encode(Encoder &encoder) const; ///< Encode the \e reference to a stream
void restoreXml(const Element *el); ///< Deserialize the \e reference from an XML element void decode(Decoder &decoder); ///< Decode the \e reference from a stream
}; };
map<CheapSorter,CPoolRecord> cpoolMap; ///< A map from \e reference to constant pool record map<CheapSorter,CPoolRecord> cpoolMap; ///< A map from \e reference to constant pool record
virtual CPoolRecord *createRecord(const vector<uintb> &refs); virtual CPoolRecord *createRecord(const vector<uintb> &refs);
@ -191,8 +201,8 @@ public:
virtual const CPoolRecord *getRecord(const vector<uintb> &refs) const; virtual const CPoolRecord *getRecord(const vector<uintb> &refs) const;
virtual bool empty(void) const { return cpoolMap.empty(); } virtual bool empty(void) const { return cpoolMap.empty(); }
virtual void clear(void) { cpoolMap.clear(); } virtual void clear(void) { cpoolMap.clear(); }
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual void restoreXml(const Element *el,TypeFactory &typegrp); virtual void decode(Decoder &decoder,TypeFactory &typegrp);
}; };
#endif #endif

View file

@ -32,9 +32,10 @@ const CPoolRecord *ConstantPoolGhidra::getRecord(const vector<uintb> &refs) cons
{ {
const CPoolRecord *rec = cache.getRecord(refs); const CPoolRecord *rec = cache.getRecord(refs);
if (rec == (const CPoolRecord *)0) { if (rec == (const CPoolRecord *)0) {
Document *doc; XmlDecode decoder;
bool success;
try { try {
doc = ghidra->getCPoolRef(refs); success = ghidra->getCPoolRef(refs,decoder);
} }
catch(JavaError &err) { catch(JavaError &err) {
throw LowlevelError("Error fetching constant pool record: " + err.explain); throw LowlevelError("Error fetching constant pool record: " + err.explain);
@ -42,24 +43,23 @@ const CPoolRecord *ConstantPoolGhidra::getRecord(const vector<uintb> &refs) cons
catch(XmlError &err) { catch(XmlError &err) {
throw LowlevelError("Error in constant pool record xml: "+err.explain); throw LowlevelError("Error in constant pool record xml: "+err.explain);
} }
if (doc == (Document *)0) { if (!success) {
ostringstream s; ostringstream s;
s << "Could not retrieve constant pool record for reference: 0x" << refs[0]; s << "Could not retrieve constant pool record for reference: 0x" << refs[0];
throw LowlevelError(s.str()); throw LowlevelError(s.str());
} }
rec = cache.restoreXmlRecord(refs,doc->getRoot(),*ghidra->types); rec = cache.decodeRecord(refs,decoder,*ghidra->types);
delete doc;
} }
return rec; return rec;
} }
void ConstantPoolGhidra::saveXml(ostream &s) const void ConstantPoolGhidra::encode(Encoder &encoder) const
{ {
throw LowlevelError("Cannot access constant pool with this method"); 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"); throw LowlevelError("Cannot access constant pool with this method");

View file

@ -25,7 +25,7 @@
/// ///
/// The actual CPoolRecord objects are cached locally, but new queries are placed /// The actual CPoolRecord objects are cached locally, but new queries are placed
/// with the Ghidra client hosting the program currently being decompiled. The /// 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, /// methods are disabled. The clear() method only releases the local cache,
/// no records on the Ghidra client are affected. /// no records on the Ghidra client are affected.
class ConstantPoolGhidra : public ConstantPool { class ConstantPoolGhidra : public ConstantPool {
@ -37,8 +37,8 @@ public:
virtual const CPoolRecord *getRecord(const vector<uintb> &refs) const; virtual const CPoolRecord *getRecord(const vector<uintb> &refs) const;
virtual bool empty(void) const { return false; } virtual bool empty(void) const { return false; }
virtual void clear(void) { cache.clear(); } virtual void clear(void) { cache.clear(); }
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual void restoreXml(const Element *el,TypeFactory &typegrp); virtual void decode(Decoder &decoder,TypeFactory &typegrp);
}; };
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -34,6 +34,28 @@ class Database;
class Symbol; class Symbol;
class PrintLanguage; 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 \<collision>
extern ElementId ELEM_DB; ///< Marshaling element \<db>
extern ElementId ELEM_EQUATESYMBOL; ///< Marshaling element \<equatesymbol>
extern ElementId ELEM_EXTERNREFSYMBOL; ///< Marshaling element \<externrefsymbol>
extern ElementId ELEM_FACETSYMBOL; ///< Marshaling element \<facetsymbol>
extern ElementId ELEM_FUNCTIONSHELL; ///< Marshaling element \<functionshell>
extern ElementId ELEM_HASH; ///< Marshaling element \<hash>
extern ElementId ELEM_HOLE; ///< Marshaling element \<hole>
extern ElementId ELEM_LABELSYM; ///< Marshaling element \<labelsym>
extern ElementId ELEM_MAPSYM; ///< Marshaling element \<mapsym>
extern ElementId ELEM_PARENT; ///< Marshaling element \<parent>
extern ElementId ELEM_PROPERTY_CHANGEPOINT; ///< Marshaling element \<property_changepoint>
extern ElementId ELEM_RANGEEQUALSSYMBOLS; ///< Marshaling element \<rangeequalssymbols>
extern ElementId ELEM_SCOPE; ///< Marshaling element \<scope>
extern ElementId ELEM_SYMBOLLIST; ///< Marshaling element \<symbollist>
/// \brief A storage location for a particular Symbol /// \brief A storage location for a particular Symbol
/// ///
/// Where a Symbol is stored, as a byte address and a size, is of particular importance /// 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 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 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 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 void encode(Encoder &encoder) const; ///< Encode \b this to a stream
List::const_iterator restoreXml(List::const_iterator iter,const AddrSpaceManager *manage); ///< Restore \b this from an XML stream void decode(Decoder &decoder,const AddrSpaceManager *manage); ///< Decode \b this from a stream
}; };
typedef rangemap<SymbolEntry> EntryMap; ///< A rangemap of SymbolEntry typedef rangemap<SymbolEntry> 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,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 const string &getName(void) const { return name; } ///< Get the local name of the symbol
Datatype *getType(void) const { return type; } ///< Get the data-type Datatype *getType(void) const { return type; } ///< Get the data-type
uint8 getId(void) const { return symbolId; } ///< Get a unique id for the symbol 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 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 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 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 encodeHeader(Encoder &encoder) const; ///< Encode basic Symbol properties as attributes
void restoreXmlHeader(const Element *el); ///< Restore basic Symbol properties from XML void decodeHeader(Decoder &decoder); ///< Decode basic Symbol properties from a \<symbol> element
void saveXmlBody(ostream &s) const; ///< Save details of the Symbol to XML void encodeBody(Encoder &encoder) const; ///< Encode details of the Symbol to a stream
void restoreXmlBody(List::const_iterator iter); ///< Restore details of the Symbol from XML void decodeBody(Decoder &decoder); ///< Decode details of the Symbol from a \<symbol> element
virtual void saveXml(ostream &s) const; ///< Save \b this Symbol to an XML stream virtual void encode(Encoder &encoder) const; ///< Encode \b this Symbol to a stream
virtual void restoreXml(const Element *el); ///< Restore \b this Symbol from an XML 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 virtual int4 getBytesConsumed(void) const; ///< Get number of bytes consumed within the address->symbol map
static uint8 ID_BASE; ///< Base of internal ID's 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 void buildType(void); ///< Build the data-type associated with \b this Symbol
public: public:
FunctionSymbol(Scope *sc,const string &nm,int4 size); ///< Construct given the name 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 Funcdata *getFunction(void); ///< Get the underlying Funcdata object
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual void restoreXml(const Element *el); virtual void decode(Decoder &decoder);
virtual int4 getBytesConsumed(void) const { return consumeSize; } virtual int4 getBytesConsumed(void) const { return consumeSize; }
}; };
@ -275,21 +297,21 @@ class EquateSymbol : public Symbol {
uintb value; ///< Value of the constant being equated uintb value; ///< Value of the constant being equated
public: public:
EquateSymbol(Scope *sc,const string &nm,uint4 format,uintb val); ///< Constructor 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 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 bool isValueClose(uintb op2Value,int4 size) const; ///< Is the given value similar to \b this equate
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual void restoreXml(const Element *el); virtual void decode(Decoder &decoder);
}; };
class UnionFacetSymbol : public Symbol { class UnionFacetSymbol : public Symbol {
int4 fieldNum; ///< Particular field to associate with Symbol access int4 fieldNum; ///< Particular field to associate with Symbol access
public: public:
UnionFacetSymbol(Scope *sc,const string &nm,Datatype *unionDt,int4 fldNum); ///< Constructor from components 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 int4 getFieldNumber(void) const { return fieldNum; } ///< Get the particular field associate with \b this
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual void restoreXml(const Element *el); virtual void decode(Decoder &decoder);
}; };
/// \brief A Symbol that labels code internal to a function /// \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 void buildType(void); ///< Build placeholder data-type
public: public:
LabSymbol(Scope *sc,const string &nm); ///< Construct given name LabSymbol(Scope *sc,const string &nm); ///< Construct given name
LabSymbol(Scope *sc); ///< Constructor for use with restoreXml LabSymbol(Scope *sc); ///< Constructor for use with decode
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual void restoreXml(const Element *el); virtual void decode(Decoder &decoder);
}; };
/// \brief A function Symbol referring to an external location /// \brief A function Symbol referring to an external location
@ -314,10 +336,10 @@ class ExternRefSymbol : public Symbol {
virtual ~ExternRefSymbol(void) {} virtual ~ExternRefSymbol(void) {}
public: public:
ExternRefSymbol(Scope *sc,const Address &ref,const string &nm); ///< Construct given a \e placeholder address 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 const Address &getRefAddr(void) const { return refaddr; } ///< Return the \e placeholder address
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual void restoreXml(const Element *el); virtual void decode(Decoder &decoder);
}; };
/// \brief Comparator for sorting Symbol objects by name /// \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<uint8,Scope *> ScopeMap; ///< A map from id to Scope typedef map<uint8,Scope *> ScopeMap; ///< A map from id to Scope
/// \brief A collection of Symbol objects within a single (namespace or functional) 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 /// \return return a unique version of the name
virtual string makeNameUnique(const string &nm) const=0; virtual string makeNameUnique(const string &nm) const=0;
virtual void saveXml(ostream &s) const=0; ///< Write out \b this as a \<scope> XML tag virtual void encode(Encoder &encoder) const=0; ///< Encode \b this as a \<scope> element
virtual void restoreXml(const Element *el)=0; ///< Restore \b this Scope from a \<scope> XML tag virtual void decode(Decoder &decoder)=0; ///< Decode \b this Scope from a \<scope> 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 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 /// \brief Get the number of Symbols in the given category
@ -709,7 +743,7 @@ public:
Scope *discoverScope(const Address &addr,int4 sz,const Address &usepoint); ///< Find the owning Scope of a given memory range 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 childrenBegin() const { return children.begin(); } ///< Beginning iterator of child scopes
ScopeMap::const_iterator childrenEnd() const { return children.end(); } ///< Ending 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 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 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 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 void setThisPointer(Symbol *sym,bool val) { sym->setThisPointer(val); } ///< Toggle the given Symbol as the "this" pointer
@ -722,7 +756,7 @@ public:
Symbol *addSymbol(const string &nm,Datatype *ct); ///< Add a new Symbol \e without mapping it to an address 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, SymbolEntry *addMapPoint(Symbol *sym,const Address &addr,
const Address &usepoint); ///< Map a Symbol to a specific address const Address &usepoint); ///< Map a Symbol to a specific address
Symbol *addMapSym(const Element *el); ///< Add a mapped Symbol from a \<mapsym> XML tag Symbol *addMapSym(Decoder &decoder); ///< Parse a mapped Symbol from a \<mapsym> element
FunctionSymbol *addFunction(const Address &addr,const string &nm); FunctionSymbol *addFunction(const Address &addr,const string &nm);
ExternRefSymbol *addExternalRef(const Address &addr,const Address &refaddr,const string &nm); ExternRefSymbol *addExternalRef(const Address &addr,const Address &refaddr,const string &nm);
LabSymbol *addCodeLabel(const Address &addr,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 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. /// a \b maptable, which is a list of rangemaps that own the SymbolEntry objects.
class ScopeInternal : public Scope { class ScopeInternal : public Scope {
void processHole(const Element *el); void decodeHole(Decoder &decoder);
void processCollision(const Element *el); void decodeCollision(Decoder &decoder);
void insertNameTree(Symbol *sym); void insertNameTree(Symbol *sym);
SymbolNameTree::const_iterator findFirstByName(const string &nm) const; SymbolNameTree::const_iterator findFirstByName(const string &nm) const;
protected: protected:
@ -799,8 +833,8 @@ public:
Datatype *ct,int4 &index,uint4 flags) const; Datatype *ct,int4 &index,uint4 flags) const;
virtual string buildUndefinedName(void) const; virtual string buildUndefinedName(void) const;
virtual string makeNameUnique(const string &nm) const; virtual string makeNameUnique(const string &nm) const;
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual void restoreXml(const Element *el); virtual void decode(Decoder &decoder);
virtual void printEntries(ostream &s) const; virtual void printEntries(ostream &s) const;
virtual int4 getCategorySize(int4 cat) const; virtual int4 getCategorySize(int4 cat) const;
virtual Symbol *getCategorySymbol(int4 cat,int4 ind) 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 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 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 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 \<parent> tag. Scope *parseParentTag(Decoder &decoder); ///< Figure out parent scope given \<parent> tag.
public: public:
Database(Architecture *g,bool idByName); ///< Constructor Database(Architecture *g,bool idByName); ///< Constructor
~Database(void); ///< Destructor ~Database(void); ///< Destructor
@ -891,9 +925,9 @@ public:
void setPropertyRange(uint4 flags,const Range &range); ///< Set boolean properties over a given memory range void setPropertyRange(uint4 flags,const Range &range); ///< Set boolean properties over a given memory range
void setProperties(const partmap<Address,uint4> &newflags) { flagbase = newflags; } ///< Replace the property map void setProperties(const partmap<Address,uint4> &newflags) { flagbase = newflags; } ///< Replace the property map
const partmap<Address,uint4> &getProperties(void) const { return flagbase; } ///< Get the entire property map const partmap<Address,uint4> &getProperties(void) const { return flagbase; } ///< Get the entire property map
void saveXml(ostream &s) const; ///< Save the whole Database to an XML stream void encode(Encoder &encoder) const; ///< Encode the whole Database to a stream
void restoreXml(const Element *el); ///< Recover the whole database from XML void decode(Decoder &decoder); ///< Decode the whole database from a stream
void restoreXmlScope(const Element *el,Scope *newScope); ///< Register and fill out a single Scope from an XML \<scope> tag void decodeScope(Decoder &decoder,Scope *newScope); ///< Register and fill out a single Scope from an XML \<scope> tag
}; };
/// \param sc is the scope containing the new symbol /// \param sc is the scope containing the new symbol

View file

@ -52,120 +52,103 @@ Scope *ScopeGhidra::reresolveScope(uint8 id) const
if (cacheScope != (Scope *)0) if (cacheScope != (Scope *)0)
return cacheScope; // Scope was previously cached return cacheScope; // Scope was previously cached
Document *doc = ghidra->getNamespacePath(id); XmlDecode decoder;
if (doc == (Document *)0) if (!ghidra->getNamespacePath(id,decoder))
throw LowlevelError("Could not get namespace info"); throw LowlevelError("Could not get namespace info");
Scope *curscope = symboltab->getGlobalScope(); // Get pointer to ourselves (which is not const) Scope *curscope = symboltab->getGlobalScope(); // Get pointer to ourselves (which is not const)
try { uint4 elemId = decoder.openElement();
const List &list(doc->getRoot()->getChildren()); uint4 subId = decoder.openElement();
List::const_iterator iter = list.begin(); decoder.closeElementSkipping(subId); // Skip element describing the root scope
++iter; // Skip element describing the root scope for(;;) {
while(iter != list.end()) { subId = decoder.openElement();
const Element *el = *iter; if (subId == 0) break;
++iter; uint8 scopeId = decoder.readUnsignedInteger(ATTRIB_ID);
uint8 scopeId; curscope = symboltab->findCreateScope(scopeId, decoder.readString(ATTRIB_CONTENT), curscope);
istringstream s(el->getAttributeValue("id")); decoder.closeElement(subId);
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;
} }
decoder.closeElement(elemId);
return curscope; return curscope;
} }
/// The Ghidra client can respond to a query negatively by sending a /// The Ghidra client can respond to a query negatively by sending a
/// \<hole> tag, which describes the (largest) range of addresses containing /// \<hole> element, which describes the (largest) range of addresses containing
/// the query address that do not have any Symbol mapped to them. This object /// 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 /// stores this information in the \b holes map, which it consults to avoid
/// sending queries for the same unmapped address repeatedly. The tag may /// sending queries for the same unmapped address repeatedly. The tag may
/// also contain boolean property information about the memory range, which /// also contain boolean property information about the memory range, which
/// also gets stored. /// also gets stored.
/// \param el is the \<hole> element /// \param decoder is the stream decoder
void ScopeGhidra::processHole(const Element *el) const void ScopeGhidra::decodeHole(Decoder &decoder) const
{ {
Range range; uint4 elemId = decoder.openElement(ELEM_HOLE);
range.restoreXml(el,ghidra);
holes.insertRange(range.getSpace(),range.getFirst(),range.getLast());
uint4 flags = 0; uint4 flags = 0;
for(int4 i=0;i<el->getNumAttributes();++i) { Range range;
if ((el->getAttributeName(i)=="readonly")&& range.decodeFromAttributes(decoder,ghidra);
xml_readbool(el->getAttributeValue(i))) decoder.rewindAttributes();
for(;;) {
uint4 attribId = decoder.getNextAttributeId();
if (attribId == 0) break;
if (attribId==ATTRIB_READONLY && decoder.readBool())
flags |= Varnode::readonly; flags |= Varnode::readonly;
else if ((el->getAttributeName(i)=="volatile")&& else if (attribId==ATTRIB_VOLATILE && decoder.readBool())
xml_readbool(el->getAttributeValue(i)))
flags |= Varnode::volatil; flags |= Varnode::volatil;
} }
holes.insertRange(range.getSpace(),range.getFirst(),range.getLast());
decoder.closeElement(elemId);
if (flags != 0) { if (flags != 0) {
ghidra->symboltab->setPropertyRange(flags,range); ghidra->symboltab->setPropertyRange(flags,range);
cacheDirty = true; cacheDirty = true;
} }
} }
/// Build the global object described by the XML document /// Build the global object described by the stream element
/// and put it in the cache. The XML can either be a /// and put it in the cache. The element can either be a \<hole>, describing the absence
/// \<hole> tag, describing the absence of symbols at the queried /// of symbols at the queried address, or one of the symbol elements.
/// address, or one of the symbol tags /// \param decoder is the stream decoder
/// \param doc is the XML document
/// \return the newly constructed Symbol or NULL if there was a hole /// \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; Symbol *sym = (Symbol *)0;
if (el->getName() == "hole") { uint4 elemId = decoder.peekElement();
processHole(el); if (elemId == ELEM_HOLE) {
decodeHole(decoder);
return sym; return sym;
} }
List::const_iterator iter = el->getChildren().begin(); decoder.openElement();
uint8 scopeId; uint8 scopeId = decoder.readUnsignedInteger(ATTRIB_ID);
{
istringstream s(el->getAttributeValue("id"));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> scopeId;
}
Scope *scope = reresolveScope(scopeId); Scope *scope = reresolveScope(scopeId);
el = *iter;
try { 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) // 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 // Check for function object where the full size is not stored in the cache
// Entries for functions always start at the entry address // Entries for functions always start at the entry address
// of the function in order to deal with non-contiguous functions // of the function in order to deal with non-contiguous functions
// But ghidra will still return the function for queries at addresses in the // But ghidra will still return the function for queries at addresses in the
// interior of the function // interior of the function
const Element *symel = *el->getChildren().begin(); if (!err.address.isInvalid()) { // Make sure the address was parsed
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
vector<Symbol *> symList; vector<Symbol *> 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.size();++i) { for(int4 i=0;i<symList.size();++i) {
FunctionSymbol *funcSym = dynamic_cast<FunctionSymbol *>(symList[i]); FunctionSymbol *funcSym = dynamic_cast<FunctionSymbol *>(symList[i]);
if (funcSym != (FunctionSymbol *)0) { // If duplicate symbol is for function 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 sym = funcSym; // use the old symbol
break; break;
} }
} }
} }
} }
if (sym == (Symbol *)0) { if (sym == (Symbol *)0)
ostringstream s; throw LowlevelError("DuplicateFunctionError, but could not recover original symbol");
s << err.explain << ": entry didn't cache";
throw LowlevelError(s.str());
}
} }
if (sym != (Symbol *)0) { if (sym != (Symbol *)0) {
SymbolEntry *entry = sym->getFirstWholeMap(); SymbolEntry *entry = sym->getFirstWholeMap();
@ -208,7 +191,6 @@ Symbol *ScopeGhidra::dump2Cache(Document *doc) const
Symbol *ScopeGhidra::removeQuery(const Address &addr) const Symbol *ScopeGhidra::removeQuery(const Address &addr) const
{ {
Document *doc;
Symbol *sym = (Symbol *)0; Symbol *sym = (Symbol *)0;
// Don't send up queries on constants or uniques // 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 // Have we queried this address before
if (holes.inRange(addr,1)) return (Symbol *)0; if (holes.inRange(addr,1)) return (Symbol *)0;
doc = ghidra->getMappedSymbolsXML(addr); // Query GHIDRA about this address XmlDecode decoder;
if (doc != (Document *)0) { if (ghidra->getMappedSymbolsXML(addr,decoder)) { // Query GHIDRA about this address
sym = dump2Cache(doc); // Add it to the cache sym = dump2Cache(decoder); // Add it to the cache
delete doc;
} }
return sym; return sym;
} }
@ -368,14 +349,12 @@ Funcdata *ScopeGhidra::resolveExternalRefFunction(ExternRefSymbol *sym) const
if (resFd == (Funcdata *)0) { if (resFd == (Funcdata *)0) {
// If the function isn't in cache, we use the special // If the function isn't in cache, we use the special
// getExternalRefXML interface to recover the external function // getExternalRefXML interface to recover the external function
Document *doc;
SymbolEntry *entry = sym->getFirstWholeMap(); SymbolEntry *entry = sym->getFirstWholeMap();
doc = ghidra->getExternalRefXML(entry->getAddr()); XmlDecode decoder;
if (doc != (Document *)0) { if (ghidra->getExternalRefXML(entry->getAddr(),decoder)) {
FunctionSymbol *funcSym; FunctionSymbol *funcSym;
// Make sure referenced function is cached // Make sure referenced function is cached
funcSym = dynamic_cast<FunctionSymbol *>(dump2Cache(doc)); funcSym = dynamic_cast<FunctionSymbol *>(dump2Cache(decoder));
delete doc;
if (funcSym != (FunctionSymbol *)0) if (funcSym != (FunctionSymbol *)0)
resFd = funcSym->getFunction(); resFd = funcSym->getFunction();
} }

View file

@ -39,9 +39,9 @@ class ScopeGhidra : public Scope {
vector<int4> spacerange; ///< List of address spaces that are in the global range vector<int4> spacerange; ///< List of address spaces that are in the global range
partmap<Address,uint4> flagbaseDefault; ///< Default boolean properties on memory partmap<Address,uint4> flagbaseDefault; ///< Default boolean properties on memory
mutable bool cacheDirty; ///< Is flagbaseDefault different from cache 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 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 \<hole> response element
Scope *reresolveScope(uint8 id) const; ///< Find the Scope that will contain a result Symbol 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 addRange(AddrSpace *spc,uintb first,uintb last);
virtual void removeRange(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 renameSymbol(Symbol *sym,const string &newname) { throw LowlevelError("renameSymbol unimplemented"); }
virtual void retypeSymbol(Symbol *sym,Datatype *ct) { throw LowlevelError("retypeSymbol unimplemented"); } virtual void retypeSymbol(Symbol *sym,Datatype *ct) { throw LowlevelError("retypeSymbol unimplemented"); }
virtual string makeNameUnique(const string &nm) const { throw LowlevelError("makeNameUnique unimplemented"); } virtual string makeNameUnique(const string &nm) const { throw LowlevelError("makeNameUnique unimplemented"); }
virtual void saveXml(ostream &s) const { throw LowlevelError("saveXml unimplemented"); } virtual void encode(Encoder &encoder) const { throw LowlevelError("encode unimplemented"); }
virtual void restoreXml(const Element *el) { throw LowlevelError("restoreXml unimplemented"); } virtual void decode(Decoder &decoder) { throw LowlevelError("decode unimplemented"); }
virtual void printEntries(ostream &s) const { throw LowlevelError("printEntries unimplemented"); } virtual void printEntries(ostream &s) const { throw LowlevelError("printEntries unimplemented"); }
virtual int4 getCategorySize(int4 cat) const { throw LowlevelError("getCategorySize unimplemented"); } virtual int4 getCategorySize(int4 cat) const { throw LowlevelError("getCategorySize unimplemented"); }
virtual Symbol *getCategorySymbol(int4 cat,int4 ind) const { throw LowlevelError("getCategorySymbol unimplemented"); } virtual Symbol *getCategorySymbol(int4 cat,int4 ind) const { throw LowlevelError("getCategorySymbol unimplemented"); }

File diff suppressed because it is too large Load diff

View file

@ -24,6 +24,38 @@
class JoinRecord; class JoinRecord;
extern AttributeId ATTRIB_CUSTOM; ///< Marshaling attribute "custom"
extern AttributeId ATTRIB_DOTDOTDOT; ///< Marshaling attribute "dotdotdot"
extern AttributeId ATTRIB_EXTENSION; ///< Marshaling attribute "extension"
extern AttributeId ATTRIB_HASTHIS; ///< Marshaling attribute "hasthis"
extern AttributeId ATTRIB_INLINE; ///< Marshaling attribute "inline"
extern AttributeId ATTRIB_KILLEDBYCALL; ///< Marshaling attribute "killedbycall"
extern AttributeId ATTRIB_MAXSIZE; ///< Marshaling attribute "maxsize"
extern AttributeId ATTRIB_MINSIZE; ///< Marshaling attribute "minsize"
extern AttributeId ATTRIB_MODELLOCK; ///< Marshaling attribute "modellock"
extern AttributeId ATTRIB_NORETURN; ///< Marshaling attribute "noreturn"
extern AttributeId ATTRIB_POINTERMAX; ///< Marshaling attribute "pointermax"
extern AttributeId ATTRIB_SEPARATEFLOAT; ///< Marshaling attribute "separatefloat"
extern AttributeId ATTRIB_STACKSHIFT; ///< Marshaling attribute "stackshift"
extern AttributeId ATTRIB_STRATEGY; ///< Marshaling attribute "strategy"
extern AttributeId ATTRIB_THISBEFORERETPOINTER; ///< Marshaling attribute "thisbeforeretpointer"
extern AttributeId ATTRIB_VOIDLOCK; ///< Marshaling attribute "voidlock"
extern ElementId ELEM_GROUP; ///< Marshaling element \<group>
extern ElementId ELEM_INTERNALLIST; ///< Marshaling element \<internallist>
extern ElementId ELEM_KILLEDBYCALL; ///< Marshaling element \<killedbycall>
extern ElementId ELEM_LIKELYTRASH; ///< Marshaling element \<likelytrash>
extern ElementId ELEM_LOCALRANGE; ///< Marshaling element \<localrange>
extern ElementId ELEM_MODEL; ///< Marshaling element \<model>
extern ElementId ELEM_PARAM; ///< Marshaling element \<param>
extern ElementId ELEM_PARAMRANGE; ///< Marshaling element \<paramrange>
extern ElementId ELEM_PENTRY; ///< Marshaling element \<pentry>
extern ElementId ELEM_PROTOTYPE; ///< Marshaling element \<prototype>
extern ElementId ELEM_RESOLVEPROTOTYPE; ///< Marshaling element \<resolveprototype>
extern ElementId ELEM_RETPARAM; ///< Marshaling element \<retparam>
extern ElementId ELEM_RETURNSYM; ///< Marshaling element \<returnsym>
extern ElementId ELEM_UNAFFECTED; ///< Marshaling element \<unaffected>
/// \brief Exception thrown when a prototype can't be modeled properly /// \brief Exception thrown when a prototype can't be modeled properly
struct ParamUnassignedError : public LowlevelError { struct ParamUnassignedError : public LowlevelError {
ParamUnassignedError(const string &s) : LowlevelError(s) {} ///< Constructor ParamUnassignedError(const string &s) : LowlevelError(s) {} ///< Constructor
@ -85,7 +117,7 @@ private:
/// \brief Is the logical value left-justified within its container /// \brief Is the logical value left-justified within its container
bool isLeftJustified(void) const { return (((flags&force_left_justify)!=0)||(!spaceid->isBigEndian())); } bool isLeftJustified(void) const { return (((flags&force_left_justify)!=0)||(!spaceid->isBigEndian())); }
public: 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 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 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. 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 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 int4 justifiedContain(const Address &addr,int4 sz) const; ///< Calculate endian aware containment
bool getContainer(const Address &addr,int4 sz,VarnodeData &res) const; 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; OpCode assumedExtension(const Address &addr,int4 sz,VarnodeData &res) const;
int4 getSlot(const Address &addr,int4 skip) const; int4 getSlot(const Address &addr,int4 skip) const;
AddrSpace *getSpace(void) const { return spaceid; } ///< Get the address space containing \b this entry 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 uintb getBase(void) const { return addressbase; } ///< Get the starting offset of \b this entry
Address getAddrBySlot(int4 &slot,int4 sz) const; Address getAddrBySlot(int4 &slot,int4 sz) const;
void restoreXml(const Element *el,const AddrSpaceManager *manage,bool normalstack,bool grouped,list<ParamEntry> &curList); void decode(Decoder &decoder,const AddrSpaceManager *manage,bool normalstack,bool grouped,list<ParamEntry> &curList);
bool isParamCheckHigh(void) const { return ((flags & extracheck_high)!=0); } ///< Return \b true if there is a high overlap 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 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 static void orderWithinGroup(const ParamEntry &entry1,const ParamEntry &entry2); ///< Enforce ParamEntry group ordering rules
@ -302,11 +334,11 @@ public:
class FspecSpace : public AddrSpace { class FspecSpace : public AddrSpace {
public: public:
FspecSpace(AddrSpaceManager *m,const Translate *t,int4 ind); ///< Constructor FspecSpace(AddrSpaceManager *m,const Translate *t,int4 ind); ///< Constructor
virtual void saveXmlAttributes(ostream &s,uintb offset) const; virtual void encodeAttributes(Encoder &encoder,uintb offset) const;
virtual void saveXmlAttributes(ostream &s,uintb offset,int4 size) const; virtual void encodeAttributes(Encoder &encoder,uintb offset,int4 size) const;
virtual void printRaw(ostream &s,uintb offset) const; virtual void printRaw(ostream &s,uintb offset) const;
virtual void saveXml(ostream &s) 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 static const string NAME; ///< Reserved name for the fspec space
}; };
@ -342,7 +374,7 @@ private:
VarnodeData range; ///< The memory range affected VarnodeData range; ///< The memory range affected
uint4 type; ///< The type of effect uint4 type; ///< The type of effect
public: 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 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 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 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 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; ///< Equality operator
bool operator!=(const EffectRecord &op2) const; ///< Inequality operator bool operator!=(const EffectRecord &op2) const; ///< Inequality operator
void saveXml(ostream &s) const; ///< Save the record to an XML stream void encode(Encoder &encoder) const; ///< Encode the record to a stream
void restoreXml(uint4 grouptype,const Element *el,const AddrSpaceManager *manage); ///< Restore the record from an XML 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); 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 /// \return the maximum number of passes across all parameters in \b this model
virtual int4 getMaxDelay(void) const=0; virtual int4 getMaxDelay(void) const=0;
/// \brief Restore the model from an XML stream /// \brief Restore the model from an \<input> or \<output> element in the stream
/// ///
/// \param el is the root \<input> or \<output> element /// \param decoder is the stream decoder
/// \param manage is used to resolve references to address spaces /// \param manage is used to resolve references to address spaces
/// \param effectlist is a container collecting EffectRecords across all parameters /// \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 /// \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<EffectRecord> &effectlist,bool normalstack)=0; virtual void decode(Decoder &decoder,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist,bool normalstack)=0;
virtual ParamList *clone(void) const=0; ///< Clone this parameter list model 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 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 addResolverRange(AddrSpace *spc,uintb first,uintb last,ParamEntry *paramEntry,int4 position);
void populateResolver(void); ///< Build the ParamEntry resolver maps void populateResolver(void); ///< Build the ParamEntry resolver maps
void parsePentry(const Element *el,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist, void parsePentry(Decoder &decoder,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist,
int4 groupid,bool normalstack,bool autokill,bool splitFloat,bool grouped); int4 groupid,bool normalstack,bool autokill,bool splitFloat,bool grouped);
void parseGroup(const Element *el,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist, void parseGroup(Decoder &decoder,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist,
int4 groupid,bool normalstack,bool autokill,bool splitFloat); int4 groupid,bool normalstack,bool autokill,bool splitFloat);
public: public:
ParamListStandard(void) {} ///< Construct for use with restoreXml() ParamListStandard(void) {} ///< Construct for use with decode()
ParamListStandard(const ParamListStandard &op2); ///< Copy constructor ParamListStandard(const ParamListStandard &op2); ///< Copy constructor
virtual ~ParamListStandard(void); virtual ~ParamListStandard(void);
const list<ParamEntry> &getEntry(void) const { return entry; } ///< Get the list of parameter entries const list<ParamEntry> &getEntry(void) const { return entry; } ///< Get the list of parameter entries
@ -562,7 +594,7 @@ public:
virtual AddrSpace *getSpacebase(void) const { return spacebase; } virtual AddrSpace *getSpacebase(void) const { return spacebase; }
virtual void getRangeList(AddrSpace *spc,RangeList &res) const; virtual void getRangeList(AddrSpace *spc,RangeList &res) const;
virtual int4 getMaxDelay(void) const { return maxdelay; } virtual int4 getMaxDelay(void) const { return maxdelay; }
virtual void restoreXml(const Element *el,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist,bool normalstack); virtual void decode(Decoder &decoder,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist,bool normalstack);
virtual ParamList *clone(void) const; virtual ParamList *clone(void) const;
}; };
@ -593,7 +625,7 @@ public:
/// conventions. The assignMap() method may make less sense in this scenario. /// conventions. The assignMap() method may make less sense in this scenario.
class ParamListRegister : public ParamListStandard { class ParamListRegister : public ParamListStandard {
public: 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 ParamListRegister(const ParamListRegister &op2) : ParamListStandard(op2) {} ///< Copy constructor
virtual uint4 getType(void) const { return p_register; } virtual uint4 getType(void) const { return p_register; }
virtual void fillinMap(ParamActive *active) const; virtual void fillinMap(ParamActive *active) const;
@ -610,11 +642,11 @@ public:
/// to inform the input model. /// to inform the input model.
class ParamListStandardOut : public ParamListRegisterOut { class ParamListStandardOut : public ParamListRegisterOut {
public: 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 ParamListStandardOut(const ParamListStandardOut &op2) : ParamListRegisterOut(op2) {} ///< Copy constructor
virtual uint4 getType(void) const { return p_standard_out; } virtual uint4 getType(void) const { return p_standard_out; }
virtual void assignMap(const vector<Datatype *> &proto,TypeFactory &typefactory,vector<ParameterPieces> &res) const; virtual void assignMap(const vector<Datatype *> &proto,TypeFactory &typefactory,vector<ParameterPieces> &res) const;
virtual void restoreXml(const Element *el,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist,bool normalstack); virtual void decode(Decoder &decoder,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist,bool normalstack);
virtual ParamList *clone(void) const; virtual ParamList *clone(void) const;
}; };
@ -628,7 +660,7 @@ public:
/// need to be invoked. /// need to be invoked.
class ParamListMerged : public ParamListStandard { class ParamListMerged : public ParamListStandard {
public: 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 ParamListMerged(const ParamListMerged &op2) : ParamListStandard(op2) {} ///< Copy constructor
void foldIn(const ParamListStandard &op2); ///< Add another model to the union void foldIn(const ParamListStandard &op2); ///< Add another model to the union
void finalize(void) { populateResolver(); } ///< Fold-ins are finished, finalize \b this void finalize(void) { populateResolver(); } ///< Fold-ins are finished, finalize \b this
@ -686,7 +718,7 @@ public:
enum { enum {
extrapop_unknown = 0x8000 ///< Reserved extrapop value meaning the function's \e extrapop is unknown 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 ProtoModel(const string &nm,const ProtoModel &op2); ///< Copy constructor changing the name
virtual ~ProtoModel(void); ///< Destructor virtual ~ProtoModel(void); ///< Destructor
const string &getName(void) const { return name; } ///< Get the name of the prototype model 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(); } int4 getMaxOutputDelay(void) const { return output->getMaxDelay(); }
virtual bool isMerged(void) const { return false; } ///< Is \b this a merged prototype model 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<EffectRecord> &efflist,const Address &addr,int4 size); static uint4 lookupEffect(const vector<EffectRecord> &efflist,const Address &addr,int4 size);
static int4 lookupRecord(const vector<EffectRecord> &efflist,int4 listSize,const Address &addr,int4 size); static int4 lookupRecord(const vector<EffectRecord> &efflist,int4 listSize,const Address &addr,int4 size);
}; };
@ -969,7 +1001,7 @@ public:
void foldIn(ProtoModel *model); ///< Fold-in an additional prototype model void foldIn(ProtoModel *model); ///< Fold-in an additional prototype model
ProtoModel *selectModel(ParamActive *active) const; ///< Select the best model given a set of trials ProtoModel *selectModel(ParamActive *active) const; ///< Select the best model given a set of trials
virtual bool isMerged(void) const { return true; } virtual bool isMerged(void) const { return true; }
virtual void restoreXml(const Element *el); virtual void decode(Decoder &decoder);
}; };
class Symbol; class Symbol;
@ -1116,18 +1148,19 @@ public:
virtual ProtoParameter *getOutput(void)=0; ///< Get the return-value description virtual ProtoParameter *getOutput(void)=0; ///< Get the return-value description
virtual ProtoStore *clone(void) const=0; ///< Clone the entire collection of parameter descriptions 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. /// Symbols are stored elsewhere, so symbol backed parameters are not serialized.
/// If there are any internal parameters an \<internallist> tag is emitted. /// If there are any internal parameters an \<internallist> element is emitted.
/// \param s is the output stream /// \param encoder is the stream encoder
virtual void saveXml(ostream &s) const=0; 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 \<internallist> element containing \<param> and \<retparam> sub-tags. /// Parse an \<internallist> element containing \<param> and \<retparam> child elements.
/// \param decoder is the stream decoder
/// \param model is prototype model for determining storage for unassigned parameters /// \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 /// \brief A parameter with a formal backing Symbol
@ -1183,8 +1216,8 @@ public:
virtual void clearOutput(void); virtual void clearOutput(void);
virtual ProtoParameter *getOutput(void); virtual ProtoParameter *getOutput(void);
virtual ProtoStore *clone(void) const; virtual ProtoStore *clone(void) const;
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual void restoreXml(const Element *el,ProtoModel *model); virtual void decode(Decoder &decoder,ProtoModel *model);
}; };
/// \brief A collection of parameter descriptions without backing symbols /// \brief A collection of parameter descriptions without backing symbols
@ -1207,8 +1240,8 @@ public:
virtual void clearOutput(void); virtual void clearOutput(void);
virtual ProtoParameter *getOutput(void); virtual ProtoParameter *getOutput(void);
virtual ProtoStore *clone(void) const; virtual ProtoStore *clone(void) const;
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual void restoreXml(const Element *el,ProtoModel *model); virtual void decode(Decoder &decoder,ProtoModel *model);
}; };
/// \brief Raw components of a function prototype (obtained from parsing source code) /// \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 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) 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 updateThisPointer(void); ///< Make sure any "this" parameter is properly marked
void saveEffectXml(ostream &s) const; ///< Save any overriding EffectRecords to XML stream void encodeEffect(Encoder &encoder) const; ///< Encode any overriding EffectRecords to stream
void saveLikelyTrashXml(ostream &s) const; ///< Save any overriding likelytrash registers to XML stream void encodeLikelyTrash(Encoder &encoder) const; ///< Encode any overriding likelytrash registers to stream
void restoreEffectXml(void); ///< Merge in any EffectRecord overrides void decodeEffect(void); ///< Merge in any EffectRecord overrides
void restoreLikelyTrashXml(void); ///< Merge in any \e likelytrash overrides void decodeLikelyTrash(void); ///< Merge in any \e likelytrash overrides
protected: protected:
void paramShift(int4 paramshift); ///< Add parameters to the front of the input parameter list void paramShift(int4 paramshift); ///< Add parameters to the front of the input parameter list
bool isParamshiftApplied(void) const { return ((flags&paramshift_applied)!=0); } ///< Has a parameter shift been applied bool isParamshiftApplied(void) const { return ((flags&paramshift_applied)!=0); } ///< Has a parameter shift been applied
@ -1502,8 +1535,8 @@ public:
/// \return the active set of flags for \b this prototype /// \return the active set of flags for \b this prototype
uint4 getComparableFlags(void) const { return (flags & (dotdotdot | is_constructor | is_destructor | has_thisptr )); } uint4 getComparableFlags(void) const { return (flags & (dotdotdot | is_constructor | is_destructor | has_thisptr )); }
void saveXml(ostream &s) const; void encode(Encoder &encoder) const;
void restoreXml(const Element *el,Architecture *glb); void decode(Decoder &decoder,Architecture *glb);
}; };
class Funcdata; class Funcdata;

View file

@ -14,7 +14,14 @@
* limitations under the License. * limitations under the License.
*/ */
#include "funcdata.hh" #include "funcdata.hh"
//#include <fstream>
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 nm is the (base) name of the function
/// \param scope is Symbol scope associated with 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; size = sz;
AddrSpace *stackid = glb->getStackSpace(); AddrSpace *stackid = glb->getStackSpace();
if (nm.size()==0) if (nm.size()==0)
localmap = (ScopeLocal *)0; // Filled in by restoreXml localmap = (ScopeLocal *)0; // Filled in by decode
else { else {
uint8 id; uint8 id;
if (sym != (FunctionSymbol *)0) if (sym != (FunctionSymbol *)0)
@ -542,66 +549,65 @@ void Funcdata::printLocalRange(ostream &s) const
} }
} }
/// This parses a \<jumptablelist> tag and builds a JumpTable object for /// Parse a \<jumptablelist> element and build a JumpTable object for
/// each \<jumptable> sub-tag. /// each \<jumptable> child element.
/// \param el is the root \<jumptablelist> tag /// \param decoder is the stream decoder
void Funcdata::restoreXmlJumpTable(const Element *el) void Funcdata::decodeJumpTable(Decoder &decoder)
{ {
const List &list( el->getChildren() ); uint4 elemId = decoder.openElement(ELEM_JUMPTABLELIST);
List::const_iterator iter; while(decoder.peekElement() != 0) {
for(iter=list.begin();iter!=list.end();++iter) {
JumpTable *jt = new JumpTable(glb); JumpTable *jt = new JumpTable(glb);
jt->restoreXml(*iter); jt->decode(decoder);
jumpvec.push_back(jt); jumpvec.push_back(jt);
} }
decoder.closeElement(elemId);
} }
/// A \<jumptablelist> tag is written with \<jumptable> sub-tags describing /// A \<jumptablelist> element is written with \<jumptable> children describing
/// each jump-table associated with the control-flow of \b this function. /// each jump-table associated with the control-flow of \b this function.
/// \param s is the output stream /// \param encoder is the stream encoder
void Funcdata::saveXmlJumpTable(ostream &s) const void Funcdata::encodeJumpTable(Encoder &encoder) const
{ {
if (jumpvec.empty()) return; if (jumpvec.empty()) return;
vector<JumpTable *>::const_iterator iter; vector<JumpTable *>::const_iterator iter;
s << "<jumptablelist>\n"; encoder.openElement(ELEM_JUMPTABLELIST);
for(iter=jumpvec.begin();iter!=jumpvec.end();++iter) for(iter=jumpvec.begin();iter!=jumpvec.end();++iter)
(*iter)->saveXml(s); (*iter)->encode(encoder);
s << "</jumptablelist>\n"; 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. /// This is an internal function for the function's marshaling system.
/// Individual XML tags are written in sequence for Varnodes in a given set. /// Individual elements are written in sequence for Varnodes in a given set.
/// The set is bounded by iterators using the 'loc' ordering. /// 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 iter is the beginning of the set
/// \param enditer is the end 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; Varnode *vn;
while(iter!=enditer) { while(iter!=enditer) {
vn = *iter++; vn = *iter++;
vn->saveXml(s); vn->encode(encoder);
s << '\n';
} }
} }
/// This produces a single \<highlist> tag, with a \<high> sub-tag for each /// This produces a single \<highlist> element, with a \<high> child for each
/// high-level variable (HighVariable) currently associated with \b this function. /// high-level variable (HighVariable) currently associated with \b this function.
/// \param s is the output stream /// \param encoder is the stream encoder
void Funcdata::saveXmlHigh(ostream &s) const void Funcdata::encodeHigh(Encoder &encoder) const
{ {
Varnode *vn; Varnode *vn;
HighVariable *high; HighVariable *high;
if (!isHighOn()) return; if (!isHighOn()) return;
s << "<highlist>"; encoder.openElement(ELEM_HIGHLIST);
VarnodeLocSet::const_iterator iter; VarnodeLocSet::const_iterator iter;
for(iter=beginLoc();iter!=endLoc();++iter) { for(iter=beginLoc();iter!=endLoc();++iter) {
vn = *iter; vn = *iter;
@ -609,104 +615,98 @@ void Funcdata::saveXmlHigh(ostream &s) const
high = vn->getHigh(); high = vn->getHigh();
if (high->isMark()) continue; if (high->isMark()) continue;
high->setMark(); high->setMark();
high->saveXml(s); high->encode(encoder);
} }
for(iter=beginLoc();iter!=endLoc();++iter) { for(iter=beginLoc();iter!=endLoc();++iter) {
vn = *iter; vn = *iter;
if (!vn->isAnnotation()) if (!vn->isAnnotation())
vn->getHigh()->clearMark(); vn->getHigh()->clearMark();
} }
encoder.closeElement(ELEM_HIGHLIST);
s << "</highlist>\n";
} }
/// A single \<ast> tag is produced with children describing Varnodes, PcodeOps, and /// A single \<ast> element is produced with children describing Varnodes, PcodeOps, and
/// basic blocks making up \b this function's current syntax tree. /// basic blocks making up \b this function's current syntax tree.
/// \param s is the output stream /// \param encoder is the stream encoder
void Funcdata::saveXmlTree(ostream &s) const void Funcdata::encodeTree(Encoder &encoder) const
{ {
s << "<ast>\n"; encoder.openElement(ELEM_AST);
s << "<varnodes>\n"; encoder.openElement(ELEM_VARNODES);
for(int4 i=0;i<glb->numSpaces();++i) { for(int4 i=0;i<glb->numSpaces();++i) {
AddrSpace *base = glb->getSpace(i); AddrSpace *base = glb->getSpace(i);
if (base == (AddrSpace *)0 || base->getType()==IPTR_IOP) continue; if (base == (AddrSpace *)0 || base->getType()==IPTR_IOP) continue;
VarnodeLocSet::const_iterator iter = vbank.beginLoc(base); VarnodeLocSet::const_iterator iter = vbank.beginLoc(base);
VarnodeLocSet::const_iterator enditer = vbank.endLoc(base); VarnodeLocSet::const_iterator enditer = vbank.endLoc(base);
saveVarnodeXml(s,iter,enditer); encodeVarnode(encoder,iter,enditer);
} }
s << "</varnodes>\n"; encoder.closeElement(ELEM_VARNODES);
list<PcodeOp *>::iterator oiter,endoiter; list<PcodeOp *>::iterator oiter,endoiter;
PcodeOp *op; PcodeOp *op;
BlockBasic *bs; BlockBasic *bs;
for(int4 i=0;i<bblocks.getSize();++i) { for(int4 i=0;i<bblocks.getSize();++i) {
bs = (BlockBasic *)bblocks.getBlock(i); bs = (BlockBasic *)bblocks.getBlock(i);
s << "<block"; encoder.openElement(ELEM_BLOCK);
a_v_i(s,"index",bs->getIndex()); encoder.writeSignedInteger(ATTRIB_INDEX, bs->getIndex());
s << ">\n"; bs->encodeBody(encoder);
bs->saveXmlBody(s);
oiter = bs->beginOp(); oiter = bs->beginOp();
endoiter = bs->endOp(); endoiter = bs->endOp();
while(oiter != endoiter) { while(oiter != endoiter) {
op = *oiter++; op = *oiter++;
op->saveXml(s); op->encode(encoder);
s << '\n';
} }
s << "</block>\n"; encoder.closeElement(ELEM_BLOCK);
} }
for(int4 i=0;i<bblocks.getSize();++i) { for(int4 i=0;i<bblocks.getSize();++i) {
bs = (BlockBasic *)bblocks.getBlock(i); bs = (BlockBasic *)bblocks.getBlock(i);
if (bs->sizeIn() == 0) continue; if (bs->sizeIn() == 0) continue;
s << "<blockedge"; encoder.openElement(ELEM_BLOCKEDGE);
a_v_i(s,"index",bs->getIndex()); encoder.writeSignedInteger(ATTRIB_INDEX, bs->getIndex());
s << ">\n"; bs->encodeEdges(encoder);
bs->saveXmlEdges(s); encoder.closeElement(ELEM_BLOCKEDGE);
s << "</blockedge>\n";
} }
s << "</ast>\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. /// including name, address, prototype, symbol, jump-table, and override information.
/// If indicated by the caller, a description of the entire PcodeOp and Varnode /// If indicated by the caller, a description of the entire PcodeOp and Varnode
/// tree is also emitted. /// 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 id is the unique id associated with the function symbol
/// \param savetree is \b true if the p-code tree should be emitted /// \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 << "<function"; encoder.openElement(ELEM_FUNCTION);
if (id != 0) if (id != 0)
a_v_u(s, "id", id); encoder.writeUnsignedInteger(ATTRIB_ID, id);
a_v(s,"name",name); encoder.writeString(ATTRIB_NAME, name);
a_v_i(s,"size",size); encoder.writeSignedInteger(ATTRIB_SIZE, size);
if (hasNoCode()) if (hasNoCode())
a_v_b(s,"nocode",true); encoder.writeBool(ATTRIB_NOCODE, true);
s << ">\n"; baseaddr.encode(encoder);
baseaddr.saveXml(s);
s << '\n';
if (!hasNoCode()) { if (!hasNoCode()) {
localmap->saveXmlRecursive(s,false); // Save scope and all subscopes localmap->encodeRecursive(encoder,false); // Save scope and all subscopes
} }
if (savetree) { if (savetree) {
saveXmlTree(s); encodeTree(encoder);
saveXmlHigh(s); encodeHigh(encoder);
} }
saveXmlJumpTable(s); encodeJumpTable(encoder);
funcp.saveXml(s); // Must be saved after database funcp.encode(encoder); // Must be saved after database
localoverride.saveXml(s,glb); localoverride.encode(encoder,glb);
s << "</function>\n"; encoder.closeElement(ELEM_FUNCTION);
} }
/// From an XML \<function> tag, recover the name, address, prototype, symbol, /// Parse a \<function> element, recovering the name, address, prototype, symbol,
/// jump-table, and override information for \b this function. /// jump-table, and override information for \b this function.
/// \param el is the root \<function> tag /// \param decoder is the stream decoder
/// \return the symbol id associated with the function /// \return the symbol id associated with the function
uint8 Funcdata::restoreXml(const Element *el) uint8 Funcdata::decode(Decoder &decoder)
{ {
// clear(); // Shouldn't be needed // clear(); // Shouldn't be needed
@ -714,22 +714,20 @@ uint8 Funcdata::restoreXml(const Element *el)
size = -1; size = -1;
uint8 id = 0; uint8 id = 0;
AddrSpace *stackid = glb->getStackSpace(); AddrSpace *stackid = glb->getStackSpace();
for(int4 i=0;i<el->getNumAttributes();++i) { uint4 elemId = decoder.openElement(ELEM_FUNCTION);
const string &attrName(el->getAttributeName(i)); for(;;) {
if (attrName == "name") uint4 attribId = decoder.getNextAttributeId();
name = el->getAttributeValue(i); if (attribId == 0) break;
else if (attrName == "size") { if (attribId == ATTRIB_NAME)
istringstream s( el->getAttributeValue(i)); name = decoder.readString();
s.unsetf(ios::dec | ios::hex | ios::oct); else if (attribId == ATTRIB_SIZE) {
s >> size; size = decoder.readSignedInteger();
} }
else if (attrName == "id") { else if (attribId == ATTRIB_ID) {
istringstream s( el->getAttributeValue(i)); id = decoder.readUnsignedInteger();
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> id;
} }
else if (attrName == "nocode") { else if (attribId == ATTRIB_NOCODE) {
if (xml_readbool(el->getAttributeValue(i))) if (decoder.readBool())
flags |= no_code; flags |= no_code;
} }
} }
@ -737,27 +735,20 @@ uint8 Funcdata::restoreXml(const Element *el)
throw LowlevelError("Missing function name"); throw LowlevelError("Missing function name");
if (size == -1) if (size == -1)
throw LowlevelError("Missing function size"); throw LowlevelError("Missing function size");
const List &list( el->getChildren() ); baseaddr = Address::decode( decoder, glb );
List::const_iterator iter = list.begin(); for(;;) {
baseaddr = Address::restoreXml( *iter, glb ); uint4 subId = decoder.peekElement();
++iter; if (subId == 0) break;
for(;iter!=list.end();++iter) { if (subId == ELEM_LOCALDB) {
if ((*iter)->getName() == "localdb") {
if (localmap != (ScopeLocal *)0) if (localmap != (ScopeLocal *)0)
throw LowlevelError("Pre-existing local scope when restoring: "+name); throw LowlevelError("Pre-existing local scope when restoring: "+name);
ScopeLocal *newMap = new ScopeLocal(id,stackid,this,glb); 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; localmap = newMap;
} }
// else if ((*iter)->getName() == "scope") { else if (subId == ELEM_OVERRIDE)
// const Element *scopeel = *iter; localoverride.decode(decoder,glb);
// ScopeInternal *subscope = new ScopeInternal("",glb); else if (subId == ELEM_PROTOTYPE) {
// subscope->restrictScope(this);
// glb->symboltab->restore_nonglobal_xml(scopeel,subscope);
// }
else if ((*iter)->getName() == "override")
localoverride.restoreXml(*iter,glb);
else if ((*iter)->getName() == "prototype") {
if (localmap == (ScopeLocal *)0) { if (localmap == (ScopeLocal *)0) {
// If we haven't seen a <localdb> tag yet, assume we have a default local scope // If we haven't seen a <localdb> tag yet, assume we have a default local scope
ScopeLocal *newMap = new ScopeLocal(id,stackid,this,glb); ScopeLocal *newMap = new ScopeLocal(id,stackid,this,glb);
@ -766,11 +757,12 @@ uint8 Funcdata::restoreXml(const Element *el)
localmap = newMap; localmap = newMap;
} }
funcp.setScope(localmap,baseaddr+ -1); // localmap built earlier funcp.setScope(localmap,baseaddr+ -1); // localmap built earlier
funcp.restoreXml(*iter,glb); funcp.decode(decoder,glb);
} }
else if ((*iter)->getName() == "jumptablelist") else if (subId == ELEM_JUMPTABLELIST)
restoreXmlJumpTable(*iter); decodeJumpTable(decoder);
} }
decoder.closeElement(elemId);
if (localmap == (ScopeLocal *)0) { // Seen neither <localdb> or <prototype> if (localmap == (ScopeLocal *)0) { // Seen neither <localdb> or <prototype>
// This is a function shell, so we provide default locals // This is a function shell, so we provide default locals
ScopeLocal *newMap = new ScopeLocal(id,stackid,this,glb); ScopeLocal *newMap = new ScopeLocal(id,stackid,this,glb);

View file

@ -28,6 +28,14 @@
class FlowInfo; class FlowInfo;
extern AttributeId ATTRIB_NOCODE; ///< Marshaling attribute "nocode"
extern ElementId ELEM_AST; ///< Marshaling element \<ast>
extern ElementId ELEM_FUNCTION; ///< Marshaling element \<function>
extern ElementId ELEM_HIGHLIST; ///< Marshaling element \<highlist>
extern ElementId ELEM_JUMPTABLELIST; ///< Marshaling element \<jumptablelist>
extern ElementId ELEM_VARNODES; ///< Marshaling element \<varnodes>
/// \brief Container for data structures associated with a single function /// \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 /// 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 nodeSplitRawDuplicate(BlockBasic *b,BlockBasic *bprime);
void nodeSplitInputPatch(BlockBasic *b,BlockBasic *bprime,int4 inedge); void nodeSplitInputPatch(BlockBasic *b,BlockBasic *bprime,int4 inedge);
static bool descendantsOutside(Varnode *vn); 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 bool checkIndirectUse(Varnode *vn);
static PcodeOp *findPrimaryBranch(PcodeOpTree::const_iterator iter,PcodeOpTree::const_iterator enditer, static PcodeOp *findPrimaryBranch(PcodeOpTree::const_iterator iter,PcodeOpTree::const_iterator enditer,
bool findbranch,bool findcall,bool findreturn); 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 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 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 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 void encode(Encoder &encoder,uint8 id,bool savetree) const; ///< Encode a description of \b this function to stream
uint8 restoreXml(const Element *el); ///< Restore the state of \b this function from an XML description uint8 decode(Decoder &decoder); ///< 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 encodeJumpTable(Encoder &encoder) const; ///< Encode a description of jump-tables to stream
void restoreXmlJumpTable(const Element *el); ///< Restore jump-tables from an XML description void decodeJumpTable(Decoder &decoder); ///< Decode jump-tables from a stream
void saveXmlTree(ostream &s) const; ///< Save an XML description of the p-code tree to stream void encodeTree(Encoder &encoder) const; ///< Encode a description of the p-code tree to stream
void saveXmlHigh(ostream &s) const; ///< Save an XML description of all HighVariables 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 Override &getOverride(void) { return localoverride; } ///< Get the Override object for \b this function

View file

@ -139,22 +139,23 @@ void ArchitectureGhidra::readStringStream(istream &s,string &res)
} }
/// The method expects to see protocol markers indicating a string from the client, /// 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. /// \param s is the input stream from the client.
/// \return the XML document /// \param decoder is the given stream decoder that will hold the result
Document *ArchitectureGhidra::readXMLStream(istream &s) /// \return \b true if a response was received
bool ArchitectureGhidra::readStream(istream &s,Decoder &decoder)
{ {
int4 type = readToAnyBurst(s); int4 type = readToAnyBurst(s);
if (type==14) { if (type==14) {
Document *doc = xml_tree(s); decoder.ingestStream(s);
type = readToAnyBurst(s); type = readToAnyBurst(s);
if (type!=15) if (type!=15)
throw JavaError("alignment","Expecting XML string end"); throw JavaError("alignment","Expecting XML string end");
return doc; return true;
} }
if ((type&1)==1) if ((type&1)==1)
return (Document *)0; return false;
throw JavaError("alignment","Expecting string or end of query response"); 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 /// 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 /// \param s is the input stream from the client
/// \return the XML document /// \param decoder is the stream decoder that will hold the result
Document *ArchitectureGhidra::readXMLAll(istream &s) /// \return \b true if we received a valid response
bool ArchitectureGhidra::readAll(istream &s,Decoder &decoder)
{ {
readToResponse(s); readToResponse(s);
Document *doc = readXMLStream(s); if (readStream(s,decoder)) {
if (doc != (Document *)0)
readResponseEnd(s); readResponseEnd(s);
return doc; return true;
}
return false;
} }
/// Read up to the beginning of a query response, check for an /// 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"); const Element *el = store.getTag("coretypes");
types = new TypeFactoryGhidra(this); types = new TypeFactoryGhidra(this);
if (el != (const Element *)0) if (el != (const Element *)0) {
types->restoreXmlCoreTypes(el); XmlDecode decoder(el);
types->decodeCoreTypes(decoder);
}
else { else {
// Put in the core types // Put in the core types
types->setCoreType("void",1,TYPE_VOID,false); 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. /// Ask the Ghidra client if it knows about a specific processor register.
/// The client responds with a \<addr> XML element describing the storage /// The client responds with a \<addr> element describing the storage
/// location of the register. /// location of the register.
/// \param regname is the name to query for /// \param regname is the name to query for
/// \return the storage address as XML or NULL if the register is unknown /// \param decoder is the stream decoder that will hold the result
Document *ArchitectureGhidra::getRegister(const string &regname) /// \return \b true if the query completed successfully
bool ArchitectureGhidra::getRegister(const string &regname,Decoder &decoder)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
@ -411,7 +417,7 @@ Document *ArchitectureGhidra::getRegister(const string &regname)
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
return readXMLAll(sin); return readAll(sin,decoder);
} }
/// Given a storage location and size, ask the Ghidra client if it knows of /// 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"); writeStringStream(sout,"getRegisterName");
sout.write("\000\000\001\016",4); // Beginning of string header sout.write("\000\000\001\016",4); // Beginning of string header
Address addr(vndata.space,vndata.offset); 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\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -438,24 +445,26 @@ string ArchitectureGhidra::getRegisterName(const VarnodeData &vndata)
return res; 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 /// known values at the given address. The response is generally a
/// \<tracked_pointset> which contains \<set> children which contains /// \<tracked_pointset> which contains \<set> children which contains
/// a storage location and value. /// a storage location and value.
/// \param addr is the given address /// \param addr is the given address
/// \return the response Document /// \param decoder is the stream decoder which will hold the result
Document *ArchitectureGhidra::getTrackedRegisters(const Address &addr) /// \return \b true if the query completed successfully
bool ArchitectureGhidra::getTrackedRegisters(const Address &addr,Decoder &decoder)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getTrackedRegisters"); writeStringStream(sout,"getTrackedRegisters");
sout.write("\000\000\001\016",4); // Beginning of string header 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\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
return readXMLAll(sin); return readAll(sin,decoder);
} }
/// The first operand to a CALLOTHER op indicates the specific user-defined op. /// 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); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getPacked"); writeStringStream(sout,"getPacked");
sout.write("\000\000\001\016",4); // Beginning of string header 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\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -499,54 +509,59 @@ uint1 *ArchitectureGhidra::getPcodePacked(const Address &addr)
return readPackedAll(sin); return readPackedAll(sin);
} }
/// The Ghidra client will return a \<symbol> tag, \<function> tag, or some /// The Ghidra client will pass back a \<symbol> element, \<function> element, or some
/// other related Symbol information. If there no symbol at the address /// other related Symbol information, in the given stream decoder. If there is no symbol at the address
/// the client should return a \<hole> tag describing the size of the /// the client will return a \<hole> element describing the size of the
/// memory region that is free of symbols. /// memory region that is free of symbols.
/// \param addr is the given address /// \param addr is the given address
/// \return the symbol document /// \param decoder is the given stream decoder that will hold the result
Document *ArchitectureGhidra::getMappedSymbolsXML(const Address &addr) /// \return \b true if the query completes successfully
bool ArchitectureGhidra::getMappedSymbolsXML(const Address &addr,Decoder &decoder)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getMappedSymbolsXML"); writeStringStream(sout,"getMappedSymbolsXML");
sout.write("\000\000\001\016",4); // Beginning of string header sout.write("\000\000\001\016",4); // Beginning of string
addr.saveXml(sout); encoder.clear();
addr.encode(encoder);
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
return readXMLAll(sin); return readAll(sin,decoder);
} }
/// This asks the Ghidra client to resolve an \e external \e reference. /// 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 /// 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 /// that is elsewhere in memory or not in memory at all. The client
/// should unravel the reference from the given address and return either /// should unravel the reference from the given address and pass back either
/// a \<function> tag describing the referred to function symbol or /// a \<function> element describing the referred to function symbol or
/// a \<hole> tag if the reference can't be resolved /// a \<hole> element if the reference can't be resolved.
/// \param addr is the given address /// \param addr is the given address
/// \return a description of the referred to function /// \param decoder is the stream decoder that will hold the result
Document *ArchitectureGhidra::getExternalRefXML(const Address &addr) /// \return \b true if the query completes successfully
bool ArchitectureGhidra::getExternalRefXML(const Address &addr,Decoder &decoder)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getExternalRefXML"); writeStringStream(sout,"getExternalRefXML");
sout.write("\000\000\001\016",4); // Beginning of string header 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\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
return readXMLAll(sin); return readAll(sin,decoder);
} }
/// Ask the Ghidra client to list all namespace elements between the global root /// 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 \<parent> tag with /// and the namespace of the given id. The client will pass back a \<parent> element with
/// a \<val> child for each namespace in the path. /// a \<val> child for each namespace in the path, in the given stream decoder
/// \param id is the given id of the namespace to resolve /// \param id is the given id of the namespace to resolve
/// \return the XML document /// \param decoder is the given stream decoder that will hold the result
Document *ArchitectureGhidra::getNamespacePath(uint8 id) /// \return \b true if the query completed successfully
bool ArchitectureGhidra::getNamespacePath(uint8 id,Decoder &decoder)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
@ -557,7 +572,7 @@ Document *ArchitectureGhidra::getNamespacePath(uint8 id)
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
return readXMLAll(sin); return readAll(sin,decoder);
} }
bool ArchitectureGhidra::isNameUsed(const string &nm,uint8 startId,uint8 stopId) 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); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getSymbol"); writeStringStream(sout,"getSymbol");
sout.write("\000\000\001\016",4); // Beginning of string header 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\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -605,12 +621,13 @@ string ArchitectureGhidra::getCodeLabel(const Address &addr)
return res; return res;
} }
/// The Ghidra client should respond with a \<type> tag giving details /// The Ghidra client will pass back a \<type> element giving details
/// about the data-type. /// about the data-type.
/// \param name is the name of 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 /// \param id is a unique id associated with the data-type, pass 0 if unknown
/// \return the data-type XML element or NULL /// \param decoder is the stream decoder that will hold the result
Document *ArchitectureGhidra::getType(const string &name,uint8 id) /// \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); 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.write("\000\000\001\005",4);
sout.flush(); sout.flush();
return readXMLAll(sin); return readAll(sin,decoder);
} }
/// Ask Ghidra client for all comments associated with one function. /// Ask Ghidra client for all comments associated with one function.
/// The caller must provide the sub-set of properties (Comment::comment_type) for /// The caller must provide the sub-set of properties (Comment::comment_type) for
/// the query to match. The client will return a \<commentdb> tag with /// the query to match. A \<commentdb> element with \<comment> element child for each comment found
/// a \<comment> tag 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 fad is the address of the function to query
/// \param flags specifies the properties the query will match (must be non-zero) /// \param flags specifies the properties the query will match (must be non-zero)
/// \return an XML document describing each comment /// \param decoder is the given stream decoder that will hold the result
Document *ArchitectureGhidra::getComments(const Address &fad,uint4 flags) /// \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); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getComments"); writeStringStream(sout,"getComments");
sout.write("\000\000\001\016",4); // Beginning of string header 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\017",4);
sout.write("\000\000\001\016",4); // Beginning of string header sout.write("\000\000\001\016",4); // Beginning of string header
sout << dec << flags; sout << dec << flags;
@ -646,7 +665,7 @@ Document *ArchitectureGhidra::getComments(const Address &fad,uint4 flags)
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
return readXMLAll(sin); return readAll(sin,decoder);
} }
/// The Ghidra client is queried for a range of bytes, which are returned /// 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); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getBytes"); writeStringStream(sout,"getBytes");
sout.write("\000\000\001\016",4); // Beginning of string header 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\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
@ -708,7 +728,8 @@ void ArchitectureGhidra::getStringData(vector<uint1> &buffer,const Address &addr
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
writeStringStream(sout,"getString"); writeStringStream(sout,"getString");
sout.write("\000\000\001\016",4); // Beginning of string header 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); sout.write("\000\000\001\017",4);
writeStringStream(sout,ct->getName()); writeStringStream(sout,ct->getName());
sout.write("\000\000\001\016",4); // Beginning of string header sout.write("\000\000\001\016",4); // Beginning of string header
@ -753,14 +774,14 @@ void ArchitectureGhidra::getStringData(vector<uint1> &buffer,const Address &addr
/// - CALLMECHANISM_TYPE /// - CALLMECHANISM_TYPE
/// - EXECUTABLEPCODE_TYPE /// - EXECUTABLEPCODE_TYPE
/// ///
/// This and additional context is provided to the Ghidra client which returns /// This and additional context is provided to the Ghidra client which passes back
/// an XML document describing the p-code. The document will be an \<inst> tag /// an \<inst> element containing individual \<op> tags corresponding to individual p-code ops.
/// containing individual \<op> tags corresponding to individual p-code ops.
/// \param name is the name of the injection /// \param name is the name of the injection
/// \param type is the type of injection /// \param type is the type of injection
/// \param con is the context object /// \param con is the context object
/// \return an XML document describing the p-code ops to inject /// \param decoder is the stream decoder which will hold the result
Document *ArchitectureGhidra::getPcodeInject(const string &name,int4 type,const InjectContext &con) /// \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); 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,"getXPcode");
writeStringStream(sout,name); writeStringStream(sout,name);
sout.write("\000\000\001\016",4); 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\017",4);
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
return readXMLAll(sin); return readAll(sin,decoder);
} }
/// The Ghidra client is provided a sequence of 1 or more integer values /// The Ghidra client is provided a sequence of 1 or more integer values
/// extracted from a CPOOLREF op. It returns an XML document describing /// extracted from a CPOOLREF op. A description of the constant pool record referenced by the integer(s)
/// the constant pool record referenced by the integer(s) or will throw /// is passed back in the given stream decoder, or an exception is thrown if the record isn't properly referenced.
/// an exception if record isn't properly referenced.
/// \param refs is an array of 1 or more integer values referencing a constant pool record /// \param refs is an array of 1 or more integer values referencing a constant pool record
/// \return a description of the record as a \<cpoolrec> XML document. /// \param decoder is the given stream decoder that will hold the result
Document *ArchitectureGhidra::getCPoolRef(const vector<uintb> &refs) /// \return \b true if the query completed successfully
bool ArchitectureGhidra::getCPoolRef(const vector<uintb> &refs,Decoder &decoder)
{ {
sout.write("\000\000\001\004",4); sout.write("\000\000\001\004",4);
@ -802,7 +824,7 @@ Document *ArchitectureGhidra::getCPoolRef(const vector<uintb> &refs)
sout.write("\000\000\001\005",4); sout.write("\000\000\001\005",4);
sout.flush(); sout.flush();
return readXMLAll(sin); return readAll(sin,decoder);
} }
// Document *ArchitectureGhidra::getScopeProperties(Scope *newscope) // 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 /// \param o is the output stream to the Ghidra client
ArchitectureGhidra::ArchitectureGhidra(const string &pspec,const string &cspec,const string &tspec, ArchitectureGhidra::ArchitectureGhidra(const string &pspec,const string &cspec,const string &tspec,
const string &corespec,istream &i,ostream &o) const string &corespec,istream &i,ostream &o)
: Architecture(), sin(i), sout(o) : Architecture(), sin(i), sout(o), encoder(sout)
{ {
print->setXML(true); print->setXML(true);

View file

@ -60,6 +60,7 @@ struct JavaError : public LowlevelError {
class ArchitectureGhidra : public Architecture { class ArchitectureGhidra : public Architecture {
istream &sin; ///< Input stream for interfacing with Ghidra istream &sin; ///< Input stream for interfacing with Ghidra
ostream &sout; ///< Output 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 mutable string warnings; ///< Warnings accumulated by the decompiler
string pspecxml; ///< XML pspec passed from Ghidra string pspecxml; ///< XML pspec passed from Ghidra
string cspecxml; ///< XML cspec passed from Ghidra string cspecxml; ///< XML cspec passed from Ghidra
@ -86,21 +87,21 @@ public:
istream &i,ostream &o); istream &i,ostream &o);
const string &getWarnings(void) const { return warnings; } ///< Get warnings produced by the last decompilation const string &getWarnings(void) const { return warnings; } ///< Get warnings produced by the last decompilation
void clearWarnings(void) { warnings.clear(); } ///< Clear warnings void clearWarnings(void) { warnings.clear(); } ///< Clear warnings
Document *getRegister(const string &regname); ///< Retrieve a register description given a name bool getRegister(const string &regname,Decoder &decoder); ///< Retrieve a register description given a name
string getRegisterName(const VarnodeData &vndata); ///< Retrieve a register name given its storage location 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 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 uint1 *getPcodePacked(const Address &addr); ///< Get p-code for a single instruction
Document *getMappedSymbolsXML(const Address &addr); ///< Get symbols associated with the given address bool getMappedSymbolsXML(const Address &addr,Decoder &decoder); ///< Get symbols associated with the given address
Document *getExternalRefXML(const Address &addr); ///< Retrieve a description of an external function bool getExternalRefXML(const Address &addr,Decoder &decoder); ///< Retrieve a description of an external function
Document *getNamespacePath(uint8 id); ///< Get a description of a namespace path 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 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 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 bool getType(const string &name,uint8 id,Decoder &decoder); ///< 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 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 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); bool getPcodeInject(const string &name,int4 type,const InjectContext &con,Decoder &decoder);
Document *getCPoolRef(const vector<uintb> &refs); ///< Resolve a constant pool reference bool getCPoolRef(const vector<uintb> &refs,Decoder &decoder); ///< Resolve a constant pool reference
// Document *getScopeProperties(Scope *newscope); // Document *getScopeProperties(Scope *newscope);
/// \brief Toggle whether the data-flow and control-flow is emitted as part of the main decompile action /// \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 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 readToResponse(istream &s); ///< Read the query response protocol marker
static void readResponseEnd(istream &s); ///< Read the ending 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 bool readAll(istream &s,Decoder &decoder); ///< Read a whole response as an XML document
static Document *readXMLStream(istream &s); ///< Receive an XML document from the client 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 *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 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); static void passJavaException(ostream &s,const string &tp,const string &msg);

View file

@ -19,11 +19,24 @@ const TrackedSet &ContextGhidra::getTrackedSet(const Address &addr) const
{ {
cache.clear(); cache.clear();
XmlDecode decoder;
((ArchitectureGhidra *)glb)->getTrackedRegisters(addr,decoder);
Document *doc = ((ArchitectureGhidra *)glb)->getTrackedRegisters(addr); uint4 elemId = decoder.openElement(ELEM_TRACKED_POINTSET);
Element *root = doc->getRoot(); decodeTracked(decoder,glb,cache);
decoder.closeElement(elemId);
restoreTracked(root,glb,cache);
delete doc;
return cache; 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
}

View file

@ -51,8 +51,8 @@ public:
virtual const TrackedSet &getTrackedSet(const Address &addr) const; virtual const TrackedSet &getTrackedSet(const Address &addr) const;
// Ignored routines (taken care of by GHIDRA) // Ignored routines (taken care of by GHIDRA)
virtual void restoreXml(const Element *el,const AddrSpaceManager *manage) {} virtual void decode(Decoder &decoder,const AddrSpaceManager *manage);
virtual void restoreFromSpec(const Element *el,const AddrSpaceManager *manage) {} virtual void decodeFromSpec(Decoder &decoder,const AddrSpaceManager *manage);
// Unimplemented routines (should never be called) // Unimplemented routines (should never be called)
virtual int getContextSize(void) const { virtual int getContextSize(void) const {
@ -63,8 +63,8 @@ public:
throw LowlevelError("getContext should not be called for GHIDRA"); } throw LowlevelError("getContext should not be called for GHIDRA"); }
virtual void registerVariable(const string &nm,int4 sbit,int4 ebit) { virtual void registerVariable(const string &nm,int4 sbit,int4 ebit) {
throw LowlevelError("registerVariable should not be called for GHIDRA"); } throw LowlevelError("registerVariable should not be called for GHIDRA"); }
virtual void saveXml(ostream &s) const { virtual void encode(Encoder &encoder) const {
throw LowlevelError("context::saveXml should not be called for GHIDRA"); } throw LowlevelError("context::encode should not be called for GHIDRA"); }
virtual TrackedSet &createSet(const Address &addr1,const Address &addr2) { virtual TrackedSet &createSet(const Address &addr1,const Address &addr2) {
throw LowlevelError("createSet should not be called for GHIDRA"); } throw LowlevelError("createSet should not be called for GHIDRA"); }

View file

@ -274,12 +274,9 @@ void DecompileAt::loadParameters(void)
{ {
GhidraCommand::loadParameters(); GhidraCommand::loadParameters();
Document *doc; XmlDecode decoder;
doc = ArchitectureGhidra::readXMLStream(sin); // Read XML of address directly from in stream ArchitectureGhidra::readStream(sin,decoder); // Read encoded address directly from in stream
addr = Address::restoreXml(doc->getRoot(),ghidra); // Parse XML for functions address addr = Address::decode(decoder,ghidra); // Decode for functions address
addr.toPhysical(); // Only for backward compatibility
// with SLED
delete doc;
} }
void DecompileAt::rawAction(void) void DecompileAt::rawAction(void)
@ -305,25 +302,18 @@ void DecompileAt::rawAction(void)
sout.write("\000\000\001\016",4); sout.write("\000\000\001\016",4);
// Write output XML directly to outstream // Write output XML directly to outstream
if (fd->isProcComplete()) { 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 << "<doc>\n"; sout << "<doc>\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")) { if (ghidra->getSendParamMeasures() && (ghidra->allacts.getCurrentName() == "paramid")) {
ParamIDAnalysis pidanalysis( fd, true ); // Only send back final prototype ParamIDAnalysis pidanalysis( fd, true ); // Only send back final prototype
pidanalysis.saveXml( sout, true ); pidanalysis.encode( encoder, true );
} }
else { else {
if (ghidra->getSendParamMeasures()) { if (ghidra->getSendParamMeasures()) {
ParamIDAnalysis pidanalysis( fd, false ); 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()&& if (ghidra->getSendCCode()&&
(ghidra->allacts.getCurrentName() == "decompile")) (ghidra->allacts.getCurrentName() == "decompile"))
ghidra->print->docFunction(fd); ghidra->print->docFunction(fd);
@ -337,10 +327,10 @@ void StructureGraph::loadParameters(void)
{ {
GhidraCommand::loadParameters(); GhidraCommand::loadParameters();
Document *doc;
doc = ArchitectureGhidra::readXMLStream(sin); XmlDecode decoder;
ingraph.restoreXml(doc->getRoot(),ghidra); ArchitectureGhidra::readStream(sin,decoder);
delete doc; ingraph.decode(decoder,ghidra);
} }
void StructureGraph::rawAction(void) void StructureGraph::rawAction(void)
@ -358,7 +348,8 @@ void StructureGraph::rawAction(void)
resultgraph.orderBlocks(); resultgraph.orderBlocks();
sout.write("\000\000\001\016",4); sout.write("\000\000\001\016",4);
resultgraph.saveXml(sout); XmlEncode encoder(sout);
resultgraph.encode(encoder);
sout.write("\000\000\001\017",4); sout.write("\000\000\001\017",4);
ingraph.clear(); ingraph.clear();
} }
@ -413,28 +404,12 @@ void SetAction::sendResult(void)
GhidraCommand::sendResult(); GhidraCommand::sendResult();
} }
SetOptions::SetOptions(void) : GhidraCommand()
{
doc = (Document *)0;
}
SetOptions::~SetOptions(void)
{
if (doc != (Document *)0)
delete doc;
}
void SetOptions::loadParameters(void) void SetOptions::loadParameters(void)
{ {
GhidraCommand::loadParameters(); GhidraCommand::loadParameters();
if (doc != (Document *)0) { decoder.clear();
delete doc; ArchitectureGhidra::readStream(sin,decoder);
doc = (Document *)0;
}
doc = ArchitectureGhidra::readXMLStream(sin);
} }
void SetOptions::rawAction(void) void SetOptions::rawAction(void)
@ -443,9 +418,8 @@ void SetOptions::rawAction(void)
res = false; res = false;
ghidra->resetDefaults(); ghidra->resetDefaults();
ghidra->options->restoreXml(doc->getRoot()); ghidra->options->decode(decoder);
delete doc; decoder.clear();
doc = (Document *)0;
res = true; res = true;
} }
@ -514,6 +488,8 @@ int main(int argc,char **argv)
{ {
signal(SIGSEGV, &ArchitectureGhidra::segvHandler); // Exit on SEGV errors signal(SIGSEGV, &ArchitectureGhidra::segvHandler); // Exit on SEGV errors
AttributeId::initialize();
ElementId::initialize();
CapabilityPoint::initializeAll(); CapabilityPoint::initializeAll();
int4 status = 0; int4 status = 0;
while(status == 0) { while(status == 0) {

View file

@ -220,12 +220,10 @@ public:
/// The command returns a single character message, 't' or 'f', indicating whether the /// The command returns a single character message, 't' or 'f', indicating whether the
/// configuration succeeded. /// configuration succeeded.
class SetOptions : public GhidraCommand { class SetOptions : public GhidraCommand {
Document *doc; ///< The XML option document XmlDecode decoder; ///< The XML option document
virtual void loadParameters(void); virtual void loadParameters(void);
virtual void sendResult(void); virtual void sendResult(void);
public: public:
SetOptions(void);
virtual ~SetOptions(void);
bool res; ///< Set to \b true if the option change succeeded bool res; ///< Set to \b true if the option change succeeded
virtual void rawAction(void); virtual void rawAction(void);
}; };

View file

@ -36,7 +36,8 @@ void GhidraTranslate::initialize(DocumentStorage &store)
const Element *el = store.getTag("sleigh"); const Element *el = store.getTag("sleigh");
if (el == (const Element *)0) if (el == (const Element *)0)
throw LowlevelError("Could not find ghidra sleigh tag"); throw LowlevelError("Could not find ghidra sleigh tag");
restoreXml(el); XmlDecode decoder(el);
decode(decoder);
} }
const VarnodeData &GhidraTranslate::getRegister(const string &nm) const const VarnodeData &GhidraTranslate::getRegister(const string &nm) const
@ -45,9 +46,10 @@ const VarnodeData &GhidraTranslate::getRegister(const string &nm) const
map<string,VarnodeData>::const_iterator iter = nm2addr.find(nm); map<string,VarnodeData>::const_iterator iter = nm2addr.find(nm);
if (iter != nm2addr.end()) if (iter != nm2addr.end())
return (*iter).second; return (*iter).second;
Document *doc; XmlDecode decoder;
try { 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) { catch(XmlError &err) {
ostringstream errmsg; ostringstream errmsg;
@ -55,16 +57,13 @@ const VarnodeData &GhidraTranslate::getRegister(const string &nm) const
errmsg << " -- " << err.explain; errmsg << " -- " << err.explain;
throw LowlevelError(errmsg.str()); throw LowlevelError(errmsg.str());
} }
if (doc == (Document *)0)
throw LowlevelError("No register named "+nm);
Address regaddr; Address regaddr;
int4 regsize; int4 regsize;
regaddr = Address::restoreXml( doc->getRoot(), this, regsize); regaddr = Address::decode( decoder, this, regsize);
VarnodeData vndata; VarnodeData vndata;
vndata.space = regaddr.getSpace(); vndata.space = regaddr.getSpace();
vndata.offset = regaddr.getOffset(); vndata.offset = regaddr.getOffset();
vndata.size = regsize; vndata.size = regsize;
delete doc;
return cacheRegister(nm,vndata); return cacheRegister(nm,vndata);
} }
@ -142,33 +141,23 @@ int4 GhidraTranslate::oneInstruction(PcodeEmit &emit,const Address &baseaddr) co
return offset; return offset;
} }
/// The Ghidra client passes descriptions of address spaces and other /// Parse the \<sleigh> element passed back by the Ghidra client, describing address spaces
/// information that needs to be cached by the decompiler /// and other information that needs to be cached by the decompiler.
/// \param el is the element of the initialization tag /// \param decoder is the stream decoder
void GhidraTranslate::restoreXml(const Element *el) void GhidraTranslate::decode(Decoder &decoder)
{ {
setBigEndian(xml_readbool(el->getAttributeValue("bigendian"))); uint4 elemId = decoder.openElement(ELEM_SLEIGH);
{ setBigEndian(decoder.readBool(ATTRIB_BIGENDIAN));
istringstream s(el->getAttributeValue("uniqbase")); setUniqueBase(decoder.readUnsignedInteger(ATTRIB_UNIQBASE));
s.unsetf(ios::dec | ios::hex | ios::oct); decodeSpaces(decoder,this);
uintm ubase; for(;;) {
s >> ubase; uint4 subId = decoder.peekElement();
setUniqueBase(ubase); if (subId != ELEM_TRUNCATE_SPACE) break;
}
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; TruncationTag tag;
tag.restoreXml(subel); tag.decode(decoder);
truncateSpace(tag); truncateSpace(tag);
} }
++iter; decoder.closeElement(elemId);
}
} }

View file

@ -36,7 +36,7 @@ class GhidraTranslate : public Translate {
mutable map<string,VarnodeData> nm2addr; ///< Mapping from register name to Varnode mutable map<string,VarnodeData> nm2addr; ///< Mapping from register name to Varnode
mutable map<VarnodeData,string> addr2nm; ///< Mapping rom Varnode to register name mutable map<VarnodeData,string> addr2nm; ///< Mapping rom Varnode to register name
const VarnodeData &cacheRegister(const string &nm,const VarnodeData &data) const; 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: public:
GhidraTranslate(ArchitectureGhidra *g) { glb = g; } ///< Constructor GhidraTranslate(ArchitectureGhidra *g) { glb = g; } ///< Constructor

View file

@ -15,6 +15,14 @@
*/ */
#include "globalcontext.hh" #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 /// 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 /// in the first word in the sequence. The new context value must be contained within a single
/// word. /// word.
@ -30,76 +38,64 @@ ContextBitRange::ContextBitRange(int4 sbit,int4 ebit)
mask = (~((uintm)0))>>(startbit+shift); mask = (~((uintm)0))>>(startbit+shift);
} }
/// The register storage and value are serialized as a \<set> tag. /// The register storage and value are encoded as a \<set> element.
/// \param s is the output stream /// \param encoder is the stream encoder
void TrackedContext::saveXml(ostream &s) const void TrackedContext::encode(Encoder &encoder) const
{ {
s << "<set"; encoder.openElement(ELEM_SET);
loc.space->saveXmlAttributes(s,loc.offset,loc.size); loc.space->encodeAttributes(encoder,loc.offset,loc.size);
a_v_u(s,"val",val); encoder.writeUnsignedInteger(ATTRIB_VAL, val);
s << "/>\n"; encoder.closeElement(ELEM_SET);
} }
/// Read a \<set> tag to fill in the storage and value details /// Parse a \<set> element to fill in the storage and value details.
/// \param el is the root \<set> tag /// \param decoder is the stream decoder
/// \param manage is the manager used to decode address references /// \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; uint4 elemId = decoder.openElement(ELEM_SET);
Address addr = Address::restoreXml(el,manage,size); loc.decodeFromAttributes(decoder, manage);
istringstream s(el->getAttributeValue("val")); val = decoder.readUnsignedInteger(ATTRIB_VAL);
s.unsetf(ios::dec | ios::hex | ios::oct); decoder.closeElement(elemId);
s >> val;
loc.space = addr.getSpace();
loc.offset = addr.getOffset();
loc.size = size;
} }
/// \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 /// Encode all the tracked register values associated with a specific target address
/// as a \<tracked_pointset> tag. /// as a \<tracked_pointset> 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 addr is the specific address we have tracked values for
/// \param vec is the list of tracked values /// \param vec is the list of tracked values
void ContextDatabase::saveTracked(ostream &s,const Address &addr, void ContextDatabase::encodeTracked(Encoder &encoder,const Address &addr,const TrackedSet &vec)
const TrackedSet &vec)
{ {
if (vec.empty()) return; if (vec.empty()) return;
s << "<tracked_pointset"; encoder.openElement(ELEM_TRACKED_POINTSET);
addr.getSpace()->saveXmlAttributes(s,addr.getOffset() ); addr.getSpace()->encodeAttributes(encoder,addr.getOffset() );
s << ">\n";
for(int4 i=0;i<vec.size();++i) { for(int4 i=0;i<vec.size();++i) {
s << " "; vec[i].encode(encoder);
vec[i].saveXml(s);
} }
s << "</tracked_pointset>\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 \<tracked_pointset> tag, decode each child in turn populating a list of /// Parse a \<tracked_pointset> element, decoding each child in turn to populate a list of
/// TrackedContext objects. /// 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 manage is used to resolve address space references
/// \param vec is the container that will hold the new TrackedContext objects /// \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) TrackedSet &vec)
{ {
vec.clear(); // Clear out any old stuff vec.clear(); // Clear out any old stuff
const List &list(el->getChildren()); while(decoder.peekElement() != 0) {
List::const_iterator iter = list.begin();
while(iter != list.end()) {
const Element *subel = *iter;
vec.emplace_back(); vec.emplace_back();
vec.back().restoreXml(subel,manage); vec.back().decode(decoder,manage);
++iter;
} }
} }
@ -314,54 +310,47 @@ ContextInternal::FreeArray &ContextInternal::FreeArray::operator=(const FreeArra
return *this; 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 /// The blob is broken up into individual values and written out as a series
/// of \<set> tags within a parent \<context_pointset> tag. /// of \<set> elements within a parent \<context_pointset> element.
/// \param s is the output stream /// \param encoder is the stream encoder
/// \param addr is the address of the split point where the blob is valid /// \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 /// \param vec is the array of words holding the blob values
void ContextInternal::saveContext(ostream &s,const Address &addr, void ContextInternal::encodeContext(Encoder &encoder,const Address &addr,const uintm *vec) const
const uintm *vec) const
{ {
s << "<context_pointset"; encoder.openElement(ELEM_CONTEXT_POINTSET);
addr.getSpace()->saveXmlAttributes(s,addr.getOffset() ); addr.getSpace()->encodeAttributes(encoder,addr.getOffset() );
s << ">\n";
map<string,ContextBitRange>::const_iterator iter; map<string,ContextBitRange>::const_iterator iter;
for(iter=variables.begin();iter!=variables.end();++iter) { for(iter=variables.begin();iter!=variables.end();++iter) {
uintm val = (*iter).second.getValue(vec); uintm val = (*iter).second.getValue(vec);
s << " <set"; encoder.openElement(ELEM_SET);
a_v(s,"name",(*iter).first); encoder.writeString(ATTRIB_NAME, (*iter).first);
a_v_u(s,"val",val); encoder.writeUnsignedInteger(ATTRIB_VAL, val);
s << "/>\n"; encoder.closeElement(ELEM_SET);
} }
s << "</context_pointset>\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 \<context_pointset> or \<context_set>. In either case, /// Parse either a \<context_pointset> or \<context_set> element. In either case,
/// children are parsed to get context variable values. Then a context blob is /// 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 /// 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 /// 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 /// the context variables are painted. The second address can be invalid, if
/// only a split point is known. /// 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 addr1 is the starting address of the given range
/// \param addr2 is the ending 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()); for(;;) {
List::const_iterator iter = list.begin(); uint4 subId = decoder.openElement();
if (subId != ELEM_SET) break;
while(iter != list.end()) { uintm val = decoder.readUnsignedInteger(ATTRIB_VAL);
const Element *subel = *iter; ContextBitRange &var(getVariable(decoder.readString(ATTRIB_NAME)));
istringstream s(subel->getAttributeValue("val"));
s.unsetf(ios::dec | ios::hex | ios::oct);
uintm val;
s >> val;
ContextBitRange &var(getVariable(subel->getAttributeValue("name")));
vector<uintm *> vec; vector<uintm *> vec;
if (addr1.isInvalid()) { // Invalid addr1, indicates we should set default value if (addr1.isInvalid()) { // Invalid addr1, indicates we should set default value
uintm *defaultBuffer = getDefaultValue(); 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()<<var.getShift()); getRegionForSet(vec,addr1,addr2,var.getWord(),var.getMask()<<var.getShift());
for(int4 i=0;i<vec.size();++i) for(int4 i=0;i<vec.size();++i)
var.setValue(vec[i],val); var.setValue(vec[i],val);
++iter; decoder.closeElement(subId);
} }
} }
@ -487,83 +476,81 @@ TrackedSet &ContextInternal::createSet(const Address &addr1,const Address &addr2
return res; return res;
} }
void ContextInternal::saveXml(ostream &s) const void ContextInternal::encode(Encoder &encoder) const
{ {
if (database.empty() && trackbase.empty()) return; if (database.empty() && trackbase.empty()) return;
s << "<context_points>\n"; encoder.openElement(ELEM_CONTEXT_POINTS);
partmap<Address,FreeArray>::const_iterator fiter,fenditer; partmap<Address,FreeArray>::const_iterator fiter,fenditer;
fiter = database.begin(); fiter = database.begin();
fenditer = database.end(); fenditer = database.end();
for(;fiter!=fenditer;++fiter) // Save context at each changepoint for(;fiter!=fenditer;++fiter) // Save context at each changepoint
saveContext(s,(*fiter).first,(*fiter).second.array); encodeContext(encoder,(*fiter).first,(*fiter).second.array);
partmap<Address,TrackedSet>::const_iterator titer,tenditer; partmap<Address,TrackedSet>::const_iterator titer,tenditer;
titer = trackbase.begin(); titer = trackbase.begin();
tenditer = trackbase.end(); tenditer = trackbase.end();
for(;titer!=tenditer;++titer) for(;titer!=tenditer;++titer)
saveTracked(s,(*titer).first,(*titer).second); encodeTracked(encoder,(*titer).first,(*titer).second);
s << "</context_points>\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()); uint4 elemId = decoder.openElement(ELEM_CONTEXT_POINTS);
List::const_iterator iter = list.begin(); for(;;) {
uint4 subId = decoder.openElement();
while(iter != list.end()) { if (subId == 0) break;
const Element *subel = *iter; if (subId == ELEM_CONTEXT_POINTSET) {
if (subel->getName() == "context_pointset") { uint4 attribId = decoder.getNextAttributeId();
if (subel->getNumAttributes()==0) { decoder.rewindAttributes();
restoreContext(subel,Address(),Address()); // Restore the default value if (attribId==0) {
decodeContext(decoder,Address(),Address()); // Restore the default value
} }
else { else {
Address addr = Address::restoreXml(subel,manage); VarnodeData vData;
restoreContext(subel,addr,Address()); vData.decodeFromAttributes(decoder, manage);
decodeContext(decoder,vData.getAddr(),Address());
} }
} }
else if (subel->getName() == "tracked_pointset") { else if (subId == ELEM_TRACKED_POINTSET) {
Address addr = Address::restoreXml(subel,manage); VarnodeData vData;
restoreTracked(subel,manage,trackbase.split(addr) ); vData.decodeFromAttributes(decoder, manage);
decodeTracked(decoder,manage,trackbase.split(vData.getAddr()) );
} }
else else
throw LowlevelError("Bad <context_points> tag: "+subel->getName()); throw LowlevelError("Bad <context_points> tag");
++iter; 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()); uint4 elemId = decoder.openElement(ELEM_CONTEXT_DATA);
List::const_iterator iter = list.begin(); for(;;) {
uint4 subId = decoder.openElement();
while(iter != list.end()) { if (subId == 0) break;
const Element *subel = *iter;
if (subel->getName() == "context_set") {
Range range; Range range;
range.restoreXml(subel,manage); // There MUST be a range range.decodeFromAttributes(decoder, manage); // There MUST be a range
Address addr1,addr2; Address addr1 = range.getFirstAddr();
addr1 = range.getFirstAddr(); Address addr2 = range.getLastAddrOpen(manage);
addr2 = range.getLastAddrOpen(manage); if (subId == ELEM_CONTEXT_SET) {
restoreContext(subel,addr1,addr2); decodeContext(decoder,addr1,addr2);
} }
else if (subel->getName() == "tracked_set") { else if (subId == ELEM_TRACKED_SET) {
Range range; decodeTracked(decoder,manage,createSet(addr1,addr2));
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 else
throw LowlevelError("Bad <context_data> tag: "+subel->getName()); throw LowlevelError("Bad <context_data> tag");
++iter; decoder.closeElement(subId);
} }
decoder.closeElement(elemId);
} }
/// \param db is the context database that will be encapsulated /// \param db is the context database that will be encapsulated

View file

@ -22,6 +22,14 @@
#include "pcoderaw.hh" #include "pcoderaw.hh"
#include "partmap.hh" #include "partmap.hh"
extern ElementId ELEM_CONTEXT_DATA; ///< Marshaling element \<context_data>
extern ElementId ELEM_CONTEXT_POINTS; ///< Marshaling element \<context_points>
extern ElementId ELEM_CONTEXT_POINTSET; ///< Marshaling element \<context_pointset>
extern ElementId ELEM_CONTEXT_SET; ///< Marshaling element \<context_set>
extern ElementId ELEM_SET; ///< Marshaling element \<set>
extern ElementId ELEM_TRACKED_POINTSET; ///< Marshaling element \<tracked_pointset>
extern ElementId ELEM_TRACKED_SET; ///< Marshaling element \<tracked_set>
/// \brief Description of a context variable within the disassembly context \e blob /// \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 /// 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 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 uintm mask; ///< Mask to apply (after shifting) when unpacking this value from its word
public: 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 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 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 uintm getMask(void) const { return mask; } ///< Return the mask for \b this value
@ -68,8 +76,8 @@ public:
struct TrackedContext { struct TrackedContext {
VarnodeData loc; ///< Storage details of the register being tracked VarnodeData loc; ///< Storage details of the register being tracked
uintb val; ///< The value of the register uintb val; ///< The value of the register
void restoreXml(const Element *el,const AddrSpaceManager *manage); ///< Restore \b this from an XML stream void decode(Decoder &decoder,const AddrSpaceManager *manage); ///< Decode \b this from a stream
void saveXml(ostream &s) const; ///< Save \b this to an XML stream void encode(Encoder &encoder) const; ///< Encode \b this to a stream
}; };
typedef vector<TrackedContext> TrackedSet; ///< A set of tracked registers and their values (at one code point) typedef vector<TrackedContext> TrackedSet; ///< A set of tracked registers and their values (at one code point)
@ -107,8 +115,8 @@ typedef vector<TrackedContext> TrackedSet; ///< A set of tracked registers and
/// a list of TrackedContext objects. /// a list of TrackedContext objects.
class ContextDatabase { class ContextDatabase {
protected: protected:
static void saveTracked(ostream &s,const Address &addr,const TrackedSet &vec); static void encodeTracked(Encoder &encoder,const Address &addr,const TrackedSet &vec);
static void restoreTracked(const Element *el,const AddrSpaceManager *manage,TrackedSet &vec); static void decodeTracked(Decoder &decoder,const AddrSpaceManager *manage,TrackedSet &vec);
/// \brief Retrieve the context variable description object by name /// \brief Retrieve the context variable description object by name
/// ///
@ -218,24 +226,24 @@ public:
/// \return the empty set of tracked register values /// \return the empty set of tracked register values
virtual TrackedSet &createSet(const Address &addr1,const Address &addr2)=0; 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 /// \param encoder is the stream encoder
virtual void saveXml(ostream &s) const=0; 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 /// \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 /// Parse a \<context_data> element from the given stream decoder from either the compiler
/// \<context_data> tags in either the compiler or processor specification file for the architecture /// or processor specification file for the architecture, initializing this database.
/// \param el is a \<context_data> tag /// \param decoder is the given stream decoder
/// \param manage is used to resolve address space references /// \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 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 uintm getDefaultValue(const string &nm) const; ///< Retrieve the default value for a context variable
@ -274,8 +282,8 @@ class ContextInternal : public ContextDatabase {
map<string,ContextBitRange> variables; ///< Map from context variable name to description object map<string,ContextBitRange> variables; ///< Map from context variable name to description object
partmap<Address,FreeArray> database; ///< Partition map of context blobs (FreeArray) partmap<Address,FreeArray> database; ///< Partition map of context blobs (FreeArray)
partmap<Address,TrackedSet> trackbase; ///< Partition map of tracked register sets partmap<Address,TrackedSet> trackbase; ///< Partition map of tracked register sets
void saveContext(ostream &s,const Address &addr,const uintm *vec) const; void encodeContext(Encoder &encoder,const Address &addr,const uintm *vec) const;
void restoreContext(const Element *el,const Address &addr1,const Address &addr2); void decodeContext(Decoder &decoder,const Address &addr1,const Address &addr2);
virtual ContextBitRange &getVariable(const string &nm); virtual ContextBitRange &getVariable(const string &nm);
virtual const ContextBitRange &getVariable(const string &nm) const; virtual const ContextBitRange &getVariable(const string &nm) const;
virtual void getRegionForSet(vector<uintm *> &res,const Address &addr1, virtual void getRegionForSet(vector<uintm *> &res,const Address &addr1,
@ -296,9 +304,9 @@ public:
virtual const TrackedSet &getTrackedSet(const Address &addr) const { return trackbase.getValue(addr); } virtual const TrackedSet &getTrackedSet(const Address &addr) const { return trackbase.getValue(addr); }
virtual TrackedSet &createSet(const Address &addr1,const Address &addr2); virtual TrackedSet &createSet(const Address &addr1,const Address &addr2);
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual void restoreXml(const Element *el,const AddrSpaceManager *manage); virtual void decode(Decoder &decoder,const AddrSpaceManager *manage);
virtual void restoreFromSpec(const Element *el,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 /// \brief A helper class for caching the active context blob to minimize database lookups

View file

@ -314,7 +314,7 @@ void IfcOption::execute(istream &s)
} }
try { 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; *status->optr << res << endl;
} }
catch(ParseError &err) { catch(ParseError &err) {
@ -2690,7 +2690,8 @@ void IfcCallGraphDump::execute(istream &s)
if (!os) if (!os)
throw IfaceExecutionError("Unable to open file "+name); throw IfaceExecutionError("Unable to open file "+name);
dcp->cgraph->saveXml(os); XmlEncode encoder(os);
dcp->cgraph->encode(encoder);
os.close(); os.close();
*status->optr << "Successfully saved callgraph to " << name << endl; *status->optr << "Successfully saved callgraph to " << name << endl;
} }
@ -2723,7 +2724,8 @@ void IfcCallGraphLoad::execute(istream &s)
Document *doc = store.parseDocument(is); Document *doc = store.parseDocument(is);
dcp->allocateCallGraph(); dcp->allocateCallGraph();
dcp->cgraph->restoreXml(doc->getRoot()); XmlDecode decoder(doc->getRoot());
dcp->cgraph->decoder(decoder);
*status->optr << "Successfully read in callgraph" << endl; *status->optr << "Successfully read in callgraph" << endl;
Scope *gscope = dcp->conf->symboltab->getGlobalScope(); Scope *gscope = dcp->conf->symboltab->getGlobalScope();
@ -3014,7 +3016,8 @@ void IfcStructureBlocks::execute(istream &s)
try { try {
BlockGraph ingraph; BlockGraph ingraph;
ingraph.restoreXml(doc->getRoot(),dcp->conf); XmlDecode decoder(doc->getRoot());
ingraph.decode(decoder,dcp->conf);
BlockGraph resultgraph; BlockGraph resultgraph;
vector<FlowBlock *> rootlist; vector<FlowBlock *> rootlist;
@ -3030,7 +3033,8 @@ void IfcStructureBlocks::execute(istream &s)
sout.open(outfile.c_str()); sout.open(outfile.c_str());
if (!sout) if (!sout)
throw IfaceExecutionError("Unable to open output file: "+outfile); throw IfaceExecutionError("Unable to open output file: "+outfile);
resultgraph.saveXml(sout); XmlEncode encoder(sout);
resultgraph.encode(encoder);
sout.close(); sout.close();
} }
catch(LowlevelError &err) { catch(LowlevelError &err) {

View file

@ -15,42 +15,43 @@
*/ */
#include "inject_ghidra.hh" #include "inject_ghidra.hh"
void InjectContextGhidra::saveXml(ostream &s) const void InjectContextGhidra::encode(Encoder &encoder) const
{ {
s << "<context>\n"; encoder.openElement(ELEM_CONTEXT);
baseaddr.saveXml(s); baseaddr.encode(encoder);
calladdr.saveXml(s); calladdr.encode(encoder);
if (!inputlist.empty()) { if (!inputlist.empty()) {
s << "<input>\n"; encoder.openElement(ELEM_INPUT);
for(int4 i=0;i<inputlist.size();++i) { for(int4 i=0;i<inputlist.size();++i) {
const VarnodeData &vn( inputlist[i] ); const VarnodeData &vn( inputlist[i] );
s << "<addr"; encoder.openElement(ELEM_ADDR);
vn.space->saveXmlAttributes(s,vn.offset,vn.size); vn.space->encodeAttributes(encoder,vn.offset,vn.size);
s << "/>\n"; encoder.closeElement(ELEM_ADDR);
} }
s << "</input>\n"; encoder.closeElement(ELEM_INPUT);
} }
if (!output.empty()) { if (!output.empty()) {
s << "<output>\n"; encoder.openElement(ELEM_OUTPUT);
for(int4 i=0;i<output.size();++i) { for(int4 i=0;i<output.size();++i) {
const VarnodeData &vn( output[i] ); const VarnodeData &vn( output[i] );
s << "<addr"; encoder.openElement(ELEM_ADDR);
vn.space->saveXmlAttributes(s,vn.offset,vn.size); vn.space->encodeAttributes(encoder,vn.offset,vn.size);
s << "/>\n"; encoder.closeElement(ELEM_ADDR);
} }
s << "</output>\n"; encoder.closeElement(ELEM_OUTPUT);
} }
s << "</context>\n"; encoder.closeElement(ELEM_CONTEXT);
} }
void InjectPayloadGhidra::inject(InjectContext &con,PcodeEmit &emit) const void InjectPayloadGhidra::inject(InjectContext &con,PcodeEmit &emit) const
{ {
Document *doc;
ArchitectureGhidra *ghidra = (ArchitectureGhidra *)con.glb; ArchitectureGhidra *ghidra = (ArchitectureGhidra *)con.glb;
XmlDecode decoder;
try { 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) { catch(JavaError &err) {
throw LowlevelError("Error getting pcode snippet: " + err.explain); throw LowlevelError("Error getting pcode snippet: " + err.explain);
@ -58,15 +59,19 @@ void InjectPayloadGhidra::inject(InjectContext &con,PcodeEmit &emit) const
catch(XmlError &err) { catch(XmlError &err) {
throw LowlevelError("Error in pcode snippet xml: "+err.explain); throw LowlevelError("Error in pcode snippet xml: "+err.explain);
} }
if (doc == (Document *)0) { uint4 elemId = decoder.openElement();
throw LowlevelError("Could not retrieve pcode snippet: "+name); while(decoder.peekElement() != 0)
} emit.decodeOp(decoder,ghidra->translate);
const Element *el = doc->getRoot(); decoder.closeElement(elemId);
const List &list(el->getChildren()); }
List::const_iterator iter;
for(iter=list.begin();iter!=list.end();++iter) void InjectPayloadGhidra::decode(Decoder &decoder)
emit.restoreXmlOp(*iter,ghidra->translate);
delete doc; {
// Restore a raw <pcode> tag. Used for uponentry, uponreturn
uint4 elemId = decoder.openElement(ELEM_PCODE);
decodePayloadAttributes(decoder);
decoder.closeElementSkipping(elemId);
} }
void InjectPayloadGhidra::printTemplate(ostream &s) const 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) 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()); uint4 elemId = decoder.openElement(ELEM_CALLOTHERFIXUP);
List::const_iterator iter; name = decoder.readString(ATTRIB_TARGETOP);
name = el->getAttributeValue("targetop"); uint4 subId = decoder.openElement();
iter = list.begin(); if (subId != ELEM_PCODE)
if ((iter == list.end()) || ((*iter)->getName() != "pcode"))
throw LowlevelError("<callotherfixup> does not contain a <pcode> tag"); throw LowlevelError("<callotherfixup> does not contain a <pcode> 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) 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 void ExecutablePcodeGhidra::inject(InjectContext &con,PcodeEmit &emit) const
{ {
Document *doc;
ArchitectureGhidra *ghidra = (ArchitectureGhidra *)con.glb; ArchitectureGhidra *ghidra = (ArchitectureGhidra *)con.glb;
XmlDecode decoder;
try { 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) { catch(JavaError &err) {
throw LowlevelError("Error getting pcode snippet: " + err.explain); throw LowlevelError("Error getting pcode snippet: " + err.explain);
@ -122,22 +132,22 @@ void ExecutablePcodeGhidra::inject(InjectContext &con,PcodeEmit &emit) const
catch(XmlError &err) { catch(XmlError &err) {
throw LowlevelError("Error in pcode snippet xml: "+err.explain); throw LowlevelError("Error in pcode snippet xml: "+err.explain);
} }
if (doc == (Document *)0) { uint4 elemId = decoder.openElement();
throw LowlevelError("Could not retrieve pcode snippet: "+name); while(decoder.peekElement() != 0)
} emit.decodeOp(decoder,ghidra->translate);
const Element *el = doc->getRoot(); decoder.closeElement(elemId);
const List &list(el->getChildren());
List::const_iterator iter;
for(iter=list.begin();iter!=list.end();++iter)
emit.restoreXmlOp(*iter,ghidra->translate);
delete doc;
} }
void ExecutablePcodeGhidra::restoreXml(const Element *el) void ExecutablePcodeGhidra::decode(Decoder &decoder)
{ {
InjectPayload::restoreXml(el); // Read parameters uint4 elemId = decoder.openElement();
// But ignore rest of body if (elemId != ELEM_CASE_PCODE && elemId != ELEM_ADDR_PCODE &&
elemId != ELEM_DEFAULT_PCODE && elemId != ELEM_SIZE_PCODE)
throw XmlError("Expecting <case_pcode>, <addr_pcode>, <default_pcode>, or <size_pcode>");
decodePayloadAttributes(decoder);
decodePayloadParams(decoder); // Parse the parameters
decoder.closeElementSkipping(elemId); // But skip rest of body
} }
void ExecutablePcodeGhidra::printTemplate(ostream &s) const void ExecutablePcodeGhidra::printTemplate(ostream &s) const

View file

@ -28,7 +28,7 @@
/// that can then be forwarded to the Ghidra client. /// that can then be forwarded to the Ghidra client.
class InjectContextGhidra : public InjectContext { class InjectContextGhidra : public InjectContext {
public: 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 /// \brief An injection payload that uses a Ghidra client to generate the p-code ops
@ -41,7 +41,7 @@ class InjectPayloadGhidra : public InjectPayload {
public: public:
InjectPayloadGhidra(const string &src,const string &nm,int4 tp) : InjectPayload(nm,tp) { source = src; } ///< Constructor 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 inject(InjectContext &context,PcodeEmit &emit) const;
virtual void restoreXml(const Element *el) {} virtual void decode(Decoder &decoder);
virtual void printTemplate(ostream &s) const; virtual void printTemplate(ostream &s) const;
virtual string getSource(void) const { return source; } virtual string getSource(void) const { return source; }
}; };
@ -50,14 +50,14 @@ public:
class InjectCallfixupGhidra : public InjectPayloadGhidra { class InjectCallfixupGhidra : public InjectPayloadGhidra {
public: public:
InjectCallfixupGhidra(const string &src,const string &nm); ///< Constructor 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 /// \brief A callother-fixup injection that uses a Ghidra client to generate the p-code ops
class InjectCallotherGhidra : public InjectPayloadGhidra { class InjectCallotherGhidra : public InjectPayloadGhidra {
public: public:
InjectCallotherGhidra(const string &src,const string &nm); ///< Constructor 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 /// \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: public:
ExecutablePcodeGhidra(Architecture *g,const string &src,const string &nm); ///< Constructor ExecutablePcodeGhidra(Architecture *g,const string &src,const string &nm); ///< Constructor
virtual void inject(InjectContext &context,PcodeEmit &emit) const; 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 void printTemplate(ostream &s) const;
}; };

View file

@ -61,22 +61,31 @@ void InjectPayloadSleigh::inject(InjectContext &context,PcodeEmit &emit) const
con.cacher.emit(con.baseaddr,&emit); 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); uint4 elemId = decoder.openElement(); // Tag may not be present
const List &list(el->getChildren()); if (elemId == ELEM_BODY) {
List::const_iterator iter; parsestring = decoder.readString(ATTRIB_CONTENT);
for(iter=list.begin();iter!=list.end();++iter) { decoder.closeElement(elemId);
const Element *subel = *iter;
if (subel->getName() == "body") {
parsestring = subel->getContent();
}
} }
if (parsestring.size() == 0 && (!dynamic)) if (parsestring.size() == 0 && (!dynamic))
throw LowlevelError("Missing <body> subtag in <pcode>: "+getSource()); throw LowlevelError("Missing <body> subtag in <pcode>: "+getSource());
} }
void InjectPayloadSleigh::decode(Decoder &decoder)
{
// Restore a raw <pcode> 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 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()); uint4 elemId = decoder.openElement(ELEM_CALLFIXUP);
List::const_iterator iter; name = decoder.readString(ATTRIB_NAME);
name = el->getAttributeValue("name");
bool pcodeSubtag = false; bool pcodeSubtag = false;
for(iter=list.begin();iter!=list.end();++iter) { for(;;) {
const Element *subel = *iter; uint4 subId = decoder.openElement();
if (subel->getName() == "pcode") { if (subId == 0) break;
InjectPayloadSleigh::restoreXml(subel); if (subId == ELEM_PCODE) {
decodePayloadAttributes(decoder);
decodePayloadParams(decoder);
decodeBody(decoder);
pcodeSubtag = true; pcodeSubtag = true;
} }
else if (subel->getName() == "target") else if (subId == ELEM_TARGET)
targetSymbolNames.push_back(subel->getAttributeValue("name")); targetSymbolNames.push_back(decoder.readString(ATTRIB_NAME));
decoder.closeElement(subId);
} }
decoder.closeElement(elemId);
if (!pcodeSubtag) if (!pcodeSubtag)
throw LowlevelError("<callfixup> is missing <pcode> subtag: "+name); throw LowlevelError("<callfixup> is missing <pcode> 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()); uint4 elemId = decoder.openElement(ELEM_CALLOTHERFIXUP);
List::const_iterator iter; name = decoder.readString(ATTRIB_TARGETOP);
name = el->getAttributeValue("targetop"); uint4 subId = decoder.openElement();
iter = list.begin(); if (subId != ELEM_PCODE)
if ((iter == list.end()) || ((*iter)->getName() != "pcode"))
throw LowlevelError("<callotherfixup> does not contain a <pcode> tag"); throw LowlevelError("<callotherfixup> does not contain a <pcode> 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) 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); con.cacher.emit(con.baseaddr,&emit);
} }
void ExecutablePcodeSleigh::restoreXml(const Element *el) void ExecutablePcodeSleigh::decode(Decoder &decoder)
{ {
InjectPayload::restoreXml(el); uint4 elemId = decoder.openElement();
const List &list(el->getChildren()); if (elemId != ELEM_CASE_PCODE && elemId != ELEM_ADDR_PCODE && elemId != ELEM_DEFAULT_PCODE && elemId != ELEM_SIZE_PCODE)
List::const_iterator iter; throw XmlError("Expecting <case_pcode>, <addr_pcode>, <default_pcode>, or <size_pcode>");
bool hasbody = false; decodePayloadAttributes(decoder);
for (iter = list.begin(); iter != list.end(); ++iter) { decodePayloadParams(decoder);
const Element *subel = *iter; uint4 subId = decoder.openElement(ELEM_BODY);
if (subel->getName() == "body") { parsestring = decoder.readString(ATTRIB_CONTENT);
hasbody = true; decoder.closeElement(subId);
parsestring = subel->getContent(); decoder.closeElement(elemId);
}
}
if (!hasbody)
throw LowlevelError("Missing <body> subtag in <pcode>: " + getSource());
} }
void ExecutablePcodeSleigh::printTemplate(ostream &s) const void ExecutablePcodeSleigh::printTemplate(ostream &s) const
@ -243,16 +255,12 @@ InjectPayloadDynamic::~InjectPayloadDynamic(void)
delete (*iter).second; delete (*iter).second;
} }
void InjectPayloadDynamic::restoreEntry(const Element *el) void InjectPayloadDynamic::decodeEntry(Decoder &decoder)
{ {
const List &list(el->getChildren()); Address addr = Address::decode(decoder,glb);
List::const_iterator iter; uint4 subId = decoder.openElement(ELEM_PAYLOAD);
istringstream s(decoder.readString(ATTRIB_CONTENT));
iter = list.begin();
Address addr = Address::restoreXml(*iter,glb);
++iter;
istringstream s((*iter)->getContent());
try { try {
Document *doc = xml_tree(s); Document *doc = xml_tree(s);
map<Address,Document *>::iterator iter = addrMap.find(addr); map<Address,Document *>::iterator iter = addrMap.find(addr);
@ -263,6 +271,7 @@ void InjectPayloadDynamic::restoreEntry(const Element *el)
catch(XmlError &err) { catch(XmlError &err) {
throw LowlevelError("Error in dynamic payload XML"); throw LowlevelError("Error in dynamic payload XML");
} }
decoder.closeElement(subId);
} }
void InjectPayloadDynamic::inject(InjectContext &context,PcodeEmit &emit) const void InjectPayloadDynamic::inject(InjectContext &context,PcodeEmit &emit) const
@ -272,10 +281,11 @@ void InjectPayloadDynamic::inject(InjectContext &context,PcodeEmit &emit) const
if (eiter == addrMap.end()) if (eiter == addrMap.end())
throw LowlevelError("Missing dynamic inject"); throw LowlevelError("Missing dynamic inject");
const Element *el = (*eiter).second->getRoot(); const Element *el = (*eiter).second->getRoot();
const List &list(el->getChildren()); XmlDecode decoder(el);
List::const_iterator iter; uint4 rootId = decoder.openElement(ELEM_INST);
for(iter=list.begin();iter!=list.end();++iter) while(decoder.peekElement() != 0)
emit.restoreXmlOp(*iter,glb->translate); emit.decodeOp(decoder,glb->translate);
decoder.closeElement(rootId);
} }
PcodeInjectLibrarySleigh::PcodeInjectLibrarySleigh(Architecture *g) 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()); uint4 elemId = decoder.openElement(ELEM_INJECTDEBUG);
List::const_iterator iter; for(;;) {
uint4 subId = decoder.openElement();
for(iter=list.begin();iter!=list.end();++iter) { if (subId != ELEM_INJECT) break;
const Element *subel = *iter; string name = decoder.readString(ATTRIB_NAME);
const string &name( subel->getAttributeValue("name") ); int4 type = decoder.readSignedInteger(ATTRIB_TYPE);
istringstream s( subel->getAttributeValue("type") );
int4 type = -1;
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> type;
int4 id = getPayloadId(type,name); int4 id = getPayloadId(type,name);
InjectPayloadDynamic *payload = dynamic_cast<InjectPayloadDynamic *>(getPayload(id)); InjectPayloadDynamic *payload = dynamic_cast<InjectPayloadDynamic *>(getPayload(id));
if (payload == (InjectPayloadDynamic *)0) { if (payload == (InjectPayloadDynamic *)0) {
payload = forceDebugDynamic(id); payload = forceDebugDynamic(id);
} }
payload->restoreEntry(subel); payload->decodeEntry(decoder);
decoder.closeElement(subId);
} }
decoder.closeElement(elemId);
} }
const vector<OpBehavior *> &PcodeInjectLibrarySleigh::getBehaviors(void) const vector<OpBehavior *> &PcodeInjectLibrarySleigh::getBehaviors(void)

View file

@ -25,7 +25,7 @@ public:
ParserContext *pos; ParserContext *pos;
InjectContextSleigh(void) { pos = (ParserContext *)0; } InjectContextSleigh(void) { pos = (ParserContext *)0; }
virtual ~InjectContextSleigh(void); 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 { class InjectPayloadSleigh : public InjectPayload {
@ -33,11 +33,13 @@ class InjectPayloadSleigh : public InjectPayload {
ConstructTpl *tpl; ConstructTpl *tpl;
string parsestring; string parsestring;
string source; string source;
protected:
void decodeBody(Decoder &decoder); ///< Parse the <body> tag
public: public:
InjectPayloadSleigh(const string &src,const string &nm,int4 tp); InjectPayloadSleigh(const string &src,const string &nm,int4 tp);
virtual ~InjectPayloadSleigh(void); virtual ~InjectPayloadSleigh(void);
virtual void inject(InjectContext &context,PcodeEmit &emit) const; 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 void printTemplate(ostream &s) const;
virtual string getSource(void) const { return source; } virtual string getSource(void) const { return source; }
@ -52,13 +54,13 @@ class InjectPayloadCallfixup : public InjectPayloadSleigh {
vector<string> targetSymbolNames; vector<string> targetSymbolNames;
public: public:
InjectPayloadCallfixup(const string &sourceName); InjectPayloadCallfixup(const string &sourceName);
virtual void restoreXml(const Element *el); virtual void decode(Decoder &decoder);
}; };
class InjectPayloadCallother : public InjectPayloadSleigh { class InjectPayloadCallother : public InjectPayloadSleigh {
public: public:
InjectPayloadCallother(const string &sourceName); InjectPayloadCallother(const string &sourceName);
virtual void restoreXml(const Element *el); virtual void decode(Decoder &decoder);
}; };
class ExecutablePcodeSleigh : public ExecutablePcode { class ExecutablePcodeSleigh : public ExecutablePcode {
@ -70,7 +72,7 @@ protected:
ExecutablePcodeSleigh(Architecture *g,const string &src,const string &nm); ExecutablePcodeSleigh(Architecture *g,const string &src,const string &nm);
virtual ~ExecutablePcodeSleigh(void); virtual ~ExecutablePcodeSleigh(void);
virtual void inject(InjectContext &context,PcodeEmit &emit) const; 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 void printTemplate(ostream &s) const;
}; };
@ -80,8 +82,9 @@ class InjectPayloadDynamic : public InjectPayload {
public: public:
InjectPayloadDynamic(Architecture *g,const string &nm,int4 tp) : InjectPayload(nm,tp) { glb = g; dynamic = true; } InjectPayloadDynamic(Architecture *g,const string &nm,int4 tp) : InjectPayload(nm,tp) { glb = g; dynamic = true; }
virtual ~InjectPayloadDynamic(void); virtual ~InjectPayloadDynamic(void);
void restoreEntry(const Element *el); void decodeEntry(Decoder &decoder);
virtual void inject(InjectContext &context,PcodeEmit &emit) const; 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 void printTemplate(ostream &s) const { s << "dynamic"; }
virtual string getSource(void) const { return "dynamic"; } virtual string getSource(void) const { return "dynamic"; }
}; };
@ -98,7 +101,7 @@ protected:
virtual void registerInject(int4 injectid); virtual void registerInject(int4 injectid);
public: public:
PcodeInjectLibrarySleigh(Architecture *g); 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 manualCallFixup(const string &name,const string &snippetstring);
virtual int4 manualCallOtherFixup(const string &name,const string &outname,const vector<string> &inname, virtual int4 manualCallOtherFixup(const string &name,const string &outname,const vector<string> &inname,
const string &snippet); const string &snippet);

View file

@ -17,32 +17,38 @@
#include "emulate.hh" #include "emulate.hh"
#include "flow.hh" #include "flow.hh"
/// \param s is the XML stream to write to AttributeId ATTRIB_LABEL = AttributeId("label",71);
void LoadTable::saveXml(ostream &s) const 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 << "<loadtable"; encoder.openElement(ELEM_LOADTABLE);
a_v_i(s,"size",size); encoder.writeSignedInteger(ATTRIB_SIZE, size);
a_v_i(s,"num",num); encoder.writeSignedInteger(ATTRIB_NUM, num);
s << ">\n "; addr.encode(encoder);
addr.saveXml(s); encoder.closeElement(ELEM_LOADTABLE);
s << "</loadtable>\n";
} }
/// \param el is the root \<loadtable> tag /// \param decoder is the stream decoder
/// \param glb is the architecture for resolving address space tags /// \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")); uint4 elemId = decoder.openElement(ELEM_LOADTABLE);
s1.unsetf(ios::dec | ios::hex | ios::oct); size = decoder.readSignedInteger(ATTRIB_SIZE);
s1 >> size; num = decoder.readSignedInteger(ATTRIB_NUM);
istringstream s2(el->getAttributeValue("num")); addr = Address::decode( decoder, glb);
s2.unsetf(ios::dec | ios::hex | ios::oct); decoder.closeElement(elemId);
s2 >> num;
const List &list( el->getChildren() );
List::const_iterator iter = list.begin();
addr = Address::restoreXml( *iter, glb);
} }
/// We assume the list of LoadTable entries is sorted and perform an in-place /// We assume the list of LoadTable entries is sorted and perform an in-place
@ -1899,55 +1905,61 @@ void JumpBasicOverride::clear(void)
istrivial = false; istrivial = false;
} }
void JumpBasicOverride::saveXml(ostream &s) const void JumpBasicOverride::encode(Encoder &encoder) const
{ {
set<Address>::const_iterator iter; set<Address>::const_iterator iter;
s << "<basicoverride>\n"; encoder.openElement(ELEM_BASICOVERRIDE);
for(iter=adset.begin();iter!=adset.end();++iter) { for(iter=adset.begin();iter!=adset.end();++iter) {
s << " <dest"; encoder.openElement(ELEM_DEST);
AddrSpace *spc = (*iter).getSpace(); AddrSpace *spc = (*iter).getSpace();
uintb off = (*iter).getOffset(); uintb off = (*iter).getOffset();
spc->saveXmlAttributes(s,off); spc->encodeAttributes(encoder,off);
s << "/>\n"; encoder.closeElement(ELEM_DEST);
} }
if (hash != 0) { if (hash != 0) {
s << " <normaddr"; encoder.openElement(ELEM_NORMADDR);
normaddress.getSpace()->saveXmlAttributes(s,normaddress.getOffset()); normaddress.getSpace()->encodeAttributes(encoder,normaddress.getOffset());
s << "/>\n"; encoder.closeElement(ELEM_NORMADDR);
s << " <normhash>0x" << hex << hash << "</normhash>\n"; encoder.openElement(ELEM_NORMHASH);
encoder.writeUnsignedInteger(ATTRIB_CONTENT, hash);
encoder.closeElement(ELEM_NORMHASH);
} }
if (startingvalue != 0) { if (startingvalue != 0) {
s << " <startval>0x" << hex << startingvalue << "</startval>\n"; encoder.openElement(ELEM_STARTVAL);
encoder.writeUnsignedInteger(ATTRIB_CONTENT, startingvalue);
encoder.closeElement(ELEM_STARTVAL);
} }
s << "</basicoverride>\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() ); uint4 elemId = decoder.openElement(ELEM_BASICOVERRIDE);
List::const_iterator iter = list.begin(); for(;;) {
while(iter != list.end()) { uint4 subId = decoder.openElement();
const Element *subel = *iter; if (subId == 0) break;
++iter; if (subId == ELEM_DEST) {
if (subel->getName() == "dest") { VarnodeData vData;
adset.insert( Address::restoreXml(subel,glb) ); vData.decodeFromAttributes(decoder, glb);
adset.insert( vData.getAddr() );
} }
else if (subel->getName() == "normaddr") else if (subId == ELEM_NORMADDR) {
normaddress = Address::restoreXml(subel,glb); VarnodeData vData;
else if (subel->getName() == "normhash") { vData.decodeFromAttributes(decoder, glb);
istringstream s1(subel->getContent()); normaddress = vData.getAddr();
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> hash;
} }
else if (subel->getName() == "startval") { else if (subId == ELEM_NORMHASH) {
istringstream s2(subel->getContent()); hash = decoder.readUnsignedInteger(ATTRIB_CONTENT);
s2.unsetf(ios::dec | ios::hex | ios::oct);
s2 >> startingvalue;
} }
else if (subId == ELEM_STARTVAL) {
startingvalue = decoder.readUnsignedInteger(ATTRIB_CONTENT);
} }
decoder.closeElement(subId);
}
decoder.closeElement(elemId);
if (adset.empty()) if (adset.empty())
throw LowlevelError("Empty jumptable override"); throw LowlevelError("Empty jumptable override");
} }
@ -2594,83 +2606,81 @@ void JumpTable::clear(void)
// -opaddress- -maxtablesize- -maxaddsub- -maxleftright- -maxext- -collectloads- are permanent // -opaddress- -maxtablesize- -maxaddsub- -maxleftright- -maxext- -collectloads- are permanent
} }
/// The recovered addresses and case labels are saved to the XML stream. /// The recovered addresses and case labels are encode to the stream.
/// If override information is present, this is also incorporated into the tag. /// If override information is present, this is also incorporated into the element.
/// \param s is the stream to write to /// \param encoder is the stream encoder
void JumpTable::saveXml(ostream &s) const void JumpTable::encode(Encoder &encoder) const
{ {
if (!isRecovered()) if (!isRecovered())
throw LowlevelError("Trying to save unrecovered jumptable"); throw LowlevelError("Trying to save unrecovered jumptable");
s << "<jumptable>\n"; encoder.openElement(ELEM_JUMPTABLE);
opaddress.saveXml(s); opaddress.encode(encoder);
s << '\n';
for(int4 i=0;i<addresstable.size();++i) { for(int4 i=0;i<addresstable.size();++i) {
s << "<dest"; encoder.openElement(ELEM_DEST);
AddrSpace *spc = addresstable[i].getSpace(); AddrSpace *spc = addresstable[i].getSpace();
uintb off = addresstable[i].getOffset(); uintb off = addresstable[i].getOffset();
if (spc != (AddrSpace *)0) if (spc != (AddrSpace *)0)
spc->saveXmlAttributes(s,off); spc->encodeAttributes(encoder,off);
if (i<label.size()) { if (i<label.size()) {
if (label[i] != 0xBAD1ABE1) if (label[i] != 0xBAD1ABE1)
a_v_u(s,"label",label[i]); encoder.writeUnsignedInteger(ATTRIB_LABEL, label[i]);
} }
s << "/>\n"; encoder.closeElement(ELEM_DEST);
} }
if (!loadpoints.empty()) { if (!loadpoints.empty()) {
for(int4 i=0;i<loadpoints.size();++i) for(int4 i=0;i<loadpoints.size();++i)
loadpoints[i].saveXml(s); loadpoints[i].encode(encoder);
} }
if ((jmodel != (JumpModel *)0)&&(jmodel->isOverride())) if ((jmodel != (JumpModel *)0)&&(jmodel->isOverride()))
jmodel->saveXml(s); jmodel->encode(encoder);
s << "</jumptable>\n"; 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 \<jumptable> element.
/// Other parts of the model and jump-table will still need to be recovered. /// Other parts of the model and jump-table will still need to be recovered.
/// \param el is the root \<jumptable> tag to restore from /// \param decoder is the stream decoder
void JumpTable::restoreXml(const Element *el) void JumpTable::decode(Decoder &decoder)
{ {
const List &list( el->getChildren() ); uint4 elemId = decoder.openElement(ELEM_JUMPTABLE);
List::const_iterator iter = list.begin(); opaddress = Address::decode( decoder, glb);
opaddress = Address::restoreXml( *iter, glb);
bool missedlabel = false; bool missedlabel = false;
++iter; for(;;) {
while(iter != list.end()) { uint4 subId = decoder.peekElement();
const Element *subel = *iter; if (subId == 0) break;
if (subel->getName() == "dest") { if (subId == ELEM_DEST) {
addresstable.push_back( Address::restoreXml( subel, glb) ); decoder.openElement();
int4 maxnum = subel->getNumAttributes(); bool foundlabel = false;
int4 i; for(;;) {
for(i=0;i<maxnum;++i) { uint4 attribId = decoder.getNextAttributeId();
if (subel->getAttributeName(i) == "label") break; if (attribId == 0) break;
} if (attribId == ATTRIB_LABEL) {
if (i<maxnum) { // Found a label attribute
if (missedlabel) if (missedlabel)
throw LowlevelError("Jumptable entries are missing labels"); throw LowlevelError("Jumptable entries are missing labels");
istringstream s1(subel->getAttributeValue(i)); uintb lab = decoder.readUnsignedInteger();
s1.unsetf(ios::dec | ios::hex | ios::oct);
uintb lab;
s1 >> lab;
label.push_back(lab); label.push_back(lab);
foundlabel = true;
break;
} }
else // No label attribute }
if (!foundlabel) // No label attribute
missedlabel = true; // No following entries are allowed to have a 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.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) if (jmodel != (JumpModel *)0)
throw LowlevelError("Duplicate jumptable override specs"); throw LowlevelError("Duplicate jumptable override specs");
jmodel = new JumpBasicOverride(this); jmodel = new JumpBasicOverride(this);
jmodel->restoreXml(subel,glb); jmodel->decode(decoder,glb);
} }
++iter;
} }
decoder.closeElement(elemId);
if (label.size()!=0) { if (label.size()!=0) {
while(label.size() < addresstable.size()) while(label.size() < addresstable.size())

View file

@ -24,6 +24,17 @@
class EmulateFunction; class EmulateFunction;
extern AttributeId ATTRIB_LABEL; ///< Marshaling attribute "label"
extern AttributeId ATTRIB_NUM; ///< Marshaling attribute "num"
extern ElementId ELEM_BASICOVERRIDE; ///< Marshaling element \<basicoverride>
extern ElementId ELEM_DEST; ///< Marshaling element \<dest>
extern ElementId ELEM_JUMPTABLE; ///< Marshaling element \<jumptable>
extern ElementId ELEM_LOADTABLE; ///< Marshaling element \<loadtable>
extern ElementId ELEM_NORMADDR; ///< Marshaling element \<normaddr>
extern ElementId ELEM_NORMHASH; ///< Marshaling element \<normhash>
extern ElementId ELEM_STARTVAL; ///< Marshaling element \<startval>
/// \brief Exception thrown for a thunk mechanism that looks like a jump-table /// \brief Exception thrown for a thunk mechanism that looks like a jump-table
struct JumptableThunkError : public LowlevelError { struct JumptableThunkError : public LowlevelError {
JumptableThunkError(const string &s) : LowlevelError(s) {} ///< Construct with an explanatory string JumptableThunkError(const string &s) : LowlevelError(s) {} ///< Construct with an explanatory string
@ -44,12 +55,12 @@ class LoadTable {
int4 size; ///< Size of table entry int4 size; ///< Size of table entry
int4 num; ///< Number of entries in table; int4 num; ///< Number of entries in table;
public: 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) { 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 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 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 \<loadtable> XML tag void encode(Encoder &encoder) const; ///< Encode a description of \b this as an \<loadtable> element
void restoreXml(const Element *el,Architecture *glb); ///< Read in \b this table from a \<loadtable> XML description void decode(Decoder &decoder,Architecture *glb); ///< Decode \b this table from a \<loadtable> element
static void collapseTable(vector<LoadTable> &table); ///< Collapse a sequence of table descriptions static void collapseTable(vector<LoadTable> &table); ///< Collapse a sequence of table descriptions
}; };
@ -309,8 +320,8 @@ public:
virtual JumpModel *clone(JumpTable *jt) const=0; ///< Clone \b this model 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 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 encode(Encoder &encoder) const {} ///< Encode this model to a stream
virtual void restoreXml(const Element *el,Architecture *glb) {} ///< Restore \b this model from an XML tag 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 /// \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<Address> &addresstable) { return true; } virtual bool sanityCheck(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable) { return true; }
virtual JumpModel *clone(JumpTable *jt) const; virtual JumpModel *clone(JumpTable *jt) const;
virtual void clear(void); virtual void clear(void);
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual void restoreXml(const Element *el,Architecture *glb); virtual void decode(Decoder &decoder,Architecture *glb);
}; };
class JumpAssistOp; class JumpAssistOp;
@ -563,8 +574,8 @@ public:
bool recoverLabels(Funcdata *fd); ///< Recover the case labels for \b this jump-table 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 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 clear(void); ///< Clear instance specific data for \b this jump-table
void saveXml(ostream &s) const; ///< Save \b this jump-table as a \<jumptable> XML tag void encode(Encoder &encoder) const; ///< Encode \b this jump-table as a \<jumptable> element
void restoreXml(const Element *el); ///< Recover \b this jump-table from a \<jumptable> XML tag void decode(Decoder &decoder); ///< Decode \b this jump-table from a \<jumptable> element
}; };
/// \param op2 is the other IndexPair to compare with \b this /// \param op2 is the other IndexPair to compare with \b this

View file

@ -18,6 +18,8 @@
void startDecompilerLibrary(const char *sleighhome) void startDecompilerLibrary(const char *sleighhome)
{ {
AttributeId::initialize();
ElementId::initialize();
CapabilityPoint::initializeAll(); CapabilityPoint::initializeAll();
ArchitectureCapability::sortCapabilities(); ArchitectureCapability::sortCapabilities();
@ -28,6 +30,8 @@ void startDecompilerLibrary(const char *sleighhome)
void startDecompilerLibrary(const vector<string> &extrapaths) void startDecompilerLibrary(const vector<string> &extrapaths)
{ {
AttributeId::initialize();
ElementId::initialize();
CapabilityPoint::initializeAll(); CapabilityPoint::initializeAll();
ArchitectureCapability::sortCapabilities(); ArchitectureCapability::sortCapabilities();
@ -38,6 +42,8 @@ void startDecompilerLibrary(const vector<string> &extrapaths)
void startDecompilerLibrary(const char *sleighhome,const vector<string> &extrapaths) void startDecompilerLibrary(const char *sleighhome,const vector<string> &extrapaths)
{ {
AttributeId::initialize();
ElementId::initialize();
CapabilityPoint::initializeAll(); CapabilityPoint::initializeAll();
ArchitectureCapability::sortCapabilities(); ArchitectureCapability::sortCapabilities();

View file

@ -16,6 +16,11 @@
#include "loadimage_xml.hh" #include "loadimage_xml.hh"
#include "translate.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 f is the (path to the) underlying XML file
/// \param el is the parsed form of the file /// \param el is the parsed form of the file
LoadImageXml::LoadImageXml(const string &f,const Element *el) : LoadImage(f) 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"); archtype = el->getAttributeValue("arch");
} }
/// Write out the byte chunks and symbols as XML tags /// Encode the byte chunks and symbols as elements
/// \param s is the output stream /// \param encoder is the stream encoder
void LoadImageXml::saveXml(ostream &s) const void LoadImageXml::encode(Encoder &encoder) const
{ {
s << "<binaryimage arch=\"" << archtype << "\">\n"; encoder.openElement(ELEM_BINARYIMAGE);
encoder.writeString(ATTRIB_ARCH, archtype);
map<Address,vector<uint1> >::const_iterator iter1; map<Address,vector<uint1> >::const_iterator iter1;
for(iter1=chunk.begin();iter1!=chunk.end();++iter1) { for(iter1=chunk.begin();iter1!=chunk.end();++iter1) {
const vector<uint1> &vec((*iter1).second); const vector<uint1> &vec((*iter1).second);
if (vec.size() == 0) continue; if (vec.size() == 0) continue;
s << " <bytechunk"; encoder.openElement(ELEM_BYTECHUNK);
(*iter1).first.getSpace()->saveXmlAttributes(s,(*iter1).first.getOffset()); (*iter1).first.getSpace()->encodeAttributes(encoder,(*iter1).first.getOffset());
if (readonlyset.find((*iter1).first) != readonlyset.end()) if (readonlyset.find((*iter1).first) != readonlyset.end())
s << " readonly=\"true\""; encoder.writeBool(ATTRIB_READONLY, "true");
s << ">\n " << setfill('0'); ostringstream s;
s << '\n' << setfill('0');
for(int4 i=0;i<vec.size();++i) { for(int4 i=0;i<vec.size();++i) {
s << hex << setw(2) << (int4)vec[i]; s << hex << setw(2) << (int4)vec[i];
if (i%20 == 19) if (i%20 == 19)
s << "\n "; s << '\n';
} }
s << "\n </bytechunk>\n"; s << '\n';
encoder.writeString(ATTRIB_CONTENT, s.str());
encoder.closeElement(ELEM_BYTECHUNK);
} }
map<Address,string>::const_iterator iter2; map<Address,string>::const_iterator iter2;
for(iter2=addrtosymbol.begin();iter2!=addrtosymbol.end();++iter2) { for(iter2=addrtosymbol.begin();iter2!=addrtosymbol.end();++iter2) {
s << " <symbol"; encoder.openElement(ELEM_SYMBOL);
(*iter2).first.getSpace()->saveXmlAttributes(s,(*iter2).first.getOffset()); (*iter2).first.getSpace()->encodeAttributes(encoder,(*iter2).first.getOffset());
s << " name=\"" << (*iter2).second << "\"/>\n"; encoder.writeString(ATTRIB_NAME, (*iter2).second);
encoder.closeElement(ELEM_SYMBOL);
} }
s << "</binaryimage>\n"; encoder.closeElement(ELEM_BINARYIMAGE);
} }
/// \param m is for looking up address space /// \param m is for looking up address space
@ -71,35 +81,40 @@ void LoadImageXml::open(const AddrSpaceManager *m)
uint4 sz; // unused size uint4 sz; // unused size
// Read parsed xml file // Read parsed xml file
const List &list(rootel->getChildren()); XmlDecode decoder(rootel);
List::const_iterator iter; uint4 elemId = decoder.openElement(ELEM_BINARYIMAGE);
iter = list.begin(); for(;;) {
while(iter != list.end()) { uint4 subId = decoder.openElement();
Element *subel = *iter++; if (subId == 0) break;
if (subel->getName()=="symbol") { if (subId==ELEM_SYMBOL) {
AddrSpace *base = (AddrSpace *)0; AddrSpace *base = (AddrSpace *)0;
base = manage->getSpaceByName(subel->getAttributeValue("space")); string spaceName = decoder.readString(ATTRIB_SPACE);
base = manage->getSpaceByName(spaceName);
if (base == (AddrSpace *)0) if (base == (AddrSpace *)0)
throw LowlevelError("Unknown space name: "+subel->getAttributeValue("space")); throw LowlevelError("Unknown space name: "+spaceName);
Address addr(base,base->restoreXmlAttributes(subel,sz)); Address addr(base,base->decodeAttributes(decoder,sz));
const string &nm(subel->getAttributeValue("name")); string nm = decoder.readString(ATTRIB_NAME);
addrtosymbol[addr] = nm; addrtosymbol[addr] = nm;
} }
else if (subel->getName() == "bytechunk") { else if (subId == ELEM_BYTECHUNK) {
AddrSpace *base = (AddrSpace *)0; AddrSpace *base = (AddrSpace *)0;
base = manage->getSpaceByName(subel->getAttributeValue("space")); string spaceName = decoder.readString(ATTRIB_SPACE);
base = manage->getSpaceByName(spaceName);
if (base == (AddrSpace *)0) if (base == (AddrSpace *)0)
throw LowlevelError("Unknown space name: "+subel->getAttributeValue("space")); throw LowlevelError("Unknown space name: "+spaceName);
Address addr(base,base->restoreXmlAttributes(subel,sz)); Address addr(base,base->decodeAttributes(decoder,sz));
map<Address,vector<uint1> >::iterator chnkiter; map<Address,vector<uint1> >::iterator chnkiter;
vector<uint1> &vec( chunk[addr] ); vector<uint1> &vec( chunk[addr] );
vec.clear(); vec.clear();
for(int4 i=0;i<subel->getNumAttributes();++i) { decoder.rewindAttributes();
if (subel->getAttributeName(i) == "readonly") for(;;) {
if (xml_readbool(subel->getAttributeValue(i))) uint4 attribId = decoder.getNextAttributeId();
if (attribId == 0) break;
if (attribId == ATTRIB_READONLY)
if (decoder.readBool())
readonlyset.insert(addr); readonlyset.insert(addr);
} }
istringstream is(subel->getContent()); istringstream is(decoder.readString(ATTRIB_CONTENT));
int4 val; int4 val;
char c1,c2; char c1,c2;
is >> ws; is >> ws;
@ -126,8 +141,10 @@ void LoadImageXml::open(const AddrSpaceManager *m)
} }
} }
else else
throw LowlevelError("Unknown LoadImageXml tag: "+subel->getName()); throw LowlevelError("Unknown LoadImageXml tag");
decoder.closeElement(subId);
} }
decoder.closeElement(elemId);
pad(); pad();
} }

View file

@ -21,6 +21,11 @@
#include "loadimage.hh" #include "loadimage.hh"
extern AttributeId ATTRIB_ARCH; ///< Marshaling attribute "arch"
extern ElementId ELEM_BINARYIMAGE; ///< Marshaling element \<binaryimage>
extern ElementId ELEM_BYTECHUNK; ///< Marshaling element \<bytechunk>
/// \brief Implementation of the LoadImage interface using underlying data stored in an XML format /// \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 \<binaryimage> file. /// The image data is stored in an XML file in a \<binaryimage> file.
@ -38,7 +43,7 @@ public:
LoadImageXml(const string &f,const Element *el); ///< Constructor LoadImageXml(const string &f,const Element *el); ///< Constructor
void open(const AddrSpaceManager *m); ///< Read XML tags into the containers void open(const AddrSpaceManager *m); ///< Read XML tags into the containers
void clear(void); ///< Clear out all the caches 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 ~LoadImageXml(void) { clear(); }
virtual void loadFill(uint1 *ptr,int4 size,const Address &addr); virtual void loadFill(uint1 *ptr,int4 size,const Address &addr);
virtual void openSymbols(void) const; virtual void openSymbols(void) const;

View file

@ -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 <sstream>
unordered_map<string,uint4> 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 *> &AttributeId::getList(void)
{
static vector<AttributeId *> 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<AttributeId *> &thelist(getList());
for(int4 i=0;i<thelist.size();++i) {
AttributeId *attrib = thelist[i];
#ifdef CPUI_DEBUG
if (lookupAttributeId.find(attrib->name) != 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<string,uint4> 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 *> &ElementId::getList(void)
{
static vector<ElementId *> 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<ElementId *> &thelist(getList());
for(int4 i=0;i<thelist.size();++i) {
ElementId *elem = thelist[i];
#ifdef CPUI_DEBUG
if (lookupElementId.find(elem->name) != 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;i<el->getNumAttributes();++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 << "</" << elemId.getName() << '>';
}
}
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

View file

@ -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 <unordered_map>
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<string,uint4> lookupAttributeId; ///< A map of AttributeId names to their associated id
static vector<AttributeId *> &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<string,uint4> lookupElementId; ///< A map of ElementId names to their associated id
static vector<ElementId *> &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<const Element *> elStack; ///< Stack of currently \e open elements
vector<List::const_iterator> 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<string,uint4>::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<string,uint4>::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 \<data>
extern ElementId ELEM_INPUT; ///< Marshaling element \<input>
extern ElementId ELEM_OFF; ///< Marshaling element \<off>
extern ElementId ELEM_OUTPUT; ///< Marshaling element \<output>
extern ElementId ELEM_RETURNADDRESS; ///< Marshaling element \<returnaddress>
extern ElementId ELEM_SYMBOL; ///< Marshaling element \<symbol>
extern ElementId ELEM_TARGET; ///< Marshaling element \<target>
extern ElementId ELEM_VAL; ///< Marshaling element \<val>
extern ElementId ELEM_VALUE; ///< Marshaling element \<value>
extern ElementId ELEM_VOID; ///< Marshaling element \<void>
#endif

View file

@ -16,6 +16,8 @@
#include "op.hh" #include "op.hh"
#include "funcdata.hh" #include "funcdata.hh"
ElementId ELEM_IOP = ElementId("iop",110);
const string IopSpace::NAME = "iop"; const string IopSpace::NAME = "iop";
/// Constructor for the \b iop space. /// Constructor for the \b iop space.
@ -56,13 +58,13 @@ void IopSpace::printRaw(ostream &s,uintb offset) const
void IopSpace::saveXml(ostream &s) 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 /// 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); 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 /// providing a reference number for each input and output Varnode
/// \param s is the stream to write to /// \param encoder is the stream encoder
void PcodeOp::saveXml(ostream &s) const void PcodeOp::encode(Encoder &encoder) const
{ {
s << "<op"; encoder.openElement(ELEM_OP);
a_v_i(s,"code",(int4)code()); encoder.writeSignedInteger(ATTRIB_CODE, (int4)code());
s << ">\n"; start.encode(encoder);
start.saveXml(s); if (output==(Varnode *)0) {
s << '\n'; encoder.openElement(ELEM_VOID);
if (output==(Varnode *)0) encoder.closeElement(ELEM_VOID);
s << "<void/>\n"; }
else else {
s << "<addr ref=\"0x" << hex << output->getCreateIndex() << "\"/>\n"; encoder.openElement(ELEM_ADDR);
encoder.writeUnsignedInteger(ATTRIB_REF, output->getCreateIndex());
encoder.closeElement(ELEM_ADDR);
}
for(int4 i=0;i<inrefs.size();++i) { for(int4 i=0;i<inrefs.size();++i) {
const Varnode *vn = getIn(i); const Varnode *vn = getIn(i);
if (vn == (const Varnode *)0) if (vn == (const Varnode *)0) {
s << "<void/>\n"; encoder.openElement(ELEM_VOID);
encoder.closeElement(ELEM_VOID);
}
else if (vn->getSpace()->getType()==IPTR_IOP) { else if (vn->getSpace()->getType()==IPTR_IOP) {
if ((i==1)&&(code()==CPUI_INDIRECT)) { if ((i==1)&&(code()==CPUI_INDIRECT)) {
PcodeOp *indop = PcodeOp::getOpFromConst(vn->getAddr()); PcodeOp *indop = PcodeOp::getOpFromConst(vn->getAddr());
s << "<iop"; encoder.openElement(ELEM_IOP);
a_v_u(s,"value",indop->getSeqNum().getTime()); encoder.writeUnsignedInteger(ATTRIB_VALUE, indop->getSeqNum().getTime());
s << "/>\n"; encoder.closeElement(ELEM_IOP);
}
else {
encoder.openElement(ELEM_VOID);
encoder.closeElement(ELEM_VOID);
} }
else
s << "<void/>\n";
} }
else if (vn->getSpace()->getType()==IPTR_CONSTANT) { else if (vn->getSpace()->getType()==IPTR_CONSTANT) {
if ((i==0)&&((code()==CPUI_STORE)||(code()==CPUI_LOAD))) { if ((i==0)&&((code()==CPUI_STORE)||(code()==CPUI_LOAD))) {
AddrSpace *spc = vn->getSpaceFromConst(); AddrSpace *spc = vn->getSpaceFromConst();
s << "<spaceid"; encoder.openElement(ELEM_SPACEID);
a_v(s,"name",spc->getName()); encoder.writeString(ATTRIB_NAME, spc->getName());
s << "/>\n"; encoder.closeElement(ELEM_SPACEID);
}
else
s << "<addr ref=\"0x" << hex << vn->getCreateIndex() << "\"/>\n";
} }
else { else {
s << "<addr ref=\"0x" << hex << vn->getCreateIndex() << "\"/>\n"; encoder.openElement(ELEM_ADDR);
encoder.writeUnsignedInteger(ATTRIB_REF, vn->getCreateIndex());
encoder.closeElement(ELEM_ADDR);
} }
} }
s << "</op>\n"; else {
encoder.openElement(ELEM_ADDR);
encoder.writeUnsignedInteger(ATTRIB_REF, vn->getCreateIndex());
encoder.closeElement(ELEM_ADDR);
}
}
encoder.closeElement(ELEM_OP);
} }
/// Assuming all the inputs to this op are constants, compute the constant result of evaluating /// Assuming all the inputs to this op are constants, compute the constant result of evaluating

View file

@ -20,6 +20,8 @@
#include "typeop.hh" #include "typeop.hh"
extern ElementId ELEM_IOP; ///< Marshaling element \<iop>
/// \brief Space for storing internal PcodeOp pointers as addresses /// \brief Space for storing internal PcodeOp pointers as addresses
/// ///
/// It is convenient and efficient to replace the formally encoded /// It is convenient and efficient to replace the formally encoded
@ -32,11 +34,11 @@
class IopSpace : public AddrSpace { class IopSpace : public AddrSpace {
public: public:
IopSpace(AddrSpaceManager *m,const Translate *t,int4 ind); IopSpace(AddrSpaceManager *m,const Translate *t,int4 ind);
virtual void saveXmlAttributes(ostream &s,uintb offset) const { s << " space=\"iop\""; } virtual void encodeAttributes(Encoder &encoder,uintb offset) const { encoder.writeString(ATTRIB_SPACE, "iop"); }
virtual void saveXmlAttributes(ostream &s,uintb offset,int4 size) const { s << " 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 printRaw(ostream &s,uintb offset) const;
virtual void saveXml(ostream &s) 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 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 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 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 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 /// \brief Retrieve the PcodeOp encoded as the address \e addr
static PcodeOp *getOpFromConst(const Address &addr) { return (PcodeOp *)(uintp)addr.getOffset(); } static PcodeOp *getOpFromConst(const Address &addr) { return (PcodeOp *)(uintp)addr.getOffset(); }

View file

@ -18,6 +18,44 @@
#include "flow.hh" #include "flow.hh"
#include "printc.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. /// If the parameter is "on" return \b true, if "off" return \b false.
/// Any other value causes an exception. /// Any other value causes an exception.
/// \param p is the parameter /// \param p is the parameter
@ -40,7 +78,8 @@ bool ArchOption::onOrOff(const string &p)
void OptionDatabase::registerOption(ArchOption *option) 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. /// 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) OptionDatabase::~OptionDatabase(void)
{ {
map<string,ArchOption *>::iterator iter; map<uint4,ArchOption *>::iterator iter;
for(iter=optionmap.begin();iter!=optionmap.end();++iter) for(iter=optionmap.begin();iter!=optionmap.end();++iter)
delete (*iter).second; delete (*iter).second;
} }
/// Perform an \e option \e command directly, given its name and optional parameters /// Perform an \e option \e command directly, given its id and optional parameters
/// \param nm is the registered name of the option /// \param nameId is the id of the option
/// \param p1 is the first optional parameter /// \param p1 is the first optional parameter
/// \param p2 is the second optional parameter /// \param p2 is the second optional parameter
/// \param p3 is the third optional parameter /// \param p3 is the third optional parameter
/// \return the confirmation/failure method after trying to apply the option /// \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<string,ArchOption *>::const_iterator iter; map<uint4,ArchOption *>::const_iterator iter;
iter = optionmap.find(nm); iter = optionmap.find(nameId);
if (iter == optionmap.end()) if (iter == optionmap.end())
throw ParseError("Unknown option: "+nm); throw ParseError("Unknown option");
ArchOption *opt = (*iter).second; ArchOption *opt = (*iter).second;
return opt->apply(glb,p1,p2,p3); return opt->apply(glb,p1,p2,p3);
} }
/// Unwrap the name and optional parameters and call method set() /// Scan the name and optional parameters and call method set()
/// \param el is the command XML tag /// \param decoder is the stream decoder
void OptionDatabase::parseOne(const Element *el) void OptionDatabase::decodeOne(Decoder &decoder)
{ {
const string &optname( el->getName() );
const List &list(el->getChildren());
List::const_iterator iter;
string p1,p2,p3; string p1,p2,p3;
iter = list.begin(); uint4 elemId = decoder.openElement();
if (iter != list.end()) { uint4 subId = decoder.openElement();
p1 = (*iter)->getContent(); if (subId == ELEM_PARAM1) {
++iter; p1 = decoder.readString(ATTRIB_CONTENT);
if (iter != list.end()) { decoder.closeElement(subId);
p2 = (*iter)->getContent(); subId = decoder.openElement();
++iter; if (subId == ELEM_PARAM2) {
if (iter != list.end()) { p2 = decoder.readString(ATTRIB_CONTENT);
p3 = (*iter)->getContent(); decoder.closeElement(subId);
++iter; subId = decoder.openElement();
if (iter != list.end()) if (subId == ELEM_PARAM3) {
throw LowlevelError("Too many parameters to option: "+optname); p3 = decoder.readString(ATTRIB_CONTENT);
decoder.closeElement(subId);
} }
} }
} }
else else if (subId == 0)
p1 = el->getContent(); // If no children, content is param 1 p1 = decoder.readString(ATTRIB_CONTENT); // If no children, content is param 1
set(optname,p1,p2,p3); decoder.closeElement(elemId);
set(elemId,p1,p2,p3);
} }
/// Parse the \<optionslist> tag, treating each sub-tag as an \e option \e command. /// Parse an \<optionslist> element, treating each child as an \e option \e command.
/// \param el is the \<optionslist> tag /// \param decoder is the stream decoder
void OptionDatabase::restoreXml(const Element *el) void OptionDatabase::decode(Decoder &decoder)
{ {
const List &list(el->getChildren()); uint4 elemId = decoder.openElement(ELEM_OPTIONSLIST);
List::const_iterator iter;
for(iter=list.begin();iter!=list.end();++iter) while(decoder.peekElement() != 0)
parseOne(*iter); decodeOne(decoder);
decoder.closeElement(elemId);
} }
/// \class OptionExtraPop /// \class OptionExtraPop

View file

@ -20,10 +20,48 @@
#define __ARCH_OPTIONS__ #define __ARCH_OPTIONS__
#include "error.hh" #include "error.hh"
#include "xml.hh" #include "marshal.hh"
class Architecture; class Architecture;
extern ElementId ELEM_ALIASBLOCK; ///< Marshaling element \<aliasblock>
extern ElementId ELEM_ALLOWCONTEXTSET; ///< Marshaling element \<allowcontextset>
extern ElementId ELEM_ANALYZEFORLOOPS; ///< Marshaling element \<analyzeforloops>
extern ElementId ELEM_COMMENTHEADER; ///< Marshaling element \<commentheader>
extern ElementId ELEM_COMMENTINDENT; ///< Marshaling element \<commentindent>
extern ElementId ELEM_COMMENTINSTRUCTION; ///< Marshaling element \<commentinstruction>
extern ElementId ELEM_COMMENTSTYLE; ///< Marshaling element \<commentstyle>
extern ElementId ELEM_CONVENTIONPRINTING; ///< Marshaling element \<conventionprinting>
extern ElementId ELEM_CURRENTACTION; ///< Marshaling element \<currentaction>
extern ElementId ELEM_DEFAULTPROTOTYPE; ///< Marshaling element \<defaultprototype>
extern ElementId ELEM_ERRORREINTERPRETED; ///< Marshaling element \<errorreinterpreted>
extern ElementId ELEM_ERRORTOOMANYINSTRUCTIONS; ///< Marshaling element \<errortoomanyinstructions>
extern ElementId ELEM_ERRORUNIMPLEMENTED; ///< Marshaling element \<errorunimplemented>
extern ElementId ELEM_EXTRAPOP; ///< Marshaling element \<extrapop>
extern ElementId ELEM_IGNOREUNIMPLEMENTED; ///< Marshaling element \<ignoreunimplemented>
extern ElementId ELEM_INDENTINCREMENT; ///< Marshaling element \<indentincrement>
extern ElementId ELEM_INFERCONSTPTR; ///< Marshaling element \<inferconstptr>
extern ElementId ELEM_INLINE; ///< Marshaling element \<inline>
extern ElementId ELEM_INPLACEOPS; ///< Marshaling element \<inplaceops>
extern ElementId ELEM_INTEGERFORMAT; ///< Marshaling element \<integerformat>
extern ElementId ELEM_JUMPLOAD; ///< Marshaling element \<jumpload>
extern ElementId ELEM_MAXINSTRUCTION; ///< Marshaling element \<maxinstruction>
extern ElementId ELEM_MAXLINEWIDTH; ///< Marshaling element \<maxlinewidth>
extern ElementId ELEM_NAMESPACESTRATEGY; ///< Marshaling element \<namespacestrategy>
extern ElementId ELEM_NOCASTPRINTING; ///< Marshaling element \<nocastprinting>
extern ElementId ELEM_NORETURN; ///< Marshaling element \<noreturn>
extern ElementId ELEM_NULLPRINTING; ///< Marshaling element \<nullprinting>
extern ElementId ELEM_OPTIONSLIST; ///< Marshaling element \<optionslist>
extern ElementId ELEM_PARAM1; ///< Marshaling element \<param1>
extern ElementId ELEM_PARAM2; ///< Marshaling element \<param2>
extern ElementId ELEM_PARAM3; ///< Marshaling element \<param3>
extern ElementId ELEM_PROTOEVAL; ///< Marshaling element \<protoeval>
extern ElementId ELEM_SETACTION; ///< Marshaling element \<setaction>
extern ElementId ELEM_SETLANGUAGE; ///< Marshaling element \<setlanguage>
extern ElementId ELEM_STRUCTALIGN; ///< Marshaling element \<structalign>
extern ElementId ELEM_TOGGLERULE; ///< Marshaling element \<togglerule>
extern ElementId ELEM_WARNING; ///< Marshaling element \<warning>
/// \brief Base class for options classes that affect the configuration of the Architecture object /// \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 /// 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 /// 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 /// 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 /// 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. /// either through the set() method directly, or via an element handed to the decode() method.
/// The restoreXml() method expects an \<optionslist> tag with one or more sub-tags. The sub-tag names /// The decode() method expects an \<optionslist> element with one or more children. The child names
/// match the registered name of the option and have up to three child tags, \<param1>, \<param2> and \<param3>, /// match the registered name of the option and have up to three child elements, \<param1>, \<param2> and \<param3>,
/// whose content is provided as the optional parameters to command. /// whose content is provided as the optional parameters to command.
class OptionDatabase { class OptionDatabase {
Architecture *glb; ///< The Architecture affected by the contained ArchOption Architecture *glb; ///< The Architecture affected by the contained ArchOption
map<string,ArchOption *> optionmap; ///< A map from option name to registered ArchOption instance map<uint4,ArchOption *> optionmap; ///< A map from option id to registered ArchOption instance
void registerOption(ArchOption *option); ///< Map from ArchOption name to its class instance void registerOption(ArchOption *option); ///< Map from ArchOption name to its class instance
public: public:
OptionDatabase(Architecture *g); ///< Construct given the owning Architecture OptionDatabase(Architecture *g); ///< Construct given the owning Architecture
~OptionDatabase(void); ///< Destructor ~OptionDatabase(void); ///< Destructor
string set(const string &nm,const string &p1="",const string &p2="",const string &p3=""); ///< Issue an option command string set(uint4 nameId,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 decodeOne(Decoder &decoder); ///< Parse and execute a single option element
void restoreXml(const Element *el); ///< Execute a series of \e option \e commands passed by XML void decode(Decoder &decoder); ///< Execute a series of \e option \e commands parsed from a stream
}; };
class OptionExtraPop : public ArchOption { class OptionExtraPop : public ArchOption {

View file

@ -16,6 +16,14 @@
#include "override.hh" #include "override.hh"
#include "funcdata.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) void Override::clear(void)
{ {
@ -276,141 +284,118 @@ void Override::generateOverrideMessages(vector<string> &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 \<override> tag. /// All the commands are written as children of a root \<override> element.
/// \param s is the output stream /// \param encoder is the stream encoder
/// \param glb is the Architecture /// \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() && if (forcegoto.empty() && deadcodedelay.empty() && indirectover.empty() && protoover.empty() &&
multistagejump.empty() && flowoverride.empty()) multistagejump.empty() && flowoverride.empty())
return; return;
s << "<override>\n"; encoder.openElement(ELEM_OVERRIDE);
map<Address,Address>::const_iterator iter; map<Address,Address>::const_iterator iter;
for(iter=forcegoto.begin();iter!=forcegoto.end();++iter) { for(iter=forcegoto.begin();iter!=forcegoto.end();++iter) {
s << "<forcegoto>"; encoder.openElement(ELEM_FORCEGOTO);
(*iter).first.saveXml(s); (*iter).first.encode(encoder);
(*iter).second.saveXml(s); (*iter).second.encode(encoder);
s << "</forcegoto>\n"; encoder.closeElement(ELEM_FORCEGOTO);
} }
for(int4 i=0;i<deadcodedelay.size();++i) { for(int4 i=0;i<deadcodedelay.size();++i) {
if (deadcodedelay[i] < 0) continue; if (deadcodedelay[i] < 0) continue;
AddrSpace *spc = glb->getSpace(i); AddrSpace *spc = glb->getSpace(i);
s << "<deadcodedelay"; encoder.openElement(ELEM_DEADCODEDELAY);
a_v(s,"space",spc->getName()); encoder.writeString(ATTRIB_SPACE, spc->getName());
a_v_i(s,"delay",deadcodedelay[i]); encoder.writeSignedInteger(ATTRIB_DELAY, deadcodedelay[i]);
s << "/>\n"; encoder.closeElement(ELEM_DEADCODEDELAY);
} }
for(iter=indirectover.begin();iter!=indirectover.end();++iter) { for(iter=indirectover.begin();iter!=indirectover.end();++iter) {
s << "<indirectoverride>"; encoder.openElement(ELEM_INDIRECTOVERRIDE);
(*iter).first.saveXml(s); (*iter).first.encode(encoder);
(*iter).second.saveXml(s); (*iter).second.encode(encoder);
s << "</indirectoverride>\n"; encoder.closeElement(ELEM_INDIRECTOVERRIDE);
} }
map<Address,FuncProto *>::const_iterator fiter; map<Address,FuncProto *>::const_iterator fiter;
for(fiter=protoover.begin();fiter!=protoover.end();++fiter) { for(fiter=protoover.begin();fiter!=protoover.end();++fiter) {
s << "<protooverride>"; encoder.openElement(ELEM_PROTOOVERRIDE);
(*fiter).first.saveXml(s); (*fiter).first.encode(encoder);
(*fiter).second->saveXml(s); (*fiter).second->encode(encoder);
s << "</protooverride>\n"; encoder.closeElement(ELEM_PROTOOVERRIDE);
} }
for(int4 i=0;i<multistagejump.size();++i) { for(int4 i=0;i<multistagejump.size();++i) {
s << "<multistagejump>"; encoder.openElement(ELEM_MULTISTAGEJUMP);
multistagejump[i].saveXml(s); multistagejump[i].encode(encoder);
s << "</multistagejump>"; encoder.closeElement(ELEM_MULTISTAGEJUMP);
} }
map<Address,uint4>::const_iterator titer; map<Address,uint4>::const_iterator titer;
for(titer=flowoverride.begin();titer!=flowoverride.end();++titer) { for(titer=flowoverride.begin();titer!=flowoverride.end();++titer) {
s << "<flow"; encoder.openElement(ELEM_FLOW);
a_v(s,"type",typeToString( (*titer).second )); encoder.writeString(ATTRIB_TYPE, typeToString( (*titer).second ));
s << ">"; (*titer).first.encode(encoder);
(*titer).first.saveXml(s); encoder.closeElement(ELEM_FLOW);
s << "</flow>\n";
} }
encoder.closeElement(ELEM_OVERRIDE);
s << "</override>\n";
} }
/// \brief Read in override commands from XML /// \brief Parse and \<override> element containing override commands
/// ///
/// \param el is the root \<override> element /// \param decoder is the stream decoder
/// \param glb is the Architecture /// \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()); uint4 elemId = decoder.openElement(ELEM_OVERRIDE);
List::const_iterator iter; for(;;) {
uint4 subId = decoder.openElement();
for(iter=list.begin();iter!=list.end();++iter) { if (subId == 0) break;
const Element *subel = *iter; if (subId == ELEM_INDIRECTOVERRIDE) {
Address callpoint = Address::decode(decoder,glb);
if (subel->getName() == "indirectoverride") { Address directcall = Address::decode(decoder,glb);
const List &list2(subel->getChildren());
List::const_iterator iter2 = list2.begin();
Address callpoint = Address::restoreXml(*iter2,glb);
++iter2;
Address directcall = Address::restoreXml(*iter2,glb);
insertIndirectOverride(callpoint,directcall); insertIndirectOverride(callpoint,directcall);
} }
else if (subel->getName() == "protooverride") { else if (subId == ELEM_PROTOOVERRIDE) {
const List &list2(subel->getChildren()); Address callpoint = Address::decode(decoder,glb);
List::const_iterator iter2 = list2.begin();
Address callpoint = Address::restoreXml(*iter2,glb);
++iter2;
FuncProto *fp = new FuncProto(); FuncProto *fp = new FuncProto();
fp->setInternal(glb->defaultfp,glb->types->getTypeVoid()); fp->setInternal(glb->defaultfp,glb->types->getTypeVoid());
fp->restoreXml(*iter2,glb); fp->decode(decoder,glb);
insertProtoOverride(callpoint,fp); insertProtoOverride(callpoint,fp);
} }
else if (subel->getName() == "forcegoto") { else if (subId == ELEM_FORCEGOTO) {
const List &list2(subel->getChildren()); Address targetpc = Address::decode(decoder,glb);
List::const_iterator iter2 = list2.begin(); Address destpc = Address::decode(decoder,glb);
Address targetpc = Address::restoreXml(*iter2,glb);
++iter2;
Address destpc = Address::restoreXml(*iter2,glb);
insertForceGoto(targetpc,destpc); insertForceGoto(targetpc,destpc);
} }
else if (subel->getName() == "deadcodedelay") { else if (subId == ELEM_DEADCODEDELAY) {
int4 delay = -1; int4 delay = decoder.readSignedInteger(ATTRIB_DELAY);
istringstream s(subel->getAttributeValue("delay")); AddrSpace *spc = glb->getSpaceByName( decoder.readString(ATTRIB_SPACE));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> delay;
AddrSpace *spc = glb->getSpaceByName( subel->getAttributeValue("space"));
if ((spc == (AddrSpace *)0)||(delay < 0)) if ((spc == (AddrSpace *)0)||(delay < 0))
throw LowlevelError("Bad deadcodedelay tag"); throw LowlevelError("Bad deadcodedelay tag");
insertDeadcodeDelay(spc,delay); insertDeadcodeDelay(spc,delay);
} }
else if (subel->getName() == "multistagejump") { else if (subId == ELEM_MULTISTAGEJUMP) {
const Element *tmpel = subel->getChildren().front(); Address callpoint = Address::decode(decoder,glb);
Address callpoint = Address::restoreXml(tmpel,glb);
insertMultistageJump(callpoint); insertMultistageJump(callpoint);
} }
else if (subel->getName() == "multistagejump") { else if (subId == ELEM_FLOW) {
const Element *tmpel = subel->getChildren().front(); uint4 type = stringToType(decoder.readString(ATTRIB_TYPE));
Address callpoint = Address::restoreXml(tmpel,glb); Address addr = Address::decode(decoder,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);
if ((type == Override::NONE)||(addr.isInvalid())) if ((type == Override::NONE)||(addr.isInvalid()))
throw LowlevelError("Bad flowoverride tag"); throw LowlevelError("Bad flowoverride tag");
insertFlowOverride(addr,type); insertFlowOverride(addr,type);
} }
decoder.closeElement(subId);
} }
decoder.closeElement(elemId);
} }
/// \param tp is the override type /// \param tp is the override type

View file

@ -23,6 +23,14 @@
class FuncCallSpecs; // Forward declaration class FuncCallSpecs; // Forward declaration
extern ElementId ELEM_DEADCODEDELAY; ///< Marshaling element \<deadcodedelay>
extern ElementId ELEM_FLOW; ///< Marshaling element \<flow>
extern ElementId ELEM_FORCEGOTO; ///< Marshaling element \<forcegoto>
extern ElementId ELEM_INDIRECTOVERRIDE; ///< Marshaling element \<indirectoverride>
extern ElementId ELEM_MULTISTAGEJUMP; ///< Marshaling element \<multistagejump>
extern ElementId ELEM_OVERRIDE; ///< Marshaling element \<override>
extern ElementId ELEM_PROTOOVERRIDE; ///< Marshaling element \<protooverride>
/// \brief A container of commands that override the decompiler's default behavior for a single function /// \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: /// Information about a particular function that can be overridden includes:
@ -75,8 +83,8 @@ public:
uint4 getFlowOverride(const Address &addr) const; uint4 getFlowOverride(const Address &addr) const;
void printRaw(ostream &s,Architecture *glb) const; void printRaw(ostream &s,Architecture *glb) const;
void generateOverrideMessages(vector<string> &messagelist,Architecture *glb) const; void generateOverrideMessages(vector<string> &messagelist,Architecture *glb) const;
void saveXml(ostream &s,Architecture *glb) const; void encode(Encoder &encoder,Architecture *glb) const;
void restoreXml(const Element *el,Architecture *glb); void decode(Decoder &decoder,Architecture *glb);
static string typeToString(uint4 tp); ///< Convert a flow override type to a string 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 static uint4 stringToType(const string &nm); ///< Convert a string to a flow override type
}; };

View file

@ -15,6 +15,10 @@
*/ */
#include "paramid.hh" #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 // NOTES FROM 20121206 W/Decompiler-Man
// direct reads is for all opcodes, with special for these: // direct reads is for all opcodes, with special for these:
// BRANCH is direct read on input0. No direct write. // 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); 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 +">\n<addr"; encoder.openElement(tag);
vndata.space->saveXmlAttributes( s, vndata.offset, vndata.size ); encoder.openElement(ELEM_ADDR);
s << "/>\n"; vndata.space->encodeAttributes( encoder, vndata.offset, vndata.size );
vntype->saveXml(s); encoder.closeElement(ELEM_ADDR);
vntype->encode(encoder);
if( moredetail ) { if( moredetail ) {
s << "<rank"; encoder.openElement(ELEM_RANK);
a_v_i(s,"val",rank); encoder.writeSignedInteger(ATTRIB_VAL, rank);
s << "/>"; encoder.closeElement(ELEM_RANK);
} }
s << "</" + tag + ">\n"; encoder.closeElement(tag);
} }
void ParamMeasure::savePretty( ostream &s,bool moredetail ) const 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 << "<parammeasures"; encoder.openElement(ELEM_PARAMMEASURES);
a_v( s, "name", fd->getName() ); encoder.writeString(ATTRIB_NAME, fd->getName());
s << ">\n "; fd->getAddress().encode( encoder );
fd->getAddress().saveXml( s ); encoder.openElement(ELEM_PROTO);
s << "\n <proto";
a_v(s,"model", fd->getFuncProto().getModelName()); encoder.writeString(ATTRIB_MODEL, fd->getFuncProto().getModelName());
int4 extrapop = fd->getFuncProto().getExtraPop(); int4 extrapop = fd->getFuncProto().getExtraPop();
if (extrapop == ProtoModel::extrapop_unknown) if (extrapop == ProtoModel::extrapop_unknown)
a_v(s,"extrapop","unknown"); encoder.writeString(ATTRIB_EXTRAPOP, "unknown");
else else
a_v_i(s,"extrapop",extrapop); encoder.writeSignedInteger(ATTRIB_EXTRAPOP, extrapop);
s << "/>\n"; encoder.closeElement(ELEM_PROTO);
list<ParamMeasure>::const_iterator pm_iter; list<ParamMeasure>::const_iterator pm_iter;
for( pm_iter = InputParamMeasures.begin(); pm_iter != InputParamMeasures.end(); ++pm_iter) { for( pm_iter = InputParamMeasures.begin(); pm_iter != InputParamMeasures.end(); ++pm_iter) {
const ParamMeasure &pm( *pm_iter ); const ParamMeasure &pm( *pm_iter );
s << " "; pm.encode(encoder,ELEM_INPUT,moredetail);
pm.saveXml(s,"input",moredetail);
} }
for( pm_iter = OutputParamMeasures.begin(); pm_iter != OutputParamMeasures.end() ; ++pm_iter) { for( pm_iter = OutputParamMeasures.begin(); pm_iter != OutputParamMeasures.end() ; ++pm_iter) {
const ParamMeasure &pm( *pm_iter ); const ParamMeasure &pm( *pm_iter );
s << " "; pm.encode( encoder, ELEM_OUTPUT, moredetail );
pm.saveXml( s, "output", moredetail );
} }
s << "</parammeasures>"; encoder.closeElement(ELEM_PARAMMEASURES);
s << "\n";
} }
void ParamIDAnalysis::savePretty( ostream &s,bool moredetail ) const void ParamIDAnalysis::savePretty( ostream &s,bool moredetail ) const

View file

@ -18,6 +18,10 @@
#include "funcdata.hh" #include "funcdata.hh"
extern ElementId ELEM_PARAMMEASURES; ///< Marshaling element \<parammeasures>
extern ElementId ELEM_PROTO; ///< Marshaling element \<proto>
extern ElementId ELEM_RANK; ///< Marshaling element \<rank>
class ParamMeasure { class ParamMeasure {
public: public:
enum ParamIDIO { enum ParamIDIO {
@ -56,7 +60,7 @@ public:
ParamMeasure( const Address &addr, int4 sz, Datatype *dt, ParamIDIO io_in) { 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; } 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 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; void savePretty( ostream &s,bool moredetail ) const;
int4 getMeasure(void) const { return (int4) rank; } int4 getMeasure(void) const { return (int4) rank; }
}; };
@ -68,7 +72,7 @@ class ParamIDAnalysis
list<ParamMeasure> OutputParamMeasures; list<ParamMeasure> OutputParamMeasures;
public: public:
ParamIDAnalysis( Funcdata *fd_in, bool justproto ); 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; void savePretty( ostream &s, bool moredetail ) const;
}; };

View file

@ -16,26 +16,47 @@
#include "pcodeinject.hh" #include "pcodeinject.hh"
#include "architecture.hh" #include "architecture.hh"
/// \brief Read in an \<input> or \<output> 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 \<input> or \<output> 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 name is used to pass back the parameter name
/// \param size is used to pass back the parameter size /// \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 = ""; name = "";
size = 0; size = 0;
int4 num = el->getNumAttributes(); uint4 elemId = decoder.openElement();
for(int4 i=0;i<num;++i) { for(;;) {
if (el->getAttributeName(i) == "name") uint4 attribId = decoder.getNextAttributeId();
name = el->getAttributeValue(i); if (attribId == 0) break;
else if (el->getAttributeName(i) == "size") { if (attribId == ATTRIB_NAME)
istringstream s(el->getAttributeValue(i)); name = decoder.readString();
s.unsetf(ios::dec | ios::hex | ios::oct); else if (attribId == ATTRIB_SIZE) {
s >> size; size = decoder.readUnsignedInteger();
} }
} }
decoder.closeElement(elemId);
if (name.size()==0) if (name.size()==0)
throw LowlevelError("Missing inject parameter name"); throw LowlevelError("Missing inject parameter name");
} }
@ -55,44 +76,55 @@ void InjectPayload::orderParameters(void)
} }
} }
/// The base class version of this method restores from a \<pcode> tag. /// The \<pcode> element must be current and already opened.
/// Derived classes may restore from a parent tag and then invoke the /// \param decoder is the stream decoder
/// base class method. void InjectPayload::decodePayloadAttributes(Decoder &decoder)
/// \param el is the XML element
void InjectPayload::restoreXml(const Element *el)
{ {
paramshift = 0; paramshift = 0;
dynamic = false; dynamic = false;
int4 num = el->getNumAttributes(); for(;;) {
for(int4 i=0;i<num;++i) { uint4 attribId = decoder.getNextAttributeId();
const string &elname(el->getAttributeName(i)); if (attribId == 0) break;
if (elname == "paramshift") { if (attribId == ATTRIB_PARAMSHIFT) {
istringstream s(el->getAttributeValue(i)); paramshift = decoder.readSignedInteger();
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> paramshift;
} }
else if (elname == "dynamic") else if (attribId == ATTRIB_DYNAMIC)
dynamic = xml_readbool(el->getAttributeValue(i)); dynamic = decoder.readBool();
else if (elname == "incidentalcopy") else if (attribId == ATTRIB_INCIDENTALCOPY)
incidentalCopy = xml_readbool(el->getAttributeValue(i)); incidentalCopy = decoder.readBool();
else if (attribId == ATTRIB_INJECT) {
string uponType = decoder.readString();
if (uponType == "uponentry")
name = name + "@@inject_uponentry";
else
name = name + "@@inject_uponreturn";
} }
const List &list(el->getChildren()); }
List::const_iterator iter; }
for(iter=list.begin();iter!=list.end();++iter) {
const Element *subel = *iter; /// Elements are processed until the first child that isn't an \<input> or \<output> tag
if (subel->getName() == "input") { /// is encountered. The \<pcode> 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; string paramName;
uint4 size; uint4 size;
readParameter(subel,paramName,size); decodeParameter(decoder,paramName,size);
inputlist.push_back(InjectParameter(paramName,size)); inputlist.push_back(InjectParameter(paramName,size));
} }
else if (subel->getName() == "output") { else if (subId == ELEM_OUTPUT) {
string paramName; string paramName;
uint4 size; uint4 size;
readParameter(subel,paramName,size); decodeParameter(decoder,paramName,size);
output.push_back(InjectParameter(paramName,size)); output.push_back(InjectParameter(paramName,size));
} }
else
break;
} }
orderParameters(); orderParameters();
} }
@ -305,21 +337,21 @@ string PcodeInjectLibrary::getCallMechanismName(int4 injectid) const
return callMechTarget[injectid]; 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 (\<pcode>, \<callfixup> /// The element is one of: \<pcode>, \<callfixup> \<callotherfixup>, etc.
/// \<callotherfixup>, etc.), the InjectPayload is allocated and then /// The InjectPayload is allocated and then initialized using the element.
/// initialized using the element. Then the InjectPayload is finalized with the library. /// Then the InjectPayload is finalized with the library.
/// \param src is a string describing the source of the payload being restored /// \param src is a string describing the source of the payload being decoded
/// \param nm is the name of the payload /// \param nm is the name of the payload
/// \param tp is the type of the payload (CALLFIXUP_TYPE, EXECUTABLEPCODE_TYPE, etc.) /// \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 /// \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); int4 injectid = allocateInject(src, nm, tp);
getPayload(injectid)->restoreXml(el); getPayload(injectid)->decode(decoder);
registerInject(injectid); registerInject(injectid);
return injectid; return injectid;
} }

View file

@ -23,6 +23,26 @@
class Architecture; 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 \<addr_pcode>
extern ElementId ELEM_BODY; ///< Marshaling element \<body>
extern ElementId ELEM_CALLFIXUP; ///< Marshaling element \<callfixup>
extern ElementId ELEM_CALLOTHERFIXUP; ///< Marshaling element \<callotherfixup>
extern ElementId ELEM_CASE_PCODE; ///< Marshaling element \<case_pcode>
extern ElementId ELEM_CONTEXT; ///< Marshaling element \<context>
extern ElementId ELEM_DEFAULT_PCODE; ///< Marshaling element \<default_pcode>
extern ElementId ELEM_INJECT; ///< Marshaling element \<inject>
extern ElementId ELEM_INJECTDEBUG; ///< Marshaling element \<injectdebug>
extern ElementId ELEM_INST; ///< Marshaling element \<inst>
extern ElementId ELEM_PAYLOAD; ///< Marshaling element \<payload>
extern ElementId ELEM_PCODE; ///< Marshaling element \<pcode>
extern ElementId ELEM_SIZE_PCODE; ///< Marshaling element \<size_pcode>
/// \brief An input or output parameter to a p-code injection payload /// \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 /// Within the chunk of p-code being injected, this is a placeholder for Varnodes
@ -64,10 +84,10 @@ public:
virtual ~InjectContext(void) {} ///< Destructor virtual ~InjectContext(void) {} ///< Destructor
virtual void clear(void) { inputlist.clear(); output.clear(); } ///< Release resources (from last injection) virtual void clear(void) { inputlist.clear(); output.clear(); } ///< Release resources (from last injection)
/// \brief Save \b this context to an XML stream as a \<context> tag /// \brief Encode \b this context to a stream as a \<context> element
/// ///
/// \param s is the output stream /// \param encoder is the stream encoder
virtual void saveXml(ostream &s) const=0; 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 /// \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 int4 paramshift; ///< Number of parameters shifted in the original call
vector<InjectParameter> inputlist; ///< List of input parameters to this payload vector<InjectParameter> inputlist; ///< List of input parameters to this payload
vector<InjectParameter> output; ///< List of output parameters vector<InjectParameter> 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 orderParameters(void); ///< Assign an index to parameters
void decodePayloadAttributes(Decoder &decoder); ///< Parse the attributes of the current \<pcode> tag
void decodePayloadParams(Decoder &decoder); ///< Parse any \<input> or \<output> children of current \<pcode> tag
public: 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 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 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 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 /// \param emit is the provovided PcodeEmit object
virtual void inject(InjectContext &context,PcodeEmit &emit) const=0; 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) 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 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.) 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 /// \brief A collection of p-code injection payloads
/// ///
/// This is a container of InjectPayload objects that can be applied for a /// 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 /// 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 /// 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, /// 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 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 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 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 /// Instantiate a special InjectPayloadDynamic object initialized with an
/// \<injectdebug> tag. Within the library, this replaces the original InjectPayload, /// \<injectdebug> element. Within the library, this replaces the original InjectPayload,
/// allowing its p-code to be \e replayed for debugging purposes. /// allowing its p-code to be \e replayed for debugging purposes.
/// \param el is the \<injectdebug> element /// \param decoder is the stream decoder
virtual void restoreDebug(const Element *el) {} virtual void decodeDebug(Decoder &decoder) {}
/// \brief Manually add a call-fixup payload given a compilable snippet of p-code \e source /// \brief Manually add a call-fixup payload given a compilable snippet of p-code \e source
/// ///

View file

@ -2904,6 +2904,9 @@ int4 PcodeLexer::moveState(void)
switch(curstate) { switch(curstate) {
case start: case start:
switch(curchar) { switch(curchar) {
case '#':
curstate = comment;
return start;
case '|': case '|':
if (lookahead1 == '|') { if (lookahead1 == '|') {
starttoken(); starttoken();
@ -3118,17 +3121,14 @@ int4 PcodeLexer::moveState(void)
advancetoken(); advancetoken();
curstate = start; curstate = start;
return identifier; return identifier;
break;
case special3: case special3:
advancetoken(); advancetoken();
curstate = special32; curstate = special32;
return start; return start;
break;
case special32: case special32:
advancetoken(); advancetoken();
curstate = start; curstate = start;
return identifier; return identifier;
break;
case comment: case comment:
if (curchar == '\n') if (curchar == '\n')
curstate = start; curstate = start;
@ -3136,28 +3136,25 @@ int4 PcodeLexer::moveState(void)
curstate = endstream; curstate = endstream;
return endstream; return endstream;
} }
break; return start;
case identifier: case identifier:
advancetoken(); advancetoken();
if (isIdent(lookahead1)) if (isIdent(lookahead1))
return start; return start;
curstate = start; curstate = start;
return identifier; return identifier;
break;
case hexstring: case hexstring:
advancetoken(); advancetoken();
if (isHex(lookahead1)) if (isHex(lookahead1))
return start; return start;
curstate = start; curstate = start;
return hexstring; return hexstring;
break;
case decstring: case decstring:
advancetoken(); advancetoken();
if (isDec(lookahead1)) if (isDec(lookahead1))
return start; return start;
curstate = start; curstate = start;
return decstring; return decstring;
break;
default: default:
curstate = endstream; curstate = endstream;
} }

View file

@ -303,6 +303,9 @@ int4 PcodeLexer::moveState(void)
switch(curstate) { switch(curstate) {
case start: case start:
switch(curchar) { switch(curchar) {
case '#':
curstate = comment;
return start;
case '|': case '|':
if (lookahead1 == '|') { if (lookahead1 == '|') {
starttoken(); starttoken();
@ -517,17 +520,14 @@ int4 PcodeLexer::moveState(void)
advancetoken(); advancetoken();
curstate = start; curstate = start;
return identifier; return identifier;
break;
case special3: case special3:
advancetoken(); advancetoken();
curstate = special32; curstate = special32;
return start; return start;
break;
case special32: case special32:
advancetoken(); advancetoken();
curstate = start; curstate = start;
return identifier; return identifier;
break;
case comment: case comment:
if (curchar == '\n') if (curchar == '\n')
curstate = start; curstate = start;
@ -535,28 +535,25 @@ int4 PcodeLexer::moveState(void)
curstate = endstream; curstate = endstream;
return endstream; return endstream;
} }
break; return start;
case identifier: case identifier:
advancetoken(); advancetoken();
if (isIdent(lookahead1)) if (isIdent(lookahead1))
return start; return start;
curstate = start; curstate = start;
return identifier; return identifier;
break;
case hexstring: case hexstring:
advancetoken(); advancetoken();
if (isHex(lookahead1)) if (isHex(lookahead1))
return start; return start;
curstate = start; curstate = start;
return hexstring; return hexstring;
break;
case decstring: case decstring:
advancetoken(); advancetoken();
if (isDec(lookahead1)) if (isDec(lookahead1))
return start; return start;
curstate = start; curstate = start;
return decstring; return decstring;
break;
default: default:
curstate = endstream; curstate = endstream;
} }

View file

@ -16,28 +16,43 @@
#include "pcoderaw.hh" #include "pcoderaw.hh"
#include "translate.hh" #include "translate.hh"
/// Build this VarnodeData from an \b \<addr\> tag /// Build this VarnodeData from an \<addr>, \<register>, or \<varnode> element.
/// \param el is the parsed tag /// \param decoder is the stream decoder
/// \param manage is the address space manager /// \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; space = (AddrSpace *)0;
size = 0; size = 0;
int4 num = el->getNumAttributes(); for(;;) {
for(int4 i=0;i<num;++i) { uint4 attribId = decoder.getNextAttributeId();
if (el->getAttributeName(i)=="space") { if (attribId == 0)
space = manage->getSpaceByName(el->getAttributeValue(i)); break; // Its possible to have no attributes in an <addr/> tag
if (attribId == ATTRIB_SPACE) {
string nm = decoder.readString();
space = manage->getSpaceByName(nm);
if (space == (AddrSpace *)0) if (space == (AddrSpace *)0)
throw LowlevelError("Unknown space name: "+el->getAttributeValue(i)); throw LowlevelError("Unknown space name: "+nm);
offset = space->restoreXmlAttributes(el,size); decoder.rewindAttributes();
return; offset = space->decodeAttributes(decoder,size);
break;
} }
else if (el->getAttributeName(i)=="name") { else if (attribId == ATTRIB_NAME) {
const Translate *trans = manage->getDefaultCodeSpace()->getTrans(); const Translate *trans = manage->getDefaultCodeSpace()->getTrans();
const VarnodeData &point(trans->getRegister(el->getAttributeValue(i))); const VarnodeData &point(trans->getRegister(decoder.readString()));
*this = point; *this = point;
return; break;
} }
} }
} }

View file

@ -44,8 +44,11 @@ struct VarnodeData {
/// Treat \b this as a constant and recover encoded address space /// Treat \b this as a constant and recover encoded address space
AddrSpace *getSpaceFromConst(void) const; AddrSpace *getSpaceFromConst(void) const;
/// Recover this object from an XML tag /// Recover this object from a stream
void restoreXml(const Element *el,const AddrSpaceManager *manage); 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 /// Does \b this container another given VarnodeData
bool contains(const VarnodeData &op2) const; bool contains(const VarnodeData &op2) const;

View file

@ -16,6 +16,8 @@
#include "prefersplit.hh" #include "prefersplit.hh"
#include "funcdata.hh" #include "funcdata.hh"
ElementId ELEM_PREFERSPLIT = ElementId("prefersplit",171);
bool PreferSplitRecord::operator<(const PreferSplitRecord &op2) const bool PreferSplitRecord::operator<(const PreferSplitRecord &op2) const
{ {

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,6 +19,8 @@
#include "varnode.hh" #include "varnode.hh"
class Funcdata; // Forward declaration class Funcdata; // Forward declaration
extern ElementId ELEM_PREFERSPLIT; ///< Marshaling element \<prefersplit>
struct PreferSplitRecord { struct PreferSplitRecord {
VarnodeData storage; VarnodeData storage;
int4 splitoffset; // Number of initial bytes (in address order) to split into first piece int4 splitoffset; // Number of initial bytes (in address order) to split into first piece

View file

@ -15,6 +15,8 @@
*/ */
#include "raw_arch.hh" #include "raw_arch.hh"
ElementId ELEM_RAW_SAVEFILE = ElementId("raw_savefile",172);
// Constructing this object registers the capability // Constructing this object registers the capability
RawBinaryArchitectureCapability RawBinaryArchitectureCapability::rawBinaryArchitectureCapability; RawBinaryArchitectureCapability RawBinaryArchitectureCapability::rawBinaryArchitectureCapability;
@ -81,16 +83,15 @@ RawBinaryArchitecture::RawBinaryArchitecture(const string &fname,const string &t
adjustvma = 0; adjustvma = 0;
} }
void RawBinaryArchitecture::saveXml(ostream &s) const void RawBinaryArchitecture::encode(Encoder &encoder) const
{ {
s << "<raw_savefile"; encoder.openElement(ELEM_RAW_SAVEFILE);
saveXmlHeader(s); encodeHeader(encoder);
a_v_u(s,"adjustvma",adjustvma); encoder.writeUnsignedInteger(ATTRIB_ADJUSTVMA, adjustvma);
s << ">\n"; types->encodeCoreTypes(encoder);
types->saveXmlCoreTypes(s); SleighArchitecture::encode(encoder);
SleighArchitecture::saveXml(s); encoder.closeElement(ELEM_RAW_SAVEFILE);
s << "</raw_savefile>\n";
} }
void RawBinaryArchitecture::restoreXml(DocumentStorage &store) void RawBinaryArchitecture::restoreXml(DocumentStorage &store)

View file

@ -18,6 +18,8 @@
#include "sleigh_arch.hh" #include "sleigh_arch.hh"
#include "loadimage.hh" #include "loadimage.hh"
extern ElementId ELEM_RAW_SAVEFILE; ///< Marshaling element \<raw_savefile>
/// \brief Extension point for building an Architecture that reads in raw images /// \brief Extension point for building an Architecture that reads in raw images
class RawBinaryArchitectureCapability : public ArchitectureCapability { class RawBinaryArchitectureCapability : public ArchitectureCapability {
static RawBinaryArchitectureCapability rawBinaryArchitectureCapability; ///< The singleton instance static RawBinaryArchitectureCapability rawBinaryArchitectureCapability; ///< The singleton instance
@ -38,7 +40,7 @@ class RawBinaryArchitecture : public SleighArchitecture {
virtual void resolveArchitecture(void); virtual void resolveArchitecture(void);
virtual void postSpecFile(void); virtual void postSpecFile(void);
public: public:
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual void restoreXml(DocumentStorage &store); virtual void restoreXml(DocumentStorage &store);
RawBinaryArchitecture(const string &fname,const string &targ,ostream *estream); ///< Constructor RawBinaryArchitecture(const string &fname,const string &targ,ostream *estream); ///< Constructor
virtual ~RawBinaryArchitecture(void) {} virtual ~RawBinaryArchitecture(void) {}

View file

@ -16,56 +16,81 @@
#include "sleigh_arch.hh" #include "sleigh_arch.hh"
#include "inject_sleigh.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<int4,Sleigh *> SleighArchitecture::translators; map<int4,Sleigh *> SleighArchitecture::translators;
vector<LanguageDescription> SleighArchitecture::description; vector<LanguageDescription> SleighArchitecture::description;
FileManage SleighArchitecture::specpaths; // Global specfile manager FileManage SleighArchitecture::specpaths; // Global specfile manager
/// Read file attributes from an XML \<compiler> tag /// Parse file attributes from a \<compiler> element
/// \param el is the XML element /// \param decoder is the stream decoder
void CompilerTag::restoreXml(const Element *el) void CompilerTag::decode(Decoder &decoder)
{ {
name = el->getAttributeValue("name"); uint4 elemId = decoder.openElement(ELEM_COMPILER);
spec = el->getAttributeValue("spec"); name = decoder.readString(ATTRIB_NAME);
id = el->getAttributeValue("id"); spec = decoder.readString(ATTRIB_SPEC);
id = decoder.readString(ATTRIB_ID);
decoder.closeElement(elemId);
} }
/// Parse an ldefs \<language> tag /// Parse an ldefs \<language> element
/// \param el is the XML element /// \param decoder is the stream decoder
void LanguageDescription::restoreXml(const Element *el) void LanguageDescription::decode(Decoder &decoder)
{ {
processor = el->getAttributeValue("processor"); uint4 elemId = decoder.openElement(ELEM_LANGUAGE);
isbigendian = (el->getAttributeValue("endian")=="big"); processor = decoder.readString(ATTRIB_PROCESSOR);
istringstream s1(el->getAttributeValue("size")); isbigendian = (decoder.readString(ATTRIB_ENDIAN)=="big");
s1.unsetf(ios::dec | ios::hex | ios::oct); size = decoder.readSignedInteger(ATTRIB_SIZE);
s1 >> size; variant = decoder.readString(ATTRIB_VARIANT);
variant = el->getAttributeValue("variant"); version = decoder.readString(ATTRIB_VERSION);
version = el->getAttributeValue("version"); slafile = decoder.readString(ATTRIB_SLAFILE);
slafile = el->getAttributeValue("slafile"); processorspec = decoder.readString(ATTRIB_PROCESSORSPEC);
processorspec = el->getAttributeValue("processorspec"); id = decoder.readString(ATTRIB_ID);
id = el->getAttributeValue("id");
deprecated = false; deprecated = false;
for(int4 i=0;i<el->getNumAttributes();++i) { for(;;) {
if (el->getAttributeName(i)=="deprecated") uint4 attribId = decoder.getNextAttributeId();
deprecated = xml_readbool(el->getAttributeValue(i)); if (attribId == 0) break;
if (attribId==ATTRIB_DEPRECATED)
deprecated = decoder.readBool();
} }
const List &sublist(el->getChildren()); for(;;) {
List::const_iterator subiter; uint4 subId = decoder.peekElement();
for(subiter=sublist.begin();subiter!=sublist.end();++subiter) { if (subId == 0) break;
const Element *subel = *subiter; if (subId == ELEM_DESCRIPTION) {
if (subel->getName() == "description") decoder.openElement();
description = subel->getContent(); description = decoder.readString(ATTRIB_CONTENT);
else if (subel->getName() == "compiler") { decoder.closeElement(subId);
}
else if (subId == ELEM_COMPILER) {
compilers.emplace_back(); 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.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 /// 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()); ifstream s(specfile.c_str());
if (!s) return; if (!s) return;
Document *doc; XmlDecode decoder;
Element *el;
try { try {
doc = xml_tree(s); decoder.ingestStream(s);
} }
catch(XmlError &err) { catch(XmlError &err) {
errs << "WARNING: Unable to parse sleigh specfile: " << specfile; errs << "WARNING: Unable to parse sleigh specfile: " << specfile;
return; return;
} }
el = doc->getRoot(); uint4 elemId = decoder.openElement(ELEM_LANGUAGE_DEFINITIONS);
const List &list(el->getChildren()); for(;;) {
List::const_iterator iter; uint4 subId = decoder.peekElement();
for(iter=list.begin();iter!=list.end();++iter) { if (subId == 0) break;
if ((*iter)->getName() != "language") continue; if (subId == ELEM_LANGUAGE) {
description.emplace_back(); description.emplace_back();
description.back().restoreXml( *iter ); description.back().decode( decoder );
} }
delete doc; else {
decoder.openElement();
decoder.closeElementSkipping(subId);
}
}
decoder.closeElement(elemId);
} }
SleighArchitecture::~SleighArchitecture(void) SleighArchitecture::~SleighArchitecture(void)
@ -307,12 +336,12 @@ void SleighArchitecture::collectSpecFiles(ostream &errs)
loadLanguageDescription(*iter,errs); loadLanguageDescription(*iter,errs);
} }
/// \param s is the XML output stream /// \param encoder is the stream encoder
void SleighArchitecture::saveXmlHeader(ostream &s) const void SleighArchitecture::encodeHeader(Encoder &encoder) const
{ {
a_v(s,"name",filename); encoder.writeString(ATTRIB_NAME, filename);
a_v(s,"target",target); encoder.writeString(ATTRIB_TARGET, target);
} }
/// \param el is the root XML element /// \param el is the root XML element
@ -457,6 +486,19 @@ void SleighArchitecture::scanForSleighDirectories(const string &rootpath)
specpaths.addDir2Path(languagesubdirs[i]); 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<LanguageDescription> &SleighArchitecture::getDescriptions(void)
{
ostringstream s;
collectSpecFiles(s);
if (!s.str().empty())
throw LowlevelError(s.str());
return description;
}
void SleighArchitecture::shutdown(void) void SleighArchitecture::shutdown(void)
{ {

View file

@ -23,6 +23,21 @@
#include "architecture.hh" #include "architecture.hh"
#include "sleigh.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 \<compiler>
extern ElementId ELEM_DESCRIPTION; ///< Marshaling element \<description>
extern ElementId ELEM_LANGUAGE; ///< Marshaling element \<language>
extern ElementId ELEM_LANGUAGE_DEFINITIONS; ///< Marshaling element \<language_definitions>
/// \brief Contents of a \<compiler> tag in a .ldefs file /// \brief Contents of a \<compiler> tag in a .ldefs file
/// ///
/// This class describes a compiler specification file as referenced by the Sleigh language subsystem. /// 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 string id; ///< Unique id for this compiler
public: public:
CompilerTag(void) {} ///< Constructor 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 &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 &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 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<TruncationTag> truncations; ///< Address space truncations required by this processor vector<TruncationTag> truncations; ///< Address space truncations required by this processor
public: public:
LanguageDescription(void) {} ///< Constructor 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 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 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 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 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 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 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 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 const TruncationTag &getTruncation(int4 i) const { return truncations[i]; } ///< Get the i-th truncation record
}; };
@ -107,8 +124,8 @@ public:
SleighArchitecture(const string &fname,const string &targ,ostream *estream); ///< Construct given executable file 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 &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 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 encodeHeader(Encoder &encoder) const; ///< Encode basic attributes of the active executable
void restoreXmlHeader(const Element *el); ///< Restore from XML basic attributes of an executable void restoreXmlHeader(const Element *el); ///< Restore from basic attributes of an executable
virtual void printMessage(const string &message) const { *errorstream << message << endl; } virtual void printMessage(const string &message) const { *errorstream << message << endl; }
virtual ~SleighArchitecture(void); virtual ~SleighArchitecture(void);
virtual string getDescription(void) const; virtual string getDescription(void) const;
@ -118,7 +135,8 @@ public:
static string normalizeSize(const string &nm); ///< Try to recover a \e language \e id size 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 string normalizeArchitecture(const string &nm); ///< Try to recover a \e language \e id string
static void scanForSleighDirectories(const string &rootpath); static void scanForSleighDirectories(const string &rootpath);
static void shutdown(void); ///< Shutdown this SleighArchitecture and free all resources. static const vector<LanguageDescription> &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. static FileManage specpaths; ///< Known directories that contain .ldefs files.
}; };

View file

@ -268,7 +268,8 @@ void SleighBase::restoreXml(const Element *el)
} }
indexer.restoreXml(*iter); indexer.restoreXml(*iter);
iter++; iter++;
restoreXmlSpaces(*iter,this); XmlDecode decoder(*iter);
decodeSpaces(decoder,this);
iter++; iter++;
symtab.restoreXml(*iter,this); symtab.restoreXml(*iter,this);
root = (SubtableSymbol *)symtab.getGlobalScope()->findSymbol("instruction"); root = (SubtableSymbol *)symtab.getGlobalScope()->findSymbol("instruction");

View file

@ -16,6 +16,21 @@
#include "space.hh" #include "space.hh"
#include "translate.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. /// Calculate \e highest based on \e addressSize, and \e wordsize.
/// This also calculates the default pointerLowerBound /// This also calculates the default pointerLowerBound
void AddrSpace::calcScaleMask(void) void AddrSpace::calcScaleMask(void)
@ -111,58 +126,51 @@ void AddrSpace::truncateSpace(uint4 newsize)
calcScaleMask(); 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 /// The caller provides only the \e offset, and this routine fills
/// in other details pertaining to this particular space. /// 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 /// \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 encoder.writeString(ATTRIB_SPACE,getName());
s << ' ' << "offset=\""; encoder.writeUnsignedInteger(ATTRIB_OFFSET, offset);
printOffset(s,offset);
s << "\"";
} }
/// 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 a size. The caller provides the \e offset and \e size,
/// and other details about this particular space are filled in. /// 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 offset is the offset of the address
/// \param size is the size of the memory location /// \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 encoder.writeString(ATTRIB_SPACE, getName());
s << ' ' << "offset=\""; encoder.writeUnsignedInteger(ATTRIB_OFFSET, offset);
printOffset(s,offset); encoder.writeSignedInteger(ATTRIB_SIZE, size);
s << "\"";
a_v_i(s,"size",size);
} }
/// For an XML tag describing an address in this space, this routine /// For an open element describing an address in \b this space, this routine
/// recovers the offset and possibly the size described by the tag /// recovers the offset and possibly the size described by the element
/// \param el is the XML address tag /// \param decoder is the stream decoder
/// \param size is a reference where the recovered size should be stored /// \param size is a reference where the recovered size should be stored
/// \return the recovered offset /// \return the recovered offset
uintb AddrSpace::restoreXmlAttributes(const Element *el,uint4 &size) const uintb AddrSpace::decodeAttributes(Decoder &decoder,uint4 &size) const
{ {
uintb offset; uintb offset;
int4 num = el->getNumAttributes();
bool foundoffset = false; bool foundoffset = false;
for(int4 i=0;i<num;++i) { for(;;) {
if (el->getAttributeName(i)=="offset") { uint4 attribId = decoder.getNextAttributeId();
if (attribId == 0) break;
if (attribId == ATTRIB_OFFSET) {
foundoffset = true; foundoffset = true;
istringstream s1(el->getAttributeValue(i)); offset = decoder.readUnsignedInteger();
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> offset;
} }
else if (el->getAttributeName(i)=="size") { else if (attribId == ATTRIB_SIZE) {
istringstream s2(el->getAttributeValue(i)); size = decoder.readUnsignedInteger();
s2.unsetf(ios::dec | ios::hex | ios::oct);
s2 >> size;
} }
} }
if (!foundoffset) 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 /// 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 /// \param s is the stream being written
void AddrSpace::saveXml(ostream &s) const void AddrSpace::saveXml(ostream &s) const
@ -291,56 +299,36 @@ void AddrSpace::saveXml(ostream &s) const
s << "/>\n"; 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 /// this space. The processor translator, \e trans, and the
/// \e type must already be filled in. /// \e type must already be filled in.
/// \param el is the parsed XML tag /// \param decoder is the stream decoder
void AddrSpace::restoreXml(const Element *el) void AddrSpace::decodeBasicAttributes(Decoder &decoder)
{ {
int4 numAttribs = el->getNumAttributes();
deadcodedelay = -1; deadcodedelay = -1;
for (int4 i=0; i < numAttribs; i++) { for (;;) {
string attrName = el->getAttributeName(i); uint4 attribId = decoder.getNextAttributeId();
string attrValue = el->getAttributeValue(i); if (attribId == 0) break;
if (attribId == ATTRIB_NAME) {
if (attrName == "name") { name = decoder.readString();
name = attrValue;
} }
if (attrName == "index") if (attribId == ATTRIB_INDEX)
{ index = decoder.readSignedInteger();
istringstream s1(attrValue); else if (attribId == ATTRIB_SIZE)
s1.unsetf(ios::dec | ios::hex | ios::oct); addressSize = decoder.readUnsignedInteger();
s1 >> index; else if (attribId == ATTRIB_WORDSIZE)
} wordsize = decoder.readUnsignedInteger();
if (attrName == "size") else if (attribId == ATTRIB_BIGENDIAN) {
{ if (decoder.readBool())
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))
flags |= big_endian; flags |= big_endian;
} }
if (attrName == "delay") { else if (attribId == ATTRIB_DELAY)
istringstream s1(attrValue); delay = decoder.readSignedInteger();
s1.unsetf(ios::dec | ios::hex | ios::oct); else if (attribId == ATTRIB_DEADCODEDELAY)
s1 >> delay; deadcodedelay = decoder.readSignedInteger();
} else if (attribId == ATTRIB_PHYSICAL) {
if (attrName == "deadcodedelay") { if (decoder.readBool())
istringstream s1(attrValue);
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> deadcodedelay;
}
if (attrName == "physical") {
if (xml_readbool(attrValue))
flags |= hasphysical; flags |= hasphysical;
} }
@ -350,6 +338,14 @@ void AddrSpace::restoreXml(const Element *el)
calcScaleMask(); calcScaleMask();
} }
void AddrSpace::decode(Decoder &decoder)
{
uint4 elemId = decoder.openElement(); // Multiple tags: <space>, <space_other>, <space_unique>
decodeBasicAttributes(decoder);
decoder.closeElement(elemId);
}
const string ConstantSpace::NAME = "const"; const string ConstantSpace::NAME = "const";
const int4 ConstantSpace::INDEX = 0; 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 /// As the ConstantSpace is never saved, it should never get
/// restored either. /// decoded either.
void ConstantSpace::restoreXml(const Element *el) 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"; 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 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 /// Encode a \e join address to the stream. This method in the interface only
/// outputs XML attributes for a single tag, so we are forced to encode what should probably /// outputs attributes for a single element, so we are forced to encode what should probably
/// be recursive tags into an attribute /// be recursive elements into an attribute.
/// \param s is the stream being written to /// \param encoder is the stream encoder
/// \param offset is the offset within the address space to encode /// \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 JoinRecord *rec = getManager()->findJoin(offset); // Record must already exist
a_v(s,"space",getName()); encoder.writeString(ATTRIB_SPACE, getName());
int4 num = rec->numPieces(); int4 num = rec->numPieces();
if (num >= 8)
throw LowlevelError("Cannot encode more than 8 pieces");
for(int4 i=0;i<num;++i) { for(int4 i=0;i<num;++i) {
const VarnodeData &vdata( rec->getPiece(i) ); const VarnodeData &vdata( rec->getPiece(i) );
ostringstream t; ostringstream t;
t << " piece" << dec << (i+1) << "=\""; AttributeId *attribId = pieceArray[i];
t << vdata.space->getName() << ":0x"; t << vdata.space->getName() << ":0x";
t << hex << vdata.offset << ':' << dec << vdata.size << '\"'; t << hex << vdata.offset << ':' << dec << vdata.size;
s << t.str(); encoder.writeString(*attribId, t.str());
} }
if (num == 1) 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 /// Encode a \e join address to the stream. This method in the interface only
/// outputs XML attributes for a single tag, so we are forced to encode what should probably /// outputs attributes for a single element, so we are forced to encode what should probably
/// be recursive tags into an attribute /// be recursive elements into an attribute.
/// \param s is the stream being written to /// \param encoder is the stream encoder
/// \param offset is the offset within the address space to encode /// \param offset is the offset within the address space to encode
/// \param size is the size of the memory location being encoded /// \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 encodeAttributes(encoder,offset); // Ignore size
a_v(s,"space",getName());
int4 num = rec->numPieces();
int4 count = 0;
for(int4 i=0;i<num;++i) {
const VarnodeData &vdata( rec->getPiece(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");
} }
/// Restore a join address from an XML tag. Pieces of the join are encoded as a sequence /// Parse a join address the current element. Pieces of the join are encoded as a sequence
/// of tag attributes. The Translate::findAddJoin method is used to construct a logical /// of attributes. The Translate::findAddJoin method is used to construct a logical
/// address within the join space. /// 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 /// \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 /// \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<VarnodeData> pieces; vector<VarnodeData> pieces;
int4 numAttribs = el->getNumAttributes();
uint4 sizesum = 0; uint4 sizesum = 0;
uint4 logicalsize = 0; uint4 logicalsize = 0;
for(int4 i=0;i<numAttribs;++i) { for(;;) {
string attrName = el->getAttributeName(i); uint4 attribId = decoder.getNextAttributeId();
if (0!=attrName.compare(0,5,"piece")) { if (attribId == 0) break;
if (attrName == "logicalsize") { if (attribId == ATTRIB_LOGICALSIZE) {
istringstream s3(el->getAttributeValue(i)); logicalsize = decoder.readUnsignedInteger();
s3.unsetf(ios::dec | ios::hex | ios::oct);
s3 >> logicalsize;
}
continue; 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) while(pieces.size() <= pos)
pieces.emplace_back(); pieces.emplace_back();
VarnodeData &vdat( pieces[pos] ); VarnodeData &vdat( pieces[pos] );
string attrVal = el->getAttributeValue(i); string attrVal = decoder.readString();
string::size_type offpos = attrVal.find(':'); string::size_type offpos = attrVal.find(':');
if (offpos == string::npos) { if (offpos == string::npos) {
const Translate *tr = getTrans(); const Translate *tr = getTrans();
@ -644,10 +625,10 @@ void JoinSpace::saveXml(ostream &s) const
throw LowlevelError("Should never save join space to XML"); 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 /// \param m is the address space manager
@ -669,18 +650,18 @@ void OverlaySpace::saveXml(ostream &s) const
s << "/>\n"; s << "/>\n";
} }
void OverlaySpace::restoreXml(const Element *el) void OverlaySpace::decode(Decoder &decoder)
{ {
name = el->getAttributeValue("name"); uint4 elemId = decoder.openElement(ELEM_SPACE_OVERLAY);
istringstream s1(el->getAttributeValue("index")); name = decoder.readString(ATTRIB_NAME);
s1.unsetf(ios::dec | ios::hex | ios::oct); index = decoder.readSignedInteger(ATTRIB_INDEX);
s1 >> index;
string basename = el->getAttributeValue("base"); string basename = decoder.readString(ATTRIB_BASE);
baseSpace = getManager()->getSpaceByName(basename); baseSpace = getManager()->getSpaceByName(basename);
if (baseSpace == (AddrSpace *)0) if (baseSpace == (AddrSpace *)0)
throw LowlevelError("Base space does not exist for overlay space: "+name); throw LowlevelError("Base space does not exist for overlay space: "+name);
decoder.closeElement(elemId);
addressSize = baseSpace->getAddrSize(); addressSize = baseSpace->getAddrSize();
wordsize = baseSpace->getWordSize(); wordsize = baseSpace->getWordSize();
delay = baseSpace->getDelay(); delay = baseSpace->getDelay();

View file

@ -20,7 +20,7 @@
#define __CPUI_SPACE__ #define __CPUI_SPACE__
#include "error.hh" #include "error.hh"
#include "xml.hh" #include "marshal.hh"
/// \brief Fundemental address space types /// \brief Fundemental address space types
/// ///
@ -40,6 +40,21 @@ class AddrSpaceManager;
struct VarnodeData; struct VarnodeData;
class Translate; 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 /// \brief A region where processor data is stored
/// ///
/// An AddrSpace (Address Space) is an arbitrary sequence of /// An AddrSpace (Address Space) is an arbitrary sequence of
@ -108,10 +123,11 @@ protected:
void setFlags(uint4 fl); ///< Set a cached attribute void setFlags(uint4 fl); ///< Set a cached attribute
void clearFlags(uint4 fl); ///< Clear a cached attribute void clearFlags(uint4 fl); ///< Clear a cached attribute
void saveBasicAttributes(ostream &s) const; ///< Write the XML attributes of this space 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); void truncateSpace(uint4 newsize);
public: 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,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 virtual ~AddrSpace(void) {} ///< The address space destructor
const string &getName(void) const; ///< Get the name const string &getName(void) const; ///< Get the name
AddrSpaceManager *getManager(void) const; ///< Get the space manager 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 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 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 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 encodeAttributes(Encoder &encoder,uintb offset) const; ///< Encode address attributes to a stream
virtual void saveXmlAttributes(ostream &s,uintb offset,int4 size) const; ///< Save an address and size as XML virtual void encodeAttributes(Encoder &encoder,uintb offset,int4 size) const; ///< Encode an address and size attributes to a stream
virtual uintb restoreXmlAttributes(const Element *el,uint4 &size) const; ///< Recover an offset and size 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 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 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 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 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 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 ConstantSpace(AddrSpaceManager *m,const Translate *t); ///< Only constructor
virtual void printRaw(ostream &s,uintb offset) const; virtual void printRaw(ostream &s,uintb offset) const;
virtual void saveXml(ostream &s) 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 string NAME; ///< Reserved name for the address space
static const int4 INDEX; ///< Reserved index for constant space static const int4 INDEX; ///< Reserved index for constant space
}; };
@ -186,7 +202,7 @@ public:
class OtherSpace : public AddrSpace { class OtherSpace : public AddrSpace {
public: public:
OtherSpace(AddrSpaceManager *m, const Translate *t, int4 ind); ///< Constructor 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 printRaw(ostream &s, uintb offset) const;
virtual void saveXml(ostream &s) const; virtual void saveXml(ostream &s) const;
static const string NAME; ///< Reserved name for the address space static const string NAME; ///< Reserved name for the address space
@ -205,7 +221,7 @@ public:
class UniqueSpace : public AddrSpace { class UniqueSpace : public AddrSpace {
public: public:
UniqueSpace(AddrSpaceManager *m,const Translate *t,int4 ind,uint4 fl); ///< Constructor 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; virtual void saveXml(ostream &s) const;
static const string NAME; ///< Reserved name for the unique space static const string NAME; ///< Reserved name for the unique space
static const uint4 SIZE; ///< Fixed size (in bytes) for unique space offsets static const uint4 SIZE; ///< Fixed size (in bytes) for unique space offsets
@ -222,13 +238,13 @@ public:
class JoinSpace : public AddrSpace { class JoinSpace : public AddrSpace {
public: public:
JoinSpace(AddrSpaceManager *m,const Translate *t,int4 ind); JoinSpace(AddrSpaceManager *m,const Translate *t,int4 ind);
virtual void saveXmlAttributes(ostream &s,uintb offset) const; virtual void encodeAttributes(Encoder &encoder,uintb offset) const;
virtual void saveXmlAttributes(ostream &s,uintb offset,int4 size) const; virtual void encodeAttributes(Encoder &encoder,uintb offset,int4 size) const;
virtual uintb restoreXmlAttributes(const Element *el,uint4 &size) const; virtual uintb decodeAttributes(Decoder &decoder,uint4 &size) const;
virtual void printRaw(ostream &s,uintb offset) const; virtual void printRaw(ostream &s,uintb offset) const;
virtual uintb read(const string &s,int4 &size) const; virtual uintb read(const string &s,int4 &size) const;
virtual void saveXml(ostream &s) 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 static const string NAME; ///< Reserved name for the join space
}; };
@ -246,7 +262,7 @@ public:
OverlaySpace(AddrSpaceManager *m,const Translate *t); ///< Constructor OverlaySpace(AddrSpaceManager *m,const Translate *t); ///< Constructor
virtual AddrSpace *getContain(void) const { return baseSpace; } virtual AddrSpace *getContain(void) const { return baseSpace; }
virtual void saveXml(ostream &s) const; 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 /// An internal method for derived classes to set space attributes

View file

@ -16,6 +16,12 @@
#include "stringmanage.hh" #include "stringmanage.hh"
#include "architecture.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 /// \param max is the maximum number of characters to allow before truncating string
StringManager::StringManager(int4 max) StringManager::StringManager(int4 max)
@ -83,46 +89,49 @@ bool StringManager::isString(const Address &addr,Datatype *charType)
return !buffer.empty(); return !buffer.empty();
} }
/// Write \<stringmanage> tag, with \<string> sub-tags. /// Encode \<stringmanage> element, with \<string> children.
/// \param s is the stream to write to /// \param encoder is the stream encoder
void StringManager::saveXml(ostream &s) const void StringManager::encode(Encoder &encoder) const
{ {
s << "<stringmanage>\n"; encoder.openElement(ELEM_STRINGMANAGE);
map<Address,StringData>::const_iterator iter1; map<Address,StringData>::const_iterator iter1;
for(iter1=stringMap.begin();iter1!=stringMap.end();++iter1) { for(iter1=stringMap.begin();iter1!=stringMap.end();++iter1) {
s << "<string>\n"; encoder.openElement(ELEM_STRING);
(*iter1).first.saveXml(s); (*iter1).first.encode(encoder);
const StringData &stringData( (*iter1).second ); const StringData &stringData( (*iter1).second );
s << " <bytes"; encoder.openElement(ELEM_BYTES);
a_v_b(s, "trunc", stringData.isTruncated); encoder.writeBool(ATTRIB_TRUNC, stringData.isTruncated);
s << ">\n" << setfill('0'); ostringstream s;
s << '\n' << setfill('0');
for(int4 i=0;i<stringData.byteData.size();++i) { for(int4 i=0;i<stringData.byteData.size();++i) {
s << hex << setw(2) << (int4)stringData.byteData[i]; s << hex << setw(2) << (int4)stringData.byteData[i];
if (i%20 == 19) if (i%20 == 19)
s << "\n "; s << "\n ";
} }
s << "\n </bytes>\n"; s << '\n';
encoder.writeString(ATTRIB_CONTENT, s.str());
encoder.closeElement(ELEM_BYTES);
} }
s << "</stringmanage>\n"; encoder.closeElement(ELEM_STRINGMANAGE);
} }
/// Read \<stringmanage> tag, with \<string> sub-tags. /// Parse a \<stringmanage> element, with \<string> children.
/// \param el is the root tag element /// \param decoder is the stream decoder
/// \param m is the manager for looking up AddressSpaces /// \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()); uint4 elemId = decoder.openElement(ELEM_STRINGMANAGE);
List::const_iterator iter1; for (;;) {
for (iter1 = list.begin(); iter1 != list.end(); ++iter1) { uint4 subId = decoder.openElement();
List::const_iterator iter2 = (*iter1)->getChildren().begin(); if (subId != ELEM_STRING) break;
Address addr = Address::restoreXml(*iter2, m); Address addr = Address::decode(decoder, m);
++iter2;
StringData &stringData(stringMap[addr]); StringData &stringData(stringMap[addr]);
stringData.isTruncated = xml_readbool((*iter2)->getAttributeValue("trunc")); uint4 subId2 = decoder.openElement(ELEM_BYTES);
istringstream is((*iter2)->getContent()); stringData.isTruncated = decoder.readBool(ATTRIB_TRUNC);
istringstream is(decoder.readString(ATTRIB_CONTENT));
int4 val; int4 val;
char c1, c2; char c1, c2;
is >> ws; is >> ws;
@ -147,7 +156,10 @@ void StringManager::restoreXml(const Element *el, const AddrSpaceManager *m)
c1 = is.get(); c1 = is.get();
c2 = is.get(); c2 = is.get();
} }
decoder.closeElement(subId2);
decoder.closeElement(subId);
} }
decoder.closeElement(elemId);
} }
/// \param buffer is the byte buffer /// \param buffer is the byte buffer

View file

@ -23,6 +23,12 @@
class Architecture; class Architecture;
extern AttributeId ATTRIB_TRUNC; ///< Marshaling attribute "trunc"
extern ElementId ELEM_BYTES; ///< Marshaling element \<bytes>
extern ElementId ELEM_STRING; ///< Marshaling element \<string>
extern ElementId ELEM_STRINGMANAGE; ///< Marshaling element \<stringmanage>
/// \brief Storage for decoding and storing strings associated with an address /// \brief Storage for decoding and storing strings associated with an address
/// ///
/// Looks at data in the loadimage to determine if it represents a "string". /// 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 /// \return the byte array of UTF8 data
virtual const vector<uint1> &getStringData(const Address &addr,Datatype *charType,bool &isTrunc)=0; virtual const vector<uint1> &getStringData(const Address &addr,Datatype *charType,bool &isTrunc)=0;
void saveXml(ostream &s) const; ///< Save cached strings to a stream as XML void encode(Encoder &encoder) const; ///< Encode cached strings to a stream
void restoreXml(const Element *el,const AddrSpaceManager *m); ///< Restore string cache from XML 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 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 static int4 readUtf16(const uint1 *buf,bool bigend); ///< Read a UTF16 code point from a byte array

View file

@ -16,6 +16,8 @@
#include "transform.hh" #include "transform.hh"
#include "funcdata.hh" #include "funcdata.hh"
AttributeId ATTRIB_VECTOR_LANE_SIZES = AttributeId("vector_lane_sizes",103);
/// \param op2 is the lane description to copy from /// \param op2 is the lane description to copy from
LaneDescription::LaneDescription(const LaneDescription &op2) LaneDescription::LaneDescription(const LaneDescription &op2)
@ -277,24 +279,32 @@ void LanedRegister::LanedIterator::normalize(void)
size = -1; // Indicate ending iterator size = -1; // Indicate ending iterator
} }
/// Read XML of the form \<register name=".." vector_lane_sizes=".."/> /// Parse any vector lane sizes.
/// \param el is the particular \e register tag /// \param decoder is the stream decoder
/// \param manage is used to map register names to storage info /// \param manage is used to map register names to storage info
/// \return \b true if the XML description provides lane sizes /// \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; string laneSizes;
for(int4 i=0;i<el->getNumAttributes();++i) { for(;;) {
if (el->getAttributeName(i) == "vector_lane_sizes") { uint4 attribId = decoder.getNextAttributeId();
laneSizes = el->getAttributeValue(i); if (attribId == 0) break;
if (attribId == ATTRIB_VECTOR_LANE_SIZES) {
laneSizes = decoder.readString();
break; break;
} }
} }
if (laneSizes.empty()) return false; if (laneSizes.empty()) {
decoder.closeElement(elemId);
return false;
}
decoder.rewindAttributes();
VarnodeData storage; VarnodeData storage;
storage.space = (AddrSpace *)0; storage.space = (AddrSpace *)0;
storage.restoreXml(el, manage); storage.decodeFromAttributes(decoder, manage);
decoder.closeElement(elemId);
wholeSize = storage.size; wholeSize = storage.size;
sizeBitMask = 0; sizeBitMask = 0;
string::size_type pos = 0; string::size_type pos = 0;

View file

@ -22,6 +22,8 @@
class Funcdata; // Forward declaration class Funcdata; // Forward declaration
class TransformOp; 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 /// \brief Placeholder node for Varnode that will exist after a transform is applied to a function
class TransformVar { class TransformVar {
friend class TransformManager; friend class TransformManager;
@ -107,9 +109,9 @@ private:
int4 wholeSize; ///< Size of the whole register int4 wholeSize; ///< Size of the whole register
uint4 sizeBitMask; ///< A 1-bit for every permissible lane size uint4 sizeBitMask; ///< A 1-bit for every permissible lane size
public: 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 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 \<register> elements for lane sizes
int4 getWholeSize(void) const { return wholeSize; } ///< Get the size in bytes of the whole laned register 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 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 void addLaneSize(int4 size) { sizeBitMask |= ((uint4)1 << size); } ///< Add a new \e size to the allowed list

View file

@ -15,15 +15,31 @@
*/ */
#include "translate.hh" #include "translate.hh"
/// Read a \<truncate_space> XML tag to configure \b this object AttributeId ATTRIB_CODE = AttributeId("code",104);
/// \param el is the XML element AttributeId ATTRIB_CONTAIN = AttributeId("contain",105);
void TruncationTag::restoreXml(const Element *el) 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 \<truncate_space> element to configure \b this object
/// \param decoder is the stream decoder
void TruncationTag::decode(Decoder &decoder)
{ {
spaceName = el->getAttributeValue("space"); uint4 elemId = decoder.openElement(ELEM_TRUNCATE_SPACE);
istringstream s(el->getAttributeValue("size")); spaceName = decoder.readString(ATTRIB_SPACE);
s.unsetf(ios::dec | ios::hex | ios::oct); size = decoder.readUnsignedInteger(ATTRIB_SIZE);
s >> size; decoder.closeElement(elemId);
} }
/// Construct a virtual space. This is usually used for the stack /// 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 /// 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 /// attributes
/// \param m is the associated address space manager /// \param m is the associated address space manager
/// \param t is the associated processor translator /// \param t is the associated processor translator
@ -111,11 +127,13 @@ void SpacebaseSpace::saveXml(ostream &s) const
s << "/>\n"; s << "/>\n";
} }
void SpacebaseSpace::restoreXml(const Element *el) void SpacebaseSpace::decode(Decoder &decoder)
{ {
AddrSpace::restoreXml(el); // Restore basic attributes uint4 elemId = decoder.openElement(ELEM_SPACE_BASE);
contain = getManager()->getSpaceByName(el->getAttributeValue("contain")); 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. /// 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 /// The initialization of address spaces is the same across all
/// variants of the Translate object. This routine initializes /// 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 /// which class derived from AddrSpace to instantiate based on
/// the tag name. /// the ElementId.
/// \param el is the parsed XML tag /// \param decoder is the stream decoder
/// \param trans is the translator object to be associated with the new space /// \param trans is the translator object to be associated with the new space
/// \return a pointer to the initialized AddrSpace /// \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; AddrSpace *res;
const string &tp(el->getName()); if (elemId == ELEM_SPACE_BASE)
if (tp == "space_base")
res = new SpacebaseSpace(this,trans); res = new SpacebaseSpace(this,trans);
else if (tp == "space_unique") else if (elemId == ELEM_SPACE_UNIQUE)
res = new UniqueSpace(this,trans); res = new UniqueSpace(this,trans);
else if (tp == "space_other") else if (elemId == ELEM_SPACE_OTHER)
res = new OtherSpace(this,trans); res = new OtherSpace(this,trans);
else if (tp == "space_overlay") else if (elemId == ELEM_SPACE_OVERLAY)
res = new OverlaySpace(this,trans); res = new OverlaySpace(this,trans);
else else
res = new AddrSpace(this,trans,IPTR_PROCESSOR); res = new AddrSpace(this,trans,IPTR_PROCESSOR);
res->restoreXml(el); res->decode(decoder);
return res; return res;
} }
/// This routine initializes (almost) all the address spaces used /// This routine initializes (almost) all the address spaces used
/// for a particular processor by using a \b \<spaces\> tag, /// for a particular processor by using a \b \<spaces\> element,
/// which contains subtags for the specific address spaces. /// which contains child elements for the specific address spaces.
/// This also instantiates the builtin \e constant space. It /// This also instantiates the builtin \e constant space. It
/// should probably also instantiate the \b iop, \b fspec, and \b join /// should probably also instantiate the \b iop, \b fspec, and \b join
/// spaces, but this is currently done by the Architecture class. /// spaces, but this is currently done by the Architecture class.
/// \param el is the parsed \b \<spaces\> tag /// \param decoder is the stream decoder
/// \param trans is the processor translator to be associated with the spaces /// \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 // The first space should always be the constant space
insertSpace(new ConstantSpace(this,trans)); insertSpace(new ConstantSpace(this,trans));
string defname(el->getAttributeValue("defaultspace")); uint4 elemId = decoder.openElement(ELEM_SPACES);
const List &list(el->getChildren()); string defname = decoder.readString(ATTRIB_DEFAULTSPACE);
List::const_iterator iter; while(decoder.peekElement() != 0) {
iter = list.begin(); AddrSpace *spc = decodeSpace(decoder,trans);
while(iter!=list.end()) {
AddrSpace *spc = restoreXmlSpace(*iter,trans);
insertSpace(spc); insertSpace(spc);
++iter;
} }
decoder.closeElement(elemId);
AddrSpace *spc = getSpaceByName(defname); AddrSpace *spc = getSpaceByName(defname);
if (spc == (AddrSpace *)0) if (spc == (AddrSpace *)0)
throw LowlevelError("Bad 'defaultspace' attribute: "+defname); throw LowlevelError("Bad 'defaultspace' attribute: "+defname);
@ -887,44 +903,48 @@ const FloatFormat *Translate::getFloatFormat(int4 size) const
return (const FloatFormat *)0; return (const FloatFormat *)0;
} }
/// A convenience method for passing around pcode operations via /// A convenience method for passing around pcode operations via stream.
/// XML. A single pcode operation is parsed from an XML tag and /// A single pcode operation is parsed from an \<op> element and
/// returned to the application via the PcodeEmit::dump method. /// 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 /// \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; int4 opcode;
VarnodeData outvar; VarnodeData outvar;
VarnodeData invar[30]; VarnodeData invar[30];
VarnodeData *outptr; VarnodeData *outptr;
istringstream i(el->getAttributeValue("code")); uint4 elemId = decoder.openElement(ELEM_OP);
i >> opcode; opcode = decoder.readSignedInteger(ATTRIB_CODE);
const List &list(el->getChildren()); Address pc = Address::decode(decoder,manage);
List::const_iterator iter = list.begin(); uint4 subId = decoder.peekElement();
Address pc = Address::restoreXml(*iter,manage); if (subId == ELEM_VOID) {
++iter; decoder.openElement();
if ((*iter)->getName() == "void") decoder.closeElement(subId);
outptr = (VarnodeData *)0; outptr = (VarnodeData *)0;
}
else { else {
outvar.restoreXml(*iter,manage); outvar.decode(decoder,manage);
outptr = &outvar; outptr = &outvar;
} }
++iter;
int4 isize = 0; int4 isize = 0;
while(iter != list.end() && isize < 30) { while(isize < 30) {
if ((*iter)->getName() == "spaceid") { subId = decoder.peekElement();
if (subId == 0) break;
if (subId == ELEM_SPACEID) {
decoder.openElement();
invar[isize].space = manage->getConstantSpace(); 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 *); invar[isize].size = sizeof(void *);
decoder.closeElement(subId);
} }
else else
invar[isize].restoreXml(*iter,manage); invar[isize].decode(decoder,manage);
isize += 1; isize += 1;
++iter;
} }
decoder.closeElement(elemId);
dump(pc,(OpCode)opcode,outptr,invar,isize); dump(pc,(OpCode)opcode,outptr,invar,isize);
} }

View file

@ -24,6 +24,22 @@
#include "pcoderaw.hh" #include "pcoderaw.hh"
#include "float.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 \<op>
extern ElementId ELEM_SLEIGH; ///< Marshaling element \<sleigh>
extern ElementId ELEM_SPACE; ///< Marshaling element \<space>
extern ElementId ELEM_SPACEID; ///< Marshaling element \<spaceid>
extern ElementId ELEM_SPACES; ///< Marshaling element \<spaces>
extern ElementId ELEM_SPACE_BASE; ///< Marshaling element \<space_base>
extern ElementId ELEM_SPACE_OTHER; ///< Marshaling element \<space_other>
extern ElementId ELEM_SPACE_OVERLAY; ///< Marshaling element \<space_overlay>
extern ElementId ELEM_SPACE_UNIQUE; ///< Marshaling element \<space_unique>
extern ElementId ELEM_TRUNCATE_SPACE; ///< Marshaling element \<truncate_space>
// Some errors specific to the translation unit // Some errors specific to the translation unit
/// \brief Exception for encountering unimplemented pcode /// \brief Exception for encountering unimplemented pcode
@ -64,7 +80,7 @@ class TruncationTag {
string spaceName; ///< Name of space to be truncated string spaceName; ///< Name of space to be truncated
uint4 size; ///< Size truncated addresses into the space uint4 size; ///< Size truncated addresses into the space
public: 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 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 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 /// \param isize is the number of input varnodes
virtual void dump(const Address &addr,OpCode opc,VarnodeData *outvar,VarnodeData *vars,int4 isize)=0; virtual void dump(const Address &addr,OpCode opc,VarnodeData *outvar,VarnodeData *vars,int4 isize)=0;
/// Emit pcode directly from an XML tag /// Emit pcode directly from an \<op> element
void restoreXmlOp(const Element *el,const AddrSpaceManager *trans); void decodeOp(Decoder &decoder,const AddrSpaceManager *trans);
enum { // Tags for packed pcode format enum { // Tags for packed pcode format
unimpl_tag = 0x20, 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 void setBaseRegister(const VarnodeData &data,int4 origSize,bool stackGrowth); ///< Set the base register at time space is created
public: public:
SpacebaseSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind,int4 sz,AddrSpace *base,int4 dl); 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 int4 numSpacebase(void) const;
virtual const VarnodeData &getSpacebase(int4 i) const; virtual const VarnodeData &getSpacebase(int4 i) const;
virtual const VarnodeData &getSpacebaseFull(int4 i) const; virtual const VarnodeData &getSpacebaseFull(int4 i) const;
virtual bool stackGrowsNegative(void) const { return isNegativeStack; } virtual bool stackGrowsNegative(void) const { return isNegativeStack; }
virtual AddrSpace *getContain(void) const { return contain; } ///< Return containing space virtual AddrSpace *getContain(void) const { return contain; } ///< Return containing space
virtual void saveXml(ostream &s) const; 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 /// \brief A record describing how logical values are split
@ -232,8 +248,8 @@ class AddrSpaceManager {
set<JoinRecord *,JoinRecordCompare> splitset; ///< Different splits that have been defined in join space set<JoinRecord *,JoinRecordCompare> splitset; ///< Different splits that have been defined in join space
vector<JoinRecord *> splitlist; ///< JoinRecords indexed by join address vector<JoinRecord *> splitlist; ///< JoinRecords indexed by join address
protected: protected:
AddrSpace *restoreXmlSpace(const Element *el,const Translate *trans); ///< Add a space to the model based an on XML tag AddrSpace *decodeSpace(Decoder &decoder,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 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 setDefaultCodeSpace(int4 index); ///< Set the default address space (for code)
void setDefaultDataSpace(int4 index); ///< Set the default address space for data void setDefaultDataSpace(int4 index); ///< Set the default address space for data
void setReverseJustified(AddrSpace *spc); ///< Set reverse justified property on this space void setReverseJustified(AddrSpace *spc); ///< Set reverse justified property on this space

File diff suppressed because it is too large Load diff

View file

@ -21,6 +21,34 @@
#include "address.hh" #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 \<coretypes>
extern ElementId ELEM_DATA_ORGANIZATION; ///< Marshaling element \<data_organization>
extern ElementId ELEM_DEF; ///< Marshaling element \<def>
extern ElementId ELEM_ENTRY; ///< Marshaling element \<entry>
extern ElementId ELEM_ENUM; ///< Marshaling element \<enum>
extern ElementId ELEM_FIELD; ///< Marshaling element \<field>
extern ElementId ELEM_INTEGER_SIZE; ///< Marshaling element \<integer_size>
extern ElementId ELEM_LONG_SIZE; ///< Marshaling element \<long_size>
extern ElementId ELEM_SIZE_ALIGNMENT_MAP; ///< Marshaling element \<size_alignment_map>
extern ElementId ELEM_TYPE; ///< Marshaling element \<type>
extern ElementId ELEM_TYPEGRP; ///< Marshaling element \<typegrp>
extern ElementId ELEM_TYPEREF; ///< Marshaling element \<typeref>
/// Print a hex dump of a data buffer to stream /// 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_data(ostream &s,uint1 *buffer,int4 size,const Address &baseaddr);
//extern void print_char(ostream &s,int4 onechar); //extern void print_char(ostream &s,int4 onechar);
@ -115,9 +143,9 @@ protected:
uint4 flags; ///< Boolean properties of the type uint4 flags; ///< Boolean properties of the type
uint8 id; ///< A unique id for the type (or 0 if an id is not assigned) uint8 id; ///< A unique id for the type (or 0 if an id is not assigned)
Datatype *typedefImm; ///< The immediate data-type being typedefed by \e this Datatype *typedefImm; ///< The immediate data-type being typedefed by \e this
void restoreXmlBasic(const Element *el); ///< Recover basic data-type properties void decodeBasic(Decoder &decoder); ///< Recover basic data-type properties
void saveXmlBasic(type_metatype meta,ostream &s) const; ///< Save basic data-type properties void encodeBasic(type_metatype meta,Encoder &encoder) const; ///< Encode basic data-type properties
void saveXmlTypedef(ostream &s) const; ///< Write \b this as a \e typedef tag to stream 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 markComplete(void) { flags &= ~(uint4)type_incomplete; } ///< Mark \b this data-type as completely defined
void setDisplayFormat(uint4 format); ///< Set a specific display format void setDisplayFormat(uint4 format); ///< Set a specific display format
virtual Datatype *clone(void) const=0; ///< Clone the data-type 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<<name[0]; } ///< Print name as short prefix virtual void printNameBase(ostream &s) const { if (!name.empty()) s<<name[0]; } ///< Print name as short prefix
virtual int4 compare(const Datatype &op,int4 level) const; ///< Order types for propagation virtual int4 compare(const Datatype &op,int4 level) const; ///< Order types for propagation
virtual int4 compareDependency(const Datatype &op) const; ///< Compare for storage in tree structure virtual int4 compareDependency(const Datatype &op) const; ///< Compare for storage in tree structure
virtual void saveXml(ostream &s) const; ///< Serialize the data-type to XML virtual void encode(Encoder &encoder) const; ///< Encode the data-type to a stream
virtual bool isPtrsubMatching(uintb off) const; ///< Is this data-type suitable as input to a CPUI_PTRSUB op virtual bool isPtrsubMatching(uintb off) const; ///< Is this data-type suitable as input to a CPUI_PTRSUB op
virtual Datatype *getStripped(void) const; ///< Get a stripped version of \b this for formal use in formal declarations virtual Datatype *getStripped(void) const; ///< Get a stripped version of \b this for formal use in formal declarations
virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot); ///< Tailor data-type propagation based on Varnode use virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot); ///< Tailor data-type propagation based on Varnode use
@ -170,7 +198,7 @@ public:
virtual int4 findCompatibleResolve(Datatype *ct) const; ///< Find a resolution compatible with the given data-type virtual int4 findCompatibleResolve(Datatype *ct) const; ///< Find a resolution compatible with the given data-type
int4 typeOrder(const Datatype &op) const { if (this==&op) return 0; return compare(op,10); } ///< Order this with -op- datatype int4 typeOrder(const Datatype &op) const { if (this==&op) return 0; return compare(op,10); } ///< Order this with -op- datatype
int4 typeOrderBool(const Datatype &op) const; ///< Order \b this with -op-, treating \e bool data-type as special int4 typeOrderBool(const Datatype &op) const; ///< Order \b this with -op-, treating \e bool data-type as special
void saveXmlRef(ostream &s) const; ///< Write an XML reference of \b this to stream void encodeRef(Encoder &encoder) const; ///< Encode a reference of \b this to a stream
static uint4 encodeIntegerFormat(const string &val); static uint4 encodeIntegerFormat(const string &val);
static string decodeIntegerFormat(uint4 val); static string decodeIntegerFormat(uint4 val);
}; };
@ -182,10 +210,10 @@ public:
int4 offset; ///< Offset (into containing structure or union) of subfield int4 offset; ///< Offset (into containing structure or union) of subfield
string name; ///< Name of subfield string name; ///< Name of subfield
Datatype *type; ///< Data-type of subfield Datatype *type; ///< Data-type of subfield
TypeField(const Element *el,TypeFactory &typegrp); ///< Restore \b this field from an XML stream TypeField(Decoder &decoder,TypeFactory &typegrp); ///< Restore \b this field from a stream
TypeField(int4 id,int4 off,const string &nm,Datatype *ct) { ident=id; offset=off; name=nm; type=ct; } ///< Construct from components TypeField(int4 id,int4 off,const string &nm,Datatype *ct) { ident=id; offset=off; name=nm; type=ct; } ///< Construct from components
bool operator<(const TypeField &op2) const { return (offset < op2.offset); } ///< Compare based on offset bool operator<(const TypeField &op2) const { return (offset < op2.offset); } ///< Compare based on offset
void saveXml(ostream &s) const; ///< Save \b this field as XML void encode(Encoder &encoder) const; ///< Encode \b this field to a stream
}; };
/// Compare two Datatype pointers for equivalence of their description /// Compare two Datatype pointers for equivalence of their description
@ -234,14 +262,14 @@ public:
class TypeChar : public TypeBase { class TypeChar : public TypeBase {
protected: protected:
friend class TypeFactory; friend class TypeFactory;
void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore \b this char data-type from an XML element void decode(Decoder &decoder,TypeFactory &typegrp); ///< Restore \b this char data-type from a stream
public: public:
/// Construct TypeChar copying properties from another data-type /// Construct TypeChar copying properties from another data-type
TypeChar(const TypeChar &op) : TypeBase(op) { flags |= Datatype::chartype; } TypeChar(const TypeChar &op) : TypeBase(op) { flags |= Datatype::chartype; }
/// Construct a char (always 1-byte) given a name /// Construct a char (always 1-byte) given a name
TypeChar(const string &n) : TypeBase(1,TYPE_INT,n) { flags |= Datatype::chartype; submeta = SUB_INT_CHAR; } TypeChar(const string &n) : TypeBase(1,TYPE_INT,n) { flags |= Datatype::chartype; submeta = SUB_INT_CHAR; }
virtual Datatype *clone(void) const { return new TypeChar(*this); } virtual Datatype *clone(void) const { return new TypeChar(*this); }
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
}; };
/// \brief The unicode data-type: i.e. wchar /// \brief The unicode data-type: i.e. wchar
@ -251,13 +279,13 @@ class TypeUnicode : public TypeBase { // Unicode character type
void setflags(void); ///< Set unicode property flags void setflags(void); ///< Set unicode property flags
protected: protected:
friend class TypeFactory; friend class TypeFactory;
void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore \b this unicode data-type from an XML element void decode(Decoder &decoder,TypeFactory &typegrp); ///< Restore \b this unicode data-type from a stream
public: public:
TypeUnicode(void) : TypeBase(0,TYPE_INT) {} ///< For use with restoreXml TypeUnicode(void) : TypeBase(0,TYPE_INT) {} ///< For use with decode
TypeUnicode(const TypeUnicode &op) : TypeBase(op) {} ///< Construct from another TypeUnicode TypeUnicode(const TypeUnicode &op) : TypeBase(op) {} ///< Construct from another TypeUnicode
TypeUnicode(const string &nm,int4 sz,type_metatype m); ///< Construct given name,size, meta-type TypeUnicode(const string &nm,int4 sz,type_metatype m); ///< Construct given name,size, meta-type
virtual Datatype *clone(void) const { return new TypeUnicode(*this); } virtual Datatype *clone(void) const { return new TypeUnicode(*this); }
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
}; };
/// \brief Formal "void" data-type object. /// \brief Formal "void" data-type object.
@ -273,7 +301,7 @@ public:
/// Constructor /// Constructor
TypeVoid(void) : Datatype(0,TYPE_VOID) { name = "void"; flags |= Datatype::coretype; } TypeVoid(void) : Datatype(0,TYPE_VOID) { name = "void"; flags |= Datatype::coretype; }
virtual Datatype *clone(void) const { return new TypeVoid(*this); } virtual Datatype *clone(void) const { return new TypeVoid(*this); }
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
}; };
/// \brief Datatype object representing a pointer /// \brief Datatype object representing a pointer
@ -283,9 +311,9 @@ protected:
Datatype *ptrto; ///< Type being pointed to Datatype *ptrto; ///< Type being pointed to
AddrSpace *spaceid; ///< If non-null, the address space \b this is intented to point into AddrSpace *spaceid; ///< If non-null, the address space \b this is intented to point into
uint4 wordsize; ///< What size unit does the pointer address uint4 wordsize; ///< What size unit does the pointer address
void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore \b this pointer data-type from an XML element void decode(Decoder &decoder,TypeFactory &typegrp); ///< Restore \b this pointer data-type from a stream
void calcSubmeta(void); ///< Calculate specific submeta for \b this pointer void calcSubmeta(void); ///< Calculate specific submeta for \b this pointer
/// Internal constructor for use with restoreXml /// Internal constructor for use with decode
TypePointer(void) : Datatype(0,TYPE_PTR) { ptrto = (Datatype *)0; wordsize=1; spaceid=(AddrSpace *)0; } TypePointer(void) : Datatype(0,TYPE_PTR) { ptrto = (Datatype *)0; wordsize=1; spaceid=(AddrSpace *)0; }
public: public:
/// Construct from another TypePointer /// Construct from another TypePointer
@ -306,7 +334,7 @@ public:
virtual int4 compare(const Datatype &op,int4 level) const; virtual int4 compare(const Datatype &op,int4 level) const;
virtual int4 compareDependency(const Datatype &op) const; virtual int4 compareDependency(const Datatype &op) const;
virtual Datatype *clone(void) const { return new TypePointer(*this); } virtual Datatype *clone(void) const { return new TypePointer(*this); }
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual TypePointer *downChain(uintb &off,TypePointer *&par,uintb &parOff,bool allowArrayWrap,TypeFactory &typegrp); virtual TypePointer *downChain(uintb &off,TypePointer *&par,uintb &parOff,bool allowArrayWrap,TypeFactory &typegrp);
virtual bool isPtrsubMatching(uintb off) const; virtual bool isPtrsubMatching(uintb off) const;
virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot); virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot);
@ -319,8 +347,8 @@ protected:
friend class TypeFactory; friend class TypeFactory;
Datatype *arrayof; ///< type of which we have an array Datatype *arrayof; ///< type of which we have an array
int4 arraysize; ///< Number of elements in the array int4 arraysize; ///< Number of elements in the array
void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore \b this array from an XML element void decode(Decoder &decoder,TypeFactory &typegrp); ///< Restore \b this array from a stream
/// Internal constructor for restoreXml /// Internal constructor for decode
TypeArray(void) : Datatype(0,TYPE_ARRAY) { arraysize = 0; arrayof = (Datatype *)0; } TypeArray(void) : Datatype(0,TYPE_ARRAY) { arraysize = 0; arrayof = (Datatype *)0; }
public: public:
/// Construct from another TypeArray /// Construct from another TypeArray
@ -338,7 +366,7 @@ public:
virtual int4 compare(const Datatype &op,int4 level) const; // For tree structure virtual int4 compare(const Datatype &op,int4 level) const; // For tree structure
virtual int4 compareDependency(const Datatype &op) const; // For tree structure virtual int4 compareDependency(const Datatype &op) const; // For tree structure
virtual Datatype *clone(void) const { return new TypeArray(*this); } virtual Datatype *clone(void) const { return new TypeArray(*this); }
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot); virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot);
virtual Datatype* findResolve(const PcodeOp *op,int4 slot); virtual Datatype* findResolve(const PcodeOp *op,int4 slot);
virtual int4 findCompatibleResolve(Datatype *ct) const; virtual int4 findCompatibleResolve(Datatype *ct) const;
@ -354,7 +382,7 @@ protected:
map<uintb,string> namemap; ///< Map from integer to name map<uintb,string> namemap; ///< Map from integer to name
vector<uintb> masklist; ///< Masks for each bitfield within the enum vector<uintb> masklist; ///< Masks for each bitfield within the enum
void setNameMap(const map<uintb,string> &nmap); ///< Establish the value -> name map void setNameMap(const map<uintb,string> &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: public:
/// Construct from another TypeEnum /// Construct from another TypeEnum
TypeEnum(const TypeEnum &op); TypeEnum(const TypeEnum &op);
@ -370,7 +398,7 @@ public:
virtual int4 compare(const Datatype &op,int4 level) const; virtual int4 compare(const Datatype &op,int4 level) const;
virtual int4 compareDependency(const Datatype &op) const; virtual int4 compareDependency(const Datatype &op) const;
virtual Datatype *clone(void) const { return new TypeEnum(*this); } 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 /// \brief A composite Datatype object: A \b structure with component \b fields
@ -381,7 +409,7 @@ protected:
void setFields(const vector<TypeField> &fd); ///< Establish fields for \b this void setFields(const vector<TypeField> &fd); ///< Establish fields for \b this
int4 getFieldIter(int4 off) const; ///< Get index into field list 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 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 int4 scoreFill(PcodeOp *op,int4 slot) const; ///< Determine best type fit for given PcodeOp use
public: public:
TypeStruct(const TypeStruct &op); ///< Construct from another TypeStruct 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 compare(const Datatype &op,int4 level) const; // For tree structure
virtual int4 compareDependency(const Datatype &op) const; // For tree structure virtual int4 compareDependency(const Datatype &op) const; // For tree structure
virtual Datatype *clone(void) const { return new TypeStruct(*this); } 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 *resolveInFlow(PcodeOp *op,int4 slot);
virtual Datatype* findResolve(const PcodeOp *op,int4 slot); virtual Datatype* findResolve(const PcodeOp *op,int4 slot);
virtual int4 findCompatibleResolve(Datatype *ct) const; virtual int4 findCompatibleResolve(Datatype *ct) const;
@ -413,7 +441,7 @@ protected:
friend class TypeFactory; friend class TypeFactory;
vector<TypeField> field; ///< The list of fields vector<TypeField> field; ///< The list of fields
void setFields(const vector<TypeField> &fd); ///< Establish fields for \b this void setFields(const vector<TypeField> &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: public:
TypeUnion(const TypeUnion &op); ///< Construct from another TypeUnion TypeUnion(const TypeUnion &op); ///< Construct from another TypeUnion
TypeUnion(void) : Datatype(0,TYPE_UNION) { flags |= (type_incomplete | needs_resolution); } ///< Construct incomplete TypeUnion TypeUnion(void) : Datatype(0,TYPE_UNION) { flags |= (type_incomplete | needs_resolution); } ///< Construct incomplete TypeUnion
@ -424,7 +452,7 @@ public:
virtual int4 compare(const Datatype &op,int4 level) const; // For tree structure virtual int4 compare(const Datatype &op,int4 level) const; // For tree structure
virtual int4 compareDependency(const Datatype &op) const; // For tree structure virtual int4 compareDependency(const Datatype &op) const; // For tree structure
virtual Datatype *clone(void) const { return new TypeUnion(*this); } 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 *resolveInFlow(PcodeOp *op,int4 slot);
virtual Datatype* findResolve(const PcodeOp *op,int4 slot); virtual Datatype* findResolve(const PcodeOp *op,int4 slot);
virtual int4 findCompatibleResolve(Datatype *ct) const; virtual int4 findCompatibleResolve(Datatype *ct) const;
@ -442,8 +470,8 @@ protected:
Datatype *parent; ///< Parent structure or array which \b this is pointing into Datatype *parent; ///< Parent structure or array which \b this is pointing into
int4 offset; ///< Byte offset within the parent where \b this points to int4 offset; ///< Byte offset within the parent where \b this points to
void cacheStrippedType(TypeFactory &typegrp); void cacheStrippedType(TypeFactory &typegrp);
void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore \b this relative pointer data-type from an XML element void decode(Decoder &decoder,TypeFactory &typegrp); ///< Restore \b this relative pointer data-type from a stream
/// Internal constructor for restoreXml /// Internal constructor for decode
TypePointerRel(void) : TypePointer() { offset = 0; parent = (Datatype *)0; stripped = (TypePointer *)0; submeta = SUB_PTRREL; } TypePointerRel(void) : TypePointer() { offset = 0; parent = (Datatype *)0; stripped = (TypePointer *)0; submeta = SUB_PTRREL; }
public: public:
/// Construct from another TypePointerRel /// Construct from another TypePointerRel
@ -464,7 +492,7 @@ public:
virtual int4 compare(const Datatype &op,int4 level) const; virtual int4 compare(const Datatype &op,int4 level) const;
virtual int4 compareDependency(const Datatype &op) const; virtual int4 compareDependency(const Datatype &op) const;
virtual Datatype *clone(void) const { return new TypePointerRel(*this); } 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 TypePointer *downChain(uintb &off,TypePointer *&par,uintb &parOff,bool allowArrayWrap,TypeFactory &typegrp);
virtual bool isPtrsubMatching(uintb off) const; virtual bool isPtrsubMatching(uintb off) const;
virtual Datatype *getStripped(void) const { return stripped; } ///< Get the plain form of the pointer virtual Datatype *getStripped(void) const { return stripped; } ///< Get the plain form of the pointer
@ -486,8 +514,8 @@ protected:
Datatype *outtype,const vector<Datatype *> &intypes, Datatype *outtype,const vector<Datatype *> &intypes,
bool dotdotdot,Datatype *voidtype); ///< Establish a function pointer bool dotdotdot,Datatype *voidtype); ///< Establish a function pointer
void setPrototype(TypeFactory *typegrp,const FuncProto *fp); ///< Set a particular function prototype on \b this 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 decodeStub(Decoder &decoder); ///< 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 decodePrototype(Decoder &decoder,bool isConstructor,bool isDestructor,TypeFactory &typegrp); ///< Restore any prototype description
public: public:
TypeCode(const TypeCode &op); ///< Construct from another TypeCode TypeCode(const TypeCode &op); ///< Construct from another TypeCode
TypeCode(void); ///< Construct an incomplete TypeCode TypeCode(void); ///< Construct an incomplete TypeCode
@ -499,7 +527,7 @@ public:
virtual int4 compare(const Datatype &op,int4 level) const; virtual int4 compare(const Datatype &op,int4 level) const;
virtual int4 compareDependency(const Datatype &op) const; virtual int4 compareDependency(const Datatype &op) const;
virtual Datatype *clone(void) const { return new TypeCode(*this); } 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 /// \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 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") Address localframe; ///< Address of function whose symbol table is indexed (or INVALID for "global")
Architecture *glb; ///< Architecture for accessing symbol table 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: public:
/// Construct from another TypeSpacebase /// Construct from another TypeSpacebase
TypeSpacebase(const TypeSpacebase &op) : Datatype(op) { TypeSpacebase(const TypeSpacebase &op) : Datatype(op) {
@ -529,7 +557,7 @@ public:
virtual int4 compare(const Datatype &op,int4 level) const; virtual int4 compare(const Datatype &op,int4 level) const;
virtual int4 compareDependency(const Datatype &op) const; // For tree structure virtual int4 compareDependency(const Datatype &op) const; // For tree structure
virtual Datatype *clone(void) const { return new TypeSpacebase(*this); } 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 /// \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 void insert(Datatype *newtype); ///< Insert pointer into the cross-reference sets
Datatype *findAdd(Datatype &ct); ///< Find data-type in this container or add it Datatype *findAdd(Datatype &ct); ///< Find data-type in this container or add it
void orderRecurse(vector<Datatype *> &deporder,DatatypeSet &mark,Datatype *ct) const; ///< Write out dependency list void orderRecurse(vector<Datatype *> &deporder,DatatypeSet &mark,Datatype *ct) const; ///< Write out dependency list
Datatype *restoreTypedef(const Element *el); ///< Restore a \<def> XML tag describing a typedef Datatype *decodeTypedef(Decoder &decoder); ///< Restore a \<def> element describing a typedef
Datatype *restoreStruct(const Element *el,bool forcecore); ///< Restore a \<type> XML tag describing a structure Datatype *decodeStruct(Decoder &decoder,bool forcecore); ///< Restore a \<type> element describing a structure
Datatype *restoreUnion(const Element *el,bool forcecore); ///< Restore a \<type> XML tag describing a union Datatype *decodeUnion(Decoder &decoder,bool forcecore); ///< Restore a \<type> element describing a union
Datatype *restoreCode(const Element *el,bool isConstructor,bool isDestructor,bool forcecore); ///< Restore XML tag describing a code object Datatype *decodeCode(Decoder &decoder,bool isConstructor,bool isDestructor,bool forcecore); ///< Restore an element describing a code object
Datatype *restoreXmlTypeNoRef(const Element *el,bool forcecore); ///< Restore from an XML tag Datatype *decodeTypeNoRef(Decoder &decoder,bool forcecore); ///< Restore from a stream
void clearCache(void); ///< Clear the common type cache void clearCache(void); ///< Clear the common type cache
TypeChar *getTypeChar(const string &n); ///< Create a default "char" type 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 TypeUnicode *getTypeUnicode(const string &nm,int4 sz,type_metatype m); ///< Create a default "unicode" type
@ -584,8 +612,8 @@ public:
const vector<uintb> &vallist, const vector<uintb> &vallist,
const vector<bool> &assignlist, const vector<bool> &assignlist,
TypeEnum *te); ///< Set named values for an enumeration TypeEnum *te); ///< Set named values for an enumeration
Datatype *restoreXmlType(const Element *el); ///< Restore Datatype from XML Datatype *decodeType(Decoder &decoder); ///< Restore Datatype from a stream
Datatype *restoreXmlTypeWithCodeFlags(const Element *el,bool isConstructor,bool isDestructor); Datatype *decodeTypeWithCodeFlags(Decoder &decoder,bool isConstructor,bool isDestructor);
TypeVoid *getTypeVoid(void); ///< Get the "void" data-type TypeVoid *getTypeVoid(void); ///< Get the "void" data-type
Datatype *getBaseNoChar(int4 s,type_metatype m); ///< Get atomic type excluding "char" Datatype *getBaseNoChar(int4 s,type_metatype m); ///< Get atomic type excluding "char"
Datatype *getBase(int4 s,type_metatype m); ///< Get atomic type 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 void destroyType(Datatype *ct); ///< Remove a data-type from \b this
Datatype *concretize(Datatype *ct); ///< Convert given data-type to concrete form Datatype *concretize(Datatype *ct); ///< Convert given data-type to concrete form
void dependentOrder(vector<Datatype *> &deporder) const; ///< Place all data-types in dependency order void dependentOrder(vector<Datatype *> &deporder) const; ///< Place all data-types in dependency order
void saveXml(ostream &s) const; ///< Save \b this container to stream void encode(Encoder &encoder) const; ///< Encode \b this container to stream
void saveXmlCoreTypes(ostream &s) const; ///< Save core types to stream void encodeCoreTypes(Encoder &encoder) const; ///< Encode core types to stream
void restoreXml(const Element *el); ///< Restore \b this container from a stream void decode(Decoder &decoder); ///< Decode \b this from a \<typegrp> element
void restoreXmlCoreTypes(const Element *el); ///< Initialize basic type names void decodeCoreTypes(Decoder &decoder); ///< Initialize basic data-types from a stream
void parseDataOrganization(const Element *el); ///< Parse the \<data_organization> tag void decodeDataOrganization(Decoder &decoder); ///< Parse a \<data_organization> element
void parseEnumConfig(const Element *el); ///< Parse the \<enum> tag void parseEnumConfig(Decoder &decoder); ///< Parse the \<enum> tag
void setCoreType(const string &name,int4 size,type_metatype meta,bool chartp); ///< Create a core data-type void setCoreType(const string &name,int4 size,type_metatype meta,bool chartp); ///< Create a core data-type
void cacheCoreTypes(void); ///< Cache common types void cacheCoreTypes(void); ///< Cache common types
}; };

View file

@ -20,16 +20,14 @@ Datatype *TypeFactoryGhidra::findById(const string &n,uint8 id,int4 sz)
{ {
Datatype *ct = TypeFactory::findById(n,id,sz); // Try internal find Datatype *ct = TypeFactory::findById(n,id,sz); // Try internal find
if (ct != (Datatype *)0) return ct; if (ct != (Datatype *)0) return ct;
XmlDecode decoder;
Document *doc;
try { 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) { catch(XmlError &err) {
throw LowlevelError("XML error: "+err.explain); throw LowlevelError("XML error: "+err.explain);
} }
if (doc == (Document *)0) return (Datatype *)0; ct = decodeType(decoder); // Parse ghidra's type
ct = restoreXmlType(doc->getRoot()); // Parse ghidra's type
delete doc;
return ct; return ct;
} }

View file

@ -16,10 +16,19 @@
#include "userop.hh" #include "userop.hh"
#include "funcdata.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); name = glb->pcodeinjectlib->getCallOtherTarget(injectid);
UserPcodeOp *base = glb->userops.getOp(name); UserPcodeOp *base = glb->userops.getOp(name);
// This tag overrides the base functionality of a userop // 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()); return appendSize(name,op->getOut()->getSize());
} }
void VolatileReadOp::restoreXml(const Element *el)
{
name = el->getAttributeValue("inputop");
}
string VolatileWriteOp::getOperatorName(const PcodeOp *op) const 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()); return appendSize(name,op->getIn(2)->getSize());
} }
void VolatileWriteOp::restoreXml(const Element *el)
{
name = el->getAttributeValue("outputop");
}
/// Process either a \<baseop> or \<innerop> 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;i<el->getNumAttributes();++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 g is the owning Architecture for this instance of the segment operation
/// \param nm is the low-level name 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 /// \param ind is the constant id identifying the specific CALLOTHER variant
@ -160,26 +120,29 @@ uintb SegmentOp::execute(const vector<uintb> &input) const
return pcodeScript->evaluate(input); 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; injectId = -1;
baseinsize = 0; baseinsize = 0;
innerinsize = 0; innerinsize = 0;
supportsfarpointer = false; supportsfarpointer = false;
name = "segment"; // Default name, might be overridden by userop attribute name = "segment"; // Default name, might be overridden by userop attribute
for(int4 i=0;i<el->getNumAttributes();++i) { for(;;) {
const string &nm(el->getAttributeName(i)); uint4 attribId = decoder.getNextAttributeId();
if (nm == "space") continue; if (attribId == 0) break;
else if (nm == "farpointer") if (attribId == ATTRIB_SPACE)
spc = glb->getSpaceByName(decoder.readString());
else if (attribId == ATTRIB_FARPOINTER)
supportsfarpointer = true; supportsfarpointer = true;
else if (nm == "userop") { // Based on existing sleigh op else if (attribId == ATTRIB_USEROP) { // Based on existing sleigh op
name = el->getAttributeValue(i); name = decoder.readString();
} }
else
throw LowlevelError("Bad segmentop tag attribute: "+nm);
} }
if (spc == (AddrSpace *)0)
throw LowlevelError("<segmentop> expecting space attribute");
UserPcodeOp *otherop = glb->userops.getOp(name); UserPcodeOp *otherop = glb->userops.getOp(name);
if (otherop == (UserPcodeOp *)0) if (otherop == (UserPcodeOp *)0)
throw LowlevelError("<segmentop> unknown userop " + name); throw LowlevelError("<segmentop> unknown userop " + name);
@ -187,30 +150,27 @@ void SegmentOp::restoreXml(const Element *el)
if (dynamic_cast<UnspecializedPcodeOp *>(otherop) == (UnspecializedPcodeOp *)0) if (dynamic_cast<UnspecializedPcodeOp *>(otherop) == (UnspecializedPcodeOp *)0)
throw LowlevelError("Redefining userop "+name); throw LowlevelError("Redefining userop "+name);
const List &list(el->getChildren()); for(;;) {
List::const_iterator iter; uint4 subId = decoder.peekElement();
for(iter=list.begin();iter!=list.end();++iter) { if (subId == 0) break;
const Element *subel = *iter; if (subId==ELEM_CONSTRESOLVE) {
if (subel->getName()=="constresolve") {
int4 sz; int4 sz;
const List &sublist(subel->getChildren()); decoder.openElement();
if (!sublist.empty()) { if (decoder.peekElement() != 0) {
List::const_iterator subiter = sublist.begin(); Address addr = Address::decode(decoder,glb,sz);
const Element *subsubel = *subiter;
Address addr = Address::restoreXml(subsubel,glb,sz);
constresolve.space = addr.getSpace(); constresolve.space = addr.getSpace();
constresolve.offset = addr.getOffset(); constresolve.offset = addr.getOffset();
constresolve.size = sz; constresolve.size = sz;
} }
decoder.closeElement(subId);
} }
else if (subel->getName() == "pcode") { else if (subId == ELEM_PCODE) {
string nm = name + "_pcode"; string nm = name + "_pcode";
string source = "cspec"; 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) if (injectId < 0)
throw LowlevelError("Missing <pcode> child in <segmentop> tag"); throw LowlevelError("Missing <pcode> child in <segmentop> tag");
InjectPayload *payload = glb->pcodeinjectlib->getPayload(injectId); InjectPayload *payload = glb->pcodeinjectlib->getPayload(injectId);
@ -237,43 +197,44 @@ JumpAssistOp::JumpAssistOp(Architecture *g)
calcsize = -1; 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 index2case = -1; // Mark as not present until we see a tag
index2addr = -1; index2addr = -1;
defaultaddr = -1; defaultaddr = -1;
calcsize = -1; calcsize = -1;
const List &list(el->getChildren()); for(;;) {
List::const_iterator iter; uint4 subId = decoder.peekElement();
for(iter=list.begin();iter!=list.end();++iter) { if (subId == 0) break;
const Element *subel = *iter; if (subId == ELEM_CASE_PCODE) {
if (subel->getName() == "case_pcode") {
if (index2case != -1) if (index2case != -1)
throw LowlevelError("Too many <case_pcode> tags"); throw LowlevelError("Too many <case_pcode> tags");
index2case = glb->pcodeinjectlib->restoreXmlInject("jumpassistop", name+"_index2case", index2case = glb->pcodeinjectlib->decodeInject("jumpassistop", name+"_index2case",
InjectPayload::EXECUTABLEPCODE_TYPE,subel); InjectPayload::EXECUTABLEPCODE_TYPE,decoder);
} }
else if (subel->getName() == "addr_pcode") { else if (subId == ELEM_ADDR_PCODE) {
if (index2addr != -1) if (index2addr != -1)
throw LowlevelError("Too many <addr_pcode> tags"); throw LowlevelError("Too many <addr_pcode> tags");
index2addr = glb->pcodeinjectlib->restoreXmlInject("jumpassistop", name+"_index2addr", index2addr = glb->pcodeinjectlib->decodeInject("jumpassistop", name+"_index2addr",
InjectPayload::EXECUTABLEPCODE_TYPE,subel); InjectPayload::EXECUTABLEPCODE_TYPE,decoder);
} }
else if (subel->getName() == "default_pcode") { else if (subId == ELEM_DEFAULT_PCODE) {
if (defaultaddr != -1) if (defaultaddr != -1)
throw LowlevelError("Too many <default_pcode> tags"); throw LowlevelError("Too many <default_pcode> tags");
defaultaddr = glb->pcodeinjectlib->restoreXmlInject("jumpassistop", name+"_defaultaddr", defaultaddr = glb->pcodeinjectlib->decodeInject("jumpassistop", name+"_defaultaddr",
InjectPayload::EXECUTABLEPCODE_TYPE,subel); InjectPayload::EXECUTABLEPCODE_TYPE,decoder);
} }
else if (subel->getName() == "size_pcode") { else if (subId == ELEM_SIZE_PCODE) {
if (calcsize != -1) if (calcsize != -1)
throw LowlevelError("Too many <size_pcode> tags"); throw LowlevelError("Too many <size_pcode> tags");
calcsize = glb->pcodeinjectlib->restoreXmlInject("jumpassistop", name+"_calcsize", calcsize = glb->pcodeinjectlib->decodeInject("jumpassistop", name+"_calcsize",
InjectPayload::EXECUTABLEPCODE_TYPE,subel); InjectPayload::EXECUTABLEPCODE_TYPE,decoder);
} }
} }
decoder.closeElement(elemId);
if (index2addr == -1) if (index2addr == -1)
throw LowlevelError("userop: " + name + " is missing <addr_pcode>"); throw LowlevelError("userop: " + name + " is missing <addr_pcode>");
@ -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. /// register it with \b this manager.
/// \param el is the root \<segmentop> element /// \param decoder is the stream decoder
/// \param glb is the owning Architecture /// \param glb is the owning Architecture
void UserOpManage::parseSegmentOp(const Element *el,Architecture *glb) void UserOpManage::decodeSegmentOp(Decoder &decoder,Architecture *glb)
{ {
SegmentOp *s_op; SegmentOp *s_op;
s_op = new SegmentOp(glb,"",useroplist.size()); s_op = new SegmentOp(glb,"",useroplist.size());
try { try {
s_op->restoreXml(el); s_op->decode(decoder);
registerOp(s_op); registerOp(s_op);
} catch(LowlevelError &err) { } catch(LowlevelError &err) {
delete s_op; 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 /// Create either a VolatileReadOp or VolatileWriteOp description object based on
/// the XML details and register it with \b this manager. /// the element and register it with \b this manager.
/// \param el is the root \<volatile> element /// \param decoder is the stream decoder
/// \param glb is the owning Architecture /// \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;i<el->getNumAttributes();++i) { for(;;) {
if (el->getAttributeName(i)=="inputop") { uint4 attribId = decoder.getNextAttributeId();
VolatileReadOp *vr_op = new VolatileReadOp(glb,"",useroplist.size()); if (attribId == 0) break;
if (attribId==ATTRIB_INPUTOP) {
VolatileReadOp *vr_op = new VolatileReadOp(glb,decoder.readString(),useroplist.size());
try { try {
vr_op->restoreXml(el);
registerOp(vr_op); registerOp(vr_op);
} catch(LowlevelError &err) { } catch(LowlevelError &err) {
delete vr_op; delete vr_op;
throw err; throw err;
} }
} }
else if (el->getAttributeName(i)=="outputop") { else if (attribId==ATTRIB_OUTPUTOP) {
// Read in the volatile output tag // 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 { try {
vw_op->restoreXml(el);
registerOp(vw_op); registerOp(vw_op);
} catch(LowlevelError &err) { } catch(LowlevelError &err) {
delete vw_op; 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. /// and register it with \b this manager.
/// \param el is the root \<callotherfixup> element /// \param decoder is the stream decoder
/// \param glb is the owning Architecture /// \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); InjectedUserOp *op = new InjectedUserOp(glb,"",0,0);
try { try {
op->restoreXml(el); op->decode(decoder);
registerOp(op); registerOp(op);
} catch(LowlevelError &err) { } catch(LowlevelError &err) {
delete op; 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. /// and register it with \b this manager.
/// \param el is the root \<jumpassist> element /// \param decoder is the stream decoder
/// \param glb is the owning Architecture /// \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); JumpAssistOp *op = new JumpAssistOp(glb);
try { try {
op->restoreXml(el); op->decode(decoder);
registerOp(op); registerOp(op);
} catch(LowlevelError &err) { } catch(LowlevelError &err) {
delete op; delete op;

View file

@ -21,6 +21,15 @@
#include "typeop.hh" #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 \<constresolve>
extern ElementId ELEM_JUMPASSIST; ///< Marshaling element \<jumpassist>
extern ElementId ELEM_SEGMENTOP; ///< Marshaling element \<segmentop>
/// \brief The base class for a detailed definition of a user-defined p-code operation /// \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 /// 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 /// 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 /// 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 { class UserPcodeOp {
protected: protected:
string name; ///< Low-level name of p-code operator string name; ///< Low-level name of p-code operator
@ -54,12 +63,11 @@ public:
virtual string getOperatorName(const PcodeOp *op) const { virtual string getOperatorName(const PcodeOp *op) const {
return name; } 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 /// The details of how a user defined operation behaves are parsed from the element.
/// from an XML tag. /// \param decoder is the stream decoder
/// \param el is the root XML element describing the op virtual void decode(Decoder &decoder)=0;
virtual void restoreXml(const Element *el)=0;
}; };
/// \brief A user defined p-code op with no specialization /// \brief A user defined p-code op with no specialization
@ -71,7 +79,7 @@ class UnspecializedPcodeOp : public UserPcodeOp {
public: public:
UnspecializedPcodeOp(Architecture *g,const string &nm,int4 ind) UnspecializedPcodeOp(Architecture *g,const string &nm,int4 ind)
: UserPcodeOp(g,nm,ind) {} ///< Constructor : 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 /// \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) InjectedUserOp(Architecture *g,const string &nm,int4 ind,int4 injid)
: UserPcodeOp(g,nm,ind) { injectid = injid; } ///< Constructor : UserPcodeOp(g,nm,ind) { injectid = injid; } ///< Constructor
uint4 getInjectId(void) const { return injectid; } ///< Get the id of the injection object 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 /// \brief A base class for operations that access volatile memory
@ -102,6 +110,7 @@ protected:
public: public:
VolatileOp(Architecture *g,const string &nm,int4 ind) VolatileOp(Architecture *g,const string &nm,int4 ind)
: UserPcodeOp(g,nm,ind) { } ///< Constructor : 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 /// \brief An operation that reads from volatile memory
@ -114,7 +123,6 @@ public:
VolatileReadOp(Architecture *g,const string &nm,int4 ind) VolatileReadOp(Architecture *g,const string &nm,int4 ind)
: VolatileOp(g,nm,ind) {} ///< Constructor : VolatileOp(g,nm,ind) {} ///< Constructor
virtual string getOperatorName(const PcodeOp *op) const; virtual string getOperatorName(const PcodeOp *op) const;
virtual void restoreXml(const Element *el);
}; };
/// \brief An operation that writes to volatile memory /// \brief An operation that writes to volatile memory
@ -128,7 +136,6 @@ public:
VolatileWriteOp(Architecture *g,const string &nm,int4 ind) VolatileWriteOp(Architecture *g,const string &nm,int4 ind)
: VolatileOp(g,nm,ind) {} ///< Constructor : VolatileOp(g,nm,ind) {} ///< Constructor
virtual string getOperatorName(const PcodeOp *op) const; 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 /// \brief A user defined p-code op that has a dynamically defined procedure
@ -161,19 +168,6 @@ public:
virtual uintb execute(const vector<uintb> &input) const=0; virtual uintb execute(const vector<uintb> &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 /// \brief The \e segmented \e address operator
/// ///
/// This op is a placeholder for address mappings involving \b segments. /// 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 int4 getNumVariableTerms(void) const { if (baseinsize!=0) return 2; return 1; }
virtual bool unify(Funcdata &data,PcodeOp *op,vector<Varnode *> &bindlist) const; virtual bool unify(Funcdata &data,PcodeOp *op,vector<Varnode *> &bindlist) const;
virtual uintb execute(const vector<uintb> &input) const; virtual uintb execute(const vector<uintb> &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. /// \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 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 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 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 /// \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 VolatileReadOp *getVolatileRead(void) const { return vol_read; } ///< Get (the) volatile read description
VolatileWriteOp *getVolatileWrite(void) const { return vol_write; } ///< Get (the) volatile write description VolatileWriteOp *getVolatileWrite(void) const { return vol_write; } ///< Get (the) volatile write description
void parseSegmentOp(const Element *el,Architecture *glb); ///< Parse a \<segmentop> XML tag void decodeSegmentOp(Decoder &decoder,Architecture *glb); ///< Parse a \<segmentop> element
void parseVolatile(const Element *el,Architecture *glb); ///< Parse a \<volatile> XML tag void decodeVolatile(Decoder &decoder,Architecture *glb); ///< Parse a \<volatile> element
void parseCallOtherFixup(const Element *el,Architecture *glb); ///< Parse a \<callotherfixup> XML tag void decodeCallOtherFixup(Decoder &decoder,Architecture *glb); ///< Parse a \<callotherfixup> element
void parseJumpAssist(const Element *el,Architecture *glb); ///< Parse a \<jumpassist> XML tag void decodeJumpAssist(Decoder &decoder,Architecture *glb); ///< Parse a \<jumpassist> element
void manualCallOtherFixup(const string &useropname,const string &outname, void manualCallOtherFixup(const string &useropname,const string &outname,
const vector<string> &inname,const string &snippet,Architecture *glb); const vector<string> &inname,const string &snippet,Architecture *glb);
}; };

View file

@ -17,6 +17,12 @@
#include "op.hh" #include "op.hh"
#include "database.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. /// The new instance starts off with no associate Symbol and all properties marked as \e dirty.
/// \param vn is the single Varnode member /// \param vn is the single Varnode member
HighVariable::HighVariable(Varnode *vn) HighVariable::HighVariable(Varnode *vn)
@ -451,44 +457,42 @@ int4 HighVariable::instanceIndex(const Varnode *vn) const
return -1; return -1;
} }
/// \param s is the output stream to write XML to /// \param encoder is the stream encoder
void HighVariable::saveXml(ostream &s) const void HighVariable::encode(Encoder &encoder) const
{ {
Varnode *vn = getNameRepresentative(); // Get representative varnode Varnode *vn = getNameRepresentative(); // Get representative varnode
s << "<high "; encoder.openElement(ELEM_HIGH);
// a_v(s,"name",high->getName()); encoder.writeUnsignedInteger(ATTRIB_REPREF, vn->getCreateIndex());
a_v_u(s,"repref",vn->getCreateIndex());
if (isSpacebase()||isImplied()) // This is a special variable 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 else if (isPersist()&&isAddrTied()) // Global variable
a_v(s,"class",string("global")); encoder.writeString(ATTRIB_CLASS, "global");
else if (isConstant()) else if (isConstant())
a_v(s,"class",string("constant")); encoder.writeString(ATTRIB_CLASS, "constant");
else if (!isPersist() && (symbol != (Symbol *)0)) { else if (!isPersist() && (symbol != (Symbol *)0)) {
if (symbol->getCategory() == Symbol::function_parameter) if (symbol->getCategory() == Symbol::function_parameter)
a_v(s,"class",string("param")); encoder.writeString(ATTRIB_CLASS, "param");
else else
a_v(s,"class",string("local")); encoder.writeString(ATTRIB_CLASS, "local");
} }
else { else {
a_v(s,"class",string("other")); encoder.writeString(ATTRIB_CLASS, "other");
} }
if (isTypeLock()) if (isTypeLock())
a_v_b(s,"typelock",true); encoder.writeBool(ATTRIB_TYPELOCK, true);
if (symbol != (Symbol *)0) { if (symbol != (Symbol *)0) {
a_v_u(s,"symref",symbol->getId()); encoder.writeUnsignedInteger(ATTRIB_SYMREF, symbol->getId());
if (symboloffset >= 0) if (symboloffset >= 0)
a_v_i(s, "offset", symboloffset); encoder.writeSignedInteger(ATTRIB_OFFSET, symboloffset);
} }
s << '>'; getType()->encode(encoder);
getType()->saveXml(s);
for(int4 j=0;j<inst.size();++j) { for(int4 j=0;j<inst.size();++j) {
s << "<addr "; encoder.openElement(ELEM_ADDR);
a_v_u(s,"ref",inst[j]->getCreateIndex()); encoder.writeUnsignedInteger(ATTRIB_REF, inst[j]->getCreateIndex());
s << "/>"; encoder.closeElement(ELEM_ADDR);
} }
s << "</high>"; encoder.closeElement(ELEM_HIGH);
} }
/// Given a Varnode at the root of an expression, we collect all the \e explicit HighVariables /// Given a Varnode at the root of an expression, we collect all the \e explicit HighVariables

View file

@ -23,6 +23,12 @@
class Symbol; 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 \<high>
/// \brief A high-level variable modeled as a list of low-level variables, each written once /// \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 /// 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 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 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 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 \<high\> tag void encode(Encoder &encoder) const; ///< Encode \b this variable to stream as a \<high> element
#ifdef MERGEMULTI_DEBUG #ifdef MERGEMULTI_DEBUG
void verifyCover(void) const; void verifyCover(void) const;
#endif #endif

View file

@ -16,6 +16,11 @@
#include "varmap.hh" #include "varmap.hh"
#include "funcdata.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 /// \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 /// 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); glb->symboltab->setRange(this,newrange);
} }
void ScopeLocal::saveXml(ostream &s) const void ScopeLocal::encode(Encoder &encoder) const
{ {
s << "<localdb"; encoder.openElement(ELEM_LOCALDB);
a_v(s,"main",space->getName()); encoder.writeString(ATTRIB_MAIN, space->getName());
a_v_b(s,"lock",rangeLocked); encoder.writeBool(ATTRIB_LOCK, rangeLocked);
s << ">\n"; ScopeInternal::encode(encoder);
ScopeInternal::saveXml(s); encoder.closeElement(ELEM_LOCALDB);
s << "</localdb>\n";
} }
void ScopeLocal::restoreXml(const Element *el) void ScopeLocal::decode(Decoder &decoder)
{
ScopeInternal::decode( decoder );
collectNameRecs();
}
void ScopeLocal::decodeWrappingAttributes(Decoder &decoder)
{ {
rangeLocked = false; rangeLocked = false;
if (xml_readbool(el->getAttributeValue("lock"))) if (decoder.readBool(ATTRIB_LOCK))
rangeLocked = true; rangeLocked = true;
space = glb->getSpaceByName(el->getAttributeValue("main")); space = glb->getSpaceByName(decoder.readString(ATTRIB_MAIN));
ScopeInternal::restoreXml( *(el->getChildren().begin()) );
collectNameRecs();
} }
/// The given range can no longer hold a \e mapped local variable. This indicates the range /// The given range can no longer hold a \e mapped local variable. This indicates the range

View file

@ -21,6 +21,11 @@
#include "database.hh" #include "database.hh"
extern AttributeId ATTRIB_LOCK; ///< Marshaling attribute "lock"
extern AttributeId ATTRIB_MAIN; ///< Marshaling attribute "main"
extern ElementId ELEM_LOCALDB; ///< Marshaling element \<localdb>
/// \brief A symbol name recommendation with its associated storage location /// \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 /// 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 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 // Routines that are specific to one address space
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual void restoreXml(const Element *el); virtual void decode(Decoder &decoder);
virtual void decodeWrappingAttributes(Decoder &decoder);
virtual string buildVariableName(const Address &addr, virtual string buildVariableName(const Address &addr,
const Address &pc, const Address &pc,
Datatype *ct, Datatype *ct,

View file

@ -16,6 +16,12 @@
#include "varnode.hh" #include "varnode.hh"
#include "funcdata.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. /// Compare by location then by definition.
/// This is the same as the normal varnode compare, but we distinguish identical frees by their /// 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 /// 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; return 0;
} }
/// Write an XML tag, \b \<addr>, with at least the following attributes: /// Encode \b this as an \<addr> element, with at least the following attributes:
/// - \b space describes the AddrSpace /// - \b space describes the AddrSpace
/// - \b offset of the Varnode within the space /// - \b offset of the Varnode within the space
/// - \b size of the Varnode is bytes /// - \b size of the Varnode is bytes
/// ///
/// Additionally the tag will contain other optional attributes. /// Additionally the element will contain other optional attributes.
/// \param s is the stream to write the tag to /// \param encoder is the stream encoder
void Varnode::saveXml(ostream &s) const void Varnode::encode(Encoder &encoder) const
{ {
s << "<addr"; encoder.openElement(ELEM_ADDR);
loc.getSpace()->saveXmlAttributes(s,loc.getOffset(),size); loc.getSpace()->encodeAttributes(encoder,loc.getOffset(),size);
a_v_u(s,"ref",getCreateIndex()); encoder.writeUnsignedInteger(ATTRIB_REF, getCreateIndex());
if (mergegroup != 0) if (mergegroup != 0)
a_v_i(s,"grp",getMergeGroup()); encoder.writeSignedInteger(ATTRIB_GRP, getMergeGroup());
if (isPersist()) if (isPersist())
s << " persists=\"true\""; encoder.writeBool(ATTRIB_PERSISTS, true);
if (isAddrTied()) if (isAddrTied())
s << " addrtied=\"true\""; encoder.writeBool(ATTRIB_ADDRTIED, true);
if (isUnaffected()) if (isUnaffected())
s << " unaff=\"true\""; encoder.writeBool(ATTRIB_UNAFF, true);
if (isInput()) if (isInput())
s << " input=\"true\""; encoder.writeBool(ATTRIB_INPUT, true);
s << "/>"; encoder.closeElement(ELEM_ADDR);
} }
/// Invoke the printRaw method on the given Varnode pointer, but take into account that it /// Invoke the printRaw method on the given Varnode pointer, but take into account that it

View file

@ -30,6 +30,12 @@ class Funcdata;
class SymbolEntry; class SymbolEntry;
class ValueSet; 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 /// \brief Compare two Varnode pointers by location then definition
struct VarnodeCompareLocDef { struct VarnodeCompareLocDef {
bool operator()(const Varnode *a,const Varnode *b) const; ///< Functional comparison operator 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 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 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 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 bool updateType(Datatype *ct,bool lock,bool override); ///< (Possibly) set the Datatype given various restrictions
void setStackStore(void) { addlflags |= Varnode::stack_store; } ///< Mark as produced by explicit CPUI_STORE void setStackStore(void) { addlflags |= Varnode::stack_store; } ///< Mark as produced by explicit CPUI_STORE
void setLockedInput(void) { addlflags |= Varnode::locked_input; } ///< Mark as existing input, even if unused void setLockedInput(void) { addlflags |= Varnode::locked_input; } ///< Mark as existing input, even if unused
@ -323,10 +329,9 @@ public:
void copySymbolIfValid(const Varnode *vn); ///< Copy symbol info from \b vn if constant value matches void copySymbolIfValid(const Varnode *vn); ///< Copy symbol info from \b vn if constant value matches
Datatype *getLocalType(bool &blockup) const; ///< Calculate type of Varnode based on local information Datatype *getLocalType(bool &blockup) const; ///< Calculate type of Varnode based on local information
bool copyShadow(const Varnode *op2) const; ///< Are \b this and \b op2 copied from the same source? bool copyShadow(const Varnode *op2) const; ///< Are \b this and \b op2 copied from the same source?
void saveXml(ostream &s) const; ///< Save a description of \b this as an XML tag void 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 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 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 /// \brief A container for Varnode objects from a specific function

View file

@ -15,6 +15,8 @@
*/ */
#include "xml_arch.hh" #include "xml_arch.hh"
ElementId ELEM_XML_SAVEFILE = ElementId("xml_savefile",207);
// Constructing the singleton registers the capability // Constructing the singleton registers the capability
XmlArchitectureCapability XmlArchitectureCapability::xmlArchitectureCapability; 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 /// Prepend extra stuff to specify binary file and spec
/// \param s is the stream to write to /// \param encoder is the stream encoder
void XmlArchitecture::saveXml(ostream &s) const void XmlArchitecture::encode(Encoder &encoder) const
{ {
s << "<xml_savefile"; encoder.openElement(ELEM_XML_SAVEFILE);
saveXmlHeader(s); encodeHeader(encoder);
a_v_u(s,"adjustvma",adjustvma); encoder.writeUnsignedInteger(ATTRIB_ADJUSTVMA, adjustvma);
s << ">\n"; ((LoadImageXml *)loader)->encode(encoder); // Save the LoadImage
((LoadImageXml *)loader)->saveXml(s); // Save the LoadImage types->encodeCoreTypes(encoder);
types->saveXmlCoreTypes(s); SleighArchitecture::encode(encoder); // Save the rest of the state
SleighArchitecture::saveXml(s); // Save the rest of the state encoder.closeElement(ELEM_XML_SAVEFILE);
s << "</xml_savefile>\n";
} }
void XmlArchitecture::restoreXml(DocumentStorage &store) void XmlArchitecture::restoreXml(DocumentStorage &store)

View file

@ -18,6 +18,8 @@
#include "sleigh_arch.hh" #include "sleigh_arch.hh"
#include "loadimage_xml.hh" #include "loadimage_xml.hh"
extern ElementId ELEM_XML_SAVEFILE; ///< Marshaling element \<xml_savefile>
/// \brief Extension for building an XML format capable Architecture /// \brief Extension for building an XML format capable Architecture
class XmlArchitectureCapability : public ArchitectureCapability { class XmlArchitectureCapability : public ArchitectureCapability {
static XmlArchitectureCapability xmlArchitectureCapability; ///< The singleton instance static XmlArchitectureCapability xmlArchitectureCapability; ///< The singleton instance
@ -38,7 +40,7 @@ class XmlArchitecture : public SleighArchitecture {
// virtual void resolveArchitecture(void); ///< Inherit SleighArchitecture's version // virtual void resolveArchitecture(void); ///< Inherit SleighArchitecture's version
virtual void postSpecFile(void); virtual void postSpecFile(void);
public: public:
virtual void saveXml(ostream &s) const; virtual void encode(Encoder &encoder) const;
virtual void restoreXml(DocumentStorage &store); virtual void restoreXml(DocumentStorage &store);
XmlArchitecture(const string &fname,const string &targ,ostream *estream); ///< Constructor XmlArchitecture(const string &fname,const string &targ,ostream *estream); ///< Constructor
virtual ~XmlArchitecture(void) {} virtual ~XmlArchitecture(void) {}

View file

@ -343,8 +343,9 @@ public class DecompileDebug {
new DataTypeDependencyOrderer(program.getDataTypeManager(), dtypes); new DataTypeDependencyOrderer(program.getDataTypeManager(), dtypes);
//First output all structures as zero size so to avoid any cyclic dependencies. //First output all structures as zero size so to avoid any cyclic dependencies.
for (DataType dataType : TypeOrderer.getCompositeList()) { for (DataType dataType : TypeOrderer.getCompositeList()) {
debugStream.write( debugStream
(dtmanage.buildCompositeZeroSizePlaceholder(dataType) + "\n").toString().getBytes()); .write((dtmanage.buildCompositeZeroSizePlaceholder(dataType) + "\n").toString()
.getBytes());
} }
//Next, use the dependency stack to output types. //Next, use the dependency stack to output types.
for (DataType dataType : TypeOrderer.getDependencyList()) { for (DataType dataType : TypeOrderer.getDependencyList()) {
@ -553,7 +554,7 @@ public class DecompileDebug {
private void dumpDatabases(OutputStream debugStream) throws IOException { private void dumpDatabases(OutputStream debugStream) throws IOException {
Namespace scopename = null; Namespace scopename = null;
ArrayList<Namespace> spaceList = orderNamespaces(); ArrayList<Namespace> spaceList = orderNamespaces();
debugStream.write("<db scodeidbyname=\"false\">\n".getBytes()); debugStream.write("<db scopeidbyname=\"false\">\n".getBytes());
for (Namespace element : spaceList) { for (Namespace element : spaceList) {
scopename = element; scopename = element;
StringBuilder datahead = new StringBuilder(); StringBuilder datahead = new StringBuilder();

View file

@ -1427,7 +1427,6 @@ public class SleighLanguage implements Language {
String tag; String tag;
int delay; int delay;
boolean physical; boolean physical;
boolean global;
for (AddressSpace element : spclist) { for (AddressSpace element : spclist) {
if ((element instanceof OverlayAddressSpace)) { if ((element instanceof OverlayAddressSpace)) {
@ -1445,25 +1444,21 @@ public class SleighLanguage implements Language {
tag = "space"; tag = "space";
delay = 1; delay = 1;
physical = true; physical = true;
global = true;
break; break;
case AddressSpace.TYPE_REGISTER: case AddressSpace.TYPE_REGISTER:
tag = "space"; tag = "space";
delay = 0; delay = 0;
physical = true; physical = true;
global = false;
break; break;
case AddressSpace.TYPE_UNIQUE: case AddressSpace.TYPE_UNIQUE:
tag = "space_unique"; tag = "space_unique";
delay = 0; delay = 0;
physical = true; physical = true;
global = false;
break; break;
case AddressSpace.TYPE_OTHER: case AddressSpace.TYPE_OTHER:
tag = "space_other"; tag = "space_other";
delay = 0; delay = 0;
physical = true; physical = true;
global = true;
break; break;
default: default:
continue; continue;
@ -1491,7 +1486,6 @@ public class SleighLanguage implements Language {
SpecXmlUtils.encodeBooleanAttribute(resBuf, "bigendian", isBigEndian()); SpecXmlUtils.encodeBooleanAttribute(resBuf, "bigendian", isBigEndian());
SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "delay", delay); SpecXmlUtils.encodeSignedIntegerAttribute(resBuf, "delay", delay);
SpecXmlUtils.encodeBooleanAttribute(resBuf, "physical", physical); SpecXmlUtils.encodeBooleanAttribute(resBuf, "physical", physical);
SpecXmlUtils.encodeBooleanAttribute(resBuf, "global", global);
resBuf.append("/>\n"); resBuf.append("/>\n");
} }