diff --git a/Ghidra/Features/Decompiler/Module.manifest b/Ghidra/Features/Decompiler/Module.manifest index e69de29bb2d..0c8cbd63801 100644 --- a/Ghidra/Features/Decompiler/Module.manifest +++ b/Ghidra/Features/Decompiler/Module.manifest @@ -0,0 +1 @@ +MODULE FILE LICENSE: src/decompile/zlib zlib License diff --git a/Ghidra/Features/Decompiler/buildNatives.gradle b/Ghidra/Features/Decompiler/buildNatives.gradle index 25a90a11e9e..d47201d67cc 100644 --- a/Ghidra/Features/Decompiler/buildNatives.gradle +++ b/Ghidra/Features/Decompiler/buildNatives.gradle @@ -26,7 +26,6 @@ if (findProject(':Generic') == null) { * Define the "native build model" for building the decompiler executables. */ model { - // Define the source files that are compiled and linked to become the decompiler. // The decompiler source is a bit weird in that all the cpp and headers all live in // the same directory with other files that are not used by the decompiler. @@ -174,6 +173,8 @@ model { include "slghpattern.cc" include "semantics.cc" include "context.cc" + include "slaformat.cc" + include "compression.cc" include "filemanage.cc" include "slgh_compile.cc" @@ -188,7 +189,27 @@ model { srcDir "src/decompile/cpp" } } // end cpp + + if (isCurrentWindows()) { + c { + source { + srcDir "src/decompile/zlib" + include "*.c" + } + } + } } // end sources (sleigh) + + binaries { + all{ b -> + if (b.toolChain in Gcc || b.toolChain in Clang) { + b.linker.args "-lz" + } + else { + b.cppCompiler.define "LOCAL_ZLIB" + } + } + } // end binaries.all (sleigh) } // end sleigh } // end components @@ -223,7 +244,15 @@ model { b.cppCompiler.define "WIN64" b.cppCompiler.define "_WIN64" } - } + } + b.cCompiler.args "/W3" + b.cCompiler.args "/O2" + b.cCompiler.args "/Oy" // Omit frame pointer + b.cCompiler.define "_CRT_SECURE_NO_DEPRECATE" + b.cCompiler.define "_CRT_NONSTDC_NO_DEPRECATE" + b.cCompiler.define "WIN64" + b.cCompiler.define "ZLIB_WINAPI" + b.cCompiler.define "NO_GZIP" } else if (b.toolChain in Clang) { b.cppCompiler.args "-std=c++11" diff --git a/Ghidra/Features/Decompiler/certification.manifest b/Ghidra/Features/Decompiler/certification.manifest index 67ce8555158..f426e48efa6 100644 --- a/Ghidra/Features/Decompiler/certification.manifest +++ b/Ghidra/Features/Decompiler/certification.manifest @@ -4,6 +4,7 @@ ##MODULE IP: Modified Nuvola Icons - LGPL 2.1 ##MODULE IP: Oxygen Icons - LGPL 3.0 ##MODULE IP: Tango Icons - Public Domain +##MODULE IP: zlib License Module.manifest||GHIDRA||||END| data/decompiler.theme.properties||GHIDRA||||END| src/decompile/.cproject||GHIDRA||||END| @@ -67,6 +68,7 @@ src/decompile/datatests/twodim.xml||GHIDRA||||END| src/decompile/datatests/union_datatype.xml||GHIDRA||||END| src/decompile/datatests/varcross.xml||GHIDRA||||END| src/decompile/datatests/wayoffarray.xml||GHIDRA||||END| +src/decompile/zlib/README.txt||GHIDRA||||END| src/main/doc/commonprofile.xsl||GHIDRA||||END| src/main/doc/cspec.xml||GHIDRA||||END| src/main/doc/cspec_html.xsl||GHIDRA||||END| diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/Makefile b/Ghidra/Features/Decompiler/src/decompile/cpp/Makefile index 24d9bcd7ab3..5e5d2984414 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/Makefile +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/Makefile @@ -50,9 +50,9 @@ YACC=bison # libraries #INCLUDES=-I$(BFDHOME)/include INCLUDES= -BFDLIB=-lbfd -lz +BFDLIB=-lbfd -LNK= +LNK=-lz # Source files ALL_SOURCE= $(wildcard *.cc) @@ -87,7 +87,7 @@ DECCORE=capability architecture options graph cover block cast typeop database c printlanguage printc printjava memstate opbehavior paramid signature $(COREEXT_NAMES) # Files used for any project that use the sleigh decoder SLEIGH= sleigh pcodeparse pcodecompile sleighbase slghsymbol \ - slghpatexpress slghpattern semantics context filemanage + slghpatexpress slghpattern semantics context slaformat compression filemanage # Additional files for the GHIDRA specific build GHIDRA= ghidra_arch inject_ghidra ghidra_translate loadimage_ghidra \ typegrp_ghidra database_ghidra ghidra_context cpool_ghidra \ @@ -260,10 +260,10 @@ test: ghidra_test_dbg ./ghidra_test_dbg ghidra_dbg: $(GHIDRA_DBG_OBJS) - $(CXX) $(DBG_CXXFLAGS) $(ADDITIONAL_FLAGS) $(MAKE_STATIC) $(ARCH_TYPE) -o ghidra_dbg $(GHIDRA_DBG_OBJS) $(LNK) + $(CXX) $(DBG_CXXFLAGS) $(ADDITIONAL_FLAGS) $(MAKE_STATIC) $(ARCH_TYPE) -o ghidra_dbg $(GHIDRA_DBG_OBJS) ghidra_opt: $(GHIDRA_OPT_OBJS) - $(CXX) $(OPT_CXXFLAGS) $(ADDITIONAL_FLAGS) $(MAKE_STATIC) $(ARCH_TYPE) -o ghidra_opt $(GHIDRA_OPT_OBJS) $(LNK) + $(CXX) $(OPT_CXXFLAGS) $(ADDITIONAL_FLAGS) $(MAKE_STATIC) $(ARCH_TYPE) -o ghidra_opt $(GHIDRA_OPT_OBJS) sleigh_dbg: $(SLEIGH_DBG_OBJS) $(CXX) $(DBG_CXXFLAGS) $(ADDITIONAL_FLAGS) $(MAKE_STATIC) $(ARCH_TYPE) -o sleigh_dbg $(SLEIGH_DBG_OBJS) $(LNK) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh index a14ea46a6b5..2ebde08a616 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/address.hh @@ -98,10 +98,10 @@ public: void encode(Encoder &encoder) const; ///< Encode \b this to a stream void encode(Encoder &encoder,int4 size) const; ///< Encode \b this and a size to a stream - /// Restore an address from parsed XML + /// Decode an address from a stream static Address decode(Decoder &decoder); - /// Restore an address and size from parsed XML + /// Decode an address and size from a stream static Address decode(Decoder &decoder,int4 &size); }; @@ -221,7 +221,7 @@ class RangeProperties { 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 + void decode(Decoder &decoder); ///< Decode \b this from a stream }; /// \brief A disjoint set of Ranges, possibly across multiple address spaces diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh index 2fe3aed26a1..73dc41296bf 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh @@ -236,7 +236,7 @@ public: void setPrototype(const PrototypePieces &pieces); ///< Set the prototype for a particular function void setPrintLanguage(const string &nm); ///< Establish a particular output language void globalify(void); ///< Mark \e all spaces as global - void decodeFlowOverride(Decoder &decoder); ///< Set flow overrides from XML + void decodeFlowOverride(Decoder &decoder); ///< Decode flow overrides from a stream virtual ~Architecture(void); ///< Destructor /// \brief Get a string describing \b this architecture diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh index 0041d0f710f..2020df08f92 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh @@ -132,7 +132,7 @@ private: // the result of the condition being false static void replaceEdgeMap(vector &vec); ///< Update block references in edges with copy map void addInEdge(FlowBlock *b,uint4 lab); ///< Add an edge coming into \b this - void decodeNextInEdge(Decoder &decoder,BlockMap &resolver); ///< Restore the next input edge from XML + void decodeNextInEdge(Decoder &decoder,BlockMap &resolver); ///< Decode the next input edge from stream void halfDeleteInEdge(int4 slot); ///< Delete the \e in half of an edge, correcting indices void halfDeleteOutEdge(int4 slot); ///< Delete the \e out half of an edge, correcting indices void removeInEdge(int4 slot); ///< Remove an incoming edge diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/comment.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/comment.hh index 5c1dfe9da46..fe2a251abaa 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/comment.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/comment.hh @@ -68,7 +68,7 @@ public: int4 getUniq(void) const { return uniq; } ///< Get the sub-sorting index const string &getText(void) const { return text; } ///< Get the body of the comment void encode(Encoder &encoder) const; ///< Encode the comment to a stream - void decode(Decoder &decoder); ///< Restore the comment from XML + void decode(Decoder &decoder); ///< Decode the comment from a stream static uint4 encodeCommentType(const string &name); ///< Convert name string to comment property static string decodeCommentType(uint4 val); ///< Convert comment property to string }; @@ -146,7 +146,7 @@ public: /// \param encoder is the stream encoder virtual void encode(Encoder &encoder) const=0; - /// \brief Restore all comments from a \ element + /// \brief Decode all comments from a \ element /// /// \param decoder is the stream decoder virtual void decode(Decoder &decoder)=0; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/compression.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/compression.cc new file mode 100644 index 00000000000..81b8c59b9f6 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/compression.cc @@ -0,0 +1,165 @@ +/* ### + * 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 "compression.hh" + +namespace ghidra { + +/// The compression \b level ranges from 1-9 from faster/least compression to slower/most compression. +/// Use a \b level of 0 for no compression and -1 for the \e default compression level. +/// \param level is the compression level +Compress::Compress(int4 level) + +{ + compStream.zalloc = Z_NULL; + compStream.zfree = Z_NULL; + compStream.opaque = Z_NULL; + int4 ret = deflateInit(&compStream, level); + if (ret != Z_OK) + throw LowlevelError("Could not initialize deflate stream state"); +} + +Compress::~Compress(void) + +{ + deflateEnd(&compStream); +} + +/// Return the number of bytes of output space still available. Output may be limited by the amount +/// of space in the output buffer or the amount of data available in the current input buffer. +/// \param buffer is where compressed bytes are stored +/// \param sz is the size, in bytes, of the buffer +/// \param finish is set to \b true if this is the final buffer to add to the stream +/// \return the number of output bytes still available +int4 Compress::deflate(uint1 *buffer,int4 sz,bool finish) + +{ + int flush = finish ? Z_FINISH : Z_NO_FLUSH; + compStream.avail_out = sz; + compStream.next_out = buffer; + + int ret = ::deflate(&compStream, flush); + if (ret == Z_STREAM_ERROR) + throw LowlevelError("Error compressing stream"); + return compStream.avail_out; +} + +Decompress::Decompress(void) + +{ + streamFinished = false; + compStream.zalloc = Z_NULL; + compStream.zfree = Z_NULL; + compStream.opaque = Z_NULL; + compStream.avail_in = 0; + compStream.next_in = Z_NULL; + int ret = inflateInit(&compStream); + if (ret != Z_OK) + throw LowlevelError("Could not initialize inflate stream state"); +} + +/// Return the number of bytes of output space still available. Output may be limited by the amount +/// of space in the output buffer or the amount of data available in the current input buffer. +/// \param buffer is where uncompressed bytes are stored +/// \param sz is the size, in bytes, of the buffer +/// \return the number of output bytes still available +int4 Decompress::inflate(uint1 *buffer,int4 sz) + +{ + compStream.avail_out = sz; + compStream.next_out = buffer; + + int ret = ::inflate(&compStream, Z_NO_FLUSH); + switch (ret) { + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_MEM_ERROR: + case Z_STREAM_ERROR: + throw LowlevelError("Error decompressing stream"); + case Z_STREAM_END: + streamFinished = true; + break; + default: + break; + } + + return compStream.avail_out; +} + +Decompress::~Decompress(void) + +{ + inflateEnd(&compStream); +} + +const int4 CompressBuffer::IN_BUFFER_SIZE = 4096; +const int4 CompressBuffer::OUT_BUFFER_SIZE = 4096; + +/// \param s is the backing output stream +/// \param level is the level of compression +CompressBuffer::CompressBuffer(ostream &s,int4 level) + : outStream(s), compressor(level) +{ + inBuffer = new uint1[IN_BUFFER_SIZE]; + outBuffer = new uint1[OUT_BUFFER_SIZE]; + setp((char *)inBuffer,(char *)inBuffer + IN_BUFFER_SIZE-1); +} + +CompressBuffer::~CompressBuffer(void) + +{ + delete [] inBuffer; + delete [] outBuffer; +} + +/// The compressor is called repeatedly and its output is written to the backing stream +/// until the compressor can no longer fill the \e output buffer. +/// \param lastBuffer is \b true if this is the final set of bytes to add to the compressed stream +void CompressBuffer::flushInput(bool lastBuffer) + +{ + int len = pptr() - pbase(); + compressor.input((uint1 *)pbase(),len); + int4 outAvail; + do { + outAvail = OUT_BUFFER_SIZE; + outAvail = compressor.deflate(outBuffer,outAvail,lastBuffer); + outStream.write((char *)outBuffer,OUT_BUFFER_SIZE-outAvail); + } while(outAvail == 0); + pbump(-len); +} + +/// \param c is the final character filling the buffer +/// \return the written character +int CompressBuffer::overflow(int c) + +{ + if (c != EOF) { + *pptr() = c; + pbump(1); + } + flushInput(false); + return c; +} + +/// \return 0 for success +int CompressBuffer::sync(void) + +{ + flushInput(true); + return 0; +} + +} diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/compression.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/compression.hh new file mode 100644 index 00000000000..1151d6d9cc8 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/compression.hh @@ -0,0 +1,100 @@ +/* ### + * 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. + */ +/// \file compression.hh +/// \brief The Compress and Decompress classes wrapping the deflate and inflate algorithms +#ifndef __COMPRESSION__ +#define __COMPRESSION__ + +#include "error.hh" +#ifdef LOCAL_ZLIB +#include "../zlib/zlib.h" +#else +#include +#endif + +namespace ghidra { + +/// \brief Wrapper for the deflate algorithm +/// +/// Initialize/free algorithm resources. Provide successive arrays of bytes to compress via +/// the input() method. Compute successive arrays of compressed bytes via the deflate() method. +class Compress { + z_stream compStream; ///< The zlib deflate algorithm state +public: + Compress(int4 level); ///< Initialize the deflate algorithm state + ~Compress(void); ///< Free algorithm state resources + + /// \brief Provide the next sequence of bytes to be compressed + /// + /// \param buffer is a pointer to the bytes to compress + /// \param sz is the number of bytes + void input(uint1 *buffer,int4 sz) { + compStream.avail_in = sz; + compStream.next_in = buffer; + } + int4 deflate(uint1 *buffer,int4 sz,bool finish); ///< Deflate as much as possible into given buffer +}; + +/// \brief Wrapper for the inflate algorithm +/// +/// Initialize/free algorithm resources. Provide successive arrays of compressed bytes via +/// the input() method. Compute successive arrays of uncompressed bytes via the inflate() method. +class Decompress { + z_stream compStream; ///< The zlib inflate algorithm state + bool streamFinished; ///< Set to \b true if the end of the compressed stream has been reached +public: + Decompress(void); ///< Initialize the inflate algorithm state + ~Decompress(void); ///< Free algorithm state resources + + /// \brief Provide the next sequence of compressed bytes + /// + /// \param buffer is a pointer to the compressed bytes + /// \param sz is the number of bytes + void input(uint1 *buffer,int4 sz) { + compStream.next_in = buffer; + compStream.avail_in = sz; + } + + bool isFinished(void) const { return streamFinished; } ///< Return \b if end of compressed stream is reached + int4 inflate(uint1 *buffer,int4 sz); ///< Inflate as much as possible into given buffer +}; + +/// \brief Stream buffer that performs compression +/// +/// Provides an ostream filter that compresses the stream using the \e deflate algorithm. +/// The stream buffer is provided a backing stream that is the ultimate destination of the compressed bytes. +/// A front-end stream is initialized with \b this stream buffer. +/// After writing the full sequence of bytes to compressed to the front-end stream, make sure to +/// call the stream's flush() method to emit the final compressed bytes to the backing stream. +class CompressBuffer : public std::streambuf { + static const int4 IN_BUFFER_SIZE; ///< Number of bytes in the \e input buffer + static const int4 OUT_BUFFER_SIZE; ///< Number of bytes in the \e output buffer + ostream &outStream; ///< The backing stream receiving compressed bytes + uint1 *inBuffer; ///< The \e input buffer + uint1 *outBuffer; ///< The \e output buffer + Compress compressor; ///< Compressor state +protected: + void flushInput(bool lastBuffer); ///< Compress the current set of bytes in the \e input buffer + virtual int overflow(int c); ///< Pass the filled input buffer to the compressor + virtual int sync(void); ///< Pass remaining bytes in the input buffer to the compressor +public: + CompressBuffer(ostream &s,int4 level); ///< Constructor + ~CompressBuffer(void); ///< Destructor +}; + +} + +#endif diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/float.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/float.cc index 2e8a4c6b2cc..913af357ed5 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/float.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/float.cc @@ -628,66 +628,4 @@ uintb FloatFormat::opRound(uintb a) const return getEncoding(round(val)); // round half away from zero } -/// Write the format out to a \ XML tag. -/// \param s is the output stream -void FloatFormat::saveXml(ostream &s) const - -{ - s << "\n"; -} - -/// Restore \b object from a \ XML tag -/// \param el is the element -void FloatFormat::restoreXml(const Element *el) - -{ - { - istringstream s(el->getAttributeValue("size")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> size; - } - { - istringstream s(el->getAttributeValue("signpos")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> signbit_pos; - } - { - istringstream s(el->getAttributeValue("fracpos")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> frac_pos; - } - { - istringstream s(el->getAttributeValue("fracsize")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> frac_size; - } - { - istringstream s(el->getAttributeValue("exppos")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> exp_pos; - } - { - istringstream s(el->getAttributeValue("expsize")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> exp_size; - } - { - istringstream s(el->getAttributeValue("bias")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> bias; - } - jbitimplied = xml_readbool(el->getAttributeValue("jbitimplied")); - maxexponent = (1<conf->options->set(ElementId::find(optname),p1,p2,p3); + string res = dcp->conf->options->set(ElementId::find(optname,0),p1,p2,p3); *status->optr << res << endl; } catch(ParseError &err) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.cc index cc8ed87b800..e3abd636f3a 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/inject_sleigh.cc @@ -91,7 +91,8 @@ void InjectPayloadSleigh::decode(Decoder &decoder) void InjectPayloadSleigh::printTemplate(ostream &s) const { - tpl->saveXml(s,-1); + XmlEncode encoder(s); + tpl->encode(encoder,-1); } void InjectPayloadSleigh::checkParameterRestrictions(InjectContextSleigh &con, @@ -247,7 +248,8 @@ void ExecutablePcodeSleigh::decode(Decoder &decoder) void ExecutablePcodeSleigh::printTemplate(ostream &s) const { - tpl->saveXml(s,-1); + XmlEncode encoder(s); + tpl->encode(encoder,-1); } InjectPayloadDynamic::~InjectPayloadDynamic(void) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc index 7e7ef1b194d..c1561dcdd27 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.cc @@ -24,6 +24,9 @@ unordered_map AttributeId::lookupAttributeId; const int4 PackedDecode::BUFFER_SIZE = 1024; +const char XmlEncode::spaces[] = "\n "; +const int4 XmlEncode::MAX_SPACES = 24+1; + /// 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 @@ -38,11 +41,13 @@ vector &AttributeId::getList(void) /// 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) +/// \param scope is an id for the scope of this attribute +AttributeId::AttributeId(const string &nm,uint4 i,int4 scope) : name(nm) { id = i; - getList().push_back(this); + if (scope == 0) + getList().push_back(this); } /// Fill the hashtable mapping attribute names to their id, from registered attribute objects @@ -78,11 +83,13 @@ vector &ElementId::getList(void) /// 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) +/// \param scope is an id for the scope of this element +ElementId::ElementId(const string &nm,uint4 i,int4 scope) : name(nm) { id = i; - getList().push_back(this); + if (scope == 0) + getList().push_back(this); } /// Fill the hashtable mapping element names to their id, from registered element objects @@ -132,7 +139,7 @@ uint4 XmlDecode::peekElement(void) return 0; el = *iter; } - return ElementId::find(el->getName()); + return ElementId::find(el->getName(),scope); } uint4 XmlDecode::openElement(void) @@ -156,7 +163,7 @@ uint4 XmlDecode::openElement(void) elStack.push_back(el); iterStack.push_back(el->getChildren().begin()); attributeIndex = -1; - return ElementId::find(el->getName()); + return ElementId::find(el->getName(),scope); } uint4 XmlDecode::openElement(const ElementId &elemId) @@ -194,7 +201,7 @@ void XmlDecode::closeElement(uint4 id) const Element *el = elStack.back(); if (iterStack.back() != el->getChildren().end()) throw DecoderError("Closing element <" + el->getName() + "> with additional children"); - if (ElementId::find(el->getName()) != id) + if (ElementId::find(el->getName(), scope) != id) throw DecoderError("Trying to close <" + el->getName() + "> with mismatching id"); #endif elStack.pop_back(); @@ -207,7 +214,7 @@ void XmlDecode::closeElementSkipping(uint4 id) { #ifdef CPUI_DEBUG const Element *el = elStack.back(); - if (ElementId::find(el->getName()) != id) + if (ElementId::find(el->getName(), scope) != id) throw DecoderError("Trying to close <" + el->getName() + "> with mismatching id"); #endif elStack.pop_back(); @@ -228,7 +235,7 @@ uint4 XmlDecode::getNextAttributeId(void) int4 nextIndex = attributeIndex + 1; if (nextIndex < el->getNumAttributes()) { attributeIndex = nextIndex; - return AttributeId::find(el->getAttributeName(attributeIndex)); + return AttributeId::find(el->getAttributeName(attributeIndex),scope); } return 0; } @@ -419,40 +426,89 @@ AddrSpace *XmlDecode::readSpace(const AttributeId &attribId) return res; } +OpCode XmlDecode::readOpcode(void) + +{ + const Element *el = elStack.back(); + string nm = el->getAttributeValue(attributeIndex); + OpCode opc = get_opcode(nm); + if (opc == (OpCode)0) + throw DecoderError("Bad encoded OpCode"); + return opc; +} + +OpCode XmlDecode::readOpcode(AttributeId &attribId) + +{ + const Element *el = elStack.back(); + string nm; + if (attribId == ATTRIB_CONTENT) { + nm = el->getContent(); + } + else { + int4 index = findMatchingAttribute(el, attribId.getName()); + nm = el->getAttributeValue(index); + } + OpCode opc = get_opcode(nm); + if (opc == (OpCode)0) + throw DecoderError("Bad encoded OpCode"); + return opc; +} + +void XmlEncode::newLine(void) + +{ + if (!doFormatting) + return; + + int numSpaces = depth * 2 + 1; + if (numSpaces > MAX_SPACES) { + numSpaces = MAX_SPACES; + } + outStream.write(spaces,numSpaces); +} + void XmlEncode::openElement(const ElementId &elemId) { - if (elementTagIsOpen) + if (tagStatus == tag_start) outStream << '>'; else - elementTagIsOpen = true; + tagStatus = tag_start; + newLine(); outStream << '<' << elemId.getName(); + depth += 1; } void XmlEncode::closeElement(const ElementId &elemId) { - if (elementTagIsOpen) { + depth -= 1; + if (tagStatus == tag_start) { outStream << "/>"; - elementTagIsOpen = false; - } - else { - outStream << "'; + tagStatus = tag_stop; + return; } + if (tagStatus != tag_content) + newLine(); + else + tagStatus = tag_stop; + + outStream << "'; } void XmlEncode::writeBool(const AttributeId &attribId,bool val) { if (attribId == ATTRIB_CONTENT) { // Special id indicating, text value - if (elementTagIsOpen) { + if (tagStatus == tag_start) { outStream << '>'; - elementTagIsOpen = false; } if (val) outStream << "true"; else outStream << "false"; + tagStatus = tag_content; return; } a_v_b(outStream, attribId.getName(), val); @@ -462,11 +518,11 @@ void XmlEncode::writeSignedInteger(const AttributeId &attribId,intb val) { if (attribId == ATTRIB_CONTENT) { // Special id indicating, text value - if (elementTagIsOpen) { + if (tagStatus == tag_start) { outStream << '>'; - elementTagIsOpen = false; } outStream << dec << val; + tagStatus = tag_content; return; } a_v_i(outStream, attribId.getName(), val); @@ -476,11 +532,11 @@ void XmlEncode::writeUnsignedInteger(const AttributeId &attribId,uintb val) { if (attribId == ATTRIB_CONTENT) { // Special id indicating, text value - if (elementTagIsOpen) { + if (tagStatus == tag_start) { outStream << '>'; - elementTagIsOpen = false; } outStream << hex << "0x" << val; + tagStatus = tag_content; return; } a_v_u(outStream, attribId.getName(), val); @@ -490,11 +546,11 @@ void XmlEncode::writeString(const AttributeId &attribId,const string &val) { if (attribId == ATTRIB_CONTENT) { // Special id indicating, text value - if (elementTagIsOpen) { + if (tagStatus == tag_start) { outStream << '>'; - elementTagIsOpen = false; } xml_escape(outStream, val.c_str()); + tagStatus = tag_content; return; } a_v(outStream,attribId.getName(),val); @@ -514,16 +570,33 @@ void XmlEncode::writeSpace(const AttributeId &attribId,const AddrSpace *spc) { if (attribId == ATTRIB_CONTENT) { // Special id indicating, text value - if (elementTagIsOpen) { + if (tagStatus == tag_start) { outStream << '>'; - elementTagIsOpen = false; } xml_escape(outStream, spc->getName().c_str()); + tagStatus = tag_content; return; } a_v(outStream,attribId.getName(),spc->getName()); } +void XmlEncode::writeOpcode(const AttributeId &attribId,OpCode opc) + +{ + const char *name = get_opname(opc); + if (attribId == ATTRIB_CONTENT) { // Special id indicating, text value + if (tagStatus == tag_start) { + outStream << '>'; + } + outStream << name; + tagStatus = tag_content; + return; + } + outStream << ' ' << attribId.getName() << "=\""; + outStream << name; + outStream << "\""; +} + /// The integer is encoded, 7-bits per byte, starting with the most significant 7-bits. /// The integer is decode from the \e current position, and the position is advanced. /// \param len is the number of bytes to extract @@ -598,6 +671,27 @@ void PackedDecode::skipAttributeRemaining(uint1 typeByte) advancePosition(curPos, length); // Skip -length- data } +/// Set decoder to beginning of the stream. Add padding to end of the stream. +/// \param bufPos is the number of bytes used by the last input buffer +void PackedDecode::endIngest(int4 bufPos) + +{ + endPos.seqIter = inStream.begin(); // Set position to beginning of stream + if (endPos.seqIter != inStream.end()) { + endPos.current = (*endPos.seqIter).start; + endPos.end = (*endPos.seqIter).end; + // Make sure there is at least one character after ingested buffer + if (bufPos == BUFFER_SIZE) { + // Last buffer was entirely filled + uint1 *endbuf = new uint1[1]; // Add one more buffer + inStream.emplace_back(endbuf,endbuf + 1); + bufPos = 0; + } + uint1 *buf = inStream.back().start; + buf[bufPos] = ELEMENT_END; + } +} + PackedDecode::~PackedDecode(void) { @@ -612,25 +706,11 @@ void PackedDecode::ingestStream(istream &s) { int4 gcount = 0; while(s.peek() > 0) { - uint1 *buf = new uint1[BUFFER_SIZE + 1]; - inStream.emplace_back(buf,buf+BUFFER_SIZE); + uint1 *buf = allocateNextInputBuffer(1); s.get((char *)buf,BUFFER_SIZE+1,'\0'); gcount = s.gcount(); } - endPos.seqIter = inStream.begin(); - if (endPos.seqIter != inStream.end()) { - endPos.current = (*endPos.seqIter).start; - endPos.end = (*endPos.seqIter).end; - // Make sure there is at least one character after ingested buffer - if (gcount == BUFFER_SIZE) { - // Last buffer was entirely filled - uint1 *endbuf = new uint1[1]; // Add one more buffer - inStream.emplace_back(endbuf,endbuf + 1); - gcount = 0; - } - uint1 *buf = inStream.back().start; - buf[gcount] = ELEMENT_END; - } + endIngest(gcount); } uint4 PackedDecode::peekElement(void) @@ -959,6 +1039,24 @@ AddrSpace *PackedDecode::readSpace(const AttributeId &attribId) return res; } +OpCode PackedDecode::readOpcode(void) + +{ + int4 val = (int4)readSignedInteger(); + if (val < 0 || val >= CPUI_MAX) + throw DecoderError("Bad encoded OpCode"); + return (OpCode)val; +} + +OpCode PackedDecode::readOpcode(AttributeId &attribId) + +{ + findMatchingAttribute(attribId); + OpCode opc = readOpcode(); + curPos = startPos; + return opc; +} + /// The value is either an unsigned integer, an address space index, or (the absolute value of) a signed integer. /// A type header is passed in with the particular type code for the value already filled in. /// This method then fills in the length code, outputs the full type header and the encoded bytes of the integer. @@ -973,7 +1071,7 @@ void PackedEncode::writeInteger(uint1 typeByte,uint8 val) lenCode = 0; sa = -1; } - if (val < 0x800000000) { + else if (val < 0x800000000) { if (val < 0x200000) { if (val < 0x80) { lenCode = 1; // 7-bits @@ -1119,6 +1217,13 @@ void PackedEncode::writeSpace(const AttributeId &attribId,const AddrSpace *spc) } } +void PackedEncode::writeOpcode(const AttributeId &attribId,OpCode opc) + +{ + writeHeader(ATTRIBUTE, attribId.getId()); + writeInteger((TYPECODE_SIGNEDINT_POSITIVE << TYPECODE_SHIFT), opc); +} + // Common attributes. Attributes with multiple uses AttributeId ATTRIB_CONTENT = AttributeId("XMLcontent",1); AttributeId ATTRIB_ALIGN = AttributeId("align",2); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.hh index b7af5bd6a08..6750a239d97 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/marshal.hh @@ -17,6 +17,7 @@ #define __MARSHAL_HH__ #include "xml.hh" +#include "opcodes.hh" #include #include @@ -43,11 +44,11 @@ class 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 + AttributeId(const string &nm,uint4 i,int4 scope=0); ///< 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 uint4 find(const string &nm,int4 scope); ///< 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 @@ -67,11 +68,11 @@ class 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 + ElementId(const string &nm,uint4 i,int4 scope=0); ///< 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 uint4 find(const string &nm,int4 scope); ///< 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 @@ -269,6 +270,21 @@ public: /// \return the address space associated with the attribute virtual AddrSpace *readSpace(const AttributeId &attribId)=0; + /// \brief Parse the current attribute as a p-code OpCode + /// + /// The last attribute, as returned by getNextAttributeId, is returned as an OpCode. + /// \return the OpCode associated with the current attribute + virtual OpCode readOpcode(void)=0; + + /// \brief Find the specific attribute in the current element and return it as an OpCode + /// + /// Search attributes from the current element for a match to the given attribute id. + /// Return this attribute as an OpCode. If there is no matching attribute id, an exception is thrown. + /// Parse via getNextAttributeId is reset. + /// \param attribId is the specific attribute id to match + /// \return the OpCode associated with the attribute + virtual OpCode readOpcode(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. @@ -350,6 +366,13 @@ public: /// \param attribId is the given AttributeId annotation /// \param spc is the address space to encode virtual void writeSpace(const AttributeId &attribId,const AddrSpace *spc)=0; + + /// \brief Write a p-code operation opcode into the encoding, associating it with the given annotation + /// + /// \param attribId is the given annotation + /// \param opc is the opcode + virtual void writeOpcode(const AttributeId &attribId,OpCode opc)=0; + }; /// \brief An XML based decoder @@ -363,12 +386,13 @@ class XmlDecode : public Decoder { vector elStack; ///< Stack of currently \e open elements vector iterStack; ///< Index of next child for each \e open element int4 attributeIndex; ///< Position of \e current attribute to parse (in \e current element) + int4 scope; ///< Scope of element/attribute tags to look up int4 findMatchingAttribute(const Element *el,const string &attribName); public: - XmlDecode(const AddrSpaceManager *spc,const Element *root) : Decoder(spc) { - document = (Document *)0; rootElement = root; attributeIndex = -1; } ///< Constructor with preparsed root - XmlDecode(const AddrSpaceManager *spc) : Decoder(spc) { - document = (Document *)0; rootElement = (const Element *)0; attributeIndex = -1; } ///< Constructor for use with ingestStream + XmlDecode(const AddrSpaceManager *spc,const Element *root,int4 sc=0) : Decoder(spc) { + document = (Document *)0; rootElement = root; attributeIndex = -1; scope = sc; } ///< Constructor with preparsed root + XmlDecode(const AddrSpaceManager *spc,int4 sc=0) : Decoder(spc) { + document = (Document *)0; rootElement = (const Element *)0; attributeIndex = -1; scope=sc; } ///< Constructor for use with ingestStream const Element *getCurrentXmlElement(void) const { return elStack.back(); } ///< Get pointer to underlying XML element object virtual ~XmlDecode(void); virtual void ingestStream(istream &s); @@ -392,6 +416,8 @@ public: virtual string readString(const AttributeId &attribId); virtual AddrSpace *readSpace(void); virtual AddrSpace *readSpace(const AttributeId &attribId); + virtual OpCode readOpcode(void); + virtual OpCode readOpcode(AttributeId &attribId); }; /// \brief An XML based encoder @@ -400,10 +426,20 @@ public: /// receive the XML document as calls are made on the encoder. class XmlEncode : public Encoder { friend class XmlDecode; + enum { + tag_start = 0, ///< Tag has been opened, attributes can be written + tag_content = 1, ///< Opening tag and content have been written + tag_stop = 2 ///< No tag is currently being written + }; + static const char spaces[]; ///< Array of ' ' characters for emitting indents + static const int4 MAX_SPACES; ostream &outStream; ///< The stream receiving the encoded data - bool elementTagIsOpen; ///< If \b true, new attributes can be written to the current element + int4 tagStatus; ///< Stage of writing an element tag + int4 depth; ///< Depth of open elements + bool doFormatting; ///< \b true if encoder should indent and emit newlines + void newLine(void); ///< Emit a newline and proper indenting for the next tag public: - XmlEncode(ostream &s) : outStream(s) { elementTagIsOpen = false; } ///< Construct from a stream + XmlEncode(ostream &s,bool doFormat=true) : outStream(s) { depth=0; tagStatus=tag_stop; doFormatting=doFormat; } ///< Construct from a stream virtual void openElement(const ElementId &elemId); virtual void closeElement(const ElementId &elemId); virtual void writeBool(const AttributeId &attribId,bool val); @@ -412,6 +448,7 @@ public: virtual void writeString(const AttributeId &attribId,const string &val); virtual void writeStringIndexed(const AttributeId &attribId,uint4 index,const string &val); virtual void writeSpace(const AttributeId &attribId,const AddrSpace *spc); + virtual void writeOpcode(const AttributeId &attribId,OpCode opc); }; /// \brief Protocol format for PackedEncode and PackedDecode classes @@ -505,6 +542,9 @@ private: void findMatchingAttribute(const AttributeId &attribId); ///< Find attribute matching the given id in open element void skipAttribute(void); ///< Skip over the attribute at the current position void skipAttributeRemaining(uint1 typeByte); ///< Skip over remaining attribute data, after a mismatch +protected: + uint1 *allocateNextInputBuffer(int4 pad); ///< Allocate the next chunk of space in the input stream + void endIngest(int4 bufPos); ///< Finish set up for reading input stream public: PackedDecode(const AddrSpaceManager *spcManager) : Decoder(spcManager) {} ///< Constructor virtual ~PackedDecode(void); @@ -529,6 +569,8 @@ public: virtual string readString(const AttributeId &attribId); virtual AddrSpace *readSpace(void); virtual AddrSpace *readSpace(const AttributeId &attribId); + virtual OpCode readOpcode(void); + virtual OpCode readOpcode(AttributeId &attribId); }; /// \brief A byte-based encoder designed to marshal from the decompiler efficiently @@ -548,6 +590,7 @@ public: virtual void writeString(const AttributeId &attribId,const string &val); virtual void writeStringIndexed(const AttributeId &attribId,uint4 index,const string &val); virtual void writeSpace(const AttributeId &attribId,const AddrSpace *spc); + virtual void writeOpcode(const AttributeId &attribId,OpCode opc); }; /// An exception is thrown if the position currently points to the last byte in the stream @@ -602,6 +645,17 @@ inline void PackedDecode::advancePosition(Position &pos,int4 skip) pos.current += skip; } +/// Allocate an array of BUFFER_SIZE bytes and add it to the in-memory stream +/// \param pad is the number of bytes of padding to add to the allocation size, above BUFFER_SIZE +/// \return the newly allocated buffer +inline uint1 *PackedDecode::allocateNextInputBuffer(int4 pad) + +{ + uint1 *buf = new uint1[BUFFER_SIZE + pad]; + inStream.emplace_back(buf,buf+BUFFER_SIZE); + return buf; +} + /// \param header is the type of header /// \param id is the id associated with the element or attribute inline void PackedEncode::writeHeader(uint1 header,uint4 id) @@ -624,29 +678,35 @@ extern ElementId ELEM_UNKNOWN; ///< Special element to represent an element wit 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 +/// The name is looked up in the scoped list of 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 +/// \param scope is the id of the scope in which to lookup of the name /// \return the associated id -inline uint4 AttributeId::find(const string &nm) +inline uint4 AttributeId::find(const string &nm,int4 scope) { - unordered_map::const_iterator iter = lookupAttributeId.find(nm); - if (iter != lookupAttributeId.end()) - return (*iter).second; + if (scope == 0) { // Current only support reverse look up for scope 0 + unordered_map::const_iterator iter = lookupAttributeId.find(nm); + if (iter != lookupAttributeId.end()) + return (*iter).second; + } return ATTRIB_UNKNOWN.id; } -/// The name is looked up in the global list of all elements. If the element is not in the list, a special +/// The name is looked up in the scoped list of 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 +/// \param scope is the id of the scope in which to search /// \return the associated id -inline uint4 ElementId::find(const string &nm) +inline uint4 ElementId::find(const string &nm,int4 scope) { - unordered_map::const_iterator iter = lookupElementId.find(nm); - if (iter != lookupElementId.end()) - return (*iter).second; + if (scope == 0) { + unordered_map::const_iterator iter = lookupElementId.find(nm); + if (iter != lookupElementId.end()) + return (*iter).second; + } return ELEM_UNKNOWN.id; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc index 0e3decc80d3..92133517392 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/op.cc @@ -31,7 +31,7 @@ const string IopSpace::NAME = "iop"; /// \param t is the associated processor translator /// \param ind is the associated index IopSpace::IopSpace(AddrSpaceManager *m,const Translate *t,int4 ind) - : AddrSpace(m,t,IPTR_IOP,NAME,sizeof(void *),1,ind,0,1) + : AddrSpace(m,t,IPTR_IOP,NAME,false,sizeof(void *),1,ind,0,1,1) { clearFlags(heritaged|does_deadcode|big_endian); if (HOST_ENDIAN==1) // Endianness always set to host @@ -58,12 +58,6 @@ void IopSpace::printRaw(ostream &s,uintb offset) const bl->getStart().printRaw(s); } -void IopSpace::saveXml(ostream &s) const - -{ - throw LowlevelError("Should never encode iop space to stream"); -} - void IopSpace::decode(Decoder &decoder) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh index 117fe953be2..b6c8cbe0d44 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh @@ -40,7 +40,6 @@ public: virtual void encodeAttributes(Encoder &encoder,uintb offset) const { encoder.writeString(ATTRIB_SPACE, "iop"); } virtual void encodeAttributes(Encoder &encoder,uintb offset,int4 size) const { encoder.writeString(ATTRIB_SPACE, "iop"); } virtual void printRaw(ostream &s,uintb offset) const; - virtual void saveXml(ostream &s) const; virtual void decode(Decoder &decoder); static const string NAME; ///< Reserved name for the iop space }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc index 877e1e2a12a..e0778433e1c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc @@ -84,7 +84,7 @@ bool ArchOption::onOrOff(const string &p) void OptionDatabase::registerOption(ArchOption *option) { - uint4 id = ElementId::find(option->getName()); // Option name must match a known element name + uint4 id = ElementId::find(option->getName(),0); // Option name must match a known element name optionmap[id] = option; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/semantics.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/semantics.cc index 2e3531ea27e..cd9b9835b18 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/semantics.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/semantics.cc @@ -290,39 +290,6 @@ void ConstTpl::transfer(const vector ¶ms) } } -void ConstTpl::printHandleSelector(ostream &s,v_field val) - -{ - switch(val) { - case v_space: - s << "space"; - break; - case v_offset: - s << "offset"; - break; - case v_size: - s << "size"; - break; - case v_offset_plus: - s << "offset_plus"; - break; - } -} - -ConstTpl::v_field ConstTpl::readHandleSelector(const string &name) - -{ - if (name == "space") - return v_space; - if (name == "offset") - return v_offset; - if (name == "size") - return v_size; - if (name == "offset_plus") - return v_offset_plus; - throw LowlevelError("Bad handle selector"); -} - void ConstTpl::changeHandleIndex(const vector &handmap) { @@ -330,120 +297,129 @@ void ConstTpl::changeHandleIndex(const vector &handmap) value.handle_index = handmap[value.handle_index]; } -void ConstTpl::saveXml(ostream &s) const +void ConstTpl::encode(Encoder &encoder) const { - s << ""; + encoder.openElement(sla::ELEM_CONST_REAL); + encoder.writeUnsignedInteger(sla::ATTRIB_VAL, value_real); + encoder.closeElement(sla::ELEM_CONST_REAL); break; case handle: - s << "handle\" val=\"" << dec << value.handle_index << "\" "; - s << "s=\""; - printHandleSelector(s,select); - s << "\""; + encoder.openElement(sla::ELEM_CONST_HANDLE); + encoder.writeSignedInteger(sla::ATTRIB_VAL, value.handle_index); + encoder.writeSignedInteger(sla::ATTRIB_S, select); if (select == v_offset_plus) - s << " plus=\"0x" << hex << value_real << "\""; - s << "/>"; + encoder.writeUnsignedInteger(sla::ATTRIB_PLUS, value_real); + encoder.closeElement(sla::ELEM_CONST_HANDLE); break; case j_start: - s << "start\"/>"; + encoder.openElement(sla::ELEM_CONST_START); + encoder.closeElement(sla::ELEM_CONST_START); break; case j_next: - s << "next\"/>"; + encoder.openElement(sla::ELEM_CONST_NEXT); + encoder.closeElement(sla::ELEM_CONST_NEXT); break; case j_next2: - s << "next2\"/>"; + encoder.openElement(sla::ELEM_CONST_NEXT2); + encoder.closeElement(sla::ELEM_CONST_NEXT2); break; case j_curspace: - s << "curspace\"/>"; + encoder.openElement(sla::ELEM_CONST_CURSPACE); + encoder.closeElement(sla::ELEM_CONST_CURSPACE); break; case j_curspace_size: - s << "curspace_size\"/>"; + encoder.openElement(sla::ELEM_CONST_CURSPACE_SIZE); + encoder.closeElement(sla::ELEM_CONST_CURSPACE_SIZE); break; case spaceid: - s << "spaceid\" name=\"" << value.spaceid->getName() << "\"/>"; + encoder.openElement(sla::ELEM_CONST_SPACEID); + encoder.writeSpace(sla::ATTRIB_SPACE, value.spaceid); + encoder.closeElement(sla::ELEM_CONST_SPACEID); break; case j_relative: - s << "relative\" val=\"0x" << hex << value_real << "\"/>"; + encoder.openElement(sla::ELEM_CONST_RELATIVE); + encoder.writeUnsignedInteger(sla::ATTRIB_VAL, value_real); + encoder.closeElement(sla::ELEM_CONST_RELATIVE); break; case j_flowref: - s << "flowref\"/>"; + encoder.openElement(sla::ELEM_CONST_FLOWREF); + encoder.closeElement(sla::ELEM_CONST_FLOWREF); break; case j_flowref_size: - s << "flowref_size\"/>"; + encoder.openElement(sla::ELEM_CONST_FLOWREF_SIZE); + encoder.closeElement(sla::ELEM_CONST_FLOWREF_SIZE); break; case j_flowdest: - s << "flowdest\"/>"; + encoder.openElement(sla::ELEM_CONST_FLOWDEST); + encoder.closeElement(sla::ELEM_CONST_FLOWDEST); break; case j_flowdest_size: - s << "flowdest_size\"/>"; + encoder.openElement(sla::ELEM_CONST_FLOWDEST_SIZE); + encoder.closeElement(sla::ELEM_CONST_FLOWDEST_SIZE); break; } } -void ConstTpl::restoreXml(const Element *el,const AddrSpaceManager *manage) +void ConstTpl::decode(Decoder &decoder) { - const string &typestring(el->getAttributeValue("type")); - if (typestring == "real") { + uint4 el = decoder.openElement(); + if (el == sla::ELEM_CONST_REAL) { type = real; - istringstream s(el->getAttributeValue("val")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> value_real; + value_real = decoder.readUnsignedInteger(sla::ATTRIB_VAL); } - else if (typestring=="handle") { + else if (el == sla::ELEM_CONST_HANDLE) { type = handle; - istringstream s(el->getAttributeValue("val")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> value.handle_index; - select = readHandleSelector(el->getAttributeValue("s")); + value.handle_index = decoder.readSignedInteger(sla::ATTRIB_VAL); + uint4 selectInt = decoder.readSignedInteger(sla::ATTRIB_S); + if (selectInt > v_offset_plus) + throw DecoderError("Bad handle selector encoding"); + select = (v_field)selectInt; if (select == v_offset_plus) { - istringstream s2(el->getAttributeValue("plus")); - s2.unsetf(ios::dec | ios::hex | ios::oct); - s2 >> value_real; + value_real = decoder.readUnsignedInteger(sla::ATTRIB_PLUS); } } - else if (typestring=="start") { + else if (el == sla::ELEM_CONST_START) { type = j_start; } - else if (typestring=="next") { + else if (el == sla::ELEM_CONST_NEXT) { type = j_next; } - else if (typestring=="next2") { + else if (el == sla::ELEM_CONST_NEXT2) { type = j_next2; } - else if (typestring=="curspace") { + else if (el == sla::ELEM_CONST_CURSPACE) { type = j_curspace; } - else if (typestring=="curspace_size") { + else if (el == sla::ELEM_CONST_CURSPACE_SIZE) { type = j_curspace_size; } - else if (typestring=="spaceid") { + else if (el == sla::ELEM_CONST_SPACEID) { type = spaceid; - value.spaceid = manage->getSpaceByName(el->getAttributeValue("name")); + value.spaceid = decoder.readSpace(sla::ATTRIB_SPACE); } - else if (typestring=="relative") { + else if (el == sla::ELEM_CONST_RELATIVE) { type = j_relative; - istringstream s(el->getAttributeValue("val")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> value_real; + value_real = decoder.readUnsignedInteger(sla::ATTRIB_VAL); } - else if (typestring == "flowref") { + else if (el == sla::ELEM_CONST_FLOWREF) { type = j_flowref; } - else if (typestring == "flowref_size") { + else if (el == sla::ELEM_CONST_FLOWREF_SIZE) { type = j_flowref_size; } - else if (typestring == "flowdest") { + else if (el == sla::ELEM_CONST_FLOWDEST) { type = j_flowdest; } - else if (typestring == "flowdest_size") { + else if (el == sla::ELEM_CONST_FLOWDEST_SIZE) { type = j_flowdest_size; } else throw LowlevelError("Bad constant type"); + decoder.closeElement(el); } VarnodeTpl::VarnodeTpl(int4 hand,bool zerosize) : @@ -544,27 +520,24 @@ bool VarnodeTpl::adjustTruncation(int4 sz,bool isbigendian) return true; } -void VarnodeTpl::saveXml(ostream &s) const +void VarnodeTpl::encode(Encoder &encoder) const { - s << ""; - space.saveXml(s); - offset.saveXml(s); - size.saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_VARNODE_TPL); + space.encode(encoder); + offset.encode(encoder); + size.encode(encoder); + encoder.closeElement(sla::ELEM_VARNODE_TPL); } -void VarnodeTpl::restoreXml(const Element *el,const AddrSpaceManager *manage) +void VarnodeTpl::decode(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - space.restoreXml(*iter,manage); - ++iter; - offset.restoreXml(*iter,manage); - ++iter; - size.restoreXml(*iter,manage); + uint4 el = decoder.openElement(sla::ELEM_VARNODE_TPL); + space.decode(decoder); + offset.decode(decoder); + size.decode(decoder); + decoder.closeElement(el); } bool VarnodeTpl::operator<(const VarnodeTpl &op2) const @@ -633,39 +606,32 @@ void HandleTpl::changeHandleIndex(const vector &handmap) temp_offset.changeHandleIndex(handmap); } -void HandleTpl::saveXml(ostream &s) const +void HandleTpl::encode(Encoder &encoder) const { - s << ""; - space.saveXml(s); - size.saveXml(s); - ptrspace.saveXml(s); - ptroffset.saveXml(s); - ptrsize.saveXml(s); - temp_space.saveXml(s); - temp_offset.saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_HANDLE_TPL); + space.encode(encoder); + size.encode(encoder); + ptrspace.encode(encoder); + ptroffset.encode(encoder); + ptrsize.encode(encoder); + temp_space.encode(encoder); + temp_offset.encode(encoder); + encoder.closeElement(sla::ELEM_HANDLE_TPL); } -void HandleTpl::restoreXml(const Element *el,const AddrSpaceManager *manage) +void HandleTpl::decode(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - space.restoreXml(*iter,manage); - ++iter; - size.restoreXml(*iter,manage); - ++iter; - ptrspace.restoreXml(*iter,manage); - ++iter; - ptroffset.restoreXml(*iter,manage); - ++iter; - ptrsize.restoreXml(*iter,manage); - ++iter; - temp_space.restoreXml(*iter,manage); - ++iter; - temp_offset.restoreXml(*iter,manage); + uint4 el = decoder.openElement(sla::ELEM_HANDLE_TPL); + space.decode(decoder); + size.decode(decoder); + ptrspace.decode(decoder); + ptroffset.decode(decoder); + ptrsize.decode(decoder); + temp_space.decode(decoder); + temp_offset.decode(decoder); + decoder.closeElement(el); } OpTpl::~OpTpl(void) @@ -710,39 +676,43 @@ void OpTpl::changeHandleIndex(const vector &handmap) (*iter)->changeHandleIndex(handmap); } -void OpTpl::saveXml(ostream &s) const +void OpTpl::encode(Encoder &encoder) const { - s << ""; - if (output == (VarnodeTpl *)0) - s << "\n"; + encoder.openElement(sla::ELEM_OP_TPL); + encoder.writeOpcode(sla::ATTRIB_CODE, opc); + if (output == (VarnodeTpl *)0) { + encoder.openElement(sla::ELEM_NULL); + encoder.closeElement(sla::ELEM_NULL); + } else - output->saveXml(s); + output->encode(encoder); for(int4 i=0;isaveXml(s); - s << "\n"; + input[i]->encode(encoder); + encoder.closeElement(sla::ELEM_OP_TPL); } -void OpTpl::restoreXml(const Element *el,const AddrSpaceManager *manage) +void OpTpl::decode(Decoder &decoder) { - opc = get_opcode(el->getAttributeValue("code")); - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - if ((*iter)->getName() == "null") + uint4 el = decoder.openElement(sla::ELEM_OP_TPL); + opc = decoder.readOpcode(sla::ATTRIB_CODE); + uint4 subel = decoder.peekElement(); + if (subel == sla::ELEM_NULL) { + decoder.openElement(); + decoder.closeElement(subel); output = (VarnodeTpl *)0; + } else { output = new VarnodeTpl(); - output->restoreXml(*iter,manage); + output->decode(decoder); } - ++iter; - while(iter != list.end()) { + while(decoder.peekElement() != 0) { VarnodeTpl *vn = new VarnodeTpl(); - vn->restoreXml(*iter,manage); + vn->decode(decoder); input.push_back(vn); - ++iter; } + decoder.closeElement(el); } ConstructTpl::~ConstructTpl(void) @@ -882,63 +852,61 @@ void ConstructTpl::deleteOps(const vector &indices) vec.pop_back(); } -void ConstructTpl::saveXml(ostream &s,int4 sectionid) const +void ConstructTpl::encode(Encoder &encoder,int4 sectionid) const { - s << "=0 ) - s << " section=\"" << dec << sectionid << "\""; + encoder.writeSignedInteger(sla::ATTRIB_SECTION, sectionid); if (delayslot != 0) - s << " delay=\"" << dec << delayslot << "\""; + encoder.writeSignedInteger(sla::ATTRIB_DELAY, delayslot); if (numlabels != 0) - s << " labels=\"" << dec << numlabels << "\""; - s << ">\n"; + encoder.writeSignedInteger(sla::ATTRIB_LABELS, numlabels); if (result != (HandleTpl *)0) - result->saveXml(s); - else - s << ""; + result->encode(encoder); + else { + encoder.openElement(sla::ELEM_NULL); + encoder.closeElement(sla::ELEM_NULL); + } for(int4 i=0;isaveXml(s); - s << "\n"; + vec[i]->encode(encoder); + encoder.closeElement(sla::ELEM_CONSTRUCT_TPL); } -int4 ConstructTpl::restoreXml(const Element *el,const AddrSpaceManager *manage) +int4 ConstructTpl::decode(Decoder &decoder) { + uint4 el = decoder.openElement(sla::ELEM_CONSTRUCT_TPL); int4 sectionid = -1; - for(int4 i=0;igetNumAttributes();++i) { - if (el->getAttributeName(i)=="delay") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> delayslot; + uint4 attrib = decoder.getNextAttributeId(); + while(attrib != 0) { + if (attrib == sla::ATTRIB_DELAY) { + delayslot = decoder.readSignedInteger(); } - else if (el->getAttributeName(i)=="labels") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> numlabels; + else if (attrib == sla::ATTRIB_LABELS) { + numlabels = decoder.readSignedInteger(); } - else if (el->getAttributeName(i)=="section") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> sectionid; + else if (attrib == sla::ATTRIB_SECTION) { + sectionid = decoder.readSignedInteger(); } + attrib = decoder.getNextAttributeId(); } - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - if ((*iter)->getName() == "null") + uint4 subel = decoder.peekElement(); + if (subel == sla::ELEM_NULL) { + decoder.openElement(); + decoder.closeElement(subel); result = (HandleTpl *)0; + } else { result = new HandleTpl(); - result->restoreXml(*iter,manage); + result->decode(decoder); } - ++iter; - while(iter != list.end()) { + while(decoder.peekElement() != 0) { OpTpl *op = new OpTpl(); - op->restoreXml(*iter,manage); + op->decode(decoder); vec.push_back(op); - ++iter; } + decoder.closeElement(el); return sectionid; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/semantics.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/semantics.hh index 8e283dca0f2..e0b069959db 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/semantics.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/semantics.hh @@ -17,6 +17,7 @@ #define __SEMANTICS_HH__ #include "context.hh" +#include "slaformat.hh" namespace ghidra { @@ -45,8 +46,6 @@ private: } value; uintb value_real; v_field select; // Which part of handle to use as constant - static void printHandleSelector(ostream &s,v_field val); - static v_field readHandleSelector(const string &name); public: ConstTpl(void) { type = real; value_real = 0; } ConstTpl(const ConstTpl &op2) { @@ -72,8 +71,8 @@ public: void changeHandleIndex(const vector &handmap); void fillinSpace(FixedHandle &hand,const ParserWalker &walker) const; void fillinOffset(FixedHandle &hand,const ParserWalker &walker) const; - void saveXml(ostream &s) const; - void restoreXml(const Element *el,const AddrSpaceManager *manage); + void encode(Encoder &encoder) const; + void decode(Decoder &decoder); }; class VarnodeTpl { @@ -102,8 +101,8 @@ public: bool isRelative(void) const { return (offset.getType() == ConstTpl::j_relative); } void changeHandleIndex(const vector &handmap); bool adjustTruncation(int4 sz,bool isbigendian); - void saveXml(ostream &s) const; - void restoreXml(const Element *el,const AddrSpaceManager *manage); + void encode(Encoder &encoder) const; + void decode(Decoder &decoder); }; class HandleTpl { @@ -132,8 +131,8 @@ public: void setTempOffset(uintb val) { temp_offset = ConstTpl(ConstTpl::real,val); } void fix(FixedHandle &hand,const ParserWalker &walker) const; void changeHandleIndex(const vector &handmap); - void saveXml(ostream &s) const; - void restoreXml(const Element *el,const AddrSpaceManager *manage); + void encode(Encoder &encoder) const; + void decode(Decoder &decoder); }; class OpTpl { @@ -156,8 +155,8 @@ public: void setInput(VarnodeTpl *vt,int4 slot) { input[slot] = vt; } void removeInput(int4 index); void changeHandleIndex(const vector &handmap); - void saveXml(ostream &s) const; - void restoreXml(const Element *el,const AddrSpaceManager *manage); + void encode(Encoder &encoder) const; + void decode(Decoder &decoder); }; class ConstructTpl { @@ -185,8 +184,8 @@ public: void setInput(VarnodeTpl *vn,int4 index,int4 slot); void setOutput(VarnodeTpl *vn,int4 index); void deleteOps(const vector &indices); - void saveXml(ostream &s,int4 sectionid) const; - int4 restoreXml(const Element *el,const AddrSpaceManager *manage); + void encode(Encoder &encoder,int4 sectionid) const; + int4 decode(Decoder &decoder); }; class PcodeEmit; // Forward declaration for emitter diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slaformat.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/slaformat.cc new file mode 100644 index 00000000000..f8b3bcfa731 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slaformat.cc @@ -0,0 +1,258 @@ +/* ### + * 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 "slaformat.hh" + +namespace ghidra { +namespace sla { +const int4 FORMAT_SCOPE = 1; +const int4 FORMAT_VERSION = 4; + +// ATTRIB_CONTEXT = 1 is reserved +AttributeId ATTRIB_VAL = AttributeId("val", 2, FORMAT_SCOPE); +AttributeId ATTRIB_ID = AttributeId("id", 3, FORMAT_SCOPE); +AttributeId ATTRIB_SPACE = AttributeId("space", 4, FORMAT_SCOPE); +AttributeId ATTRIB_S = AttributeId("s", 5, FORMAT_SCOPE); +AttributeId ATTRIB_OFF = AttributeId("off", 6, FORMAT_SCOPE); +AttributeId ATTRIB_CODE = AttributeId("code", 7, FORMAT_SCOPE); +AttributeId ATTRIB_MASK = AttributeId("mask", 8, FORMAT_SCOPE); +AttributeId ATTRIB_INDEX = AttributeId("index", 9, FORMAT_SCOPE); +AttributeId ATTRIB_NONZERO = AttributeId("nonzero", 10, FORMAT_SCOPE); +AttributeId ATTRIB_PIECE = AttributeId("piece", 11, FORMAT_SCOPE); +AttributeId ATTRIB_NAME = AttributeId("name", 12, FORMAT_SCOPE); +AttributeId ATTRIB_SCOPE = AttributeId("scope", 13, FORMAT_SCOPE); +AttributeId ATTRIB_STARTBIT = AttributeId("startbit", 14, FORMAT_SCOPE); +AttributeId ATTRIB_SIZE = AttributeId("size", 15, FORMAT_SCOPE); +AttributeId ATTRIB_TABLE = AttributeId("table", 16, FORMAT_SCOPE); +AttributeId ATTRIB_CT = AttributeId("ct", 17, FORMAT_SCOPE); +AttributeId ATTRIB_MINLEN = AttributeId("minlen", 18, FORMAT_SCOPE); +AttributeId ATTRIB_BASE = AttributeId("base", 19, FORMAT_SCOPE); +AttributeId ATTRIB_NUMBER = AttributeId("number", 20, FORMAT_SCOPE); +AttributeId ATTRIB_CONTEXT = AttributeId("context", 21, FORMAT_SCOPE); +AttributeId ATTRIB_PARENT = AttributeId("parent", 22, FORMAT_SCOPE); +AttributeId ATTRIB_SUBSYM = AttributeId("subsym", 23, FORMAT_SCOPE); +AttributeId ATTRIB_LINE = AttributeId("line", 24, FORMAT_SCOPE); +AttributeId ATTRIB_SOURCE = AttributeId("source", 25, FORMAT_SCOPE); +AttributeId ATTRIB_LENGTH = AttributeId("length", 26, FORMAT_SCOPE); +AttributeId ATTRIB_FIRST = AttributeId("first", 27, FORMAT_SCOPE); +AttributeId ATTRIB_PLUS = AttributeId("plus", 28, FORMAT_SCOPE); +AttributeId ATTRIB_SHIFT = AttributeId("shift", 29, FORMAT_SCOPE); +AttributeId ATTRIB_ENDBIT = AttributeId("endbit", 30, FORMAT_SCOPE); +AttributeId ATTRIB_SIGNBIT = AttributeId("signbit", 31, FORMAT_SCOPE); +AttributeId ATTRIB_ENDBYTE = AttributeId("endbyte", 32, FORMAT_SCOPE); +AttributeId ATTRIB_STARTBYTE = AttributeId("startbyte", 33, FORMAT_SCOPE); + +AttributeId ATTRIB_VERSION = AttributeId("version", 34, FORMAT_SCOPE); +AttributeId ATTRIB_BIGENDIAN = AttributeId("bigendian", 35, FORMAT_SCOPE); +AttributeId ATTRIB_ALIGN = AttributeId("align", 36, FORMAT_SCOPE); +AttributeId ATTRIB_UNIQBASE = AttributeId("uniqbase", 37, FORMAT_SCOPE); +AttributeId ATTRIB_MAXDELAY = AttributeId("maxdelay", 38, FORMAT_SCOPE); +AttributeId ATTRIB_UNIQMASK = AttributeId("uniqmask", 39, FORMAT_SCOPE); +AttributeId ATTRIB_NUMSECTIONS = AttributeId("numsections", 40, FORMAT_SCOPE); +AttributeId ATTRIB_DEFAULTSPACE = AttributeId("defaultspace", 41, FORMAT_SCOPE); +AttributeId ATTRIB_DELAY = AttributeId("delay", 42, FORMAT_SCOPE); +AttributeId ATTRIB_WORDSIZE = AttributeId("wordsize", 43, FORMAT_SCOPE); +AttributeId ATTRIB_PHYSICAL = AttributeId("physical", 44, FORMAT_SCOPE); +AttributeId ATTRIB_SCOPESIZE = AttributeId("scopesize", 45, FORMAT_SCOPE); +AttributeId ATTRIB_SYMBOLSIZE = AttributeId("symbolsize", 46, FORMAT_SCOPE); +AttributeId ATTRIB_VARNODE = AttributeId("varnode", 47, FORMAT_SCOPE); +AttributeId ATTRIB_LOW = AttributeId("low", 48, FORMAT_SCOPE); +AttributeId ATTRIB_HIGH = AttributeId("high", 49, FORMAT_SCOPE); +AttributeId ATTRIB_FLOW = AttributeId("flow", 50, FORMAT_SCOPE); +AttributeId ATTRIB_CONTAIN = AttributeId("contain", 51, FORMAT_SCOPE); +AttributeId ATTRIB_I = AttributeId("i", 52, FORMAT_SCOPE); +AttributeId ATTRIB_NUMCT = AttributeId("numct", 53, FORMAT_SCOPE); +AttributeId ATTRIB_SECTION = AttributeId("section", 54, FORMAT_SCOPE); +AttributeId ATTRIB_LABELS = AttributeId("labels", 55, FORMAT_SCOPE); + +ElementId ELEM_CONST_REAL = ElementId("const_real", 1, FORMAT_SCOPE); +ElementId ELEM_VARNODE_TPL = ElementId("varnode_tpl", 2, FORMAT_SCOPE); +ElementId ELEM_CONST_SPACEID = ElementId("const_spaceid", 3, FORMAT_SCOPE); +ElementId ELEM_CONST_HANDLE = ElementId("const_handle", 4, FORMAT_SCOPE); +ElementId ELEM_OP_TPL = ElementId("op_tpl", 5, FORMAT_SCOPE); +ElementId ELEM_MASK_WORD = ElementId("mask_word", 6, FORMAT_SCOPE); +ElementId ELEM_PAT_BLOCK = ElementId("pat_block", 7, FORMAT_SCOPE); +ElementId ELEM_PRINT = ElementId("print", 8, FORMAT_SCOPE); +ElementId ELEM_PAIR = ElementId("pair", 9, FORMAT_SCOPE); +ElementId ELEM_CONTEXT_PAT = ElementId("context_pat", 10, FORMAT_SCOPE); +ElementId ELEM_NULL = ElementId("null", 11, FORMAT_SCOPE); +ElementId ELEM_OPERAND_EXP = ElementId("operand_exp", 12, FORMAT_SCOPE); +ElementId ELEM_OPERAND_SYM = ElementId("operand_sym", 13, FORMAT_SCOPE); +ElementId ELEM_OPERAND_SYM_HEAD = ElementId("operand_sym_head", 14, FORMAT_SCOPE); +ElementId ELEM_OPER = ElementId("oper", 15, FORMAT_SCOPE); +ElementId ELEM_DECISION = ElementId("decision", 16, FORMAT_SCOPE); +ElementId ELEM_OPPRINT = ElementId("opprint", 17, FORMAT_SCOPE); +ElementId ELEM_INSTRUCT_PAT = ElementId("instruct_pat", 18, FORMAT_SCOPE); +ElementId ELEM_COMBINE_PAT = ElementId("combine_pat", 19, FORMAT_SCOPE); +ElementId ELEM_CONSTRUCTOR = ElementId("constructor", 20, FORMAT_SCOPE); +ElementId ELEM_CONSTRUCT_TPL = ElementId("construct_tpl", 21, FORMAT_SCOPE); +ElementId ELEM_SCOPE = ElementId("scope", 22, FORMAT_SCOPE); +ElementId ELEM_VARNODE_SYM = ElementId("varnode_sym", 23, FORMAT_SCOPE); +ElementId ELEM_VARNODE_SYM_HEAD = ElementId("varnode_sym_head", 24, FORMAT_SCOPE); +ElementId ELEM_USEROP = ElementId("userop", 25, FORMAT_SCOPE); +ElementId ELEM_USEROP_HEAD = ElementId("userop_head", 26, FORMAT_SCOPE); +ElementId ELEM_TOKENFIELD = ElementId("tokenfield", 27, FORMAT_SCOPE); +ElementId ELEM_VAR = ElementId("var", 28, FORMAT_SCOPE); +ElementId ELEM_CONTEXTFIELD = ElementId("contextfield", 29, FORMAT_SCOPE); +ElementId ELEM_HANDLE_TPL = ElementId("handle_tpl", 30, FORMAT_SCOPE); +ElementId ELEM_CONST_RELATIVE = ElementId("const_relative", 31, FORMAT_SCOPE); +ElementId ELEM_CONTEXT_OP = ElementId("context_op", 32, FORMAT_SCOPE); + +ElementId ELEM_SLEIGH = ElementId("sleigh", 33, FORMAT_SCOPE); +ElementId ELEM_SPACES = ElementId("spaces", 34, FORMAT_SCOPE); +ElementId ELEM_SOURCEFILES = ElementId("sourcefiles", 35, FORMAT_SCOPE); +ElementId ELEM_SOURCEFILE = ElementId("sourcefile", 36, FORMAT_SCOPE); +ElementId ELEM_SPACE = ElementId("space", 37, FORMAT_SCOPE); +ElementId ELEM_SYMBOL_TABLE = ElementId("symbol_table", 38, FORMAT_SCOPE); +ElementId ELEM_VALUE_SYM = ElementId("value_sym", 39, FORMAT_SCOPE); +ElementId ELEM_VALUE_SYM_HEAD = ElementId("value_sym_head", 40, FORMAT_SCOPE); +ElementId ELEM_CONTEXT_SYM = ElementId("context_sym", 41, FORMAT_SCOPE); +ElementId ELEM_CONTEXT_SYM_HEAD = ElementId("context_sym_head", 42, FORMAT_SCOPE); +ElementId ELEM_END_SYM = ElementId("end_sym", 43, FORMAT_SCOPE); +ElementId ELEM_END_SYM_HEAD = ElementId("end_sym_head", 44, FORMAT_SCOPE); +ElementId ELEM_SPACE_OTHER = ElementId("space_other", 45, FORMAT_SCOPE); +ElementId ELEM_SPACE_UNIQUE = ElementId("space_unique", 46, FORMAT_SCOPE); +ElementId ELEM_AND_EXP = ElementId("and_exp", 47, FORMAT_SCOPE); +ElementId ELEM_DIV_EXP = ElementId("div_exp", 48, FORMAT_SCOPE); +ElementId ELEM_LSHIFT_EXP = ElementId("lshift_exp", 49, FORMAT_SCOPE); +ElementId ELEM_MINUS_EXP = ElementId("minus_exp", 50, FORMAT_SCOPE); +ElementId ELEM_MULT_EXP = ElementId("mult_exp", 51, FORMAT_SCOPE); +ElementId ELEM_NOT_EXP = ElementId("not_exp", 52, FORMAT_SCOPE); +ElementId ELEM_OR_EXP = ElementId("or_exp", 53, FORMAT_SCOPE); +ElementId ELEM_PLUS_EXP = ElementId("plus_exp", 54, FORMAT_SCOPE); +ElementId ELEM_RSHIFT_EXP = ElementId("rshift_exp", 55, FORMAT_SCOPE); +ElementId ELEM_SUB_EXP = ElementId("sub_exp", 56, FORMAT_SCOPE); +ElementId ELEM_XOR_EXP = ElementId("xor_exp", 57, FORMAT_SCOPE); +ElementId ELEM_INTB = ElementId("intb", 58, FORMAT_SCOPE); +ElementId ELEM_END_EXP = ElementId("end_exp", 59, FORMAT_SCOPE); +ElementId ELEM_NEXT2_EXP = ElementId("next2_exp", 60, FORMAT_SCOPE); +ElementId ELEM_START_EXP = ElementId("start_exp", 61, FORMAT_SCOPE); +ElementId ELEM_EPSILON_SYM = ElementId("epsilon_sym", 62, FORMAT_SCOPE); +ElementId ELEM_EPSILON_SYM_HEAD = ElementId("epsilon_sym_head", 63, FORMAT_SCOPE); +ElementId ELEM_NAME_SYM = ElementId("name_sym", 64, FORMAT_SCOPE); +ElementId ELEM_NAME_SYM_HEAD = ElementId("name_sym_head", 65, FORMAT_SCOPE); +ElementId ELEM_NAMETAB = ElementId("nametab", 66, FORMAT_SCOPE); +ElementId ELEM_NEXT2_SYM = ElementId("next2_sym", 67, FORMAT_SCOPE); +ElementId ELEM_NEXT2_SYM_HEAD = ElementId("next2_sym_head", 68, FORMAT_SCOPE); +ElementId ELEM_START_SYM = ElementId("start_sym", 69, FORMAT_SCOPE); +ElementId ELEM_START_SYM_HEAD = ElementId("start_sym_head", 70, FORMAT_SCOPE); +ElementId ELEM_SUBTABLE_SYM = ElementId("subtable_sym", 71, FORMAT_SCOPE); +ElementId ELEM_SUBTABLE_SYM_HEAD = ElementId("subtable_sym_head", 72, FORMAT_SCOPE); +ElementId ELEM_VALUEMAP_SYM = ElementId("valuemap_sym", 73, FORMAT_SCOPE); +ElementId ELEM_VALUEMAP_SYM_HEAD = ElementId("valuemap_sym_head", 74, FORMAT_SCOPE); +ElementId ELEM_VALUETAB = ElementId("valuetab", 75, FORMAT_SCOPE); +ElementId ELEM_VARLIST_SYM = ElementId("varlist_sym", 76, FORMAT_SCOPE); +ElementId ELEM_VARLIST_SYM_HEAD = ElementId("varlist_sym_head", 77, FORMAT_SCOPE); +ElementId ELEM_OR_PAT = ElementId("or_pat", 78, FORMAT_SCOPE); +ElementId ELEM_COMMIT = ElementId("commit", 79, FORMAT_SCOPE); +ElementId ELEM_CONST_START = ElementId("const_start", 80, FORMAT_SCOPE); +ElementId ELEM_CONST_NEXT = ElementId("const_next", 81, FORMAT_SCOPE); +ElementId ELEM_CONST_NEXT2 = ElementId("const_next2", 82, FORMAT_SCOPE); +ElementId ELEM_CONST_CURSPACE = ElementId("const_curspace", 83, FORMAT_SCOPE); +ElementId ELEM_CONST_CURSPACE_SIZE = ElementId("const_curspace_size", 84, FORMAT_SCOPE); +ElementId ELEM_CONST_FLOWREF = ElementId("const_flowref", 85, FORMAT_SCOPE); +ElementId ELEM_CONST_FLOWREF_SIZE = ElementId("const_flowref_size", 86, FORMAT_SCOPE); +ElementId ELEM_CONST_FLOWDEST = ElementId("const_flowdest", 87, FORMAT_SCOPE); +ElementId ELEM_CONST_FLOWDEST_SIZE = ElementId("const_flowdest_size", 88, FORMAT_SCOPE); + +/// The bytes of the header are read from the stream and verified against the required form and current version. +/// If the form matches, \b true is returned. No additional bytes are read. +/// \param s is the given stream +/// \return \b true if a valid header is present +bool isSlaFormat(istream &s) + +{ + uint1 header[4]; + s.read((char *)header,4); + if (!s) + return false; + if (header[0] != 's' || header[1] != 'l' || header[2] != 'a') + return false; + if (header[3] != FORMAT_VERSION) + return false; + return true; +} + +/// A valid header, including the format version number, is written to the stream. +/// \param s is the given stream +void writeSlaHeader(ostream &s) + +{ + char header[4]; + header[0] = 's'; + header[1] = 'l'; + header[2] = 'a'; + header[3] = FORMAT_VERSION; + s.write(header,4); +} + +/// \param s is the backing stream that will receive the final bytes of the .sla file +/// \param level is the compression level +FormatEncode::FormatEncode(ostream &s,int4 level) + : PackedEncode(compStream), compBuffer(s,level), compStream(&compBuffer) +{ + writeSlaHeader(s); +} + +void FormatEncode::flush(void) + +{ + compStream.flush(); +} + +const int4 FormatDecode::IN_BUFFER_SIZE = 4096; + +/// \param spcManager is the (uninitialized) manager that will hold decoded address spaces +FormatDecode::FormatDecode(const AddrSpaceManager *spcManager) + : PackedDecode(spcManager) +{ + inBuffer = new uint1[IN_BUFFER_SIZE]; +} + +FormatDecode::~FormatDecode(void) + +{ + delete [] inBuffer; +} + +void FormatDecode::ingestStream(istream &s) + +{ + if (!isSlaFormat(s)) + throw LowlevelError("Missing SLA format header"); + Decompress decompressor; + uint1 *outBuf; + int4 outAvail = 0; + + while(!decompressor.isFinished()) { + s.read((char *)inBuffer,IN_BUFFER_SIZE); + int4 gcount = s.gcount(); + if (gcount == 0) + break; + decompressor.input(inBuffer,gcount); + do { + if (outAvail == 0) { + outBuf = allocateNextInputBuffer(0); + outAvail = BUFFER_SIZE; + } + outAvail = decompressor.inflate(outBuf + (BUFFER_SIZE - outAvail), outAvail); + } while(outAvail == 0); + + } + endIngest(BUFFER_SIZE - outAvail); +} + +} // End sla namespace +} // End ghidra namespace diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slaformat.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/slaformat.hh new file mode 100644 index 00000000000..a8eb11b63c8 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slaformat.hh @@ -0,0 +1,205 @@ +/* ### + * 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. + */ +/// \file slaformat.hh +/// \brief Encoding values for the SLA file format +#ifndef __SLAFORMAT__ +#define __SLAFORMAT__ + +#include "compression.hh" +#include "marshal.hh" + +namespace ghidra { +namespace sla { + +extern const int4 FORMAT_SCOPE; ///< Grouping elements/attributes for SLA file format +extern const int4 FORMAT_VERSION; ///< Current version of the .sla file + +extern AttributeId ATTRIB_VAL; ///< SLA format attribute "val" +extern AttributeId ATTRIB_ID; ///< SLA format attribute "id" +extern AttributeId ATTRIB_SPACE; ///< SLA format attribute "space" +extern AttributeId ATTRIB_S; ///< SLA format attribute "s" +extern AttributeId ATTRIB_OFF; ///< SLA format attribute "off" +extern AttributeId ATTRIB_CODE; ///< SLA format attribute "code" +extern AttributeId ATTRIB_MASK; ///< SLA format attribute "mask" +extern AttributeId ATTRIB_INDEX; ///< SLA format attribute "index" +extern AttributeId ATTRIB_NONZERO; ///< SLA format attribute "nonzero" +extern AttributeId ATTRIB_PIECE; ///< SLA format attribute "piece" +extern AttributeId ATTRIB_NAME; ///< SLA format attribute "name" +extern AttributeId ATTRIB_SCOPE; ///< SLA format attribute "scope" +extern AttributeId ATTRIB_STARTBIT; ///< SLA format attribute "startbit" +extern AttributeId ATTRIB_SIZE; ///< SLA format attribute "size" +extern AttributeId ATTRIB_TABLE; ///< SLA format attribute "table" +extern AttributeId ATTRIB_CT; ///< SLA format attribute "ct" +extern AttributeId ATTRIB_MINLEN; ///< SLA format attribute "minlen" +extern AttributeId ATTRIB_BASE; ///< SLA format attribute "base" +extern AttributeId ATTRIB_NUMBER; ///< SLA format attribute "number" +extern AttributeId ATTRIB_CONTEXT; ///< SLA format attribute "context" +extern AttributeId ATTRIB_PARENT; ///< SLA format attribute "parent" +extern AttributeId ATTRIB_SUBSYM; ///< SLA format attribute "subsym" +extern AttributeId ATTRIB_LINE; ///< SLA format attribute "line" +extern AttributeId ATTRIB_SOURCE; ///< SLA format attribute "source" +extern AttributeId ATTRIB_LENGTH; ///< SLA format attribute "length" +extern AttributeId ATTRIB_FIRST; ///< SLA format attribute "first" +extern AttributeId ATTRIB_PLUS; ///< SLA format attribute "plus" +extern AttributeId ATTRIB_SHIFT; ///< SLA format attribute "shift" +extern AttributeId ATTRIB_ENDBIT; ///< SLA format attribute "endbit" +extern AttributeId ATTRIB_SIGNBIT; ///< SLA format attribute "signbit" +extern AttributeId ATTRIB_ENDBYTE; ///< SLA format attribute "endbyte" +extern AttributeId ATTRIB_STARTBYTE; ///< SLA format attribute "startbyte" + +extern AttributeId ATTRIB_VERSION; ///< SLA format attribute "version" +extern AttributeId ATTRIB_BIGENDIAN; ///< SLA format attribute "bigendian" +extern AttributeId ATTRIB_ALIGN; ///< SLA format attribute "align" +extern AttributeId ATTRIB_UNIQBASE; ///< SLA format attribute "uniqbase" +extern AttributeId ATTRIB_MAXDELAY; ///< SLA format attribute "maxdelay" +extern AttributeId ATTRIB_UNIQMASK; ///< SLA format attribute "uniqmask" +extern AttributeId ATTRIB_NUMSECTIONS; ///< SLA format attribute "numsections" +extern AttributeId ATTRIB_DEFAULTSPACE; ///< SLA format attribute "defaultspace" +extern AttributeId ATTRIB_DELAY; ///< SLA format attribute "delay" +extern AttributeId ATTRIB_WORDSIZE; ///< SLA format attribute "wordsize" +extern AttributeId ATTRIB_PHYSICAL; ///< SLA format attribute "physical" +extern AttributeId ATTRIB_SCOPESIZE; ///< SLA format attribute "scopesize" +extern AttributeId ATTRIB_SYMBOLSIZE; ///< SLA format attribute "symbolsize" +extern AttributeId ATTRIB_VARNODE; ///< SLA format attribute "varnode" +extern AttributeId ATTRIB_LOW; ///< SLA format attribute "low" +extern AttributeId ATTRIB_HIGH; ///< SLA format attribute "high" +extern AttributeId ATTRIB_FLOW; ///< SLA format attribute "flow" +extern AttributeId ATTRIB_CONTAIN; ///< SLA format attribute "contain" +extern AttributeId ATTRIB_I; ///< SLA format attribute "i" +extern AttributeId ATTRIB_NUMCT; ///< SLA format attribute "numct" +extern AttributeId ATTRIB_SECTION; ///< SLA format attribute "section" +extern AttributeId ATTRIB_LABELS; ///< SLA format attribute "labels" + +extern ElementId ELEM_CONST_REAL; ///< SLA format element "const_real" +extern ElementId ELEM_VARNODE_TPL; ///< SLA format element "varnode_tpl" +extern ElementId ELEM_CONST_SPACEID; ///< SLA format element "const_spaceid" +extern ElementId ELEM_CONST_HANDLE; ///< SLA format element "const_handle" +extern ElementId ELEM_OP_TPL; ///< SLA format element "op_tpl" +extern ElementId ELEM_MASK_WORD; ///< SLA format element "mask_word" +extern ElementId ELEM_PAT_BLOCK; ///< SLA format element "pat_block" +extern ElementId ELEM_PRINT; ///< SLA format element "print" +extern ElementId ELEM_PAIR; ///< SLA format element "pair" +extern ElementId ELEM_CONTEXT_PAT; ///< SLA format element "context_pat" +extern ElementId ELEM_NULL; ///< SLA format element "null" +extern ElementId ELEM_OPERAND_EXP; ///< SLA format element "operand_exp" +extern ElementId ELEM_OPERAND_SYM; ///< SLA format element "operand_sym" +extern ElementId ELEM_OPERAND_SYM_HEAD; ///< SLA format element "operand_sym_head" +extern ElementId ELEM_OPER; ///< SLA format element "oper" +extern ElementId ELEM_DECISION; ///< SLA format element "decision" +extern ElementId ELEM_OPPRINT; ///< SLA format element "opprint" +extern ElementId ELEM_INSTRUCT_PAT; ///< SLA format element "instruct_pat" +extern ElementId ELEM_COMBINE_PAT; ///< SLA format element "combine_pat" +extern ElementId ELEM_CONSTRUCTOR; ///< SLA format element "constructor" +extern ElementId ELEM_CONSTRUCT_TPL; ///< SLA format element "construct_tpl" +extern ElementId ELEM_SCOPE; ///< SLA format element "scope" +extern ElementId ELEM_VARNODE_SYM; ///< SLA format element "varnode_sym" +extern ElementId ELEM_VARNODE_SYM_HEAD; ///< SLA format element "varnode_sym_head" +extern ElementId ELEM_USEROP; ///< SLA format element "userop" +extern ElementId ELEM_USEROP_HEAD; ///< SLA format element "userop_head" +extern ElementId ELEM_TOKENFIELD; ///< SLA format element "tokenfield" +extern ElementId ELEM_VAR; ///< SLA format element "var" +extern ElementId ELEM_CONTEXTFIELD; ///< SLA format element "contextfield" +extern ElementId ELEM_HANDLE_TPL; ///< SLA format element "handle_tpl" +extern ElementId ELEM_CONST_RELATIVE; ///< SLA format element "const_relative" +extern ElementId ELEM_CONTEXT_OP; ///< SLA format element "context_op" + +extern ElementId ELEM_SLEIGH; ///< SLA format element "sleigh" +extern ElementId ELEM_SPACES; ///< SLA format element "spaces" +extern ElementId ELEM_SOURCEFILES; ///< SLA format element "sourcefiles" +extern ElementId ELEM_SOURCEFILE; ///< SLA format element "sourcefile" +extern ElementId ELEM_SPACE; ///< SLA format element "space" +extern ElementId ELEM_SYMBOL_TABLE; ///< SLA format element "symbol_table" +extern ElementId ELEM_VALUE_SYM; ///< SLA format element "value_sym" +extern ElementId ELEM_VALUE_SYM_HEAD; ///< SLA format element "value_sym_head" +extern ElementId ELEM_CONTEXT_SYM; ///< SLA format element "context_sym" +extern ElementId ELEM_CONTEXT_SYM_HEAD; ///< SLA format element "context_sym_head" +extern ElementId ELEM_END_SYM; ///< SLA format element "end_sym" +extern ElementId ELEM_END_SYM_HEAD; ///< SLA format element "end_sym_head" +extern ElementId ELEM_SPACE_OTHER; ///< SLA format element "space_other" +extern ElementId ELEM_SPACE_UNIQUE; ///< SLA format element "space_unique" +extern ElementId ELEM_AND_EXP; ///< SLA format element "and_exp" +extern ElementId ELEM_DIV_EXP; ///< SLA format element "div_exp" +extern ElementId ELEM_LSHIFT_EXP; ///< SLA format element "lshift_exp" +extern ElementId ELEM_MINUS_EXP; ///< SLA format element "minus_exp" +extern ElementId ELEM_MULT_EXP; ///< SLA format element "mult_exp" +extern ElementId ELEM_NOT_EXP; ///< SLA format element "not_exp" +extern ElementId ELEM_OR_EXP; ///< SLA format element "or_exp" +extern ElementId ELEM_PLUS_EXP; ///< SLA format element "plus_exp" +extern ElementId ELEM_RSHIFT_EXP; ///< SLA format element "rshift_exp" +extern ElementId ELEM_SUB_EXP; ///< SLA format element "sub_exp" +extern ElementId ELEM_XOR_EXP; ///< SLA format element "xor_exp" +extern ElementId ELEM_INTB; ///< SLA format element "intb" +extern ElementId ELEM_END_EXP; ///< SLA format element "end_exp" +extern ElementId ELEM_NEXT2_EXP; ///< SLA format element "next2_exp" +extern ElementId ELEM_START_EXP; ///< SLA format element "start_exp" +extern ElementId ELEM_EPSILON_SYM; ///< SLA format element "epsilon_sym" +extern ElementId ELEM_EPSILON_SYM_HEAD; ///< SLA format element "epsilon_sym_head" +extern ElementId ELEM_NAME_SYM; ///< SLA format element "name_sym" +extern ElementId ELEM_NAME_SYM_HEAD; ///< SLA format element "name_sym_head" +extern ElementId ELEM_NAMETAB; ///< SLA format element "nametab" +extern ElementId ELEM_NEXT2_SYM; ///< SLA format element "next2_sym" +extern ElementId ELEM_NEXT2_SYM_HEAD; ///< SLA format element "next2_sym_head" +extern ElementId ELEM_START_SYM; ///< SLA format element "start_sym" +extern ElementId ELEM_START_SYM_HEAD; ///< SLA format element "start_sym_head" +extern ElementId ELEM_SUBTABLE_SYM; ///< SLA format element "subtable_sym" +extern ElementId ELEM_SUBTABLE_SYM_HEAD; ///< SLA format element "subtable_sym_head" +extern ElementId ELEM_VALUEMAP_SYM; ///< SLA format element "valuemap_sym" +extern ElementId ELEM_VALUEMAP_SYM_HEAD; ///< SLA format element "valuemap_sym_head" +extern ElementId ELEM_VALUETAB; ///< SLA format element "valuetab" +extern ElementId ELEM_VARLIST_SYM; ///< SLA format element "varlist_sym" +extern ElementId ELEM_VARLIST_SYM_HEAD; ///< SLA format element "varlist_sym_head" +extern ElementId ELEM_OR_PAT; ///< SLA format element "or_pat" +extern ElementId ELEM_COMMIT; ///< SLA format element "commit" +extern ElementId ELEM_CONST_START; ///< SLA format element "const_start" +extern ElementId ELEM_CONST_NEXT; ///< SLA format element "const_next" +extern ElementId ELEM_CONST_NEXT2; ///< SLA format element "const_next2" +extern ElementId ELEM_CONST_CURSPACE; ///< SLA format element "curspace" +extern ElementId ELEM_CONST_CURSPACE_SIZE; ///< SLA format element "curspace_size" +extern ElementId ELEM_CONST_FLOWREF; ///< SLA format element "const_flowref" +extern ElementId ELEM_CONST_FLOWREF_SIZE; ///< SLA format element "const_flowref_size" +extern ElementId ELEM_CONST_FLOWDEST; ///< SLA format element "const_flowdest" +extern ElementId ELEM_CONST_FLOWDEST_SIZE; ///< SLA format element "const_flowdest_size" + +extern bool isSlaFormat(istream &s); ///< Verify a .sla file header at the current point of the given stream +extern void writeSlaHeader(ostream &s); ///< Write a .sla file header to the given stream + +/// \brief The encoder for the .sla file format +/// +/// This provides the format header, does compression, and encodes the raw data elements/attributes. +class FormatEncode : public PackedEncode { + CompressBuffer compBuffer; ///< The compression stream filter + ostream compStream; ///< The front-end stream receiving uncompressed bytes +public: + FormatEncode(ostream &s,int4 level); ///< Initialize an encoder at a specific compression level + void flush(void); ///< Flush any buffered bytes in the encoder to the backing stream +}; + +/// \brief The decoder for the .sla file format +/// +/// This verifies the .sla file header, does decompression, and decodes the raw data elements/attributes. +class FormatDecode : public PackedDecode { + static const int4 IN_BUFFER_SIZE; ///< The size of the \e input buffer + uint1 *inBuffer; ///< The \e input buffer +public: + FormatDecode(const AddrSpaceManager *spcManager); ///< Initialize the decoder + virtual ~FormatDecode(void); ///< Destructor + virtual void ingestStream(istream &s); +}; + +} // End namespace sla +} // End namespace ghidra + +#endif diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh.cc index 965fbd41e62..471b99199a0 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh.cc @@ -559,7 +559,13 @@ void Sleigh::initialize(DocumentStorage &store) const Element *el = store.getTag("sleigh"); if (el == (const Element *)0) throw LowlevelError("Could not find sleigh tag"); - restoreXml(el); + sla::FormatDecode decoder(this); + ifstream s(el->getContent()); + if (!s) + throw LowlevelError("Could not open .sla file: " + el->getContent()); + decoder.ingestStream(s); + s.close(); + decode(decoder); } else reregisterContext(); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc index ab5fd936dde..b8690157c6d 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc @@ -356,8 +356,11 @@ void SleighArchitecture::buildSpecFile(DocumentStorage &store) specpaths.findFile(processorfile,language.getProcessorSpec()); specpaths.findFile(compilerfile,compilertag.getSpec()); - if (!language_reuse) + if (!language_reuse) { specpaths.findFile(slafile,language.getSlaFile()); + if (slafile.empty()) + throw SleighError("Could not find .sla file for " + archid); + } try { Document *doc = store.openDocument(processorfile); @@ -394,16 +397,11 @@ void SleighArchitecture::buildSpecFile(DocumentStorage &store) } if (!language_reuse) { + istringstream s("" + slafile + ""); try { - Document *doc = store.openDocument(slafile); + Document *doc = store.parseDocument(s); store.registerTag(doc->getRoot()); } - catch(DecoderError &err) { - ostringstream serr; - serr << "XML error parsing SLEIGH file: " << slafile; - serr << "\n " << err.explain; - throw SleighError(serr.str()); - } catch(LowlevelError &err) { ostringstream serr; serr << "Error reading SLEIGH file: " << slafile; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/sleighbase.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/sleighbase.cc index 080de2b0b3a..c2082884e24 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/sleighbase.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/sleighbase.cc @@ -17,8 +17,6 @@ namespace ghidra { -const int4 SleighBase::SLA_FORMAT_VERSION = 3; - const uint4 SleighBase::MAX_UNIQUE_SIZE = 128; int4 SourceFileIndexer::index(const string filename){ @@ -39,26 +37,32 @@ string SourceFileIndexer::getFilename(int4 index){ return indexToFile[index]; } -void SourceFileIndexer::restoreXml(const Element *el){ - const List &sourceFiles(el->getChildren()); - List::const_iterator iter = sourceFiles.begin(); - for (; iter != sourceFiles.end(); ++iter){ - string filename = (*iter)->getAttributeValue("name"); - int4 index = stoi((*iter)->getAttributeValue("index"),NULL,10); - fileToIndex[filename] = index; - indexToFile[index] = filename; - } +void SourceFileIndexer::decode(Decoder &decoder) + +{ + uint4 el = decoder.openElement(sla::ELEM_SOURCEFILES); + while(decoder.peekElement() == sla::ELEM_SOURCEFILE) { + int4 subel = decoder.openElement(); + string filename = decoder.readString(sla::ATTRIB_NAME); + int4 index = decoder.readSignedInteger(sla::ATTRIB_INDEX); + decoder.closeElement(subel); + fileToIndex[filename] = index; + indexToFile[index] = filename; + } + decoder.closeElement(el); } -void SourceFileIndexer::saveXml(ostream& s) const { - s << "\n"; - for (int4 i = 0; i < leastUnusedIndex; ++i){ - s << ("\n"; - } - s << "\n"; +void SourceFileIndexer::encode(Encoder &encoder) const + +{ + encoder.openElement(sla::ELEM_SOURCEFILES); + for (int4 i = 0; i < leastUnusedIndex; ++i){ + encoder.openElement(sla::ELEM_SOURCEFILE); + encoder.writeString(sla::ATTRIB_NAME, indexToFile.at(i)); + encoder.writeSignedInteger(sla::ATTRIB_INDEX, i); + encoder.closeElement(sla::ELEM_SOURCEFILE); + } + encoder.closeElement(sla::ELEM_SOURCEFILES); } SleighBase::SleighBase(void) @@ -175,27 +179,55 @@ void SleighBase::getUserOpNames(vector &res) const res = userop; // Return list of all language defined user ops (with index) } +/// Write a tag fully describing the details of the space. +/// \param encoder is the stream being written +/// \param spc is the given address space +void SleighBase::encodeSlaSpace(Encoder &encoder,AddrSpace *spc) const + +{ + if (spc->getType() == IPTR_INTERNAL) + encoder.openElement(sla::ELEM_SPACE_UNIQUE); + else if (spc->isOtherSpace()) + encoder.openElement(sla::ELEM_SPACE_OTHER); + else + encoder.openElement(sla::ELEM_SPACE); + encoder.writeString(sla::ATTRIB_NAME,spc->getName()); + encoder.writeSignedInteger(sla::ATTRIB_INDEX, spc->getIndex()); + encoder.writeBool(sla::ATTRIB_BIGENDIAN, isBigEndian()); + encoder.writeSignedInteger(sla::ATTRIB_DELAY, spc->getDelay()); +// if (spc->getDelay() != spc->getDeadcodeDelay()) +// encoder.writeSignedInteger(sla::ATTRIB_DEADCODEDELAY, spc->getDeadcodeDelay()); + encoder.writeSignedInteger(sla::ATTRIB_SIZE, spc->getAddrSize()); + if (spc->getWordSize() > 1) + encoder.writeSignedInteger(sla::ATTRIB_WORDSIZE, spc->getWordSize()); + encoder.writeBool(sla::ATTRIB_PHYSICAL, spc->hasPhysical()); + if (spc->getType() == IPTR_INTERNAL) + encoder.closeElement(sla::ELEM_SPACE_UNIQUE); + else if (spc->isOtherSpace()) + encoder.closeElement(sla::ELEM_SPACE_OTHER); + else + encoder.closeElement(sla::ELEM_SPACE); +} + /// This does the bulk of the work of creating a .sla file -/// \param s is the output stream -void SleighBase::saveXml(ostream &s) const +/// \param encoder is the stream encoder +void SleighBase::encode(Encoder &encoder) const { - s << " 0) - a_v_u(s,"maxdelay",maxdelayslotbytes); + encoder.writeUnsignedInteger(sla::ATTRIB_MAXDELAY, maxdelayslotbytes); if (unique_allocatemask != 0) - a_v_u(s,"uniqmask",unique_allocatemask); + encoder.writeUnsignedInteger(sla::ATTRIB_UNIQMASK, unique_allocatemask); if (numSections != 0) - a_v_u(s,"numsections",numSections); - s << ">\n"; - indexer.saveXml(s); - s << "getName()); - s << ">\n"; + encoder.writeUnsignedInteger(sla::ATTRIB_NUMSECTIONS, numSections); + indexer.encode(encoder); + encoder.openElement(sla::ELEM_SPACES); + encoder.writeString(sla::ATTRIB_DEFAULTSPACE, getDefaultCodeSpace()->getName()); for(int4 i=0;igetType()==IPTR_IOP)|| (spc->getType()==IPTR_JOIN)) continue; - spc->saveXml(s); + encodeSlaSpace(encoder,spc); + } + encoder.closeElement(sla::ELEM_SPACES); + symtab.encode(encoder); + encoder.closeElement(sla::ELEM_SLEIGH); +} + +/// This is identical to the functionality of decodeSpace, but the AddrSpace information is stored +/// in the .sla file format. +/// \param decoder is the stream decoder +/// \param trans is the translator object to be associated with the new space +/// \return a pointer to the initialized AddrSpace +AddrSpace *SleighBase::decodeSlaSpace(Decoder &decoder,const Translate *trans) + +{ + uint4 elemId = decoder.openElement(); + AddrSpace *res; + int4 index = 0; + int4 addressSize = 0; + int4 delay = -1; + int4 deadcodedelay = -1; + string name; + int4 wordsize = 1; + bool bigEnd = false; + uint4 flags = 0; + for (;;) { + uint4 attribId = decoder.getNextAttributeId(); + if (attribId == 0) break; + if (attribId == sla::ATTRIB_NAME) { + name = decoder.readString(); + } + if (attribId == sla::ATTRIB_INDEX) + index = decoder.readSignedInteger(); + else if (attribId == sla::ATTRIB_SIZE) + addressSize = decoder.readSignedInteger(); + else if (attribId == sla::ATTRIB_WORDSIZE) + wordsize = decoder.readUnsignedInteger(); + else if (attribId == sla::ATTRIB_BIGENDIAN) { + bigEnd = decoder.readBool(); + } + else if (attribId == sla::ATTRIB_DELAY) + delay = decoder.readSignedInteger(); + else if (attribId == sla::ATTRIB_PHYSICAL) { + if (decoder.readBool()) + flags |= AddrSpace::hasphysical; + } + } + decoder.closeElement(elemId); + if (deadcodedelay == -1) + deadcodedelay = delay; // If deadcodedelay attribute not present, set it to delay + if (index == 0) + throw LowlevelError("Expecting index attribute"); + if (elemId == sla::ELEM_SPACE_UNIQUE) + res = new UniqueSpace(this,trans,index,flags); + else if (elemId == sla::ELEM_SPACE_OTHER) + res = new OtherSpace(this,trans,index); + else { + if (addressSize == 0 || delay == -1 || name.size() == 0) + throw LowlevelError("Expecting size/delay/name attributes"); + res = new AddrSpace(this,trans,IPTR_PROCESSOR,name,bigEnd,addressSize,wordsize,index,flags,delay,deadcodedelay); + } + + return res; +} + +/// This is identical in functionality to decodeSpaces but the AddrSpace information +/// is stored in the .sla file format. +/// \param decoder is the stream decoder +/// \param trans is the processor translator to be associated with the spaces +void SleighBase::decodeSlaSpaces(Decoder &decoder,const Translate *trans) + +{ + // The first space should always be the constant space + insertSpace(new ConstantSpace(this,trans)); + + uint4 elemId = decoder.openElement(sla::ELEM_SPACES); + string defname = decoder.readString(sla::ATTRIB_DEFAULTSPACE); + while(decoder.peekElement() != 0) { + AddrSpace *spc = decodeSlaSpace(decoder,trans); + insertSpace(spc); } - s << "\n"; - symtab.saveXml(s); - s << "\n"; + decoder.closeElement(elemId); + AddrSpace *spc = getSpaceByName(defname); + if (spc == (AddrSpace *)0) + throw LowlevelError("Bad 'defaultspace' attribute: "+defname); + setDefaultCodeSpace(spc->getIndex()); } /// This parses the main \ tag (from a .sla file), which includes the description /// of address spaces and the symbol table, with its associated decoding tables -/// \param el is the root XML element -void SleighBase::restoreXml(const Element *el) +/// \param decoder is the stream to decode +void SleighBase::decode(Decoder &decoder) { maxdelayslotbytes = 0; unique_allocatemask = 0; numSections = 0; int4 version = 0; - setBigEndian(xml_readbool(el->getAttributeValue("bigendian"))); - { - istringstream s(el->getAttributeValue("align")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> alignment; - } - { - istringstream s(el->getAttributeValue("uniqbase")); - s.unsetf(ios::dec | ios::hex | ios::oct); - uintm ubase; - s >> ubase; - setUniqueBase(ubase); + uint4 el = decoder.openElement(sla::ELEM_SLEIGH); + uint4 attrib = decoder.getNextAttributeId(); + while(attrib != 0) { + if (attrib == sla::ATTRIB_BIGENDIAN) + setBigEndian(decoder.readBool()); + else if (attrib == sla::ATTRIB_ALIGN) + alignment = decoder.readSignedInteger(); + else if (attrib == sla::ATTRIB_UNIQBASE) + setUniqueBase(decoder.readUnsignedInteger()); + else if (attrib == sla::ATTRIB_MAXDELAY) + maxdelayslotbytes = decoder.readUnsignedInteger(); + else if (attrib == sla::ATTRIB_UNIQMASK) + unique_allocatemask = decoder.readUnsignedInteger(); + else if (attrib == sla::ATTRIB_NUMSECTIONS) + numSections = decoder.readUnsignedInteger(); + else if (attrib == sla::ATTRIB_VERSION) + version = decoder.readSignedInteger(); + attrib = decoder.getNextAttributeId(); } - int4 numattr = el->getNumAttributes(); - for(int4 i=0;igetAttributeName(i) ); - if (attrname == "maxdelay") { - istringstream s1(el->getAttributeValue(i)); - s1.unsetf(ios::dec | ios::hex | ios::oct); - s1 >> maxdelayslotbytes; - } - else if (attrname == "uniqmask") { - istringstream s2(el->getAttributeValue(i)); - s2.unsetf(ios::dec | ios::hex | ios::oct); - s2 >> unique_allocatemask; - } - else if (attrname == "numsections") { - istringstream s3(el->getAttributeValue(i)); - s3.unsetf(ios::dec | ios::hex | ios::oct); - s3 >> numSections; - } - else if (attrname == "version") { - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> version; - } - } - if (version != SLA_FORMAT_VERSION) + if (version != sla::FORMAT_VERSION) throw LowlevelError(".sla file has wrong format"); - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - while((*iter)->getName() == "floatformat") { - floatformats.emplace_back(); - floatformats.back().restoreXml(*iter); - ++iter; - } - indexer.restoreXml(*iter); - iter++; - XmlDecode decoder(this,*iter); - decodeSpaces(decoder,this); - iter++; - symtab.restoreXml(*iter,this); + indexer.decode(decoder); + decodeSlaSpaces(decoder,this); + symtab.decode(decoder,this); + decoder.closeElement(el); root = (SubtableSymbol *)symtab.getGlobalScope()->findSymbol("instruction"); vector errorPairs; buildXrefs(errorPairs); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/sleighbase.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/sleighbase.hh index 21c9f995aef..edc055f503e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/sleighbase.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/sleighbase.hh @@ -19,6 +19,7 @@ #define __SLEIGHBASE_HH__ #include "translate.hh" +#include "slaformat.hh" #include "slghsymbol.hh" namespace ghidra { @@ -41,8 +42,8 @@ public: int4 index(const string filename); int4 getIndex(const string); ///< get the index of a file. Error if the file is not in the index. string getFilename(int4); ///< get the filename corresponding to an index - void restoreXml(const Element *el); ///< read a stored index mapping from an XML file - void saveXml(ostream&) const; ///< save the index mapping to an XML file + void decode(Decoder &decoder); ///< decode a stored index mapping from a stream + void encode(Encoder &encoder) const; ///< Encode the index mapping to stream private: int4 leastUnusedIndex; ///< one-up count for assigning indices to files @@ -57,7 +58,6 @@ private: /// - Reading the various SLEIGH specification files /// - Building and writing out SLEIGH specification files class SleighBase : public Translate { - static const int4 SLA_FORMAT_VERSION; ///< Current version of the .sla file read/written by SleighBash vector userop; ///< Names of user-define p-code ops for \b this Translate object map varnode_xref; ///< A map from Varnodes in the \e register space to register names protected: @@ -69,7 +69,9 @@ protected: SourceFileIndexer indexer; ///< source file index used when generating SLEIGH constructor debug info void buildXrefs(vector &errorPairs); ///< Build register map. Collect user-ops and context-fields. void reregisterContext(void); ///< Reregister context fields for a new executable - void restoreXml(const Element *el); ///< Read a SLEIGH specification from XML + AddrSpace *decodeSlaSpace(Decoder &decoder,const Translate *trans); ///< Add a space parsed from a .sla file + void decodeSlaSpaces(Decoder &decoder,const Translate *trans); ///< Restore address spaces from a .sla file + void decode(Decoder &decoder); /// Decode a SELIGH specification from a stream public: static const uint4 MAX_UNIQUE_SIZE; ///< Maximum size of a varnode in the unique space (should match value in SleighBase.java) SleighBase(void); ///< Construct an uninitialized translator @@ -83,7 +85,8 @@ public: SleighSymbol *findSymbol(const string &nm) const { return symtab.findSymbol(nm); } ///< Find a specific SLEIGH symbol by name in the current scope SleighSymbol *findSymbol(uintm id) const { return symtab.findSymbol(id); } ///< Find a specific SLEIGH symbol by id SleighSymbol *findGlobalSymbol(const string &nm) const { return symtab.findGlobalSymbol(nm); } ///< Find a specific global SLEIGH symbol by name - void saveXml(ostream &s) const; ///< Write out the SLEIGH specification as an XML \ tag. + void encodeSlaSpace(Encoder &encoder,AddrSpace *spc) const; ///< Write the details of given space in .sla format + void encode(Encoder &encoder) const; ///< Write out the SLEIGH specification as a \ tag. }; } // End namespace ghidra diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc index b40f74389e5..c060053bfe1 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc @@ -1789,6 +1789,7 @@ SleighCompile::SleighCompile(void) warnalllocalcollisions = false; warnallnops = false; failinsensitivedups = true; + debugoutput = false; root = (SubtableSymbol *)0; curmacro = (MacroSymbol *)0; curct = (Constructor *)0; @@ -2301,7 +2302,7 @@ uint4 SleighCompile::getUniqueAddr(void) /// A number of checks are also performed, which may generate errors or warnings, including /// size restriction checks, pattern conflict checks, NOP constructor checks, and /// local collision checks. Once this method is run, \b this SleighCompile is ready for the -/// saveXml method. +/// encode method. void SleighCompile::process(void) { @@ -2546,7 +2547,8 @@ void SleighCompile::newSpace(SpaceQuality *qual) } int4 delay = (qual->type == SpaceQuality::registertype) ? 0 : 1; - AddrSpace *spc = new AddrSpace(this,this,IPTR_PROCESSOR,qual->name,qual->size,qual->wordsize,numSpaces(),AddrSpace::hasphysical,delay); + AddrSpace *spc = new AddrSpace(this,this,IPTR_PROCESSOR,qual->name,isBigEndian(), + qual->size,qual->wordsize,numSpaces(),AddrSpace::hasphysical,delay,delay); insertSpace(spc); if (qual->isdefault) { if (getDefaultCodeSpace() != (AddrSpace *)0) @@ -3594,13 +3596,23 @@ int4 SleighCompile::run_compilation(const string &filein,const string &fileout) if (parseres==0) process(); // Do all the post-processing if ((parseres==0)&&(numErrors()==0)) { // If no errors - ofstream s(fileout); + ofstream s(fileout,ios::binary); if (!s) { ostringstream errs; errs << "Unable to open output file: " << fileout; throw SleighError(errs.str()); } - saveXml(s); // Dump output xml + if (debugoutput) { + // If the debug output format was requested, use the XML encoder + XmlEncode encoder(s); + encode(encoder); + } + else { + // Use the standard .sla format encoder + sla::FormatEncode encoder(s,-1); + encode(encoder); + encoder.flush(); + } s.close(); } else { @@ -3697,7 +3709,7 @@ static void findSlaSpecs(vector &res, const string &dir, const string &s void SleighCompile::setAllOptions(const map &defines, bool unnecessaryPcodeWarning, bool lenientConflict, bool allCollisionWarning, bool allNopWarning,bool deadTempWarning,bool enforceLocalKeyWord, - bool largeTemporaryWarning, bool caseSensitiveRegisterNames) + bool largeTemporaryWarning, bool caseSensitiveRegisterNames,bool debugOutput) { map::const_iterator iter = defines.begin(); for (iter = defines.begin(); iter != defines.end(); iter++) { @@ -3711,6 +3723,7 @@ void SleighCompile::setAllOptions(const map &defines, bool unnece setEnforceLocalKeyWord(enforceLocalKeyWord); setLargeTemporaryWarning(largeTemporaryWarning); setInsensitiveDuplicateError(!caseSensitiveRegisterNames); + setDebugOutput(debugOutput); } static void segvHandler(int sig) { @@ -3736,6 +3749,7 @@ int main(int argc,char **argv) cerr << "USAGE: sleigh [-x] [-dNAME=VALUE] inputfile [outputfile]" << endl; cerr << " -a scan for all slaspec files recursively where inputfile is a directory" << endl; cerr << " -x turns on parser debugging" << endl; + cerr << " -y write .sla using XML debug format" << endl; cerr << " -u print warnings for unnecessary pcode instructions" << endl; cerr << " -l report pattern conflicts" << endl; cerr << " -n print warnings for all NOP constructors" << endl; @@ -3759,6 +3773,7 @@ int main(int argc,char **argv) bool enforceLocalKeyWord = false; bool largeTemporaryWarning = false; bool caseSensitiveRegisterNames = false; + bool debugOutput = false; bool compileAll = false; @@ -3794,6 +3809,8 @@ int main(int argc,char **argv) largeTemporaryWarning = true; else if (argv[i][1] == 's') caseSensitiveRegisterNames = true; + else if (argv[i][1] == 'y') + debugOutput = true; #ifdef YYDEBUG else if (argv[i][1] == 'x') sleighdebug = 1; // Debug option @@ -3825,7 +3842,8 @@ int main(int argc,char **argv) sla.replace(slaspec.length() - slaspecExtLen, slaspecExtLen, SLAEXT); SleighCompile compiler; compiler.setAllOptions(defines, unnecessaryPcodeWarning, lenientConflict, allCollisionWarning, allNopWarning, - deadTempWarning, enforceLocalKeyWord,largeTemporaryWarning, caseSensitiveRegisterNames); + deadTempWarning, enforceLocalKeyWord,largeTemporaryWarning, caseSensitiveRegisterNames, + debugOutput); retval = compiler.run_compilation(slaspec,sla); if (retval != 0) { return retval; // stop on first error @@ -3861,7 +3879,8 @@ int main(int argc,char **argv) SleighCompile compiler; compiler.setAllOptions(defines, unnecessaryPcodeWarning, lenientConflict, allCollisionWarning, allNopWarning, - deadTempWarning, enforceLocalKeyWord,largeTemporaryWarning,caseSensitiveRegisterNames); + deadTempWarning, enforceLocalKeyWord,largeTemporaryWarning,caseSensitiveRegisterNames, + debugOutput); if (i < argc - 1) { string fileoutExamine(argv[i+1]); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.hh index 83bc36154e5..88fe7df7890 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.hh @@ -300,6 +300,7 @@ private: bool warnalllocalcollisions; ///< \b true if local export collisions generate individual warnings bool warnallnops; ///< \b true if pcode NOPs generate individual warnings bool failinsensitivedups; ///< \b true if case insensitive register duplicates cause error + bool debugoutput; ///< \b true if output .sla is written in XML debug format vector noplist; ///< List of individual NOP warnings mutable Location currentLocCache; ///< Location for (last) request of current location int4 errors; ///< Number of fatal errors encountered @@ -382,6 +383,11 @@ public: /// \param val is \b true is duplicates cause an error. void setInsensitiveDuplicateError(bool val) { failinsensitivedups = val; } + /// \brief Set whether the output .sla file should be written in XML debug format + /// + /// \param val is \b true if the XML debug format should be used + void setDebugOutput(bool val) { debugoutput = val; } + // Lexer functions void calcContextLayout(void); ///< Calculate the internal context field layout string grabCurrentFilePath(void) const; ///< Get the path to the current source file @@ -448,7 +454,7 @@ public: void setAllOptions(const map &defines, bool unnecessaryPcodeWarning, bool lenientConflict, bool allCollisionWarning, bool allNopWarning,bool deadTempWarning,bool enforceLocalKeyWord, - bool largeTemporaryWarning, bool caseSensitiveRegisterNames); + bool largeTemporaryWarning, bool caseSensitiveRegisterNames,bool debugOutput); int4 run_compilation(const string &filein,const string &fileout); }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.cc index 5418473ab7e..94109785953 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.cc @@ -462,50 +462,50 @@ void PatternExpression::release(PatternExpression *p) delete p; } -PatternExpression *PatternExpression::restoreExpression(const Element *el,Translate *trans) +PatternExpression *PatternExpression::decodeExpression(Decoder &decoder,Translate *trans) { PatternExpression *res; - const string &nm(el->getName()); + uint4 el = decoder.peekElement(); - if (nm == "tokenfield") + if (el == sla::ELEM_TOKENFIELD) res = new TokenField(); - else if (nm == "contextfield") + else if (el == sla::ELEM_CONTEXTFIELD) res = new ContextField(); - else if (nm == "intb") + else if (el == sla::ELEM_INTB) res = new ConstantValue(); - else if (nm == "operand_exp") + else if (el == sla::ELEM_OPERAND_EXP) res = new OperandValue(); - else if (nm == "start_exp") + else if (el == sla::ELEM_START_EXP) res = new StartInstructionValue(); - else if (nm == "end_exp") + else if (el == sla::ELEM_END_EXP) res = new EndInstructionValue(); - else if (nm == "plus_exp") + else if (el == sla::ELEM_PLUS_EXP) res = new PlusExpression(); - else if (nm == "sub_exp") + else if (el == sla::ELEM_SUB_EXP) res = new SubExpression(); - else if (nm == "mult_exp") + else if (el == sla::ELEM_MULT_EXP) res = new MultExpression(); - else if (nm == "lshift_exp") + else if (el == sla::ELEM_LSHIFT_EXP) res = new LeftShiftExpression(); - else if (nm == "rshift_exp") + else if (el == sla::ELEM_RSHIFT_EXP) res = new RightShiftExpression(); - else if (nm == "and_exp") + else if (el == sla::ELEM_AND_EXP) res = new AndExpression(); - else if (nm == "or_exp") + else if (el == sla::ELEM_OR_EXP) res = new OrExpression(); - else if (nm == "xor_exp") + else if (el == sla::ELEM_XOR_EXP) res = new XorExpression(); - else if (nm == "div_exp") + else if (el == sla::ELEM_DIV_EXP) res = new DivExpression(); - else if (nm == "minus_exp") + else if (el == sla::ELEM_MINUS_EXP) res = new MinusExpression(); - else if (nm == "not_exp") + else if (el == sla::ELEM_NOT_EXP) res = new NotExpression(); else return (PatternExpression *)0; - res->restoreXml(el,trans); + res->decode(decoder,trans); return res; } @@ -597,58 +597,33 @@ TokenPattern TokenField::genPattern(intb val) const return TokenPattern(tok,val,bitstart,bitend); } -void TokenField::saveXml(ostream &s) const +void TokenField::encode(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_TOKENFIELD); + encoder.writeBool(sla::ATTRIB_BIGENDIAN, bigendian); + encoder.writeBool(sla::ATTRIB_SIGNBIT, signbit); + encoder.writeSignedInteger(sla::ATTRIB_STARTBIT, bitstart); + encoder.writeSignedInteger(sla::ATTRIB_ENDBIT, bitend); + encoder.writeSignedInteger(sla::ATTRIB_STARTBYTE, bytestart); + encoder.writeSignedInteger(sla::ATTRIB_ENDBYTE, byteend); + encoder.writeSignedInteger(sla::ATTRIB_SHIFT, shift); + encoder.closeElement(sla::ELEM_TOKENFIELD); } -void TokenField::restoreXml(const Element *el,Translate *trans) +void TokenField::decode(Decoder &decoder,Translate *trans) { + uint4 el = decoder.openElement(sla::ELEM_TOKENFIELD); tok = (Token *)0; - bigendian = xml_readbool(el->getAttributeValue("bigendian")); - signbit = xml_readbool(el->getAttributeValue("signbit")); - { - istringstream s(el->getAttributeValue("bitstart")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> bitstart; - } - { - istringstream s(el->getAttributeValue("bitend")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> bitend; - } - { - istringstream s(el->getAttributeValue("bytestart")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> bytestart; - } - { - istringstream s(el->getAttributeValue("byteend")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> byteend; - } - { - istringstream s(el->getAttributeValue("shift")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> shift; - } + bigendian = decoder.readBool(sla::ATTRIB_BIGENDIAN); + signbit = decoder.readBool(sla::ATTRIB_SIGNBIT); + bitstart = decoder.readSignedInteger(sla::ATTRIB_STARTBIT); + bitend = decoder.readSignedInteger(sla::ATTRIB_ENDBIT); + bytestart = decoder.readSignedInteger(sla::ATTRIB_STARTBYTE); + byteend = decoder.readSignedInteger(sla::ATTRIB_ENDBYTE); + shift = decoder.readSignedInteger(sla::ATTRIB_SHIFT); + decoder.closeElement(el); } ContextField::ContextField(bool s,int4 sbit,int4 ebit) @@ -680,65 +655,88 @@ TokenPattern ContextField::genPattern(intb val) const return TokenPattern(val,startbit,endbit); } -void ContextField::saveXml(ostream &s) const +void ContextField::encode(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_CONTEXTFIELD); + encoder.writeBool(sla::ATTRIB_SIGNBIT, signbit); + encoder.writeSignedInteger(sla::ATTRIB_STARTBIT, startbit); + encoder.writeSignedInteger(sla::ATTRIB_ENDBIT, endbit); + encoder.writeSignedInteger(sla::ATTRIB_STARTBYTE, startbyte); + encoder.writeSignedInteger(sla::ATTRIB_ENDBYTE, endbyte); + encoder.writeSignedInteger(sla::ATTRIB_SHIFT, shift); + encoder.closeElement(sla::ELEM_CONTEXTFIELD); } -void ContextField::restoreXml(const Element *el,Translate *trans) +void ContextField::decode(Decoder &decoder,Translate *trans) { - signbit = xml_readbool(el->getAttributeValue("signbit")); - { - istringstream s(el->getAttributeValue("startbit")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> startbit; - } - { - istringstream s(el->getAttributeValue("endbit")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> endbit; - } - { - istringstream s(el->getAttributeValue("startbyte")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> startbyte; - } - { - istringstream s(el->getAttributeValue("endbyte")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> endbyte; - } - { - istringstream s(el->getAttributeValue("shift")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> shift; - } + uint4 el = decoder.openElement(sla::ELEM_CONTEXTFIELD); + signbit = decoder.readBool(sla::ATTRIB_SIGNBIT); + startbit = decoder.readSignedInteger(sla::ATTRIB_STARTBIT); + endbit = decoder.readSignedInteger(sla::ATTRIB_ENDBIT); + startbyte = decoder.readSignedInteger(sla::ATTRIB_STARTBYTE); + endbyte = decoder.readSignedInteger(sla::ATTRIB_ENDBYTE); + shift = decoder.readSignedInteger(sla::ATTRIB_SHIFT); + decoder.closeElement(el); +} + +void ConstantValue::encode(Encoder &encoder) const + +{ + encoder.openElement(sla::ELEM_INTB); + encoder.writeSignedInteger(sla::ATTRIB_VAL, val); + encoder.closeElement(sla::ELEM_INTB); +} + +void ConstantValue::decode(Decoder &decoder,Translate *trans) + +{ + uint4 el = decoder.openElement(sla::ELEM_INTB); + val = decoder.readSignedInteger(sla::ATTRIB_VAL); + decoder.closeElement(el); +} + +void StartInstructionValue::encode(Encoder &encoder) const + +{ + encoder.openElement(sla::ELEM_START_EXP); + encoder.closeElement(sla::ELEM_START_EXP); } -void ConstantValue::saveXml(ostream &s) const +void StartInstructionValue::decode(Decoder &decoder,Translate *trans) { - s << "\n"; + uint4 el = decoder.openElement(sla::ELEM_START_EXP); + decoder.closeElement(el); } -void ConstantValue::restoreXml(const Element *el,Translate *trans) +void EndInstructionValue::encode(Encoder &encoder) const { - istringstream s(el->getAttributeValue("val")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> val; + encoder.openElement(sla::ELEM_END_EXP); + encoder.closeElement(sla::ELEM_END_EXP); +} + +void EndInstructionValue::decode(Decoder &decoder,Translate *trans) + +{ + uint4 el = decoder.openElement(sla::ELEM_END_EXP); + decoder.closeElement(el); +} + +void Next2InstructionValue::encode(Encoder &encoder) const + +{ + encoder.openElement(sla::ELEM_NEXT2_EXP); + encoder.closeElement(sla::ELEM_NEXT2_EXP); +} + +void Next2InstructionValue::decode(Decoder &decoder,Translate *trans) + +{ + uint4 el = decoder.openElement(sla::ELEM_NEXT2_EXP); + decoder.closeElement(el); } TokenPattern OperandValue::genPattern(intb val) const @@ -809,37 +807,27 @@ const string &OperandValue::getName(void) const return sym->getName(); } -void OperandValue::saveXml(ostream &s) const +void OperandValue::encode(Encoder &encoder) const { - s << "getParent()->getId() << "\""; - s << " ct=\"0x" << ct->getId() << "\"/>\n"; // Save id of our constructor + encoder.openElement(sla::ELEM_OPERAND_EXP); + encoder.writeSignedInteger(sla::ATTRIB_INDEX, index); + encoder.writeUnsignedInteger(sla::ATTRIB_TABLE, ct->getParent()->getId()); + encoder.writeUnsignedInteger(sla::ATTRIB_CT, ct->getId()); // Save id of our constructor + encoder.closeElement(sla::ELEM_OPERAND_EXP); } -void OperandValue::restoreXml(const Element *el,Translate *trans) +void OperandValue::decode(Decoder &decoder,Translate *trans) { - uintm ctid,tabid; - { - istringstream s(el->getAttributeValue("index")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> index; - } - { - istringstream s(el->getAttributeValue("table")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> tabid; - } - { - istringstream s(el->getAttributeValue("ct")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> ctid; - } + uint4 el = decoder.openElement(sla::ELEM_OPERAND_EXP); + index = decoder.readSignedInteger(sla::ATTRIB_INDEX); + uintm tabid = decoder.readUnsignedInteger(sla::ATTRIB_TABLE); + uintm ctid = decoder.readUnsignedInteger(sla::ATTRIB_CT); SleighBase *sleigh = (SleighBase *)trans; SubtableSymbol *tab = dynamic_cast(sleigh->findSymbol(tabid)); ct = tab->getConstructor(ctid); + decoder.closeElement(el); } BinaryExpression::BinaryExpression(PatternExpression *l,PatternExpression *r) @@ -858,24 +846,22 @@ BinaryExpression::~BinaryExpression(void) PatternExpression::release(right); } -void BinaryExpression::saveXml(ostream &s) const +void BinaryExpression::encode(Encoder &encoder) const { // Outer tag is generated by derived classes - left->saveXml(s); - right->saveXml(s); + left->encode(encoder); + right->encode(encoder); } -void BinaryExpression::restoreXml(const Element *el,Translate *trans) +void BinaryExpression::decode(Decoder &decoder,Translate *trans) { - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - left = PatternExpression::restoreExpression(*iter,trans); - ++iter; - right = PatternExpression::restoreExpression(*iter,trans); + uint4 el = decoder.openElement(); + left = PatternExpression::decodeExpression(decoder,trans); + right = PatternExpression::decodeExpression(decoder,trans); left->layClaim(); right->layClaim(); + decoder.closeElement(el); } UnaryExpression::UnaryExpression(PatternExpression *u) @@ -891,20 +877,19 @@ UnaryExpression::~UnaryExpression(void) PatternExpression::release(unary); } -void UnaryExpression::saveXml(ostream &s) const +void UnaryExpression::encode(Encoder &encoder) const { // Outer tag is generated by derived classes - unary->saveXml(s); + unary->encode(encoder); } -void UnaryExpression::restoreXml(const Element *el,Translate *trans) +void UnaryExpression::decode(Decoder &decoder,Translate *trans) { - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - unary = PatternExpression::restoreExpression(*iter,trans); + uint4 el = decoder.openElement(); + unary = PatternExpression::decodeExpression(decoder,trans); unary->layClaim(); + decoder.closeElement(el); } intb PlusExpression::getValue(ParserWalker &walker) const @@ -923,12 +908,12 @@ intb PlusExpression::getSubValue(const vector &replace,int4 &listpos) cons return leftval + rightval; } -void PlusExpression::saveXml(ostream &s) const +void PlusExpression::encode(Encoder &encoder) const { - s << "\n"; - BinaryExpression::saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_PLUS_EXP); + BinaryExpression::encode(encoder); + encoder.closeElement(sla::ELEM_PLUS_EXP); } intb SubExpression::getValue(ParserWalker &walker) const @@ -947,12 +932,12 @@ intb SubExpression::getSubValue(const vector &replace,int4 &listpos) const return leftval - rightval; } -void SubExpression::saveXml(ostream &s) const +void SubExpression::encode(Encoder &encoder) const { - s << "\n"; - BinaryExpression::saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_SUB_EXP); + BinaryExpression::encode(encoder); + encoder.closeElement(sla::ELEM_SUB_EXP); } intb MultExpression::getValue(ParserWalker &walker) const @@ -971,12 +956,12 @@ intb MultExpression::getSubValue(const vector &replace,int4 &listpos) cons return leftval * rightval; } -void MultExpression::saveXml(ostream &s) const +void MultExpression::encode(Encoder &encoder) const { - s << "\n"; - BinaryExpression::saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_MULT_EXP); + BinaryExpression::encode(encoder); + encoder.closeElement(sla::ELEM_MULT_EXP); } intb LeftShiftExpression::getValue(ParserWalker &walker) const @@ -995,12 +980,12 @@ intb LeftShiftExpression::getSubValue(const vector &replace,int4 &listpos) return leftval << rightval; } -void LeftShiftExpression::saveXml(ostream &s) const +void LeftShiftExpression::encode(Encoder &encoder) const { - s << "\n"; - BinaryExpression::saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_LSHIFT_EXP); + BinaryExpression::encode(encoder); + encoder.closeElement(sla::ELEM_LSHIFT_EXP); } intb RightShiftExpression::getValue(ParserWalker &walker) const @@ -1019,12 +1004,12 @@ intb RightShiftExpression::getSubValue(const vector &replace,int4 &listpos return leftval >> rightval; } -void RightShiftExpression::saveXml(ostream &s) const +void RightShiftExpression::encode(Encoder &encoder) const { - s << "\n"; - BinaryExpression::saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_RSHIFT_EXP); + BinaryExpression::encode(encoder); + encoder.closeElement(sla::ELEM_RSHIFT_EXP); } intb AndExpression::getValue(ParserWalker &walker) const @@ -1043,12 +1028,12 @@ intb AndExpression::getSubValue(const vector &replace,int4 &listpos) const return leftval & rightval; } -void AndExpression::saveXml(ostream &s) const +void AndExpression::encode(Encoder &encoder) const { - s << "\n"; - BinaryExpression::saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_AND_EXP); + BinaryExpression::encode(encoder); + encoder.closeElement(sla::ELEM_AND_EXP); } intb OrExpression::getValue(ParserWalker &walker) const @@ -1067,12 +1052,12 @@ intb OrExpression::getSubValue(const vector &replace,int4 &listpos) const return leftval | rightval; } -void OrExpression::saveXml(ostream &s) const +void OrExpression::encode(Encoder &encoder) const { - s << "\n"; - BinaryExpression::saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_OR_EXP); + BinaryExpression::encode(encoder); + encoder.closeElement(sla::ELEM_OR_EXP); } intb XorExpression::getValue(ParserWalker &walker) const @@ -1091,12 +1076,12 @@ intb XorExpression::getSubValue(const vector &replace,int4 &listpos) const return leftval ^ rightval; } -void XorExpression::saveXml(ostream &s) const +void XorExpression::encode(Encoder &encoder) const { - s << "\n"; - BinaryExpression::saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_XOR_EXP); + BinaryExpression::encode(encoder); + encoder.closeElement(sla::ELEM_XOR_EXP); } intb DivExpression::getValue(ParserWalker &walker) const @@ -1115,12 +1100,12 @@ intb DivExpression::getSubValue(const vector &replace,int4 &listpos) const return leftval / rightval; } -void DivExpression::saveXml(ostream &s) const +void DivExpression::encode(Encoder &encoder) const { - s << "\n"; - BinaryExpression::saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_DIV_EXP); + BinaryExpression::encode(encoder); + encoder.closeElement(sla::ELEM_DIV_EXP); } intb MinusExpression::getValue(ParserWalker &walker) const @@ -1137,12 +1122,12 @@ intb MinusExpression::getSubValue(const vector &replace,int4 &listpos) con return -val; } -void MinusExpression::saveXml(ostream &s) const +void MinusExpression::encode(Encoder &encoder) const { - s << "\n"; - UnaryExpression::saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_MINUS_EXP); + UnaryExpression::encode(encoder); + encoder.closeElement(sla::ELEM_MINUS_EXP); } intb NotExpression::getValue(ParserWalker &walker) const @@ -1159,12 +1144,12 @@ intb NotExpression::getSubValue(const vector &replace,int4 &listpos) const return ~val; } -void NotExpression::saveXml(ostream &s) const +void NotExpression::encode(Encoder &encoder) const { - s << "\n"; - UnaryExpression::saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_NOT_EXP); + UnaryExpression::encode(encoder); + encoder.closeElement(sla::ELEM_NOT_EXP); } static bool advance_combo(vector &val,const vector &min,vector &max) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.hh index 48af95afccf..118fe3cc943 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.hh @@ -67,14 +67,14 @@ public: virtual void listValues(vector &list) const=0; virtual void getMinMax(vector &minlist,vector &maxlist) const=0; virtual intb getSubValue(const vector &replace,int4 &listpos) const=0; - virtual void saveXml(ostream &s) const=0; - virtual void restoreXml(const Element *el,Translate *trans)=0; + virtual void encode(Encoder &encoder) const=0; + virtual void decode(Decoder &decoder,Translate *trans)=0; intb getSubValue(const vector &replace) { int4 listpos = 0; return getSubValue(replace,listpos); } void layClaim(void) { refcount += 1; } static void release(PatternExpression *p); - static PatternExpression *restoreExpression(const Element *el,Translate *trans); + static PatternExpression *decodeExpression(Decoder &decoder,Translate *trans); }; class PatternValue : public PatternExpression { @@ -96,15 +96,15 @@ class TokenField : public PatternValue { int4 bytestart,byteend; // Bytes to read to get value int4 shift; // Amount to shift to align value (bitstart % 8) public: - TokenField(void) {} // For use with restoreXml + TokenField(void) {} // For use with decode TokenField(Token *tk,bool s,int4 bstart,int4 bend); virtual intb getValue(ParserWalker &walker) const; virtual TokenPattern genMinPattern(const vector &ops) const { return TokenPattern(tok); } virtual TokenPattern genPattern(intb val) const; virtual intb minValue(void) const { return 0; } virtual intb maxValue(void) const { intb res=0; return zero_extend(~res,bitend-bitstart); } - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el,Translate *trans); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,Translate *trans); }; class ContextField : public PatternValue { @@ -113,7 +113,7 @@ class ContextField : public PatternValue { int4 shift; bool signbit; public: - ContextField(void) {} // For use with restoreXml + ContextField(void) {} // For use with decode ContextField(bool s,int4 sbit,int4 ebit); int4 getStartBit(void) const { return startbit; } int4 getEndBit(void) const { return endbit; } @@ -123,22 +123,22 @@ public: virtual TokenPattern genPattern(intb val) const; virtual intb minValue(void) const { return 0; } virtual intb maxValue(void) const { intb res=0; return zero_extend(~res,(endbit-startbit)); } - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el,Translate *trans); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,Translate *trans); }; class ConstantValue : public PatternValue { intb val; public: - ConstantValue(void) {} // For use with restoreXml + ConstantValue(void) {} // For use with decode ConstantValue(intb v) { val = v; } virtual intb getValue(ParserWalker &walker) const { return val; } virtual TokenPattern genMinPattern(const vector &ops) const { return TokenPattern(); } virtual TokenPattern genPattern(intb v) const { return TokenPattern(val==v); } virtual intb minValue(void) const { return val; } virtual intb maxValue(void) const { return val; } - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el,Translate *trans); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,Translate *trans); }; class StartInstructionValue : public PatternValue { @@ -150,8 +150,8 @@ public: virtual TokenPattern genPattern(intb val) const { return TokenPattern(); } virtual intb minValue(void) const { return (intb)0; } virtual intb maxValue(void) const { return (intb)0; } - virtual void saveXml(ostream &s) const { s << ""; } - virtual void restoreXml(const Element *el,Translate *trans) {} + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,Translate *trans); }; class EndInstructionValue : public PatternValue { @@ -163,8 +163,8 @@ public: virtual TokenPattern genPattern(intb val) const { return TokenPattern(); } virtual intb minValue(void) const { return (intb)0; } virtual intb maxValue(void) const { return (intb)0; } - virtual void saveXml(ostream &s) const { s << ""; } - virtual void restoreXml(const Element *el,Translate *trans) {} + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,Translate *trans); }; class Next2InstructionValue : public PatternValue { @@ -176,8 +176,8 @@ public: virtual TokenPattern genPattern(intb val) const { return TokenPattern(); } virtual intb minValue(void) const { return (intb)0; } virtual intb maxValue(void) const { return (intb)0; } - virtual void saveXml(ostream &s) const { s << ""; } - virtual void restoreXml(const Element *el,Translate *trans) {} + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,Translate *trans); }; class Constructor; // Forward declaration @@ -186,7 +186,7 @@ class OperandValue : public PatternValue { int4 index; // This is the defining field of expression Constructor *ct; // cached pointer to constructor public: - OperandValue(void) { } // For use with restoreXml + OperandValue(void) { } // For use with decode OperandValue(int4 ind,Constructor *c) { index = ind; ct = c; } void changeIndex(int4 newind) { index = newind; } bool isConstructorRelative(void) const; @@ -197,8 +197,8 @@ public: virtual intb getSubValue(const vector &replace,int4 &listpos) const; virtual intb minValue(void) const; virtual intb maxValue(void) const; - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el,Translate *trans); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,Translate *trans); }; class BinaryExpression : public PatternExpression { @@ -206,7 +206,7 @@ class BinaryExpression : public PatternExpression { protected: virtual ~BinaryExpression(void); public: - BinaryExpression(void) { left = (PatternExpression *)0; right = (PatternExpression *)0; } // For use with restoreXml + BinaryExpression(void) { left = (PatternExpression *)0; right = (PatternExpression *)0; } // For use with decode BinaryExpression(PatternExpression *l,PatternExpression *r); PatternExpression *getLeft(void) const { return left; } PatternExpression *getRight(void) const { return right; } @@ -215,8 +215,8 @@ public: left->listValues(list); right->listValues(list); } virtual void getMinMax(vector &minlist,vector &maxlist) const { left->getMinMax(minlist,maxlist); right->getMinMax(minlist,maxlist); } - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el,Translate *trans); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,Translate *trans); }; class UnaryExpression : public PatternExpression { @@ -224,7 +224,7 @@ class UnaryExpression : public PatternExpression { protected: virtual ~UnaryExpression(void); public: - UnaryExpression(void) { unary = (PatternExpression *)0; } // For use with restoreXml + UnaryExpression(void) { unary = (PatternExpression *)0; } // For use with decode UnaryExpression(PatternExpression *u); PatternExpression *getUnary(void) const { return unary; } virtual TokenPattern genMinPattern(const vector &ops) const { return TokenPattern(); } @@ -233,35 +233,35 @@ public: virtual void getMinMax(vector &minlist,vector &maxlist) const { unary->getMinMax(minlist,maxlist); } - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el,Translate *trans); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,Translate *trans); }; class PlusExpression : public BinaryExpression { public: - PlusExpression(void) {} // For use by restoreXml + PlusExpression(void) {} // For use by decode PlusExpression(PatternExpression *l,PatternExpression *r) : BinaryExpression(l,r) {} virtual intb getValue(ParserWalker &walker) const; virtual intb getSubValue(const vector &replace,int4 &listpos) const; - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; }; class SubExpression : public BinaryExpression { public: - SubExpression(void) {} // For use with restoreXml + SubExpression(void) {} // For use with decode SubExpression(PatternExpression *l,PatternExpression *r) : BinaryExpression(l,r) {} virtual intb getValue(ParserWalker &walker) const; virtual intb getSubValue(const vector &replace,int4 &listpos) const; - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; }; class MultExpression : public BinaryExpression { public: - MultExpression(void) {} // For use with restoreXml + MultExpression(void) {} // For use with decode MultExpression(PatternExpression *l,PatternExpression *r) : BinaryExpression(l,r) {} virtual intb getValue(ParserWalker &walker) const; virtual intb getSubValue(const vector &replace,int4 &listpos) const; - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; }; class LeftShiftExpression : public BinaryExpression { @@ -270,7 +270,7 @@ public: LeftShiftExpression(PatternExpression *l,PatternExpression *r) : BinaryExpression(l,r) {} virtual intb getValue(ParserWalker &walker) const; virtual intb getSubValue(const vector &replace,int4 &listpos) const; - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; }; class RightShiftExpression : public BinaryExpression { @@ -279,7 +279,7 @@ public: RightShiftExpression(PatternExpression *l,PatternExpression *r) : BinaryExpression(l,r) {} virtual intb getValue(ParserWalker &walker) const; virtual intb getSubValue(const vector &replace,int4 &listpos) const; - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; }; class AndExpression : public BinaryExpression { @@ -288,7 +288,7 @@ public: AndExpression(PatternExpression *l,PatternExpression *r) : BinaryExpression(l,r) {} virtual intb getValue(ParserWalker &walker) const; virtual intb getSubValue(const vector &replace,int4 &listpos) const; - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; }; class OrExpression : public BinaryExpression { @@ -297,7 +297,7 @@ public: OrExpression(PatternExpression *l,PatternExpression *r) : BinaryExpression(l,r) {} virtual intb getValue(ParserWalker &walker) const; virtual intb getSubValue(const vector &replace,int4 &listpos) const; - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; }; class XorExpression : public BinaryExpression { @@ -306,7 +306,7 @@ public: XorExpression(PatternExpression *l,PatternExpression *r) : BinaryExpression(l,r) {} virtual intb getValue(ParserWalker &walker) const; virtual intb getSubValue(const vector &replace,int4 &listpos) const; - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; }; class DivExpression : public BinaryExpression { @@ -315,7 +315,7 @@ public: DivExpression(PatternExpression *l,PatternExpression *r) : BinaryExpression(l,r) {} virtual intb getValue(ParserWalker &walker) const; virtual intb getSubValue(const vector &replace,int4 &listpos) const; - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; }; class MinusExpression : public UnaryExpression { @@ -324,7 +324,7 @@ public: MinusExpression(PatternExpression *u) : UnaryExpression(u) {} virtual intb getValue(ParserWalker &walker) const; virtual intb getSubValue(const vector &replace,int4 &listpos) const; - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; }; class NotExpression : public UnaryExpression { @@ -333,7 +333,7 @@ public: NotExpression(PatternExpression *u) : UnaryExpression(u) {} virtual intb getValue(ParserWalker &walker) const; virtual intb getSubValue(const vector &replace,int4 &listpos) const; - virtual void saveXml(ostream &s) const; + virtual void encode(Encoder &encoder) const; }; struct OperandResolve { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slghpattern.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/slghpattern.cc index 755af9682cf..fc993930b49 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slghpattern.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slghpattern.cc @@ -14,6 +14,7 @@ * limitations under the License. */ #include "slghpattern.hh" +#include "slaformat.hh" namespace ghidra { @@ -137,17 +138,18 @@ bool DisjointPattern::resolvesIntersect(const DisjointPattern *op1,const Disjoin return resolveIntersectBlock(op1->getBlock(true),op2->getBlock(true),getBlock(true)); } -DisjointPattern *DisjointPattern::restoreDisjoint(const Element *el) +DisjointPattern *DisjointPattern::decodeDisjoint(Decoder &decoder) { // DisjointPattern factory DisjointPattern *res; - if (el->getName() == "instruct_pat") + uint4 el = decoder.peekElement(); + if (el == sla::ELEM_INSTRUCT_PAT) res = new InstructionPattern(); - else if (el->getName() == "context_pat") + else if (el == sla::ELEM_CONTEXT_PAT) res = new ContextPattern(); else res = new CombinePattern(); - res->restoreXml(el); + res->decode(decoder); return res; } @@ -485,54 +487,37 @@ bool PatternBlock::isContextMatch(ParserWalker &walker) const return true; } -void PatternBlock::saveXml(ostream &s) const +void PatternBlock::encode(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_PAT_BLOCK); + encoder.writeSignedInteger(sla::ATTRIB_OFF, offset); + encoder.writeSignedInteger(sla::ATTRIB_NONZERO, nonzerosize); for(int4 i=0;i\n"; + encoder.openElement(sla::ELEM_MASK_WORD); + encoder.writeUnsignedInteger(sla::ATTRIB_MASK, maskvec[i]); + encoder.writeUnsignedInteger(sla::ATTRIB_VAL, valvec[i]); + encoder.closeElement(sla::ELEM_MASK_WORD); } - s << "\n"; + encoder.closeElement(sla::ELEM_PAT_BLOCK); } -void PatternBlock::restoreXml(const Element *el) +void PatternBlock::decode(Decoder &decoder) { - { - istringstream s(el->getAttributeValue("offset")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> offset; - } - { - istringstream s(el->getAttributeValue("nonzero")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> nonzerosize; - } - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - uintm mask,val; - while(iter != list.end()) { - Element *subel = *iter; - { - istringstream s(subel->getAttributeValue("mask")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> mask; - } - { - istringstream s(subel->getAttributeValue("val")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> val; - } + uint4 el = decoder.openElement(sla::ELEM_PAT_BLOCK); + offset = decoder.readSignedInteger(sla::ATTRIB_OFF); + nonzerosize = decoder.readSignedInteger(sla::ATTRIB_NONZERO); + while(decoder.peekElement() != 0) { + uint4 subel = decoder.openElement(sla::ELEM_MASK_WORD); + uintm mask = decoder.readUnsignedInteger(sla::ATTRIB_MASK); + uintm val = decoder.readUnsignedInteger(sla::ATTRIB_VAL); maskvec.push_back(mask); valvec.push_back(val); - ++iter; + decoder.closeElement(subel); } normalize(); + decoder.closeElement(el); } Pattern *InstructionPattern::doAnd(const Pattern *b,int4 sa) const @@ -623,22 +608,21 @@ Pattern *InstructionPattern::doOr(const Pattern *b,int4 sa) const return new OrPattern(res1,res2); } -void InstructionPattern::saveXml(ostream &s) const +void InstructionPattern::encode(Encoder &encoder) const { - s << "\n"; - maskvalue->saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_INSTRUCT_PAT); + maskvalue->encode(encoder); + encoder.closeElement(sla::ELEM_INSTRUCT_PAT); } -void InstructionPattern::restoreXml(const Element *el) +void InstructionPattern::decode(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); + uint4 el = decoder.openElement(sla::ELEM_INSTRUCT_PAT); maskvalue = new PatternBlock(true); - maskvalue->restoreXml(*iter); + maskvalue->decode(decoder); + decoder.closeElement(el); } Pattern *ContextPattern::doOr(const Pattern *b,int4 sa) const @@ -673,22 +657,21 @@ Pattern *ContextPattern::commonSubPattern(const Pattern *b,int4 sa) const return new ContextPattern(resblock); } -void ContextPattern::saveXml(ostream &s) const +void ContextPattern::encode(Encoder &encoder) const { - s << "\n"; - maskvalue->saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_CONTEXT_PAT); + maskvalue->encode(encoder); + encoder.closeElement(sla::ELEM_CONTEXT_PAT); } -void ContextPattern::restoreXml(const Element *el) +void ContextPattern::decode(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); + uint4 el = decoder.openElement(sla::ELEM_CONTEXT_PAT); maskvalue = new PatternBlock(true); - maskvalue->restoreXml(*iter); + maskvalue->decode(decoder); + decoder.closeElement(el); } CombinePattern::~CombinePattern(void) @@ -804,26 +787,24 @@ Pattern *CombinePattern::simplifyClone(void) const (InstructionPattern *)instr->simplifyClone()); } -void CombinePattern::saveXml(ostream &s) const +void CombinePattern::encode(Encoder &encoder) const { - s << "\n"; - context->saveXml(s); - instr->saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_COMBINE_PAT); + context->encode(encoder); + instr->encode(encoder); + encoder.closeElement(sla::ELEM_COMBINE_PAT); } -void CombinePattern::restoreXml(const Element *el) +void CombinePattern::decode(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); + uint4 el = decoder.openElement(sla::ELEM_COMBINE_PAT); context = new ContextPattern(); - context->restoreXml(*iter); - ++iter; + context->decode(decoder); instr = new InstructionPattern(); - instr->restoreXml(*iter); + instr->decode(decoder); + decoder.closeElement(el); } OrPattern::OrPattern(DisjointPattern *a,DisjointPattern *b) @@ -995,26 +976,24 @@ Pattern *OrPattern::simplifyClone(void) const return new OrPattern(newlist); } -void OrPattern::saveXml(ostream &s) const +void OrPattern::encode(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_OR_PAT); for(int4 i=0;isaveXml(s); - s << "\n"; + orlist[i]->encode(encoder); + encoder.closeElement(sla::ELEM_OR_PAT); } -void OrPattern::restoreXml(const Element *el) +void OrPattern::decode(Decoder &decoder) { - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - while(iter != list.end()) { - DisjointPattern *pat = DisjointPattern::restoreDisjoint(*iter); + uint4 el = decoder.openElement(sla::ELEM_OR_PAT); + while(decoder.peekElement() != 0) { + DisjointPattern *pat = DisjointPattern::decodeDisjoint(decoder); orlist.push_back(pat); - ++iter; } + decoder.closeElement(el); } } // End namespace ghidra diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slghpattern.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/slghpattern.hh index 8d2f8d43761..de90a885dd6 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slghpattern.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slghpattern.hh @@ -45,8 +45,8 @@ public: bool alwaysFalse(void) const { return (nonzerosize==-1); } bool isInstructionMatch(ParserWalker &walker) const; bool isContextMatch(ParserWalker &walker) const; - void saveXml(ostream &s) const; - void restoreXml(const Element *el); + void encode(Encoder &encoder) const; + void decode(Decoder &decoder); }; class DisjointPattern; @@ -64,8 +64,8 @@ public: virtual bool alwaysTrue(void) const=0; virtual bool alwaysFalse(void) const=0; virtual bool alwaysInstructionTrue(void) const=0; - virtual void saveXml(ostream &s) const=0; - virtual void restoreXml(const Element *el)=0; + virtual void encode(Encoder &encoder) const=0; + virtual void decode(Decoder &decoder)=0; }; class DisjointPattern : public Pattern { // A pattern with no ORs in it @@ -79,14 +79,14 @@ public: bool specializes(const DisjointPattern *op2) const; bool identical(const DisjointPattern *op2) const; bool resolvesIntersect(const DisjointPattern *op1,const DisjointPattern *op2) const; - static DisjointPattern *restoreDisjoint(const Element *el); + static DisjointPattern *decodeDisjoint(Decoder &decoder); }; class InstructionPattern : public DisjointPattern { // Matches the instruction bitstream PatternBlock *maskvalue; virtual PatternBlock *getBlock(bool context) const { return context ? (PatternBlock *)0 : maskvalue; } public: - InstructionPattern(void) { maskvalue = (PatternBlock *)0; } // For use with restoreXml + InstructionPattern(void) { maskvalue = (PatternBlock *)0; } // For use with decode InstructionPattern(PatternBlock *mv) { maskvalue = mv; } InstructionPattern(bool tf) { maskvalue = new PatternBlock(tf); } PatternBlock *getBlock(void) { return maskvalue; } @@ -100,15 +100,15 @@ public: virtual bool alwaysTrue(void) const { return maskvalue->alwaysTrue(); } virtual bool alwaysFalse(void) const { return maskvalue->alwaysFalse(); } virtual bool alwaysInstructionTrue(void) const { return maskvalue->alwaysTrue(); } - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder); }; class ContextPattern : public DisjointPattern { // Matches the context bitstream PatternBlock *maskvalue; virtual PatternBlock *getBlock(bool context) const { return context ? maskvalue : (PatternBlock *)0; } public: - ContextPattern(void) { maskvalue = (PatternBlock *)0; } // For use with restoreXml + ContextPattern(void) { maskvalue = (PatternBlock *)0; } // For use with decode ContextPattern(PatternBlock *mv) { maskvalue = mv; } PatternBlock *getBlock(void) { return maskvalue; } virtual ~ContextPattern(void) { if (maskvalue != (PatternBlock *)0) delete maskvalue; } @@ -121,8 +121,8 @@ public: virtual bool alwaysTrue(void) const { return maskvalue->alwaysTrue(); } virtual bool alwaysFalse(void) const { return maskvalue->alwaysFalse(); } virtual bool alwaysInstructionTrue(void) const { return true; } - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder); }; // A pattern with a context piece and an instruction piece @@ -144,14 +144,14 @@ public: virtual Pattern *doOr(const Pattern *b,int4 sa) const; virtual Pattern *doAnd(const Pattern *b,int4 sa) const; virtual Pattern *commonSubPattern(const Pattern *b,int4 sa) const; - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder); }; class OrPattern : public Pattern { vector orlist; public: - OrPattern(void) {} // For use with restoreXml + OrPattern(void) {} // For use with decode OrPattern(DisjointPattern *a,DisjointPattern *b); OrPattern(const vector &list); virtual ~OrPattern(void); @@ -166,8 +166,8 @@ public: virtual Pattern *doOr(const Pattern *b,int4 sa) const; virtual Pattern *doAnd(const Pattern *b,int4 sa) const; virtual Pattern *commonSubPattern(const Pattern *b,int4 sa) const; - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder); }; } // End namespace ghidra diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slghsymbol.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/slghsymbol.cc index b8735099af4..b35dd6ec797 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slghsymbol.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slghsymbol.cc @@ -140,133 +140,99 @@ void SymbolTable::replaceSymbol(SleighSymbol *a,SleighSymbol *b) } } -void SymbolTable::saveXml(ostream &s) const +void SymbolTable::encode(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_SYMBOL_TABLE); + encoder.writeSignedInteger(sla::ATTRIB_SCOPESIZE, table.size()); + encoder.writeSignedInteger(sla::ATTRIB_SYMBOLSIZE, symbollist.size()); for(int4 i=0;igetId() << "\""; - s << " parent=\"0x"; + encoder.openElement(sla::ELEM_SCOPE); + encoder.writeUnsignedInteger(sla::ATTRIB_ID, table[i]->getId()); if (table[i]->getParent() == (SymbolScope *)0) - s << "0"; + encoder.writeUnsignedInteger(sla::ATTRIB_PARENT, 0); else - s << hex << table[i]->getParent()->getId(); - s << "\"/>\n"; + encoder.writeUnsignedInteger(sla::ATTRIB_PARENT, table[i]->getParent()->getId()); + encoder.closeElement(sla::ELEM_SCOPE); } // First save the headers for(int4 i=0;isaveXmlHeader(s); + symbollist[i]->encodeHeader(encoder); // Now save the content of each symbol for(int4 i=0;isaveXml(s); - s << "\n"; -} - -void SymbolTable::restoreXml(const Element *el,SleighBase *trans) - -{ - { - uint4 size; - istringstream s(el->getAttributeValue("scopesize")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> size; - table.resize(size,(SymbolScope *)0); - } - { - uint4 size; - istringstream s(el->getAttributeValue("symbolsize")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> size; - symbollist.resize(size,(SleighSymbol *)0); - } - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - for(int4 i=0;igetName() != "scope") - throw SleighError("Misnumbered symbol scopes"); - uintm id; - uintm parent; - { - istringstream s(subel->getAttributeValue("id")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> id; - } - { - istringstream s(subel->getAttributeValue("parent")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> parent; - } + symbollist[i]->encode(encoder); + encoder.closeElement(sla::ELEM_SYMBOL_TABLE); +} + +void SymbolTable::decode(Decoder &decoder,SleighBase *trans) + +{ + int4 el = decoder.openElement(sla::ELEM_SYMBOL_TABLE); + table.resize(decoder.readSignedInteger(sla::ATTRIB_SCOPESIZE), (SymbolScope *)0); + symbollist.resize(decoder.readSignedInteger(sla::ATTRIB_SYMBOLSIZE), (SleighSymbol *)0); + for(int4 i=0;igetAttributeValue("id")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> id; - } sym = findSymbol(id); - sym->restoreXml(subel,trans); - ++iter; + sym->decode(decoder,trans); + // Tag closed by decode method + // decoder.closeElement(subel); } + decoder.closeElement(el); } -void SymbolTable::restoreSymbolHeader(const Element *el) +void SymbolTable::decodeSymbolHeader(Decoder &decoder) { // Put the shell of a symbol in the symbol table // in order to allow recursion SleighSymbol *sym; - if (el->getName() == "userop_head") + uint4 el = decoder.peekElement(); + if (el == sla::ELEM_USEROP_HEAD) sym = new UserOpSymbol(); - else if (el->getName() == "epsilon_sym_head") + else if (el == sla::ELEM_EPSILON_SYM_HEAD) sym = new EpsilonSymbol(); - else if (el->getName() == "value_sym_head") + else if (el == sla::ELEM_VALUE_SYM_HEAD) sym = new ValueSymbol(); - else if (el->getName() == "valuemap_sym_head") + else if (el == sla::ELEM_VALUEMAP_SYM_HEAD) sym = new ValueMapSymbol(); - else if (el->getName() == "name_sym_head") + else if (el == sla::ELEM_NAME_SYM_HEAD) sym = new NameSymbol(); - else if (el->getName() == "varnode_sym_head") + else if (el == sla::ELEM_VARNODE_SYM_HEAD) sym = new VarnodeSymbol(); - else if (el->getName() == "context_sym_head") + else if (el == sla::ELEM_CONTEXT_SYM_HEAD) sym = new ContextSymbol(); - else if (el->getName() == "varlist_sym_head") + else if (el == sla::ELEM_VARLIST_SYM_HEAD) sym = new VarnodeListSymbol(); - else if (el->getName() == "operand_sym_head") + else if (el == sla::ELEM_OPERAND_SYM_HEAD) sym = new OperandSymbol(); - else if (el->getName() == "start_sym_head") + else if (el == sla::ELEM_START_SYM_HEAD) sym = new StartSymbol(); - else if (el->getName() == "end_sym_head") + else if (el == sla::ELEM_END_SYM_HEAD) sym = new EndSymbol(); - else if (el->getName() == "next2_sym_head") + else if (el == sla::ELEM_NEXT2_SYM_HEAD) sym = new Next2Symbol(); - else if (el->getName() == "subtable_sym_head") + else if (el == sla::ELEM_SUBTABLE_SYM_HEAD) sym = new SubtableSymbol(); - else if (el->getName() == "flowdest_sym_head") - sym = new FlowDestSymbol(); - else if (el->getName() == "flowref_sym_head") - sym = new FlowRefSymbol(); else throw SleighError("Bad symbol xml"); - sym->restoreXmlHeader(el); // Restore basic elements of symbol + sym->decodeHeader(decoder); // Restore basic elements of symbol symbollist[sym->id] = sym; // Put the basic symbol in the table table[sym->scopeid]->addSymbol(sym); // to allow recursion } @@ -361,60 +327,63 @@ void SymbolTable::renumber(void) symbollist = newsymbol; } -void SleighSymbol::saveXmlHeader(ostream &s) const +void SleighSymbol::encodeHeader(Encoder &encoder) const { // Save the basic attributes of a symbol - s << " name=\"" << name << "\""; - s << " id=\"0x" << hex << id << "\""; - s << " scope=\"0x" << scopeid << "\""; + encoder.writeString(sla::ATTRIB_NAME, name); + encoder.writeUnsignedInteger(sla::ATTRIB_ID, id); + encoder.writeUnsignedInteger(sla::ATTRIB_SCOPE, scopeid); } -void SleighSymbol::restoreXmlHeader(const Element *el) +void SleighSymbol::decodeHeader(Decoder &decoder) { - name = el->getAttributeValue("name"); - { - istringstream s(el->getAttributeValue("id")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> id; - } - { - istringstream s(el->getAttributeValue("scope")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> scopeid; - } + uint4 el = decoder.openElement(); + name = decoder.readString(sla::ATTRIB_NAME); + id = decoder.readUnsignedInteger(sla::ATTRIB_ID); + scopeid = decoder.readUnsignedInteger(sla::ATTRIB_SCOPE); + decoder.closeElement(el); +} + +void SleighSymbol::encode(Encoder &encoder) const + +{ + throw LowlevelError("Symbol "+name+" cannot be encoded to stream directly"); } -void UserOpSymbol::saveXml(ostream &s) const +void SleighSymbol::decode(Decoder &decoder,SleighBase *trans) { - s << "\n"; + throw LowlevelError("Symbol "+name+" cannot be decoded from stream directly"); } -void UserOpSymbol::saveXmlHeader(ostream &s) const +void UserOpSymbol::encode(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_USEROP); + encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); + encoder.writeSignedInteger(sla::ATTRIB_INDEX, index); + encoder.closeElement(sla::ELEM_USEROP); } -void UserOpSymbol::restoreXml(const Element *el,SleighBase *trans) +void UserOpSymbol::encodeHeader(Encoder &encoder) const { - istringstream s(el->getAttributeValue("index")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> index; + encoder.openElement(sla::ELEM_USEROP_HEAD); + SleighSymbol::encodeHeader(encoder); + encoder.closeElement(sla::ELEM_USEROP_HEAD); +} + +void UserOpSymbol::decode(Decoder &decoder,SleighBase *trans) + +{ + index = decoder.readSignedInteger(sla::ATTRIB_INDEX); + decoder.closeElement(sla::ELEM_USEROP.getId()); } PatternlessSymbol::PatternlessSymbol(void) -{ // The void constructor must explicitly build - // the ConstantValue because it is not stored - // or restored via xml +{ // The void constructor must explicitly build the ConstantValue. It is not decode (or encoded) patexp = new ConstantValue((intb)0); patexp->layClaim(); } @@ -456,26 +425,27 @@ VarnodeTpl *EpsilonSymbol::getVarnode(void) const return res; } -void EpsilonSymbol::saveXml(ostream &s) const +void EpsilonSymbol::encode(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_EPSILON_SYM); + encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); + encoder.closeElement(sla::ELEM_EPSILON_SYM); } -void EpsilonSymbol::saveXmlHeader(ostream &s) const +void EpsilonSymbol::encodeHeader(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_EPSILON_SYM_HEAD); + SleighSymbol::encodeHeader(encoder); + encoder.closeElement(sla::ELEM_EPSILON_SYM_HEAD); } -void EpsilonSymbol::restoreXml(const Element *el,SleighBase *trans) +void EpsilonSymbol::decode(Decoder &decoder,SleighBase *trans) { const_space = trans->getConstantSpace(); + decoder.closeElement(sla::ELEM_EPSILON_SYM.getId()); } ValueSymbol::ValueSymbol(const string &nm,PatternValue *pv) @@ -510,32 +480,29 @@ void ValueSymbol::print(ostream &s,ParserWalker &walker) const s << "-0x" << hex << -val; } -void ValueSymbol::saveXml(ostream &s) const +void ValueSymbol::encode(Encoder &encoder) const { - s << "\n"; - patval->saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_VALUE_SYM); + encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); + patval->encode(encoder); + encoder.closeElement(sla::ELEM_VALUE_SYM); } -void ValueSymbol::saveXmlHeader(ostream &s) const +void ValueSymbol::encodeHeader(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_VALUE_SYM_HEAD); + SleighSymbol::encodeHeader(encoder); + encoder.closeElement(sla::ELEM_VALUE_SYM_HEAD); } -void ValueSymbol::restoreXml(const Element *el,SleighBase *trans) +void ValueSymbol::decode(Decoder &decoder,SleighBase *trans) { - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - patval = (PatternValue *) PatternExpression::restoreExpression(*iter,trans); + patval = (PatternValue *) PatternExpression::decodeExpression(decoder,trans); patval->layClaim(); + decoder.closeElement(sla::ELEM_VALUE_SYM.getId()); } void ValueMapSymbol::checkTableFill(void) @@ -589,43 +556,40 @@ void ValueMapSymbol::print(ostream &s,ParserWalker &walker) const s << "-0x" << hex << -val; } -void ValueMapSymbol::saveXml(ostream &s) const +void ValueMapSymbol::encode(Encoder &encoder) const { - s << "\n"; - patval->saveXml(s); - for(uint4 i=0;i\n"; - s << "\n"; + encoder.openElement(sla::ELEM_VALUEMAP_SYM); + encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); + patval->encode(encoder); + for(uint4 i=0;i\n"; + encoder.openElement(sla::ELEM_VALUEMAP_SYM_HEAD); + SleighSymbol::encodeHeader(encoder); + encoder.closeElement(sla::ELEM_VALUEMAP_SYM_HEAD); } -void ValueMapSymbol::restoreXml(const Element *el,SleighBase *trans) +void ValueMapSymbol::decode(Decoder &decoder,SleighBase *trans) { - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - patval = (PatternValue *) PatternExpression::restoreExpression(*iter,trans); + patval = (PatternValue *) PatternExpression::decodeExpression(decoder,trans); patval->layClaim(); - ++iter; - while(iter != list.end()) { - istringstream s((*iter)->getAttributeValue("val")); - s.unsetf(ios::dec | ios::hex | ios::oct); - intb val; - s >> val; + while(decoder.peekElement() != 0) { + uint4 subel = decoder.openElement(); + intb val = decoder.readSignedInteger(sla::ATTRIB_VAL); valuetable.push_back(val); - ++iter; + decoder.closeElement(subel); } + decoder.closeElement(sla::ELEM_VALUEMAP_SYM.getId()); checkTableFill(); } @@ -667,47 +631,46 @@ void NameSymbol::print(ostream &s,ParserWalker &walker) const s << nametable[ind]; } -void NameSymbol::saveXml(ostream &s) const +void NameSymbol::encode(Encoder &encoder) const { - s << "\n"; - patval->saveXml(s); + encoder.openElement(sla::ELEM_NAME_SYM); + encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); + patval->encode(encoder); for(int4 i=0;i\n"; // Emit tag with no name attribute + encoder.openElement(sla::ELEM_NAMETAB); + if (nametable[i] == "\t") { // TAB indicates an illegal index + // Emit tag with no name attribute + } else - s << "\n"; + encoder.writeString(sla::ATTRIB_NAME, nametable[i]); + encoder.closeElement(sla::ELEM_NAMETAB); } - s << "\n"; + encoder.closeElement(sla::ELEM_NAME_SYM); } -void NameSymbol::saveXmlHeader(ostream &s) const +void NameSymbol::encodeHeader(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_NAME_SYM_HEAD); + SleighSymbol::encodeHeader(encoder); + encoder.closeElement(sla::ELEM_NAME_SYM_HEAD); } -void NameSymbol::restoreXml(const Element *el,SleighBase *trans) +void NameSymbol::decode(Decoder &decoder,SleighBase *trans) { - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - patval = (PatternValue *) PatternExpression::restoreExpression(*iter,trans); + patval = (PatternValue *) PatternExpression::decodeExpression(decoder,trans); patval->layClaim(); - ++iter; - while(iter != list.end()) { - const Element *subel = *iter; - if (subel->getNumAttributes() >= 1) - nametable.push_back(subel->getAttributeValue("name")); + while(decoder.peekElement() != 0) { + uint4 subel = decoder.openElement(); + if (decoder.getNextAttributeId() == sla::ATTRIB_NAME) + nametable.push_back(decoder.readString()); else nametable.push_back("\t"); // TAB indicates an illegal index - ++iter; + decoder.closeElement(subel); } + decoder.closeElement(sla::ELEM_NAME_SYM.getId()); checkTableFill(); } @@ -742,42 +705,33 @@ void VarnodeSymbol::collectLocalValues(vector &results) const results.push_back(fix.offset); } -void VarnodeSymbol::saveXml(ostream &s) const +void VarnodeSymbol::encode(Encoder &encoder) const { - s << "getName() << "\""; - s << " offset=\"0x" << hex << fix.offset << "\""; - s << " size=\"" << dec << fix.size << "\""; - s << ">\n"; - PatternlessSymbol::saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_VARNODE_SYM); + encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); + encoder.writeSpace(sla::ATTRIB_SPACE,fix.space); + encoder.writeUnsignedInteger(sla::ATTRIB_OFF, fix.offset); + encoder.writeSignedInteger(sla::ATTRIB_SIZE, fix.size); + encoder.closeElement(sla::ELEM_VARNODE_SYM); } -void VarnodeSymbol::saveXmlHeader(ostream &s) const +void VarnodeSymbol::encodeHeader(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_VARNODE_SYM_HEAD); + SleighSymbol::encodeHeader(encoder); + encoder.closeElement(sla::ELEM_VARNODE_SYM_HEAD); } -void VarnodeSymbol::restoreXml(const Element *el,SleighBase *trans) +void VarnodeSymbol::decode(Decoder &decoder,SleighBase *trans) { - fix.space = trans->getSpaceByName(el->getAttributeValue("space")); - { - istringstream s(el->getAttributeValue("offset")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> fix.offset; - } - { - istringstream s(el->getAttributeValue("size")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> fix.size; - } + fix.space = decoder.readSpace(sla::ATTRIB_SPACE); + fix.offset = decoder.readUnsignedInteger(sla::ATTRIB_OFF); + fix.size = decoder.readSignedInteger(sla::ATTRIB_SIZE); // PatternlessSymbol does not need restoring + decoder.closeElement(sla::ELEM_VARNODE_SYM.getId()); } ContextSymbol::ContextSymbol(const string &nm,ContextField *pate,VarnodeSymbol *v, @@ -790,56 +744,59 @@ ContextSymbol::ContextSymbol(const string &nm,ContextField *pate,VarnodeSymbol * flow = fl; } -void ContextSymbol::saveXml(ostream &s) const +void ContextSymbol::encode(Encoder &encoder) const { - s << "getId() << "\""; - s << " low=\"" << dec << low << "\""; - s << " high=\"" << high << "\""; - a_v_b(s,"flow",flow); - s << ">\n"; - patval->saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_CONTEXT_SYM); + encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); + encoder.writeUnsignedInteger(sla::ATTRIB_VARNODE, vn->getId()); + encoder.writeSignedInteger(sla::ATTRIB_LOW, low); + encoder.writeSignedInteger(sla::ATTRIB_HIGH, high); + encoder.writeBool(sla::ATTRIB_FLOW, flow); + patval->encode(encoder); + encoder.closeElement(sla::ELEM_CONTEXT_SYM); } -void ContextSymbol::saveXmlHeader(ostream &s) const +void ContextSymbol::encodeHeader(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_CONTEXT_SYM_HEAD); + SleighSymbol::encodeHeader(encoder); + encoder.closeElement(sla::ELEM_CONTEXT_SYM_HEAD); } -void ContextSymbol::restoreXml(const Element *el,SleighBase *trans) +void ContextSymbol::decode(Decoder &decoder,SleighBase *trans) { - ValueSymbol::restoreXml(el,trans); - { - uintm id; - istringstream s(el->getAttributeValue("varnode")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> id; - vn = (VarnodeSymbol *)trans->findSymbol(id); - } - { - istringstream s(el->getAttributeValue("low")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> low; - } - { - istringstream s(el->getAttributeValue("high")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> high; - } - flow = true; - for(int4 i=el->getNumAttributes()-1;i>=0;--i) { - if (el->getAttributeName(i)=="flow") { - flow = xml_readbool(el->getAttributeValue(i)); - break; + // SleighSymbol::decodeHeader(decoder); // Already filled in by the header tag + flow = false; + bool highMissing = true; + bool lowMissing = true; + uint4 attrib = decoder.getNextAttributeId(); + while(attrib != 0) { + if (attrib == sla::ATTRIB_VARNODE) { + uintm id = decoder.readUnsignedInteger(); + vn = (VarnodeSymbol *)trans->findSymbol(id); + } + else if (attrib == sla::ATTRIB_LOW) { + low = decoder.readSignedInteger(); + lowMissing = false; + } + else if (attrib == sla::ATTRIB_HIGH) { + high = decoder.readSignedInteger(); + highMissing = false; } + else if (attrib == sla::ATTRIB_FLOW) { + flow = decoder.readBool(); + } + attrib = decoder.getNextAttributeId(); + } + if (lowMissing || highMissing) { + throw DecoderError("Missing high/low attributes"); } + patval = (PatternValue *) PatternExpression::decodeExpression(decoder,trans); + patval->layClaim(); + decoder.closeElement(sla::ELEM_CONTEXT_SYM.getId()); } VarnodeListSymbol::VarnodeListSymbol(const string &nm,PatternValue *pv,const vector &vt) @@ -910,52 +867,50 @@ void VarnodeListSymbol::print(ostream &s,ParserWalker &walker) const s << varnode_table[ind]->getName(); } -void VarnodeListSymbol::saveXml(ostream &s) const +void VarnodeListSymbol::encode(Encoder &encoder) const { - s << "\n"; - patval->saveXml(s); + encoder.openElement(sla::ELEM_VARLIST_SYM); + encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); + patval->encode(encoder); for(int4 i=0;i\n"; - else - s << "getId() << "\"/>\n"; + if (varnode_table[i] == (VarnodeSymbol *)0) { + encoder.openElement(sla::ELEM_NULL); + encoder.closeElement(sla::ELEM_NULL); + } + else { + encoder.openElement(sla::ELEM_VAR); + encoder.writeUnsignedInteger(sla::ATTRIB_ID, varnode_table[i]->getId()); + encoder.closeElement(sla::ELEM_VAR); + } } - s << "\n"; + encoder.closeElement(sla::ELEM_VARLIST_SYM); } -void VarnodeListSymbol::saveXmlHeader(ostream &s) const +void VarnodeListSymbol::encodeHeader(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_VARLIST_SYM_HEAD); + SleighSymbol::encodeHeader(encoder); + encoder.closeElement(sla::ELEM_VARLIST_SYM_HEAD); } -void VarnodeListSymbol::restoreXml(const Element *el,SleighBase *trans) +void VarnodeListSymbol::decode(Decoder &decoder,SleighBase *trans) { - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - patval = (PatternValue *) PatternExpression::restoreExpression(*iter,trans); + patval = (PatternValue *) PatternExpression::decodeExpression(decoder,trans); patval->layClaim(); - ++iter; - while(iter!=list.end()) { - const Element *subel = *iter; - if (subel->getName() == "var") { - uintm id; - istringstream s(subel->getAttributeValue("id")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> id; + while(decoder.peekElement() != 0) { + uint4 subel = decoder.openElement(); + if (subel == sla::ELEM_VAR) { + uintm id = decoder.readUnsignedInteger(sla::ATTRIB_ID); varnode_table.push_back( (VarnodeSymbol *)trans->findSymbol(id) ); } else varnode_table.push_back( (VarnodeSymbol *)0 ); - ++iter; + decoder.closeElement(subel); } + decoder.closeElement(sla::ELEM_VARLIST_SYM.getId()); checkTableFill(); } @@ -1055,82 +1010,66 @@ void OperandSymbol::collectLocalValues(vector &results) const triple->collectLocalValues(results); } -void OperandSymbol::saveXml(ostream &s) const +void OperandSymbol::encode(Encoder &encoder) const { - s << "getId() << "\""; - s << " off=\"" << dec << reloffset << "\""; - s << " base=\"" << offsetbase << "\""; - s << " minlen=\"" << minimumlength << "\""; + encoder.writeUnsignedInteger(sla::ATTRIB_SUBSYM, triple->getId()); + encoder.writeSignedInteger(sla::ATTRIB_OFF, reloffset); + encoder.writeSignedInteger(sla::ATTRIB_BASE, offsetbase); + encoder.writeSignedInteger(sla::ATTRIB_MINLEN, minimumlength); if (isCodeAddress()) - s << " code=\"true\""; - s << " index=\"" << dec << hand << "\">\n"; - localexp->saveXml(s); + encoder.writeBool(sla::ATTRIB_CODE, true); + encoder.writeSignedInteger(sla::ATTRIB_INDEX, hand); + localexp->encode(encoder); if (defexp != (PatternExpression *)0) - defexp->saveXml(s); - s << "\n"; + defexp->encode(encoder); + encoder.closeElement(sla::ELEM_OPERAND_SYM); } -void OperandSymbol::saveXmlHeader(ostream &s) const +void OperandSymbol::encodeHeader(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_OPERAND_SYM_HEAD); + SleighSymbol::encodeHeader(encoder); + encoder.closeElement(sla::ELEM_OPERAND_SYM_HEAD); } -void OperandSymbol::restoreXml(const Element *el,SleighBase *trans) +void OperandSymbol::decode(Decoder &decoder,SleighBase *trans) { defexp = (PatternExpression *)0; triple = (TripleSymbol *)0; flags = 0; - { - istringstream s(el->getAttributeValue("index")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> hand; - } - { - istringstream s(el->getAttributeValue("off")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> reloffset; - } - { - istringstream s(el->getAttributeValue("base")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> offsetbase; - } - { - istringstream s(el->getAttributeValue("minlen")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> minimumlength; - } - for(int4 i=0;igetNumAttributes();++i) { - if (el->getAttributeName(i) == "subsym") { - uintm id; - istringstream s(el->getAttributeValue(i)); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> id; + uint4 attrib = decoder.getNextAttributeId(); + while(attrib != 0) { + attrib = decoder.getNextAttributeId(); + if (attrib == sla::ATTRIB_INDEX) + hand = decoder.readSignedInteger(); + else if (attrib == sla::ATTRIB_OFF) + reloffset = decoder.readSignedInteger(); + else if (attrib == sla::ATTRIB_BASE) + offsetbase = decoder.readSignedInteger(); + else if (attrib == sla::ATTRIB_MINLEN) + minimumlength = decoder.readSignedInteger(); + else if (attrib == sla::ATTRIB_SUBSYM) { + uintm id = decoder.readUnsignedInteger(); triple = (TripleSymbol *)trans->findSymbol(id); } - else if (el->getAttributeName(i) == "code") { - if (xml_readbool(el->getAttributeValue(i))) + else if (attrib == sla::ATTRIB_CODE) { + if (decoder.readBool()) flags |= code_address; } } - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - localexp = (OperandValue *)PatternExpression::restoreExpression(*iter,trans); + localexp = (OperandValue *)PatternExpression::decodeExpression(decoder,trans); localexp->layClaim(); - ++iter; - if (iter != list.end()) { - defexp = PatternExpression::restoreExpression(*iter,trans); + if (decoder.peekElement() != 0) { + defexp = PatternExpression::decodeExpression(decoder,trans); defexp->layClaim(); } + decoder.closeElement(sla::ELEM_OPERAND_SYM.getId()); } StartSymbol::StartSymbol(const string &nm,AddrSpace *cspc) : SpecificSymbol(nm) @@ -1173,28 +1112,29 @@ void StartSymbol::print(ostream &s,ParserWalker &walker) const s << "0x" << hex << val; } -void StartSymbol::saveXml(ostream &s) const +void StartSymbol::encode(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_START_SYM); + encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); + encoder.closeElement(sla::ELEM_START_SYM); } -void StartSymbol::saveXmlHeader(ostream &s) const +void StartSymbol::encodeHeader(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_START_SYM_HEAD); + SleighSymbol::encodeHeader(encoder); + encoder.closeElement(sla::ELEM_START_SYM_HEAD); } -void StartSymbol::restoreXml(const Element *el,SleighBase *trans) +void StartSymbol::decode(Decoder &decoder,SleighBase *trans) { const_space = trans->getConstantSpace(); patexp = new StartInstructionValue(); patexp->layClaim(); + decoder.closeElement(sla::ELEM_START_SYM.getId()); } EndSymbol::EndSymbol(const string &nm,AddrSpace *cspc) : SpecificSymbol(nm) @@ -1237,28 +1177,29 @@ void EndSymbol::print(ostream &s,ParserWalker &walker) const s << "0x" << hex << val; } -void EndSymbol::saveXml(ostream &s) const +void EndSymbol::encode(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_END_SYM); + encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); + encoder.closeElement(sla::ELEM_END_SYM); } -void EndSymbol::saveXmlHeader(ostream &s) const +void EndSymbol::encodeHeader(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_END_SYM_HEAD); + SleighSymbol::encodeHeader(encoder); + encoder.closeElement(sla::ELEM_END_SYM_HEAD); } -void EndSymbol::restoreXml(const Element *el,SleighBase *trans) +void EndSymbol::decode(Decoder &decoder,SleighBase *trans) { const_space = trans->getConstantSpace(); patexp = new EndInstructionValue(); patexp->layClaim(); + decoder.closeElement(sla::ELEM_END_SYM.getId()); } Next2Symbol::Next2Symbol(const string &nm,AddrSpace *cspc) : SpecificSymbol(nm) @@ -1301,28 +1242,29 @@ void Next2Symbol::print(ostream &s,ParserWalker &walker) const s << "0x" << hex << val; } -void Next2Symbol::saveXml(ostream &s) const +void Next2Symbol::encode(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_NEXT2_SYM); + encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); + encoder.closeElement(sla::ELEM_NEXT2_SYM); } -void Next2Symbol::saveXmlHeader(ostream &s) const +void Next2Symbol::encodeHeader(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_NEXT2_SYM_HEAD); + SleighSymbol::encodeHeader(encoder); + encoder.closeElement(sla::ELEM_NEXT2_SYM_HEAD); } -void Next2Symbol::restoreXml(const Element *el,SleighBase *trans) +void Next2Symbol::decode(Decoder &decoder,SleighBase *trans) { const_space = trans->getConstantSpace(); patexp = new Next2InstructionValue(); patexp->layClaim(); + decoder.closeElement(sla::ELEM_NEXT2_SYM.getId()); } FlowDestSymbol::FlowDestSymbol(const string &nm,AddrSpace *cspc) : SpecificSymbol(nm) @@ -1357,28 +1299,6 @@ void FlowDestSymbol::print(ostream &s,ParserWalker &walker) const s << "0x" << hex << val; } -void FlowDestSymbol::saveXml(ostream &s) const - -{ - s << "\n"; -} - -void FlowDestSymbol::saveXmlHeader(ostream &s) const - -{ - s << "\n"; -} - -void FlowDestSymbol::restoreXml(const Element *el,SleighBase *trans) - -{ - const_space = trans->getConstantSpace(); -} - FlowRefSymbol::FlowRefSymbol(const string &nm,AddrSpace *cspc) : SpecificSymbol(nm) { @@ -1411,28 +1331,6 @@ void FlowRefSymbol::print(ostream &s,ParserWalker &walker) const s << "0x" << hex << val; } -void FlowRefSymbol::saveXml(ostream &s) const - -{ - s << "\n"; -} - -void FlowRefSymbol::saveXmlHeader(ostream &s) const - -{ - s << "\n"; -} - -void FlowRefSymbol::restoreXml(const Element *el,SleighBase *trans) - -{ - const_space = trans->getConstantSpace(); -} - Constructor::Constructor(void) { @@ -1660,103 +1558,90 @@ bool Constructor::isRecursive(void) const return false; } -void Constructor::saveXml(ostream &s) const +void Constructor::encode(Encoder &encoder) const { - s << "getId() << "\""; - s << " first=\"" << dec << firstwhitespace << "\""; - s << " length=\"" << minimumlength << "\""; - s << " line=\"" << src_index << ":" << lineno << "\">\n"; - for(int4 i=0;igetId() << "\"/>\n"; + encoder.openElement(sla::ELEM_CONSTRUCTOR); + encoder.writeUnsignedInteger(sla::ATTRIB_PARENT, parent->getId()); + encoder.writeSignedInteger(sla::ATTRIB_FIRST, firstwhitespace); + encoder.writeSignedInteger(sla::ATTRIB_LENGTH, minimumlength); + encoder.writeSignedInteger(sla::ATTRIB_SOURCE, src_index); + encoder.writeSignedInteger(sla::ATTRIB_LINE, lineno); + for(int4 i=0;igetId()); + encoder.closeElement(sla::ELEM_OPER); + } for(int4 i=0;i\n"; + encoder.openElement(sla::ELEM_OPPRINT); + encoder.writeSignedInteger(sla::ATTRIB_ID, index); + encoder.closeElement(sla::ELEM_OPPRINT); } else { - s << "\n"; + encoder.openElement(sla::ELEM_PRINT); + encoder.writeString(sla::ATTRIB_PIECE,printpiece[i]); + encoder.closeElement(sla::ELEM_PRINT); } } for(int4 i=0;isaveXml(s); + context[i]->encode(encoder); if (templ != (ConstructTpl *)0) - templ->saveXml(s,-1); + templ->encode(encoder,-1); for(int4 i=0;isaveXml(s,i); - } - s << "\n"; -} - -void Constructor::restoreXml(const Element *el,SleighBase *trans) - -{ - uintm id; - { - istringstream s(el->getAttributeValue("parent")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> id; - parent = (SubtableSymbol *)trans->findSymbol(id); - } - { - istringstream s(el->getAttributeValue("first")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> firstwhitespace; - } - { - istringstream s(el->getAttributeValue("length")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> minimumlength; - } - { - string src_and_line = el->getAttributeValue("line"); - size_t pos = src_and_line.find(":"); - src_index = stoi(src_and_line.substr(0, pos),NULL,10); - lineno = stoi(src_and_line.substr(pos+1,src_and_line.length()),NULL,10); - } - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - while(iter != list.end()) { - if ((*iter)->getName() == "oper") { - uintm id; - { - istringstream s((*iter)->getAttributeValue("id")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> id; - } + namedtempl[i]->encode(encoder,i); + } + encoder.closeElement(sla::ELEM_CONSTRUCTOR); +} + +void Constructor::decode(Decoder &decoder,SleighBase *trans) + +{ + uint4 el = decoder.openElement(sla::ELEM_CONSTRUCTOR); + uintm id = decoder.readUnsignedInteger(sla::ATTRIB_PARENT); + parent = (SubtableSymbol *)trans->findSymbol(id); + firstwhitespace = decoder.readSignedInteger(sla::ATTRIB_FIRST); + minimumlength = decoder.readSignedInteger(sla::ATTRIB_LENGTH); + src_index = decoder.readSignedInteger(sla::ATTRIB_SOURCE); + lineno = decoder.readSignedInteger(sla::ATTRIB_LINE); + uint4 subel = decoder.peekElement(); + while(subel != 0) { + if (subel == sla::ELEM_OPER) { + decoder.openElement(); + uintm id = decoder.readUnsignedInteger(sla::ATTRIB_ID); OperandSymbol *sym = (OperandSymbol *)trans->findSymbol(id); operands.push_back(sym); + decoder.closeElement(subel); + } + else if (subel == sla::ELEM_PRINT) { + decoder.openElement(); + printpiece.push_back( decoder.readString(sla::ATTRIB_PIECE)); + decoder.closeElement(subel); } - else if ((*iter)->getName() == "print") - printpiece.push_back( (*iter)->getAttributeValue("piece")); - else if ((*iter)->getName() == "opprint") { - int4 index; - istringstream s((*iter)->getAttributeValue("id")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> index; + else if (subel == sla::ELEM_OPPRINT) { + decoder.openElement(); + int4 index = decoder.readSignedInteger(sla::ATTRIB_ID); string operstring = "\n "; operstring[1] = ('A' + index); printpiece.push_back(operstring); + decoder.closeElement(subel); } - else if ((*iter)->getName() == "context_op") { + else if (subel == sla::ELEM_CONTEXT_OP) { ContextOp *c_op = new ContextOp(); - c_op->restoreXml(*iter,trans); + c_op->decode(decoder,trans); context.push_back(c_op); } - else if ((*iter)->getName() == "commit") { + else if (subel == sla::ELEM_COMMIT) { ContextCommit *c_op = new ContextCommit(); - c_op->restoreXml(*iter,trans); + c_op->decode(decoder,trans); context.push_back(c_op); } else { ConstructTpl *cur = new ConstructTpl(); - int4 sectionid = cur->restoreXml(*iter,trans); + int4 sectionid = cur->decode(decoder); if (sectionid < 0) { if (templ != (ConstructTpl *)0) throw LowlevelError("Duplicate main section"); @@ -1770,13 +1655,14 @@ void Constructor::restoreXml(const Element *el,SleighBase *trans) namedtempl[sectionid] = cur; } } - ++iter; + subel = decoder.peekElement(); } pattern = (TokenPattern *)0; if ((printpiece.size()==1)&&(printpiece[0][0]=='\n')) flowthruindex = printpiece[0][1] - 'A'; else flowthruindex = -1; + decoder.closeElement(el); } void Constructor::orderOperands(void) @@ -1978,55 +1864,49 @@ void SubtableSymbol::collectLocalValues(vector &results) const construct[i]->collectLocalExports(results); } -void SubtableSymbol::saveXml(ostream &s) const +void SubtableSymbol::encode(Encoder &encoder) const { if (decisiontree == (DecisionNode *)0) return; // Not fully formed - s << "\n"; + encoder.openElement(sla::ELEM_SUBTABLE_SYM); + encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); + encoder.writeSignedInteger(sla::ATTRIB_NUMCT, construct.size()); for(int4 i=0;isaveXml(s); - decisiontree->saveXml(s); - s << "\n"; + construct[i]->encode(encoder); + decisiontree->encode(encoder); + encoder.closeElement(sla::ELEM_SUBTABLE_SYM); } -void SubtableSymbol::saveXmlHeader(ostream &s) const +void SubtableSymbol::encodeHeader(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_SUBTABLE_SYM_HEAD); + SleighSymbol::encodeHeader(encoder); + encoder.closeElement(sla::ELEM_SUBTABLE_SYM_HEAD); } -void SubtableSymbol::restoreXml(const Element *el,SleighBase *trans) +void SubtableSymbol::decode(Decoder &decoder,SleighBase *trans) { - { - int4 numct; - istringstream s(el->getAttributeValue("numct")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> numct; - construct.reserve(numct); - } - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - while(iter != list.end()) { - if ((*iter)->getName() == "constructor") { + int4 numct = decoder.readSignedInteger(sla::ATTRIB_NUMCT); + construct.reserve(numct); + uint4 subel = decoder.peekElement(); + while(subel != 0) { + if (subel == sla::ELEM_CONSTRUCTOR) { Constructor *ct = new Constructor(); addConstructor(ct); - ct->restoreXml(*iter,trans); + ct->decode(decoder,trans); } - else if ((*iter)->getName() == "decision") { + else if (subel == sla::ELEM_DECISION) { decisiontree = new DecisionNode(); - decisiontree->restoreXml(*iter,(DecisionNode *)0,this); + decisiontree->decode(decoder,(DecisionNode *)0,this); } - ++iter; + subel = decoder.peekElement(); } pattern = (TokenPattern *)0; beingbuilt = false; errors = 0; + decoder.closeElement(sla::ELEM_SUBTABLE_SYM.getId()); } void SubtableSymbol::buildDecisionTree(DecisionProperties &props) @@ -2421,73 +2301,52 @@ Constructor *DecisionNode::resolve(ParserWalker &walker) const return children[val]->resolve(walker); } -void DecisionNode::saveXml(ostream &s) const +void DecisionNode::encode(Encoder &encoder) const { - s << "\n"; + encoder.openElement(sla::ELEM_DECISION); + encoder.writeSignedInteger(sla::ATTRIB_NUMBER, num); + encoder.writeBool(sla::ATTRIB_CONTEXT, contextdecision); + encoder.writeSignedInteger(sla::ATTRIB_STARTBIT, startbit); + encoder.writeSignedInteger(sla::ATTRIB_SIZE, bitsize); for(int4 i=0;igetId() << "\">\n"; - list[i].first->saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_PAIR); + encoder.writeSignedInteger(sla::ATTRIB_ID, list[i].second->getId()); + list[i].first->encode(encoder); + encoder.closeElement(sla::ELEM_PAIR); } for(int4 i=0;isaveXml(s); - s << "\n"; + children[i]->encode(encoder); + encoder.closeElement(sla::ELEM_DECISION); } -void DecisionNode::restoreXml(const Element *el,DecisionNode *par,SubtableSymbol *sub) +void DecisionNode::decode(Decoder &decoder,DecisionNode *par,SubtableSymbol *sub) { + uint4 el = decoder.openElement(sla::ELEM_DECISION); parent = par; - { - istringstream s(el->getAttributeValue("number")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> num; - } - contextdecision = xml_readbool(el->getAttributeValue("context")); - { - istringstream s(el->getAttributeValue("start")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> startbit; - } - { - istringstream s(el->getAttributeValue("size")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> bitsize; - } - const List &childlist(el->getChildren()); - List::const_iterator iter; - iter = childlist.begin(); - while(iter != childlist.end()) { - if ((*iter)->getName() == "pair") { - Constructor *ct; - DisjointPattern *pat; - uintm id; - istringstream s((*iter)->getAttributeValue("id")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> id; - ct = sub->getConstructor(id); - pat = DisjointPattern::restoreDisjoint((*iter)->getChildren().front()); - //This increments num addConstructorPair(pat,ct); + num = decoder.readSignedInteger(sla::ATTRIB_NUMBER); + contextdecision = decoder.readBool(sla::ATTRIB_CONTEXT); + startbit = decoder.readSignedInteger(sla::ATTRIB_STARTBIT); + bitsize = decoder.readSignedInteger(sla::ATTRIB_SIZE); + uint4 subel = decoder.peekElement(); + while(subel != 0) { + if (subel == sla::ELEM_PAIR) { + decoder.openElement(); + uintm id = decoder.readSignedInteger(sla::ATTRIB_ID); + Constructor *ct = sub->getConstructor(id); + DisjointPattern *pat = DisjointPattern::decodeDisjoint(decoder); list.push_back(pair(pat,ct)); - //delete pat; // addConstructorPair makes its own copy + decoder.closeElement(subel); } - else if ((*iter)->getName() == "decision") { + else if (subel == sla::ELEM_DECISION) { DecisionNode *subnode = new DecisionNode(); - subnode->restoreXml(*iter,this,sub); + subnode->decode(decoder,this,sub); children.push_back(subnode); } - ++iter; + subel = decoder.peekElement(); } + decoder.closeElement(el); } static void calc_maskword(int4 sbit,int4 ebit,int4 &num,int4 &shift,uintm &mask) @@ -2538,40 +2397,27 @@ void ContextOp::validate(void) const } } -void ContextOp::saveXml(ostream &s) const +void ContextOp::encode(Encoder &encoder) const { - s << "\n"; - patexp->saveXml(s); - s << "\n"; + encoder.openElement(sla::ELEM_CONTEXT_OP); + encoder.writeSignedInteger(sla::ATTRIB_I, num); + encoder.writeSignedInteger(sla::ATTRIB_SHIFT, shift); + encoder.writeUnsignedInteger(sla::ATTRIB_MASK, mask); + patexp->encode(encoder); + encoder.closeElement(sla::ELEM_CONTEXT_OP); } -void ContextOp::restoreXml(const Element *el,SleighBase *trans) +void ContextOp::decode(Decoder &decoder,SleighBase *trans) { - { - istringstream s(el->getAttributeValue("i")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> num; - } - { - istringstream s(el->getAttributeValue("shift")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> shift; - } - { - istringstream s(el->getAttributeValue("mask")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> mask; - } - const List &list(el->getChildren()); - List::const_iterator iter; - iter = list.begin(); - patexp = (PatternValue *)PatternExpression::restoreExpression(*iter,trans); + uint4 el = decoder.openElement(sla::ELEM_CONTEXT_OP); + num = decoder.readSignedInteger(sla::ATTRIB_I); + shift = decoder.readSignedInteger(sla::ATTRIB_SHIFT); + mask = decoder.readUnsignedInteger(sla::ATTRIB_MASK); + patexp = (PatternValue *)PatternExpression::decodeExpression(decoder,trans); patexp->layClaim(); + decoder.closeElement(el); } ContextChange *ContextOp::clone(void) const @@ -2601,41 +2447,27 @@ void ContextCommit::apply(ParserWalkerChange &walker) const walker.getParserContext()->addCommit(sym,num,mask,flow,walker.getPoint()); } -void ContextCommit::saveXml(ostream &s) const +void ContextCommit::encode(Encoder &encoder) const { - s << "getId()); - a_v_i(s,"num",num); - a_v_u(s,"mask",mask); - a_v_b(s,"flow",flow); - s << "/>\n"; + encoder.openElement(sla::ELEM_COMMIT); + encoder.writeUnsignedInteger(sla::ATTRIB_ID, sym->getId()); + encoder.writeSignedInteger(sla::ATTRIB_NUMBER, num); + encoder.writeUnsignedInteger(sla::ATTRIB_MASK, mask); + encoder.writeBool(sla::ATTRIB_FLOW, flow); + encoder.closeElement(sla::ELEM_COMMIT); } -void ContextCommit::restoreXml(const Element *el,SleighBase *trans) +void ContextCommit::decode(Decoder &decoder,SleighBase *trans) { - uintm id; - { - istringstream s(el->getAttributeValue("id")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> id; - sym = (TripleSymbol *)trans->findSymbol(id); - } - { - istringstream s(el->getAttributeValue("num")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> num; - } - { - istringstream s(el->getAttributeValue("mask")); - s.unsetf(ios::dec | ios::hex | ios::oct); - s >> mask; - } - if (el->getNumAttributes()==4) - flow = xml_readbool(el->getAttributeValue("flow")); - else - flow = true; // Default is to flow. flow=true + uint4 el = decoder.openElement(sla::ELEM_COMMIT); + uintm id = decoder.readUnsignedInteger(sla::ATTRIB_ID); + sym = (TripleSymbol *)trans->findSymbol(id); + num = decoder.readSignedInteger(sla::ATTRIB_NUMBER); + mask = decoder.readUnsignedInteger(sla::ATTRIB_MASK); + flow = decoder.readBool(sla::ATTRIB_FLOW); + decoder.closeElement(el); } ContextChange *ContextCommit::clone(void) const diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slghsymbol.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/slghsymbol.hh index 2fc1e192163..ed357c5fcec 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slghsymbol.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slghsymbol.hh @@ -35,16 +35,16 @@ private: uintm id; // Unique id across all symbols uintm scopeid; // Unique id of scope this symbol is in public: - SleighSymbol(void) {} // For use with restoreXml + SleighSymbol(void) {} // For use with decode SleighSymbol(const string &nm) { name = nm; id = 0; } virtual ~SleighSymbol(void) {} const string &getName(void) const { return name; } uintm getId(void) const { return id; } virtual symbol_type getType(void) const { return dummy_symbol; } - virtual void saveXmlHeader(ostream &s) const; - void restoreXmlHeader(const Element *el); - virtual void saveXml(ostream &s) const {} - virtual void restoreXml(const Element *el,SleighBase *trans) {} + virtual void encodeHeader(Encoder &encoder) const; + void decodeHeader(Decoder &decoder); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,SleighBase *trans); }; struct SymbolCompare { @@ -92,9 +92,9 @@ public: SleighSymbol *findGlobalSymbol(const string &nm) const { return findSymbolInternal(table[0],nm); } SleighSymbol *findSymbol(uintm id) const { return symbollist[id]; } void replaceSymbol(SleighSymbol *a,SleighSymbol *b); - void saveXml(ostream &s) const; - void restoreXml(const Element *el,SleighBase *trans); - void restoreSymbolHeader(const Element *el); + void encode(Encoder &encoder) const; + void decode(Decoder &decoder,SleighBase *trans); + void decodeSymbolHeader(Decoder &decoder); void purge(void); }; @@ -127,20 +127,19 @@ public: int4 getDefineCount(void) const { return define_count; } int4 getRefCount(void) const { return ref_count; } virtual symbol_type getType(void) const { return section_symbol; } - // Not saved or restored }; class UserOpSymbol : public SleighSymbol { // A user-defined pcode-op uint4 index; public: - UserOpSymbol(void) {} // For use with restoreXml + UserOpSymbol(void) {} // For use with decode UserOpSymbol(const string &nm) : SleighSymbol(nm) { index = 0; } void setIndex(uint4 ind) { index = ind; } uint4 getIndex(void) const { return index; } virtual symbol_type getType(void) const { return userop_symbol; } - virtual void saveXml(ostream &s) const; - virtual void saveXmlHeader(ostream &s) const; - virtual void restoreXml(const Element *el,SleighBase *trans); + virtual void encode(Encoder &encoder) const; + virtual void encodeHeader(Encoder &encoder) const; + virtual void decode(Decoder &decoder,SleighBase *trans); }; class Constructor; // Forward declaration @@ -174,33 +173,31 @@ public: class PatternlessSymbol : public SpecificSymbol { // Behaves like constant 0 pattern ConstantValue *patexp; public: - PatternlessSymbol(void); // For use with restoreXml + PatternlessSymbol(void); // For use with decode PatternlessSymbol(const string &nm); virtual ~PatternlessSymbol(void); virtual PatternExpression *getPatternExpression(void) const { return patexp; } - virtual void saveXml(ostream &s) const {} - virtual void restoreXml(const Element *el,SleighBase *trans) {} }; class EpsilonSymbol : public PatternlessSymbol { // Another name for zero pattern/value AddrSpace *const_space; public: - EpsilonSymbol(void) {} // For use with restoreXml + EpsilonSymbol(void) {} // For use with decode EpsilonSymbol(const string &nm,AddrSpace *spc) : PatternlessSymbol(nm) { const_space=spc; } virtual void getFixedHandle(FixedHandle &hand,ParserWalker &walker) const; virtual void print(ostream &s,ParserWalker &walker) const; virtual symbol_type getType(void) const { return epsilon_symbol; } virtual VarnodeTpl *getVarnode(void) const; - virtual void saveXml(ostream &s) const; - virtual void saveXmlHeader(ostream &s) const; - virtual void restoreXml(const Element *el,SleighBase *trans); + virtual void encode(Encoder &encoder) const; + virtual void encodeHeader(Encoder &encoder) const; + virtual void decode(Decoder &decoder,SleighBase *trans); }; class ValueSymbol : public FamilySymbol { protected: PatternValue *patval; public: - ValueSymbol(void) { patval = (PatternValue *)0; } // For use with restoreXml + ValueSymbol(void) { patval = (PatternValue *)0; } // For use with decode ValueSymbol(const string &nm,PatternValue *pv); virtual ~ValueSymbol(void); virtual PatternValue *getPatternValue(void) const { return patval; } @@ -208,9 +205,9 @@ public: virtual void getFixedHandle(FixedHandle &hand,ParserWalker &walker) const; virtual void print(ostream &s,ParserWalker &walker) const; virtual symbol_type getType(void) const { return value_symbol; } - virtual void saveXml(ostream &s) const; - virtual void saveXmlHeader(ostream &s) const; - virtual void restoreXml(const Element *el,SleighBase *trans); + virtual void encode(Encoder &encoder) const; + virtual void encodeHeader(Encoder &encoder) const; + virtual void decode(Decoder &decoder,SleighBase *trans); }; class ValueMapSymbol : public ValueSymbol { @@ -218,15 +215,15 @@ class ValueMapSymbol : public ValueSymbol { bool tableisfilled; void checkTableFill(void); public: - ValueMapSymbol(void) {} // For use with restoreXml + ValueMapSymbol(void) {} // For use with decode ValueMapSymbol(const string &nm,PatternValue *pv,const vector &vt) : ValueSymbol(nm,pv) { valuetable=vt; checkTableFill(); } virtual Constructor *resolve(ParserWalker &walker); virtual void getFixedHandle(FixedHandle &hand,ParserWalker &walker) const; virtual void print(ostream &s,ParserWalker &walker) const; virtual symbol_type getType(void) const { return valuemap_symbol; } - virtual void saveXml(ostream &s) const; - virtual void saveXmlHeader(ostream &s) const; - virtual void restoreXml(const Element *el,SleighBase *trans); + virtual void encode(Encoder &encoder) const; + virtual void encodeHeader(Encoder &encoder) const; + virtual void decode(Decoder &decoder,SleighBase *trans); }; class NameSymbol : public ValueSymbol { @@ -234,21 +231,21 @@ class NameSymbol : public ValueSymbol { bool tableisfilled; void checkTableFill(void); public: - NameSymbol(void) {} // For use with restoreXml + NameSymbol(void) {} // For use with decode NameSymbol(const string &nm,PatternValue *pv,const vector &nt) : ValueSymbol(nm,pv) { nametable=nt; checkTableFill(); } virtual Constructor *resolve(ParserWalker &walker); virtual void print(ostream &s,ParserWalker &walker) const; virtual symbol_type getType(void) const { return name_symbol; } - virtual void saveXml(ostream &s) const; - virtual void saveXmlHeader(ostream &s) const; - virtual void restoreXml(const Element *el,SleighBase *trans); + virtual void encode(Encoder &encoder) const; + virtual void encodeHeader(Encoder &encoder) const; + virtual void decode(Decoder &decoder,SleighBase *trans); }; class VarnodeSymbol : public PatternlessSymbol { // A global varnode VarnodeData fix; bool context_bits; public: - VarnodeSymbol(void) {} // For use with restoreXml + VarnodeSymbol(void) {} // For use with decode VarnodeSymbol(const string &nm,AddrSpace *base,uintb offset,int4 size); void markAsContext(void) { context_bits = true; } const VarnodeData &getFixedVarnode(void) const { return fix; } @@ -259,9 +256,9 @@ public: s << getName(); } virtual void collectLocalValues(vector &results) const; virtual symbol_type getType(void) const { return varnode_symbol; } - virtual void saveXml(ostream &s) const; - virtual void saveXmlHeader(ostream &s) const; - virtual void restoreXml(const Element *el,SleighBase *trans); + virtual void encode(Encoder &encoder) const; + virtual void encodeHeader(Encoder &encoder) const; + virtual void decode(Decoder &decoder,SleighBase *trans); }; class BitrangeSymbol : public SleighSymbol { // A smaller bitrange within a varnode @@ -269,7 +266,7 @@ class BitrangeSymbol : public SleighSymbol { // A smaller bitrange within a varn uint4 bitoffset; // least significant bit of range uint4 numbits; // number of bits in the range public: - BitrangeSymbol(void) {} // For use with restoreXml + BitrangeSymbol(void) {} // For use with decode BitrangeSymbol(const string &nm,VarnodeSymbol *sym,uint4 bitoff,uint4 num) : SleighSymbol(nm) { varsym=sym; bitoffset=bitoff; numbits=num; } VarnodeSymbol *getParentSymbol(void) const { return varsym; } @@ -283,16 +280,16 @@ class ContextSymbol : public ValueSymbol { uint4 low,high; // into a varnode bool flow; public: - ContextSymbol(void) {} // For use with restoreXml + ContextSymbol(void) {} // For use with decode ContextSymbol(const string &nm,ContextField *pate,VarnodeSymbol *v,uint4 l,uint4 h,bool flow); VarnodeSymbol *getVarnode(void) const { return vn; } uint4 getLow(void) const { return low; } uint4 getHigh(void) const { return high; } bool getFlow(void) const { return flow; } virtual symbol_type getType(void) const { return context_symbol; } - virtual void saveXml(ostream &s) const; - virtual void saveXmlHeader(ostream &s) const; - virtual void restoreXml(const Element *el,SleighBase *trans); + virtual void encode(Encoder &encoder) const; + virtual void encodeHeader(Encoder &encoder) const; + virtual void decode(Decoder &decoder,SleighBase *trans); }; class VarnodeListSymbol : public ValueSymbol { @@ -300,16 +297,16 @@ class VarnodeListSymbol : public ValueSymbol { bool tableisfilled; void checkTableFill(void); public: - VarnodeListSymbol(void) {} // For use with restoreXml + VarnodeListSymbol(void) {} // For use with decode VarnodeListSymbol(const string &nm,PatternValue *pv,const vector &vt); virtual Constructor *resolve(ParserWalker &walker); virtual void getFixedHandle(FixedHandle &hand,ParserWalker &walker) const; virtual int4 getSize(void) const; virtual void print(ostream &s,ParserWalker &walker) const; virtual symbol_type getType(void) const { return varnodelist_symbol; } - virtual void saveXml(ostream &s) const; - virtual void saveXmlHeader(ostream &s) const; - virtual void restoreXml(const Element *el,SleighBase *trans); + virtual void encode(Encoder &encoder) const; + virtual void encodeHeader(Encoder &encoder) const; + virtual void decode(Decoder &decoder,SleighBase *trans); }; class OperandSymbol : public SpecificSymbol { @@ -329,7 +326,7 @@ private: void setVariableLength(void) { flags |= variable_len; } bool isVariableLength(void) const { return ((flags&variable_len)!=0); } public: - OperandSymbol(void) {} // For use with restoreXml + OperandSymbol(void) {} // For use with decode OperandSymbol(const string &nm,int4 index,Constructor *ct); uint4 getRelativeOffset(void) const { return reloffset; } int4 getOffsetBase(void) const { return offsetbase; } @@ -354,16 +351,16 @@ public: virtual void print(ostream &s,ParserWalker &walker) const; virtual void collectLocalValues(vector &results) const; virtual symbol_type getType(void) const { return operand_symbol; } - virtual void saveXml(ostream &s) const; - virtual void saveXmlHeader(ostream &s) const; - virtual void restoreXml(const Element *el,SleighBase *trans); + virtual void encode(Encoder &encoder) const; + virtual void encodeHeader(Encoder &encoder) const; + virtual void decode(Decoder &decoder,SleighBase *trans); }; class StartSymbol : public SpecificSymbol { AddrSpace *const_space; PatternExpression *patexp; public: - StartSymbol(void) { patexp = (PatternExpression *)0; } // For use with restoreXml + StartSymbol(void) { patexp = (PatternExpression *)0; } // For use with decode StartSymbol(const string &nm,AddrSpace *cspc); virtual ~StartSymbol(void); virtual VarnodeTpl *getVarnode(void) const; @@ -371,16 +368,16 @@ public: virtual void getFixedHandle(FixedHandle &hand,ParserWalker &walker) const; virtual void print(ostream &s,ParserWalker &walker) const; virtual symbol_type getType(void) const { return start_symbol; } - virtual void saveXml(ostream &s) const; - virtual void saveXmlHeader(ostream &s) const; - virtual void restoreXml(const Element *el,SleighBase *trans); + virtual void encode(Encoder &encoder) const; + virtual void encodeHeader(Encoder &encoder) const; + virtual void decode(Decoder &decoder,SleighBase *trans); }; class EndSymbol : public SpecificSymbol { AddrSpace *const_space; PatternExpression *patexp; public: - EndSymbol(void) { patexp = (PatternExpression *)0; } // For use with restoreXml + EndSymbol(void) { patexp = (PatternExpression *)0; } // For use with decode EndSymbol(const string &nm,AddrSpace *cspc); virtual ~EndSymbol(void); virtual VarnodeTpl *getVarnode(void) const; @@ -388,16 +385,16 @@ public: virtual void getFixedHandle(FixedHandle &hand,ParserWalker &walker) const; virtual void print(ostream &s,ParserWalker &walker) const; virtual symbol_type getType(void) const { return end_symbol; } - virtual void saveXml(ostream &s) const; - virtual void saveXmlHeader(ostream &s) const; - virtual void restoreXml(const Element *el,SleighBase *trans); + virtual void encode(Encoder &encoder) const; + virtual void encodeHeader(Encoder &encoder) const; + virtual void decode(Decoder &decoder,SleighBase *trans); }; class Next2Symbol : public SpecificSymbol { AddrSpace *const_space; PatternExpression *patexp; public: - Next2Symbol(void) { patexp = (PatternExpression *)0; } // For use with restoreXml + Next2Symbol(void) { patexp = (PatternExpression *)0; } // For use with decode Next2Symbol(const string &nm,AddrSpace *cspc); virtual ~Next2Symbol(void); virtual VarnodeTpl *getVarnode(void) const; @@ -405,47 +402,41 @@ public: virtual void getFixedHandle(FixedHandle &hand,ParserWalker &walker) const; virtual void print(ostream &s,ParserWalker &walker) const; virtual symbol_type getType(void) const { return next2_symbol; } - virtual void saveXml(ostream &s) const; - virtual void saveXmlHeader(ostream &s) const; - virtual void restoreXml(const Element *el,SleighBase *trans); + virtual void encode(Encoder &encoder) const; + virtual void encodeHeader(Encoder &encoder) const; + virtual void decode(Decoder &decoder,SleighBase *trans); }; class FlowDestSymbol : public SpecificSymbol { AddrSpace *const_space; public: - FlowDestSymbol(void) {} // For use with restoreXml + FlowDestSymbol(void) {} // For use with decode FlowDestSymbol(const string &nm,AddrSpace *cspc); virtual VarnodeTpl *getVarnode(void) const; virtual PatternExpression *getPatternExpression(void) const { throw SleighError("Cannot use symbol in pattern"); } virtual void getFixedHandle(FixedHandle &hand,ParserWalker &walker) const; virtual void print(ostream &s,ParserWalker &walker) const; virtual symbol_type getType(void) const { return start_symbol; } - virtual void saveXml(ostream &s) const; - virtual void saveXmlHeader(ostream &s) const; - virtual void restoreXml(const Element *el,SleighBase *trans); }; class FlowRefSymbol : public SpecificSymbol { AddrSpace *const_space; public: - FlowRefSymbol(void) {} // For use with restoreXml + FlowRefSymbol(void) {} // For use with decode FlowRefSymbol(const string &nm,AddrSpace *cspc); virtual VarnodeTpl *getVarnode(void) const; virtual PatternExpression *getPatternExpression(void) const { throw SleighError("Cannot use symbol in pattern"); } virtual void getFixedHandle(FixedHandle &hand,ParserWalker &walker) const; virtual void print(ostream &s,ParserWalker &walker) const; virtual symbol_type getType(void) const { return start_symbol; } - virtual void saveXml(ostream &s) const; - virtual void saveXmlHeader(ostream &s) const; - virtual void restoreXml(const Element *el,SleighBase *trans); }; class ContextChange { // Change to context command public: virtual ~ContextChange(void) {} virtual void validate(void) const=0; - virtual void saveXml(ostream &s) const=0; - virtual void restoreXml(const Element *el,SleighBase *trans)=0; + virtual void encode(Encoder &encoder) const=0; + virtual void decode(Decoder &decoder,SleighBase *trans)=0; virtual void apply(ParserWalkerChange &walker) const=0; virtual ContextChange *clone(void) const=0; }; @@ -457,11 +448,11 @@ class ContextOp : public ContextChange { int4 shift; // Number of bits to shift value into place public: ContextOp(int4 startbit,int4 endbit,PatternExpression *pe); - ContextOp(void) {} // For use with restoreXml + ContextOp(void) {} // For use with decode virtual ~ContextOp(void) { PatternExpression::release(patexp); } virtual void validate(void) const; - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el,SleighBase *trans); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,SleighBase *trans); virtual void apply(ParserWalkerChange &walker) const; virtual ContextChange *clone(void) const; }; @@ -472,11 +463,11 @@ class ContextCommit : public ContextChange { uintm mask; // mask of bits in word being committed bool flow; // Whether the context "flows" from the point of change public: - ContextCommit(void) {} // For use with restoreXml + ContextCommit(void) {} // For use with decode ContextCommit(TripleSymbol *s,int4 sbit,int4 ebit,bool fl); virtual void validate(void) const {} - virtual void saveXml(ostream &s) const; - virtual void restoreXml(const Element *el,SleighBase *trans); + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,SleighBase *trans); virtual void apply(ParserWalkerChange &walker) const; virtual ContextChange *clone(void) const; }; @@ -500,7 +491,7 @@ class Constructor { // This is NOT a symbol mutable bool inerror; // An error is associated with this Constructor void orderOperands(void); public: - Constructor(void); // For use with restoreXml + Constructor(void); // For use with decode Constructor(SubtableSymbol *p); ~Constructor(void); TokenPattern *buildPattern(ostream &s); @@ -542,8 +533,8 @@ public: void setError(bool val) const { inerror = val; } bool isError(void) const { return inerror; } bool isRecursive(void) const; - void saveXml(ostream &s) const; - void restoreXml(const Element *el,SleighBase *trans); + void encode(Encoder &encoder) const; + void decode(Decoder &decoder,SleighBase *trans); }; class DecisionProperties { @@ -569,15 +560,15 @@ class DecisionNode { int4 getMaximumLength(bool context); void consistentValues(vector &bins,DisjointPattern *pat); public: - DecisionNode(void) {} // For use with restoreXml + DecisionNode(void) {} // For use with decode DecisionNode(DecisionNode *p); ~DecisionNode(void); Constructor *resolve(ParserWalker &walker) const; void addConstructorPair(const DisjointPattern *pat,Constructor *ct); void split(DecisionProperties &props); void orderPatterns(DecisionProperties &props); - void saveXml(ostream &s) const; - void restoreXml(const Element *el,DecisionNode *par,SubtableSymbol *sub); + void encode(Encoder &encoder) const; + void decode(Decoder &decoder,DecisionNode *par,SubtableSymbol *sub); }; class SubtableSymbol : public TripleSymbol { @@ -586,7 +577,7 @@ class SubtableSymbol : public TripleSymbol { vector construct; // All the Constructors in this table DecisionNode *decisiontree; public: - SubtableSymbol(void) { pattern = (TokenPattern *)0; decisiontree = (DecisionNode *)0; } // For use with restoreXml + SubtableSymbol(void) { pattern = (TokenPattern *)0; decisiontree = (DecisionNode *)0; } // For use with decode SubtableSymbol(const string &nm); virtual ~SubtableSymbol(void); bool isBeingBuilt(void) const { return beingbuilt; } @@ -606,9 +597,9 @@ public: throw SleighError("Cannot use subtable in expression"); } virtual void collectLocalValues(vector &results) const; virtual symbol_type getType(void) const { return subtable_symbol; } - virtual void saveXml(ostream &s) const; - virtual void saveXmlHeader(ostream &s) const; - virtual void restoreXml(const Element *el,SleighBase *trans); + virtual void encode(Encoder &encoder) const; + virtual void encodeHeader(Encoder &encoder) const; + virtual void decode(Decoder &decoder,SleighBase *trans); }; class MacroSymbol : public SleighSymbol { // A user-defined pcode-macro diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/space.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/space.cc index 5d8657da848..bda09fc94c5 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/space.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/space.cc @@ -45,13 +45,15 @@ void AddrSpace::calcScaleMask(void) /// \param t is the processor translator associated with the new space /// \param tp is the type of the new space (PROCESSOR, CONSTANT, INTERNAL,...) /// \param nm is the name of the new space +/// \param bigEnd is \b true for big endian encoding /// \param size is the (offset encoding) size of the new space /// \param ws is the number of bytes in an addressable unit /// \param ind is the integer identifier for the new space /// \param fl can be 0 or AddrSpace::hasphysical /// \param dl is the number of rounds to delay heritage for the new space -AddrSpace::AddrSpace(AddrSpaceManager *m,const Translate *t,spacetype tp,const string &nm, - uint4 size,uint4 ws, int4 ind,uint4 fl,int4 dl) +/// \param dead is the number of rounds to delay before dead code removal +AddrSpace::AddrSpace(AddrSpaceManager *m,const Translate *t,spacetype tp,const string &nm,bool bigEnd, + uint4 size,uint4 ws, int4 ind,uint4 fl,int4 dl,int4 dead) { refcount = 0; // No references to this space yet manage = m; @@ -62,13 +64,13 @@ AddrSpace::AddrSpace(AddrSpaceManager *m,const Translate *t,spacetype tp,const s wordsize = ws; index = ind; delay = dl; - deadcodedelay = dl; // Deadcode delay initially starts the same as heritage delay + deadcodedelay = dead; minimumPointerSize = 0; // (initially) assume pointers must match the space size exactly shortcut = ' '; // Placeholder meaning shortcut is unassigned // These are the flags we allow to be set from constructor flags = (fl & hasphysical); - if (t->isBigEndian()) + if (bigEnd) flags |= big_endian; flags |= (heritaged | does_deadcode); // Always on unless explicitly turned off in derived constructor @@ -94,24 +96,6 @@ AddrSpace::AddrSpace(AddrSpaceManager *m,const Translate *t,spacetype tp) // We let big_endian get set by attribute } -/// Save the \e name, \e index, \e bigendian, \e delay, -/// \e size, \e wordsize, and \e physical attributes which -/// are common with all address spaces derived from AddrSpace -/// \param s the stream where the attributes are written -void AddrSpace::saveBasicAttributes(ostream &s) const - -{ - a_v(s,"name",name); - a_v_i(s,"index",index); - a_v_b(s,"bigendian",isBigEndian()); - a_v_i(s,"delay",delay); - if (delay != deadcodedelay) - a_v_i(s,"deadcodedelay",deadcodedelay); - a_v_i(s,"size",addressSize); - if (wordsize > 1) a_v_i(s,"wordsize",wordsize); - a_v_b(s,"physical",hasPhysical()); -} - /// The logical form of the space is truncated from its actual size /// Pointers may refer to this original size put the most significant bytes are ignored /// \param newsize is the size (in bytes) of the truncated (logical) space @@ -310,17 +294,6 @@ uintb AddrSpace::read(const string &s,int4 &size) const return offset; } -/// Write a tag fully describing the details of this space -/// suitable for later recovery via decode. -/// \param s is the stream being written -void AddrSpace::saveXml(ostream &s) const - -{ - s << "\n"; -} - /// Walk attributes of the current element and recover all the properties defining /// this space. The processor translator, \e trans, and the /// \e type must already be filled in. @@ -378,7 +351,7 @@ const int4 ConstantSpace::INDEX = 0; /// \param m is the associated address space manager /// \param t is the associated processor translator ConstantSpace::ConstantSpace(AddrSpaceManager *m,const Translate *t) - : AddrSpace(m,t,IPTR_CONSTANT,NAME,sizeof(uintb),1,INDEX,0,0) + : AddrSpace(m,t,IPTR_CONSTANT,NAME,false,sizeof(uintb),1,INDEX,0,0,0) { clearFlags(heritaged|does_deadcode|big_endian); if (HOST_ENDIAN==1) // Endianness always matches host @@ -399,14 +372,6 @@ void ConstantSpace::printRaw(ostream &s,uintb offset) const s << "0x" << hex << offset; } -/// The ConstantSpace should never be explicitly saved as it is -/// always built automatically -void ConstantSpace::saveXml(ostream &s) const - -{ - throw LowlevelError("Should never save the constant space as XML"); -} - /// As the ConstantSpace is never saved, it should never get /// decoded either. void ConstantSpace::decode(Decoder &decoder) @@ -426,7 +391,7 @@ const int4 OtherSpace::INDEX = 1; /// \param t is the associated processor translator /// \param ind is the integer identifier OtherSpace::OtherSpace(AddrSpaceManager *m,const Translate *t,int4 ind) - : AddrSpace(m,t,IPTR_PROCESSOR,NAME,sizeof(uintb),1,INDEX,0,0) + : AddrSpace(m,t,IPTR_PROCESSOR,NAME,false,sizeof(uintb),1,INDEX,0,0,0) { clearFlags(heritaged|does_deadcode); setFlags(is_otherspace); @@ -445,14 +410,6 @@ void OtherSpace::printRaw(ostream &s,uintb offset) const s << "0x" << hex << offset; } -void OtherSpace::saveXml(ostream &s) const - -{ - s << "\n"; -} - const string UniqueSpace::NAME = "unique"; const uint4 UniqueSpace::SIZE = 4; @@ -465,7 +422,7 @@ const uint4 UniqueSpace::SIZE = 4; /// \param ind is the integer identifier /// \param fl are attribute flags (currently unused) UniqueSpace::UniqueSpace(AddrSpaceManager *m,const Translate *t,int4 ind,uint4 fl) - : AddrSpace(m,t,IPTR_INTERNAL,NAME,SIZE,1,ind,fl,0) + : AddrSpace(m,t,IPTR_INTERNAL,NAME,t->isBigEndian(),SIZE,1,ind,fl,0,0) { setFlags(hasphysical); } @@ -476,14 +433,6 @@ UniqueSpace::UniqueSpace(AddrSpaceManager *m,const Translate *t) setFlags(hasphysical); } -void UniqueSpace::saveXml(ostream &s) const - -{ - s << "\n"; -} - const string JoinSpace::NAME = "join"; /// This is the constructor for the \b join space, which is automatically constructed by the @@ -492,7 +441,7 @@ const string JoinSpace::NAME = "join"; /// \param t is the associated processor translator /// \param ind is the integer identifier JoinSpace::JoinSpace(AddrSpaceManager *m,const Translate *t,int4 ind) - : AddrSpace(m,t,IPTR_JOIN,NAME,sizeof(uintm),1,ind,0,0) + : AddrSpace(m,t,IPTR_JOIN,NAME,t->isBigEndian(),sizeof(uintm),1,ind,0,0,0) { // This is a virtual space // setFlags(hasphysical); @@ -691,12 +640,6 @@ uintb JoinSpace::read(const string &s,int4 &size) const return rec->getUnified().offset; } -void JoinSpace::saveXml(ostream &s) const - -{ - throw LowlevelError("Should never save join space to XML"); -} - void JoinSpace::decode(Decoder &decoder) { @@ -712,16 +655,6 @@ OverlaySpace::OverlaySpace(AddrSpaceManager *m,const Translate *t) setFlags(overlay); } -void OverlaySpace::saveXml(ostream &s) const - -{ - s << "getName()); - s << "/>\n"; -} - void OverlaySpace::decode(Decoder &decoder) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/space.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/space.hh index 4a8791cfd5f..bc88fcd6c58 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/space.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/space.hh @@ -117,11 +117,11 @@ protected: void calcScaleMask(void); ///< Calculate scale and mask void setFlags(uint4 fl); ///< Set a cached attribute void clearFlags(uint4 fl); ///< Clear a cached attribute - void saveBasicAttributes(ostream &s) const; ///< Write the XML attributes of this space void decodeBasicAttributes(Decoder &decoder); ///< Read attributes for \b this space from an open XML element void truncateSpace(uint4 newsize); public: - AddrSpace(AddrSpaceManager *m,const Translate *t,spacetype tp,const string &nm,uint4 size,uint4 ws,int4 ind,uint4 fl,int4 dl); + AddrSpace(AddrSpaceManager *m,const Translate *t,spacetype tp,const string &nm,bool bigEnd, + uint4 size,uint4 ws,int4 ind,uint4 fl,int4 dl,int4 dead); AddrSpace(AddrSpaceManager *m,const Translate *t,spacetype tp); ///< For use with decode virtual ~AddrSpace(void) {} ///< The address space destructor const string &getName(void) const; ///< Get the name @@ -163,8 +163,7 @@ public: virtual uintb decodeAttributes(Decoder &decoder,uint4 &size) const; ///< Recover an offset and size virtual void printRaw(ostream &s,uintb offset) const; ///< Write an address in this space to a stream virtual uintb read(const string &s,int4 &size) const; ///< Read in an address (and possible size) from a string - virtual void saveXml(ostream &s) const; ///< Write the details of this space as XML - virtual void decode(Decoder &decoder); ///< Recover the details of this space from XML + virtual void decode(Decoder &decoder); ///< Recover the details of this space from a stream 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 @@ -190,7 +189,6 @@ public: ConstantSpace(AddrSpaceManager *m,const Translate *t); ///< Only constructor virtual int4 overlapJoin(uintb offset,int4 size,AddrSpace *pointSpace,uintb pointOff,int4 pointSkip) const; virtual void printRaw(ostream &s,uintb offset) const; - virtual void saveXml(ostream &s) const; virtual void decode(Decoder &decoder); static const string NAME; ///< Reserved name for the address space static const int4 INDEX; ///< Reserved index for constant space @@ -202,7 +200,6 @@ public: OtherSpace(AddrSpaceManager *m, const Translate *t, int4 ind); ///< Constructor OtherSpace(AddrSpaceManager *m, const Translate *t); ///< For use with decode virtual void printRaw(ostream &s, uintb offset) const; - virtual void saveXml(ostream &s) const; static const string NAME; ///< Reserved name for the address space static const int4 INDEX; ///< Reserved index for the other space }; @@ -220,7 +217,6 @@ class UniqueSpace : public AddrSpace { public: UniqueSpace(AddrSpaceManager *m,const Translate *t,int4 ind,uint4 fl); ///< Constructor UniqueSpace(AddrSpaceManager *m,const Translate *t); ///< For use with decode - virtual void saveXml(ostream &s) const; static const string NAME; ///< Reserved name for the unique space static const uint4 SIZE; ///< Fixed size (in bytes) for unique space offsets }; @@ -243,7 +239,6 @@ public: virtual uintb decodeAttributes(Decoder &decoder,uint4 &size) const; virtual void printRaw(ostream &s,uintb offset) const; virtual uintb read(const string &s,int4 &size) const; - virtual void saveXml(ostream &s) const; virtual void decode(Decoder &decoder); static const string NAME; ///< Reserved name for the join space }; @@ -261,7 +256,6 @@ class OverlaySpace : public AddrSpace { public: OverlaySpace(AddrSpaceManager *m,const Translate *t); ///< Constructor virtual AddrSpace *getContain(void) const { return baseSpace; } - virtual void saveXml(ostream &s) const; virtual void decode(Decoder &decoder); }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/translate.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/translate.cc index f07cc7048e1..3ef40d30d68 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/translate.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/translate.cc @@ -56,7 +56,7 @@ void TruncationTag::decode(Decoder &decoder) /// \param isFormal is the formal stack space indicator SpacebaseSpace::SpacebaseSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind,int4 sz, AddrSpace *base,int4 dl,bool isFormal) - : AddrSpace(m,t,IPTR_SPACEBASE,nm,sz,base->getWordSize(),ind,0,dl) + : AddrSpace(m,t,IPTR_SPACEBASE,nm,t->isBigEndian(),sz,base->getWordSize(),ind,0,dl,dl) { contain = base; hasbaseregister = false; // No base register assigned yet @@ -123,15 +123,6 @@ const VarnodeData &SpacebaseSpace::getSpacebaseFull(int4 i) const return baseOrig; } -void SpacebaseSpace::saveXml(ostream &s) const - -{ - s << "getName()); - s << "/>\n"; -} - void SpacebaseSpace::decode(Decoder &decoder) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/translate.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/translate.hh index 6892bf5d0f5..520efa94397 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/translate.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/translate.hh @@ -185,7 +185,6 @@ public: virtual const VarnodeData &getSpacebaseFull(int4 i) const; virtual bool stackGrowsNegative(void) const { return isNegativeStack; } virtual AddrSpace *getContain(void) const { return contain; } ///< Return containing space - virtual void saveXml(ostream &s) const; virtual void decode(Decoder &decoder); }; @@ -235,7 +234,7 @@ class AddrSpaceManager { vector splitlist; ///< JoinRecords indexed by join address protected: AddrSpace *decodeSpace(Decoder &decoder,const Translate *trans); ///< Add a space to the model based an on XML tag - void decodeSpaces(Decoder &decoder,const Translate *trans); ///< Restore address spaces in the model from an XML tag + void decodeSpaces(Decoder &decoder,const Translate *trans); ///< Restore address spaces in the model from a stream void setDefaultCodeSpace(int4 index); ///< Set the default address space (for code) void setDefaultDataSpace(int4 index); ///< Set the default address space for data void setReverseJustified(AddrSpace *spc); ///< Set reverse justified property on this space diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc index 16655080879..e6292e138d8 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc @@ -598,8 +598,8 @@ const TypeField *Datatype::resolveTruncation(int8 offset,PcodeOp *op,int4 slot,i return (const TypeField *)0; } -/// Restore the basic properties (name,size,id) of a data-type from an XML element -/// Properties are read from the attributes of the element +/// Restore the basic properties (name,size,id) of a data-type from a stream. +/// Properties are read from the attributes of the element. /// \param decoder is the stream decoder void Datatype::decodeBasic(Decoder &decoder) diff --git a/Ghidra/Features/Decompiler/src/decompile/unittests/testfuncproto.cc b/Ghidra/Features/Decompiler/src/decompile/unittests/testfuncproto.cc index a25315dc25b..963aae19c75 100644 --- a/Ghidra/Features/Decompiler/src/decompile/unittests/testfuncproto.cc +++ b/Ghidra/Features/Decompiler/src/decompile/unittests/testfuncproto.cc @@ -34,7 +34,7 @@ class FuncProtoTestEnvironment { static FuncProtoTestEnvironment theEnviron; -static Architecture *glb; +static Architecture *glb = (Architecture *)0; FuncProtoTestEnvironment::FuncProtoTestEnvironment(void) @@ -46,7 +46,11 @@ FuncProtoTestEnvironment::FuncProtoTestEnvironment(void) void FuncProtoTestEnvironment::build(void) { - if (theEnviron.g != (Architecture *)0) return; + if (theEnviron.g != (Architecture *)0) { + if (glb == (Architecture *)0) + throw LowlevelError("Architecture did not load"); + return; + } ArchitectureCapability *xmlCapability = ArchitectureCapability::getCapability("xml"); istringstream s( "" diff --git a/Ghidra/Features/Decompiler/src/decompile/unittests/testmarshal.cc b/Ghidra/Features/Decompiler/src/decompile/unittests/testmarshal.cc index 44a31cc16f0..7845a9fce4f 100644 --- a/Ghidra/Features/Decompiler/src/decompile/unittests/testmarshal.cc +++ b/Ghidra/Features/Decompiler/src/decompile/unittests/testmarshal.cc @@ -49,7 +49,7 @@ static MarshalTestEnvironment theEnviron; TestAddrSpaceManager::TestAddrSpaceManager(Translate *t) : AddrSpaceManager() { - insertSpace(new AddrSpace(this,t,IPTR_PROCESSOR,"ram",8,1,3,AddrSpace::hasphysical,1)); + insertSpace(new AddrSpace(this,t,IPTR_PROCESSOR,"ram",t->isBigEndian(),8,1,3,AddrSpace::hasphysical,1,1)); } MarshalTestEnvironment::MarshalTestEnvironment(void) diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/README.txt b/Ghidra/Features/Decompiler/src/decompile/zlib/README.txt new file mode 100644 index 00000000000..91728797704 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/README.txt @@ -0,0 +1,10 @@ +The source files in this directory are copied from the zlib compression library, version 1.3.1 +available from https://www.zlib.net/ . + +The source files here are only a subset of the complete zlib library. The files have not been +changed except for the addition of a comment at the top of each file, noting its association +with the zlib license and the version number. + +Within Ghidra, the zlib license is available (in both the source repository and distributions) +in licenses/zlib_License.txt. Additionally the license appears at the top of zlib.h in this +directory. diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/adler32.c b/Ghidra/Features/Decompiler/src/decompile/zlib/adler32.c new file mode 100644 index 00000000000..42bdb65b888 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/adler32.c @@ -0,0 +1,168 @@ +/* ### + * IP: zlib License + * NOTE: from zlib 1.3.1 + */ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#define BASE 65521U /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware -- + try it both ways to see which is faster */ +#ifdef NO_DIVIDE +/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 + (thank you to John Reiser for pointing this out) */ +# define CHOP(a) \ + do { \ + unsigned long tmp = a >> 16; \ + a &= 0xffffUL; \ + a += (tmp << 4) - tmp; \ + } while (0) +# define MOD28(a) \ + do { \ + CHOP(a); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD(a) \ + do { \ + CHOP(a); \ + MOD28(a); \ + } while (0) +# define MOD63(a) \ + do { /* this assumes a is not negative */ \ + z_off64_t tmp = a >> 32; \ + a &= 0xffffffffL; \ + a += (tmp << 8) - (tmp << 5) + tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD28(a) a %= BASE +# define MOD63(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len) { + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD28(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len) { + return adler32_z(adler, buf, len); +} + +/* ========================================================================= */ +local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2) { + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* for negative len, return invalid adler32 as a clue for debugging */ + if (len2 < 0) + return 0xffffffffUL; + + /* the derivation of this formula is left as an exercise for the reader */ + MOD63(len2); /* assumes len2 >= 0 */ + rem = (unsigned)len2; + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 >= BASE) sum1 -= BASE; + if (sum1 >= BASE) sum1 -= BASE; + if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); + if (sum2 >= BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2) { + return adler32_combine_(adler1, adler2, len2); +} + +uLong ZEXPORT adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2) { + return adler32_combine_(adler1, adler2, len2); +} diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/deflate.c b/Ghidra/Features/Decompiler/src/decompile/zlib/deflate.c new file mode 100644 index 00000000000..3575d3b6aa7 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/deflate.c @@ -0,0 +1,2143 @@ +/* ### + * IP: zlib License + * NOTE: from zlib 1.3.1 + */ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://tools.ietf.org/html/rfc1951 + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.3.1 Copyright 1995-2024 Jean-loup Gailly and Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func)(deflate_state *s, int flush); +/* Compression function. Returns the block state after the call. */ + +local block_state deflate_stored(deflate_state *s, int flush); +local block_state deflate_fast(deflate_state *s, int flush); +#ifndef FASTEST +local block_state deflate_slow(deflate_state *s, int flush); +#endif +local block_state deflate_rle(deflate_state *s, int flush); +local block_state deflate_huff(deflate_state *s, int flush); + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ +#define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0)) + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to UPDATE_HASH are made with consecutive input + * characters, so that a running hash key can be computed from the previous + * key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h) << s->hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to INSERT_STRING are made with consecutive input + * characters and the first MIN_MATCH bytes of str are valid (except for + * the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + do { \ + s->head[s->hash_size - 1] = NIL; \ + zmemzero((Bytef *)s->head, \ + (unsigned)(s->hash_size - 1)*sizeof(*s->head)); \ + } while (0) + +/* =========================================================================== + * Slide the hash table when sliding the window down (could be avoided with 32 + * bit values at the expense of memory usage). We slide even when level == 0 to + * keep the hash table consistent if we switch back to level > 0 later. + */ +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) + __attribute__((no_sanitize("memory"))) +# endif +#endif +local void slide_hash(deflate_state *s) { + unsigned n, m; + Posf *p; + uInt wsize = s->w_size; + + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m - wsize : NIL); + } while (--n); + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m - wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local unsigned read_buf(z_streamp strm, Bytef *buf, unsigned size) { + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + zmemcpy(buf, strm->next_in, len); + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, buf, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, buf, len); + } +#endif + strm->next_in += len; + strm->total_in += len; + + return len; +} + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(deflate_state *s) { + unsigned n; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize + MAX_DIST(s)) { + + zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + if (s->insert > s->strstart) + s->insert = s->strstart; + slide_hash(s); + more += wsize; + } + if (s->strm->avail_in == 0) break; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead + s->insert >= MIN_MATCH) { + uInt str = s->strstart - s->insert; + s->ins_h = s->window[str]; + UPDATE_HASH(s, s->ins_h, s->window[str + 1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + while (s->insert) { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + s->insert--; + if (s->lookahead + s->insert < MIN_MATCH) + break; + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ + if (s->high_water < s->window_size) { + ulg curr = s->strstart + (ulg)(s->lookahead); + ulg init; + + if (s->high_water < curr) { + /* Previous high water mark below current data -- zero WIN_INIT + * bytes or up to end of window, whichever is less. + */ + init = s->window_size - curr; + if (init > WIN_INIT) + init = WIN_INIT; + zmemzero(s->window + curr, (unsigned)init); + s->high_water = curr + init; + } + else if (s->high_water < (ulg)curr + WIN_INIT) { + /* High water mark at or above current data, but below current data + * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + * to end of window, whichever is less. + */ + init = (ulg)curr + WIN_INIT - s->high_water; + if (init > s->window_size - s->high_water) + init = s->window_size - s->high_water; + zmemzero(s->window + s->high_water, (unsigned)init); + s->high_water += init; + } + } + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "not enough room for search"); +} + +/* ========================================================================= */ +int ZEXPORT deflateInit_(z_streamp strm, int level, const char *version, + int stream_size) { + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, + int windowBits, int memLevel, int strategy, + const char *version, int stream_size) { + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + if (windowBits < -15) + return Z_STREAM_ERROR; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + s->status = INIT_STATE; /* to pass state test in deflateReset() */ + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = (uInt)windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = (uInt)memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits + MIN_MATCH-1) / MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->high_water = 0; /* nothing written to s->window yet */ + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + /* We overlay pending_buf and sym_buf. This works since the average size + * for length/distance pairs over any compressed block is assured to be 31 + * bits or less. + * + * Analysis: The longest fixed codes are a length code of 8 bits plus 5 + * extra bits, for lengths 131 to 257. The longest fixed distance codes are + * 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest + * possible fixed-codes length/distance pair is then 31 bits total. + * + * sym_buf starts one-fourth of the way into pending_buf. So there are + * three bytes in sym_buf for every four bytes in pending_buf. Each symbol + * in sym_buf is three bytes -- two for the distance and one for the + * literal/length. As each symbol is consumed, the pointer to the next + * sym_buf value to read moves forward three bytes. From that symbol, up to + * 31 bits are written to pending_buf. The closest the written pending_buf + * bits gets to the next sym_buf symbol to read is just before the last + * code is written. At that time, 31*(n - 2) bits have been written, just + * after 24*(n - 2) bits have been consumed from sym_buf. sym_buf starts at + * 8*n bits into pending_buf. (Note that the symbol buffer fills when n - 1 + * symbols are written.) The closest the writing gets to what is unread is + * then n + 14 bits. Here n is lit_bufsize, which is 16384 by default, and + * can range from 128 to 32768. + * + * Therefore, at a minimum, there are 142 bits of space between what is + * written and what is read in the overlain buffers, so the symbols cannot + * be overwritten by the compressed data. That space is actually 139 bits, + * due to the three-bit fixed-code block header. + * + * That covers the case where either Z_FIXED is specified, forcing fixed + * codes, or when the use of fixed codes is chosen, because that choice + * results in a smaller compressed block than dynamic codes. That latter + * condition then assures that the above analysis also covers all dynamic + * blocks. A dynamic-code block will only be chosen to be emitted if it has + * fewer bits than a fixed-code block would for the same set of symbols. + * Therefore its average symbol length is assured to be less than 31. So + * the compressed data for a dynamic block also cannot overwrite the + * symbols from which it is being constructed. + */ + + s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, LIT_BUFS); + s->pending_buf_size = (ulg)s->lit_bufsize * 4; + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } +#ifdef LIT_MEM + s->d_buf = (ushf *)(s->pending_buf + (s->lit_bufsize << 1)); + s->l_buf = s->pending_buf + (s->lit_bufsize << 2); + s->sym_end = s->lit_bufsize - 1; +#else + s->sym_buf = s->pending_buf + s->lit_bufsize; + s->sym_end = (s->lit_bufsize - 1) * 3; +#endif + /* We avoid equality with lit_bufsize*3 because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= + * Check for a valid deflate stream state. Return 0 if ok, 1 if not. + */ +local int deflateStateCheck(z_streamp strm) { + deflate_state *s; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + s = strm->state; + if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE && +#ifdef GZIP + s->status != GZIP_STATE && +#endif + s->status != EXTRA_STATE && + s->status != NAME_STATE && + s->status != COMMENT_STATE && + s->status != HCRC_STATE && + s->status != BUSY_STATE && + s->status != FINISH_STATE)) + return 1; + return 0; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary(z_streamp strm, const Bytef *dictionary, + uInt dictLength) { + deflate_state *s; + uInt str, n; + int wrap; + unsigned avail; + z_const unsigned char *next; + + if (deflateStateCheck(strm) || dictionary == Z_NULL) + return Z_STREAM_ERROR; + s = strm->state; + wrap = s->wrap; + if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) + return Z_STREAM_ERROR; + + /* when using zlib wrappers, compute Adler-32 for provided dictionary */ + if (wrap == 1) + strm->adler = adler32(strm->adler, dictionary, dictLength); + s->wrap = 0; /* avoid computing Adler-32 in read_buf */ + + /* if dictionary would fill window, just replace the history */ + if (dictLength >= s->w_size) { + if (wrap == 0) { /* already empty otherwise */ + CLEAR_HASH(s); + s->strstart = 0; + s->block_start = 0L; + s->insert = 0; + } + dictionary += dictLength - s->w_size; /* use the tail */ + dictLength = s->w_size; + } + + /* insert dictionary into window and hash */ + avail = strm->avail_in; + next = strm->next_in; + strm->avail_in = dictLength; + strm->next_in = (z_const Bytef *)dictionary; + fill_window(s); + while (s->lookahead >= MIN_MATCH) { + str = s->strstart; + n = s->lookahead - (MIN_MATCH-1); + do { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + } while (--n); + s->strstart = str; + s->lookahead = MIN_MATCH-1; + fill_window(s); + } + s->strstart += s->lookahead; + s->block_start = (long)s->strstart; + s->insert = s->lookahead; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + strm->next_in = next; + strm->avail_in = avail; + s->wrap = wrap; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateGetDictionary(z_streamp strm, Bytef *dictionary, + uInt *dictLength) { + deflate_state *s; + uInt len; + + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + s = strm->state; + len = s->strstart + s->lookahead; + if (len > s->w_size) + len = s->w_size; + if (dictionary != Z_NULL && len) + zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len); + if (dictLength != Z_NULL) + *dictLength = len; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateResetKeep(z_streamp strm) { + deflate_state *s; + + if (deflateStateCheck(strm)) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = +#ifdef GZIP + s->wrap == 2 ? GZIP_STATE : +#endif + INIT_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = -2; + + _tr_init(s); + + return Z_OK; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init(deflate_state *s) { + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->insert = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset(z_streamp strm) { + int ret; + + ret = deflateResetKeep(strm); + if (ret == Z_OK) + lm_init(strm->state); + return ret; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader(z_streamp strm, gz_headerp head) { + if (deflateStateCheck(strm) || strm->state->wrap != 2) + return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePending(z_streamp strm, unsigned *pending, int *bits) { + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + if (pending != Z_NULL) + *pending = strm->state->pending; + if (bits != Z_NULL) + *bits = strm->state->bi_valid; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime(z_streamp strm, int bits, int value) { + deflate_state *s; + int put; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + s = strm->state; +#ifdef LIT_MEM + if (bits < 0 || bits > 16 || + (uchf *)s->d_buf < s->pending_out + ((Buf_size + 7) >> 3)) + return Z_BUF_ERROR; +#else + if (bits < 0 || bits > 16 || + s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3)) + return Z_BUF_ERROR; +#endif + do { + put = Buf_size - s->bi_valid; + if (put > bits) + put = bits; + s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); + s->bi_valid += put; + _tr_flush_bits(s); + value >>= put; + bits -= put; + } while (bits); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(z_streamp strm, int level, int strategy) { + deflate_state *s; + compress_func func; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if ((strategy != s->strategy || func != configuration_table[level].func) && + s->last_flush != -2) { + /* Flush the last buffer: */ + int err = deflate(strm, Z_BLOCK); + if (err == Z_STREAM_ERROR) + return err; + if (strm->avail_in || (s->strstart - s->block_start) + s->lookahead) + return Z_BUF_ERROR; + } + if (s->level != level) { + if (s->level == 0 && s->matches != 0) { + if (s->matches == 1) + slide_hash(s); + else + CLEAR_HASH(s); + s->matches = 0; + } + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(z_streamp strm, int good_length, int max_lazy, + int nice_length, int max_chain) { + deflate_state *s; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = (uInt)good_length; + s->max_lazy_match = (uInt)max_lazy; + s->nice_match = nice_length; + s->max_chain_length = (uInt)max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns a + * close to exact, as well as small, upper bound on the compressed size. This + * is an expansion of ~0.03%, plus a small constant. + * + * For any setting other than those defaults for windowBits and memLevel, one + * of two worst case bounds is returned. This is at most an expansion of ~4% or + * ~13%, plus a small constant. + * + * Both the 0.03% and 4% derive from the overhead of stored blocks. The first + * one is for stored blocks of 16383 bytes (memLevel == 8), whereas the second + * is for stored blocks of 127 bytes (the worst case memLevel == 1). The + * expansion results from five bytes of header for each stored block. + * + * The larger expansion of 13% results from a window size less than or equal to + * the symbols buffer size (windowBits <= memLevel + 7). In that case some of + * the data being compressed may have slid out of the sliding window, impeding + * a stored block from being emitted. Then the only choice is a fixed or + * dynamic block, where a fixed block limits the maximum expansion to 9 bits + * per 8-bit byte, plus 10 bits for every block. The smallest block size for + * which this can occur is 255 (memLevel == 2). + * + * Shifts are used to approximate divisions, for speed. + */ +uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen) { + deflate_state *s; + uLong fixedlen, storelen, wraplen; + + /* upper bound for fixed blocks with 9-bit literals and length 255 + (memLevel == 2, which is the lowest that may not use stored blocks) -- + ~13% overhead plus a small constant */ + fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) + + (sourceLen >> 9) + 4; + + /* upper bound for stored blocks with length 127 (memLevel == 1) -- + ~4% overhead plus a small constant */ + storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) + + (sourceLen >> 11) + 7; + + /* if can't get parameters, return larger bound plus a zlib wrapper */ + if (deflateStateCheck(strm)) + return (fixedlen > storelen ? fixedlen : storelen) + 6; + + /* compute wrapper length */ + s = strm->state; + switch (s->wrap) { + case 0: /* raw deflate */ + wraplen = 0; + break; + case 1: /* zlib wrapper */ + wraplen = 6 + (s->strstart ? 4 : 0); + break; +#ifdef GZIP + case 2: /* gzip wrapper */ + wraplen = 18; + if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ + Bytef *str; + if (s->gzhead->extra != Z_NULL) + wraplen += 2 + s->gzhead->extra_len; + str = s->gzhead->name; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + str = s->gzhead->comment; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + if (s->gzhead->hcrc) + wraplen += 2; + } + break; +#endif + default: /* for compiler happiness */ + wraplen = 6; + } + + /* if not default parameters, return one of the conservative bounds */ + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return (s->w_bits <= s->hash_bits && s->level ? fixedlen : storelen) + + wraplen; + + /* default settings: return tight bound for that case -- ~0.03% overhead + plus a small constant */ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13 - 6 + wraplen; +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB(deflate_state *s, uInt b) { + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output, except for + * some deflate_stored() output, goes through this function so some + * applications may wish to modify it to avoid allocating a large + * strm->next_out buffer and copying into it. (See also read_buf()). + */ +local void flush_pending(z_streamp strm) { + unsigned len; + deflate_state *s = strm->state; + + _tr_flush_bits(s); + len = s->pending; + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, s->pending_out, len); + strm->next_out += len; + s->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + s->pending -= len; + if (s->pending == 0) { + s->pending_out = s->pending_buf; + } +} + +/* =========================================================================== + * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1]. + */ +#define HCRC_UPDATE(beg) \ + do { \ + if (s->gzhead->hcrc && s->pending > (beg)) \ + strm->adler = crc32(strm->adler, s->pending_buf + (beg), \ + s->pending - (beg)); \ + } while (0) + +/* ========================================================================= */ +int ZEXPORT deflate(z_streamp strm, int flush) { + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->avail_in != 0 && strm->next_in == Z_NULL) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + old_flush = s->last_flush; + s->last_flush = flush; + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Write the header */ + if (s->status == INIT_STATE && s->wrap == 0) + s->status = BUSY_STATE; + if (s->status == INIT_STATE) { + /* zlib header */ + uInt header = (Z_DEFLATED + ((s->w_bits - 8) << 4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } +#ifdef GZIP + if (s->status == GZIP_STATE) { + /* gzip header */ + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == Z_NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != Z_NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex; + while (s->pending + left > s->pending_buf_size) { + uInt copy = s->pending_buf_size - s->pending; + zmemcpy(s->pending_buf + s->pending, + s->gzhead->extra + s->gzindex, copy); + s->pending = s->pending_buf_size; + HCRC_UPDATE(beg); + s->gzindex += copy; + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + left -= copy; + } + zmemcpy(s->pending_buf + s->pending, + s->gzhead->extra + s->gzindex, left); + s->pending += left; + HCRC_UPDATE(beg); + s->gzindex = 0; + } + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + int val; + do { + if (s->pending == s->pending_buf_size) { + HCRC_UPDATE(beg); + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + HCRC_UPDATE(beg); + s->gzindex = 0; + } + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + int val; + do { + if (s->pending == s->pending_buf_size) { + HCRC_UPDATE(beg); + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + HCRC_UPDATE(beg); + } + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) { + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + } + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } +#endif + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = s->level == 0 ? deflate_stored(s, flush) : + s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : + s->strategy == Z_RLE ? deflate_rle(s, flush) : + (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + if (s->lookahead == 0) { + s->strstart = 0; + s->block_start = 0L; + s->insert = 0; + } + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd(z_streamp strm) { + int status; + + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; + + status = strm->state->status; + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) { +#ifdef MAXSEG_64K + (void)dest; + (void)source; + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + + + if (deflateStateCheck(source) || dest == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, LIT_BUFS); + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, ds->lit_bufsize * LIT_BUFS); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); +#ifdef LIT_MEM + ds->d_buf = (ushf *)(ds->pending_buf + (ds->lit_bufsize << 1)); + ds->l_buf = ds->pending_buf + (ds->lit_bufsize << 2); +#else + ds->sym_buf = ds->pending_buf + ds->lit_bufsize; +#endif + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +local uInt longest_match(deflate_state *s, IPos cur_match) { + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = (int)s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan + best_len - 1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len - 1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match + best_len - 1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart + 3, + 5, up to strstart + 257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart + 257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window + strstart + 257 */ + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend - scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len - 1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len - 1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart + 258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan + best_len - 1); +#else + scan_end1 = scan[best_len - 1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} + +#else /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for FASTEST only + */ +local uInt longest_match(deflate_state *s, IPos cur_match) { + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len - 1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart + 258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#endif /* FASTEST */ + +#ifdef ZLIB_DEBUG + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(deflate_state *s, IPos start, IPos match, int length) { + /* check that the match is indeed a match */ + Bytef *back = s->window + (int)match, *here = s->window + start; + IPos len = length; + if (match == (IPos)-1) { + /* match starts one byte before the current window -- just compare the + subsequent length-1 bytes */ + back++; + here++; + len--; + } + if (zmemcmp(back, here, len) != EQUAL) { + fprintf(stderr, " start %u, match %d, length %d\n", + start, (int)match, length); + do { + fprintf(stderr, "(%02x %02x)", *back++, *here++); + } while (--len != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start - match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* ZLIB_DEBUG */ + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, last) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (last)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, last) { \ + FLUSH_BLOCK_ONLY(s, last); \ + if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ +} + +/* Maximum stored block length in deflate format (not including header). */ +#define MAX_STORED 65535 + +/* Minimum of a and b. */ +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * + * In case deflateParams() is used to later switch to a non-zero compression + * level, s->matches (otherwise unused when storing) keeps track of the number + * of hash table slides to perform. If s->matches is 1, then one hash table + * slide will be done when switching. If s->matches is 2, the maximum value + * allowed here, then the hash table will be cleared, since two or more slides + * is the same as a clear. + * + * deflate_stored() is written to minimize the number of times an input byte is + * copied. It is most efficient with large input and output buffers, which + * maximizes the opportunities to have a single copy from next_in to next_out. + */ +local block_state deflate_stored(deflate_state *s, int flush) { + /* Smallest worthy block size when not flushing or finishing. By default + * this is 32K. This can be as small as 507 bytes for memLevel == 1. For + * large input and output buffers, the stored block size will be larger. + */ + unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size); + + /* Copy as many min_block or larger stored blocks directly to next_out as + * possible. If flushing, copy the remaining available input to next_out as + * stored blocks, if there is enough space. + */ + unsigned len, left, have, last = 0; + unsigned used = s->strm->avail_in; + do { + /* Set len to the maximum size block that we can copy directly with the + * available input data and output space. Set left to how much of that + * would be copied from what's left in the window. + */ + len = MAX_STORED; /* maximum deflate stored block length */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + if (s->strm->avail_out < have) /* need room for header */ + break; + /* maximum stored block length that will fit in avail_out: */ + have = s->strm->avail_out - have; + left = s->strstart - s->block_start; /* bytes left in window */ + if (len > (ulg)left + s->strm->avail_in) + len = left + s->strm->avail_in; /* limit len to the input */ + if (len > have) + len = have; /* limit len to the output */ + + /* If the stored block would be less than min_block in length, or if + * unable to copy all of the available input when flushing, then try + * copying to the window and the pending buffer instead. Also don't + * write an empty block when flushing -- deflate() does that. + */ + if (len < min_block && ((len == 0 && flush != Z_FINISH) || + flush == Z_NO_FLUSH || + len != left + s->strm->avail_in)) + break; + + /* Make a dummy stored block in pending to get the header bytes, + * including any pending bits. This also updates the debugging counts. + */ + last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0; + _tr_stored_block(s, (char *)0, 0L, last); + + /* Replace the lengths in the dummy stored block with len. */ + s->pending_buf[s->pending - 4] = len; + s->pending_buf[s->pending - 3] = len >> 8; + s->pending_buf[s->pending - 2] = ~len; + s->pending_buf[s->pending - 1] = ~len >> 8; + + /* Write the stored block header bytes. */ + flush_pending(s->strm); + +#ifdef ZLIB_DEBUG + /* Update debugging counts for the data about to be copied. */ + s->compressed_len += len << 3; + s->bits_sent += len << 3; +#endif + + /* Copy uncompressed bytes from the window to next_out. */ + if (left) { + if (left > len) + left = len; + zmemcpy(s->strm->next_out, s->window + s->block_start, left); + s->strm->next_out += left; + s->strm->avail_out -= left; + s->strm->total_out += left; + s->block_start += left; + len -= left; + } + + /* Copy uncompressed bytes directly from next_in to next_out, updating + * the check value. + */ + if (len) { + read_buf(s->strm, s->strm->next_out, len); + s->strm->next_out += len; + s->strm->avail_out -= len; + s->strm->total_out += len; + } + } while (last == 0); + + /* Update the sliding window with the last s->w_size bytes of the copied + * data, or append all of the copied data to the existing window if less + * than s->w_size bytes were copied. Also update the number of bytes to + * insert in the hash tables, in the event that deflateParams() switches to + * a non-zero compression level. + */ + used -= s->strm->avail_in; /* number of input bytes directly copied */ + if (used) { + /* If any input was used, then no unused input remains in the window, + * therefore s->block_start == s->strstart. + */ + if (used >= s->w_size) { /* supplant the previous history */ + s->matches = 2; /* clear hash */ + zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); + s->strstart = s->w_size; + s->insert = s->strstart; + } + else { + if (s->window_size - s->strstart <= used) { + /* Slide the window down. */ + s->strstart -= s->w_size; + zmemcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + if (s->insert > s->strstart) + s->insert = s->strstart; + } + zmemcpy(s->window + s->strstart, s->strm->next_in - used, used); + s->strstart += used; + s->insert += MIN(used, s->w_size - s->insert); + } + s->block_start = s->strstart; + } + if (s->high_water < s->strstart) + s->high_water = s->strstart; + + /* If the last block was written to next_out, then done. */ + if (last) + return finish_done; + + /* If flushing and all input has been consumed, then done. */ + if (flush != Z_NO_FLUSH && flush != Z_FINISH && + s->strm->avail_in == 0 && (long)s->strstart == s->block_start) + return block_done; + + /* Fill the window with any remaining input. */ + have = s->window_size - s->strstart; + if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) { + /* Slide the window down. */ + s->block_start -= s->w_size; + s->strstart -= s->w_size; + zmemcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + have += s->w_size; /* more space now */ + if (s->insert > s->strstart) + s->insert = s->strstart; + } + if (have > s->strm->avail_in) + have = s->strm->avail_in; + if (have) { + read_buf(s->strm, s->window + s->strstart, have); + s->strstart += have; + s->insert += MIN(have, s->w_size - s->insert); + } + if (s->high_water < s->strstart) + s->high_water = s->strstart; + + /* There was not enough avail_out to write a complete worthy or flushed + * stored block to next_out. Write a stored block to pending instead, if we + * have enough input for a worthy block, or if flushing and there is enough + * room for the remaining input as a stored block in the pending buffer. + */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + /* maximum stored block length that will fit in pending: */ + have = MIN(s->pending_buf_size - have, MAX_STORED); + min_block = MIN(have, s->w_size); + left = s->strstart - s->block_start; + if (left >= min_block || + ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && + s->strm->avail_in == 0 && left <= have)) { + len = MIN(left, have); + last = flush == Z_FINISH && s->strm->avail_in == 0 && + len == left ? 1 : 0; + _tr_stored_block(s, (charf *)s->window + s->block_start, len, last); + s->block_start += len; + flush_pending(s->strm); + } + + /* We've done all we can with the available input and output. */ + return last ? finish_started : need_more; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(deflate_state *s, int flush) { + IPos hash_head; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart + 2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit(s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(deflate_state *s, int flush) { + IPos hash_head; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart + 2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart - 1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart - 1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart - 1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length - 1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); + s->match_available = 0; + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} +#endif /* FASTEST */ + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(deflate_state *s, int flush) { + int bflush; /* set if current block must be flushed */ + uInt prev; /* byte at distance one to match */ + Bytef *scan, *strend; /* scan goes up to strend for length of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest run, plus one for the unrolled loop. + */ + if (s->lookahead <= MAX_MATCH) { + fill_window(s); + if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s->match_length = 0; + if (s->lookahead >= MIN_MATCH && s->strstart > 0) { + scan = s->window + s->strstart - 1; + prev = *scan; + if (prev == *++scan && prev == *++scan && prev == *++scan) { + strend = s->window + s->strstart + MAX_MATCH; + do { + } while (prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + scan < strend); + s->match_length = MAX_MATCH - (uInt)(strend - scan); + if (s->match_length > s->lookahead) + s->match_length = s->lookahead; + } + Assert(scan <= s->window + (uInt)(s->window_size - 1), + "wild scan"); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, s->match_length); + + _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + s->strstart += s->match_length; + s->match_length = 0; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit(s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +local block_state deflate_huff(deflate_state *s, int flush) { + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s->lookahead == 0) { + fill_window(s); + if (s->lookahead == 0) { + if (flush == Z_NO_FLUSH) + return need_more; + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + s->match_length = 0; + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit(s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->sym_next) + FLUSH_BLOCK(s, 0); + return block_done; +} diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/deflate.h b/Ghidra/Features/Decompiler/src/decompile/zlib/deflate.h new file mode 100644 index 00000000000..c7a973dc3f1 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/deflate.h @@ -0,0 +1,381 @@ +/* ### + * IP: zlib License + * NOTE: from zlib 1.3.1 + */ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2024 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* define LIT_MEM to slightly increase the speed of deflate (order 1% to 2%) at + the cost of a larger memory footprint */ +/* #define LIT_MEM */ + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define Buf_size 16 +/* size of bit buffer in bi_buf */ + +#define INIT_STATE 42 /* zlib header -> BUSY_STATE */ +#ifdef GZIP +# define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */ +#endif +#define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */ +#define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */ +#define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */ +#define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */ +#define BUSY_STATE 113 /* deflate -> FINISH_STATE */ +#define FINISH_STATE 666 /* stream complete */ +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + const static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + ulg pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + ulg gzindex; /* where in extra, name, or comment */ + Byte method; /* can only be DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to suppress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + +#ifdef LIT_MEM +# define LIT_BUFS 5 + ushf *d_buf; /* buffer for distances */ + uchf *l_buf; /* buffer for literals/lengths */ +#else +# define LIT_BUFS 4 + uchf *sym_buf; /* buffer for distances and literals/lengths */ +#endif + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt sym_next; /* running index in symbol buffer */ + uInt sym_end; /* symbol table full when sym_next reaches this */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + uInt insert; /* bytes at end of window left to insert */ + +#ifdef ZLIB_DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + ulg high_water; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + +#define WIN_INIT MAX_MATCH +/* Number of bytes after end of data in window to initialize in order to avoid + memory checker errors from longest match routines */ + + /* in trees.c */ +void ZLIB_INTERNAL _tr_init(deflate_state *s); +int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc); +void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf, + ulg stored_len, int last); +void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s); +void ZLIB_INTERNAL _tr_align(deflate_state *s); +void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, + ulg stored_len, int last); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef ZLIB_DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch ZLIB_INTERNAL _length_code[]; + extern uch ZLIB_INTERNAL _dist_code[]; +#else + extern const uch ZLIB_INTERNAL _length_code[]; + extern const uch ZLIB_INTERNAL _dist_code[]; +#endif + +#ifdef LIT_MEM +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->sym_next] = 0; \ + s->l_buf[s->sym_next++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (uch)(length); \ + ush dist = (ush)(distance); \ + s->d_buf[s->sym_next] = dist; \ + s->l_buf[s->sym_next++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } +#else +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->sym_buf[s->sym_next++] = 0; \ + s->sym_buf[s->sym_next++] = 0; \ + s->sym_buf[s->sym_next++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (uch)(length); \ + ush dist = (ush)(distance); \ + s->sym_buf[s->sym_next++] = (uch)dist; \ + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); \ + s->sym_buf[s->sym_next++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->sym_next == s->sym_end); \ + } +#endif +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/gzguts.h b/Ghidra/Features/Decompiler/src/decompile/zlib/gzguts.h new file mode 100644 index 00000000000..e4e25c4d612 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/gzguts.h @@ -0,0 +1,218 @@ +/* ### + * IP: zlib License + * NOTE: from zlib 1.3.1 + */ +/* gzguts.h -- zlib internal header definitions for gz* operations + * Copyright (C) 2004-2024 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef _LARGEFILE64_SOURCE +# ifndef _LARGEFILE_SOURCE +# define _LARGEFILE_SOURCE 1 +# endif +# undef _FILE_OFFSET_BITS +# undef _TIME_BITS +#endif + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include +#include "zlib.h" +#ifdef STDC +# include +# include +# include +#endif + +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +#endif +#include + +#ifdef _WIN32 +# include +#endif + +#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) +# include +#endif + +#if defined(_WIN32) +# define WIDECHAR +#endif + +#ifdef WINAPI_FAMILY +# define open _open +# define read _read +# define write _write +# define close _close +#endif + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS +/* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 +/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +# ifdef VMS +# define NO_vsnprintf +# endif +# ifdef __OS400__ +# define NO_vsnprintf +# endif +# ifdef __MVS__ +# define NO_vsnprintf +# endif +#endif + +/* unlike snprintf (which is required in C99), _snprintf does not guarantee + null termination of the result -- however this is only used in gzlib.c where + the result is assured to fit in the space provided */ +#if defined(_MSC_VER) && _MSC_VER < 1900 +# define snprintf _snprintf +#endif + +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +/* gz* functions always use library allocation functions */ +#ifndef STDC + extern voidp malloc(uInt size); + extern void free(voidpf ptr); +#endif + +/* get errno and strerror definition */ +#if defined UNDER_CE +# include +# define zstrerror() gz_strwinerror((DWORD)GetLastError()) +#else +# ifndef NO_STRERROR +# include +# define zstrerror() strerror(errno) +# else +# define zstrerror() "stdio error (consult errno)" +# endif +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int); + ZEXTERN z_off64_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile); +#endif + +/* default memLevel */ +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif + +/* default i/o buffer size -- double this for output when reading (this and + twice this must be able to fit in an unsigned type) */ +#define GZBUFSIZE 8192 + +/* gzip modes, also provide a little integrity check on the passed structure */ +#define GZ_NONE 0 +#define GZ_READ 7247 +#define GZ_WRITE 31153 +#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ + +/* values for gz_state how */ +#define LOOK 0 /* look for a gzip header */ +#define COPY 1 /* copy input directly */ +#define GZIP 2 /* decompress a gzip stream */ + +/* internal gzip file state data structure */ +typedef struct { + /* exposed contents for gzgetc() macro */ + struct gzFile_s x; /* "x" for exposed */ + /* x.have: number of bytes available at x.next */ + /* x.next: next output data to deliver or write */ + /* x.pos: current position in uncompressed data */ + /* used for both reading and writing */ + int mode; /* see gzip modes above */ + int fd; /* file descriptor */ + char *path; /* path or fd for error messages */ + unsigned size; /* buffer size, zero if not allocated yet */ + unsigned want; /* requested buffer size, default is GZBUFSIZE */ + unsigned char *in; /* input buffer (double-sized when writing) */ + unsigned char *out; /* output buffer (double-sized when reading) */ + int direct; /* 0 if processing gzip, 1 if transparent */ + /* just for reading */ + int how; /* 0: get header, 1: copy, 2: decompress */ + z_off64_t start; /* where the gzip data started, for rewinding */ + int eof; /* true if end of input file reached */ + int past; /* true if read requested past end */ + /* just for writing */ + int level; /* compression level */ + int strategy; /* compression strategy */ + int reset; /* true if a reset is pending after a Z_FINISH */ + /* seek request */ + z_off64_t skip; /* amount to skip (already rewound if backwards) */ + int seek; /* true if seek request pending */ + /* error information */ + int err; /* error code */ + char *msg; /* error message */ + /* zlib inflate or deflate stream */ + z_stream strm; /* stream structure in-place (not a pointer) */ +} gz_state; +typedef gz_state FAR *gz_statep; + +/* shared functions */ +void ZLIB_INTERNAL gz_error(gz_statep, int, const char *); +#if defined UNDER_CE +char ZLIB_INTERNAL *gz_strwinerror(DWORD error); +#endif + +/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t + value -- needed when comparing unsigned to z_off64_t, which is signed + (possible z_off64_t types off_t, off64_t, and long are all signed) */ +unsigned ZLIB_INTERNAL gz_intmax(void); +#define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/inffast.c b/Ghidra/Features/Decompiler/src/decompile/zlib/inffast.c new file mode 100644 index 00000000000..aab1cdcb39a --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/inffast.c @@ -0,0 +1,324 @@ +/* ### + * IP: zlib License + * NOTE: from zlib 1.3.1 + */ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2017 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef ASMINF +# pragma message("Assembler code may have bugs -- use at your own risk") +#else + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) { + struct inflate_state FAR *state; + z_const unsigned char FAR *in; /* local strm->next_in */ + z_const unsigned char FAR *last; /* have enough input while in < last */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code const *here; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in; + last = in + (strm->avail_in - 5); + out = strm->next_out; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + wnext = state->wnext; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + here = lcode + (hold & lmask); + dolen: + op = (unsigned)(here->bits); + hold >>= op; + bits -= op; + op = (unsigned)(here->op); + if (op == 0) { /* literal */ + Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here->val)); + *out++ = (unsigned char)(here->val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(here->val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + here = dcode + (hold & dmask); + dodist: + op = (unsigned)(here->bits); + hold >>= op; + bits -= op; + op = (unsigned)(here->op); + if (op & 16) { /* distance base */ + dist = (unsigned)(here->val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(*in++) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state->sane) { + strm->msg = + (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (len <= op - whave) { + do { + *out++ = 0; + } while (--len); + continue; + } + len -= op - whave; + do { + *out++ = 0; + } while (--op > whave); + if (op == 0) { + from = out - dist; + do { + *out++ = *from++; + } while (--len); + continue; + } +#endif + } + from = window; + if (wnext == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = window; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + *out++ = *from++; + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; + len -= 3; + } while (len > 2); + if (len) { + *out++ = *from++; + if (len > 1) + *out++ = *from++; + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + here = dcode + here->val + (hold & ((1U << op) - 1)); + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + here = lcode + here->val + (hold & ((1U << op) - 1)); + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in; + strm->next_out = out; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and wnext == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/inffast.h b/Ghidra/Features/Decompiler/src/decompile/zlib/inffast.h new file mode 100644 index 00000000000..0fc61bb234b --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/inffast.h @@ -0,0 +1,15 @@ +/* ### + * IP: zlib License + * NOTE: from zlib 1.3.1 + */ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start); diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/inffixed.h b/Ghidra/Features/Decompiler/src/decompile/zlib/inffixed.h new file mode 100644 index 00000000000..485f0ba9632 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/inffixed.h @@ -0,0 +1,98 @@ +/* ### + * IP: zlib License + * NOTE: from zlib 1.3.1 + */ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/inflate.c b/Ghidra/Features/Decompiler/src/decompile/zlib/inflate.c new file mode 100644 index 00000000000..f1ffd195084 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/inflate.c @@ -0,0 +1,1530 @@ +/* ### + * IP: zlib License + * NOTE: from zlib 1.3.1 + */ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2022 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common wnext == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +local int inflateStateCheck(z_streamp strm) { + struct inflate_state FAR *state; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + state = (struct inflate_state FAR *)strm->state; + if (state == Z_NULL || state->strm != strm || + state->mode < HEAD || state->mode > SYNC) + return 1; + return 0; +} + +int ZEXPORT inflateResetKeep(z_streamp strm) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + if (state->wrap) /* to support ill-conceived Java test suite */ + strm->adler = state->wrap & 1; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->flags = -1; + state->dmax = 32768U; + state->head = Z_NULL; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + state->sane = 1; + state->back = -1; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateReset(z_streamp strm) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + state->wsize = 0; + state->whave = 0; + state->wnext = 0; + return inflateResetKeep(strm); +} + +int ZEXPORT inflateReset2(z_streamp strm, int windowBits) { + int wrap; + struct inflate_state FAR *state; + + /* get the state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + if (windowBits < -15) + return Z_STREAM_ERROR; + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 5; +#ifdef GUNZIP + if (windowBits < 48) + windowBits &= 15; +#endif + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) + return Z_STREAM_ERROR; + if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { + ZFREE(strm, state->window); + state->window = Z_NULL; + } + + /* update state and reset the rest of it */ + state->wrap = wrap; + state->wbits = (unsigned)windowBits; + return inflateReset(strm); +} + +int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, + const char *version, int stream_size) { + int ret; + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->strm = strm; + state->window = Z_NULL; + state->mode = HEAD; /* to pass state test in inflateReset2() */ + ret = inflateReset2(strm, windowBits); + if (ret != Z_OK) { + ZFREE(strm, state); + strm->state = Z_NULL; + } + return ret; +} + +int ZEXPORT inflateInit_(z_streamp strm, const char *version, + int stream_size) { + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +int ZEXPORT inflatePrime(z_streamp strm, int bits, int value) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + if (bits == 0) + return Z_OK; + state = (struct inflate_state FAR *)strm->state; + if (bits < 0) { + state->hold = 0; + state->bits = 0; + return Z_OK; + } + if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += (unsigned)value << state->bits; + state->bits += (uInt)bits; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(struct inflate_state FAR *state) { +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed(void) +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, + state.lencode[low].bits, state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(z_streamp strm, const Bytef *end, unsigned copy) { + struct inflate_state FAR *state; + unsigned dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->wnext = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state->wsize) { + zmemcpy(state->window, end - state->wsize, state->wsize); + state->wnext = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->wnext; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->wnext, end - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, end - copy, copy); + state->wnext = copy; + state->whave = state->wsize; + } + else { + state->wnext += dist; + if (state->wnext == state->wsize) state->wnext = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE_CHECK(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE_CHECK(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(z_streamp strm, int flush) { + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (inflateStateCheck(strm) || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + if (state->wbits == 0) + state->wbits = 15; + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (state->wbits == 0) + state->wbits = len; + if (len > 15 || len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + state->flags = 0; /* indicate zlib header */ + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + /* fallthrough */ + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + /* fallthrough */ + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + /* fallthrough */ + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + /* fallthrough */ + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL && + (len = state->head->extra_len - state->length) < + state->head->extra_max) { + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + /* fallthrough */ + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + /* fallthrough */ + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = (Bytef)len; + } while (len && copy < have); + if ((state->flags & 0x0200) && (state->wrap & 4)) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + /* fallthrough */ + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if ((state->wrap & 4) && hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = ZSWAP32(hold); + INITBITS(); + state->mode = DICT; + /* fallthrough */ + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + /* fallthrough */ + case TYPE: + if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN_; /* decode codes */ + if (flush == Z_TREES) { + DROPBITS(2); + goto inf_leave; + } + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY_; + if (flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case COPY_: + state->mode = COPY; + /* fallthrough */ + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + /* fallthrough */ + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + /* fallthrough */ + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (const code FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN_; + if (flush == Z_TREES) goto inf_leave; + /* fallthrough */ + case LEN_: + state->mode = LEN; + /* fallthrough */ + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + if (state->mode == TYPE) + state->back = -1; + break; + } + state->back = 0; + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + state->length = (unsigned)here.val; + if ((int)(here.op) == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + state->mode = LIT; + break; + } + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->back = -1; + state->mode = TYPE; + break; + } + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(here.op) & 15; + state->mode = LENEXT; + /* fallthrough */ + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->was = state->length; + state->mode = DIST; + /* fallthrough */ + case DIST: + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + state->extra = (unsigned)(here.op) & 15; + state->mode = DISTEXT; + /* fallthrough */ + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + /* fallthrough */ + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->whave) { + if (state->sane) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + Trace((stderr, "inflate.c too far\n")); + copy -= state->whave; + if (copy > state->length) copy = state->length; + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = 0; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; +#endif + } + if (copy > state->wnext) { + copy -= state->wnext; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->wnext - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE_CHECK(state->check, put - out, out); + out = left; + if ((state->wrap & 4) && ( +#ifdef GUNZIP + state->flags ? hold : +#endif + ZSWAP32(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + /* fallthrough */ + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + /* fallthrough */ + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + /* fallthrough */ + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH))) + if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if ((state->wrap & 4) && out) + strm->adler = state->check = + UPDATE_CHECK(state->check, strm->next_out - out, out); + strm->data_type = (int)state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0) + + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(z_streamp strm) { + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateGetDictionary(z_streamp strm, Bytef *dictionary, + uInt *dictLength) { + struct inflate_state FAR *state; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* copy dictionary */ + if (state->whave && dictionary != Z_NULL) { + zmemcpy(dictionary, state->window + state->wnext, + state->whave - state->wnext); + zmemcpy(dictionary + state->whave - state->wnext, + state->window, state->wnext); + } + if (dictLength != Z_NULL) + *dictLength = state->whave; + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(z_streamp strm, const Bytef *dictionary, + uInt dictLength) { + struct inflate_state FAR *state; + unsigned long dictid; + int ret; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary identifier */ + if (state->mode == DICT) { + dictid = adler32(0L, Z_NULL, 0); + dictid = adler32(dictid, dictionary, dictLength); + if (dictid != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + ret = updatewindow(strm, dictionary + dictLength, dictLength); + if (ret) { + state->mode = MEM; + return Z_MEM_ERROR; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(z_streamp strm, gz_headerp head) { + struct inflate_state FAR *state; + + /* check state */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(unsigned FAR *have, const unsigned char FAR *buf, + unsigned len) { + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(z_streamp strm) { + unsigned len; /* number of bytes to look at or looked at */ + int flags; /* temporary to save header status */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold >>= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + if (state->flags == -1) + state->wrap = 0; /* if no header yet, treat as raw */ + else + state->wrap &= ~4; /* no point in computing a check value now */ + flags = state->flags; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->flags = flags; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(z_streamp strm) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) { + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (inflateStateCheck(source) || dest == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); + copy->strm = dest; + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} + +int ZEXPORT inflateUndermine(z_streamp strm, int subvert) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + state->sane = !subvert; + return Z_OK; +#else + (void)subvert; + state->sane = 1; + return Z_DATA_ERROR; +#endif +} + +int ZEXPORT inflateValidate(z_streamp strm, int check) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (check && state->wrap) + state->wrap |= 4; + else + state->wrap &= ~4; + return Z_OK; +} + +long ZEXPORT inflateMark(z_streamp strm) { + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) + return -(1L << 16); + state = (struct inflate_state FAR *)strm->state; + return (long)(((unsigned long)((long)state->back)) << 16) + + (state->mode == COPY ? state->length : + (state->mode == MATCH ? state->was - state->length : 0)); +} + +unsigned long ZEXPORT inflateCodesUsed(z_streamp strm) { + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) return (unsigned long)-1; + state = (struct inflate_state FAR *)strm->state; + return (unsigned long)(state->next - state->codes); +} diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/inflate.h b/Ghidra/Features/Decompiler/src/decompile/zlib/inflate.h new file mode 100644 index 00000000000..ef28a24bda2 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/inflate.h @@ -0,0 +1,130 @@ +/* ### + * IP: zlib License + * NOTE: from zlib 1.3.1 + */ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2019 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD = 16180, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY_, /* i/o: same as COPY below, but only first time in */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN_, /* i: same as LEN below, but only first time in */ + LEN, /* i: waiting for length/lit/eob code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to BAD or MEM on error -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) or (raw) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> + HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + (raw) -> TYPEDO + Read deflate blocks: + TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK + STORED -> COPY_ -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN_ + LEN_ -> LEN + Read deflate codes in fixed or dynamic block: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* State maintained between inflate() calls -- approximately 7K bytes, not + including the allocated sliding window, which is up to 32K bytes. */ +struct inflate_state { + z_streamp strm; /* pointer back to this zlib stream */ + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip, + bit 2 true to validate check value */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags, 0 if zlib, or + -1 if raw or no header yet */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ + int sane; /* if false, allow invalid distance too far */ + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ +}; diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/inftrees.c b/Ghidra/Features/Decompiler/src/decompile/zlib/inftrees.c new file mode 100644 index 00000000000..b71204d4d95 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/inftrees.c @@ -0,0 +1,303 @@ +/* ### + * IP: zlib License + * NOTE: from zlib 1.3.1 + */ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2024 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.3.1 Copyright 1995-2024 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work) { + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code here; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + unsigned match; /* use base and extra for symbol >= match */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 203, 77}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)1; + here.val = (unsigned short)0; + *(*table)++ = here; /* make a table to force an error */ + *(*table)++ = here; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + match = 20; + break; + case LENS: + base = lbase; + extra = lext; + match = 257; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + match = 0; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + here.bits = (unsigned char)(len - drop); + if (work[sym] + 1U < match) { + here.op = (unsigned char)0; + here.val = work[sym]; + } + else if (work[sym] >= match) { + here.op = (unsigned char)(extra[work[sym] - match]); + here.val = base[work[sym] - match]; + } + else { + here.op = (unsigned char)(32 + 64); /* end of block */ + here.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = here; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff != 0) { + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)(len - drop); + here.val = (unsigned short)0; + next[huff] = here; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/inftrees.h b/Ghidra/Features/Decompiler/src/decompile/zlib/inftrees.h new file mode 100644 index 00000000000..a44a98631a5 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/inftrees.h @@ -0,0 +1,66 @@ +/* ### + * IP: zlib License + * NOTE: from zlib 1.3.1 + */ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1444, which is the sum of 852 for literal/length codes and 592 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns 852, and "enough 30 6 15" for distance codes returns 592. The + initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in inflate.c and infback.c. If the root table size is + changed, then these maximum sizes would be need to be recalculated and + updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 592 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work); diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/trees.c b/Ghidra/Features/Decompiler/src/decompile/zlib/trees.c new file mode 100644 index 00000000000..ab1026313ea --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/trees.c @@ -0,0 +1,1121 @@ +/* ### + * IP: zlib License + * NOTE: from zlib 1.3.1 + */ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2024 Jean-loup Gailly + * detect_data_type() function provided freely by Cosmin Truta, 2006 + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef ZLIB_DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +#ifdef NO_INIT_GLOBAL_POINTERS +# define TCONST +#else +# define TCONST const +#endif + +local TCONST static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local TCONST static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local TCONST static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(unsigned code, int len) { + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(deflate_state *s) { + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(deflate_state *s) { + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef ZLIB_DEBUG + s->bits_sent = (s->bits_sent + 7) & ~7; +#endif +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes(ct_data *tree, int max_code, ushf *bl_count) { + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + unsigned code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + code = (code + bl_count[bits - 1]) << 1; + next_code[bits] = (ush)code; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1, + "inconsistent bit counts"); + Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); + + for (n = 0; n <= max_code; n++) { + int len = tree[n].Len; + if (len == 0) continue; + /* Now reverse the bits */ + tree[n].Code = (ush)bi_reverse(next_code[len]++, len); + + Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", + n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len] - 1)); + } +} + +#ifdef GEN_TREES_H +local void gen_trees_header(void); +#endif + +#ifndef ZLIB_DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* !ZLIB_DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef ZLIB_DEBUG +local void send_bits(deflate_state *s, int value, int length) { + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16 - bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (ush)value << s->bi_valid; + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= (ush)value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !ZLIB_DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = (int)value;\ + s->bi_buf |= (ush)val << s->bi_valid;\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (ush)(value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* ZLIB_DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init(void) { +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ +#ifdef NO_INIT_GLOBAL_POINTERS + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; +#endif + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1 << extra_lbits[code]); n++) { + _length_code[length++] = (uch)code; + } + } + Assert (length == 256, "tr_static_init: length != 256"); + /* Note that the length 255 (match length 258) can be represented + * in two different ways: code 284 + 5 bits or code 285, so we + * overwrite length_code[255] to use the best encoding: + */ + _length_code[length - 1] = (uch)code; + + /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1 << extra_dbits[code]); n++) { + _dist_code[dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: dist != 256"); + dist >>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256 + dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Generate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef ZLIB_DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width) - 1 ? ",\n" : ", ")) + +void gen_trees_header(void) { + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, + "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(deflate_state *s) { + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->sym_next = s->matches = 0; +} + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void ZLIB_INTERNAL _tr_init(deflate_state *s) { + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef ZLIB_DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(deflate_state *s, ct_data *tree, int k) { + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j + 1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(deflate_state *s, tree_desc *desc) { + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max + 1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n - base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (unsigned)(bits + xbits); + if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); + } + if (overflow == 0) return; + + Tracev((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length - 1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits + 1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +#ifdef DUMP_BL_TREE +# include +#endif + +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ +local void build_tree(deflate_state *s, tree_desc *desc) { + ct_data *tree = desc->dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n + 1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2 + 1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree(deflate_state *s, ct_data *tree, int max_code) { + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code + 1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n + 1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree(deflate_state *s, ct_data *tree, int max_code) { + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code + 1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n + 1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count - 3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count - 3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count - 11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(deflate_state *s) { + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except the + * lengths of the bit lengths codes and the 5 + 5 + 4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*((ulg)max_blindex + 1) + 5 + 5 + 4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(deflate_state *s, int lcodes, int dcodes, + int blcodes) { + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes - 1, 5); + send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, + ulg stored_len, int last) { + send_bits(s, (STORED_BLOCK<<1) + last, 3); /* send block type */ + bi_windup(s); /* align on byte boundary */ + put_short(s, (ush)stored_len); + put_short(s, (ush)~stored_len); + if (stored_len) + zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len); + s->pending += stored_len; +#ifdef ZLIB_DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; + s->bits_sent += 2*16; + s->bits_sent += stored_len << 3; +#endif +} + +/* =========================================================================== + * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) + */ +void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s) { + bi_flush(s); +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + */ +void ZLIB_INTERNAL _tr_align(deflate_state *s) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef ZLIB_DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(deflate_state *s, const ct_data *ltree, + const ct_data *dtree) { + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned sx = 0; /* running index in symbol buffers */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->sym_next != 0) do { +#ifdef LIT_MEM + dist = s->d_buf[sx]; + lc = s->l_buf[sx++]; +#else + dist = s->sym_buf[sx++] & 0xff; + dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8; + lc = s->sym_buf[sx++]; +#endif + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code + LITERALS + 1, ltree); /* send length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= (unsigned)base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check for no overlay of pending_buf on needed symbols */ +#ifdef LIT_MEM + Assert(s->pending < 2 * (s->lit_bufsize + sx), "pendingBuf overflow"); +#else + Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow"); +#endif + + } while (sx < s->sym_next); + + send_code(s, END_BLOCK, ltree); +} + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "block list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local int detect_data_type(deflate_state *s) { + /* block_mask is the bit mask of block-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + unsigned long block_mask = 0xf3ffc07fUL; + int n; + + /* Check for non-textual ("block-listed") bytes. */ + for (n = 0; n <= 31; n++, block_mask >>= 1) + if ((block_mask & 1) && (s->dyn_ltree[n].Freq != 0)) + return Z_BINARY; + + /* Check for textual ("allow-listed") bytes. */ + if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 + || s->dyn_ltree[13].Freq != 0) + return Z_TEXT; + for (n = 32; n < LITERALS; n++) + if (s->dyn_ltree[n].Freq != 0) + return Z_TEXT; + + /* There are no "block-listed" or "allow-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and write out the encoded block. + */ +void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf, + ulg stored_len, int last) { + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (s->strm->data_type == Z_UNKNOWN) + s->strm->data_type = detect_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len + 3 + 7) >> 3; + static_lenb = (s->static_len + 3 + 7) >> 3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->sym_next / 3)); + +#ifndef FORCE_STATIC + if (static_lenb <= opt_lenb || s->strategy == Z_FIXED) +#endif + opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len + 4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, last); + + } else if (static_lenb == opt_lenb) { + send_bits(s, (STATIC_TREES<<1) + last, 3); + compress_block(s, (const ct_data *)static_ltree, + (const ct_data *)static_dtree); +#ifdef ZLIB_DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1) + last, 3); + send_all_trees(s, s->l_desc.max_code + 1, s->d_desc.max_code + 1, + max_blindex + 1); + compress_block(s, (const ct_data *)s->dyn_ltree, + (const ct_data *)s->dyn_dtree); +#ifdef ZLIB_DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (last) { + bi_windup(s); +#ifdef ZLIB_DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len >> 3, + s->compressed_len - 7*last)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc) { +#ifdef LIT_MEM + s->d_buf[s->sym_next] = (ush)dist; + s->l_buf[s->sym_next++] = (uch)lc; +#else + s->sym_buf[s->sym_next++] = (uch)dist; + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); + s->sym_buf[s->sym_next++] = (uch)lc; +#endif + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc] + LITERALS + 1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + return (s->sym_next == s->sym_end); +} diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/trees.h b/Ghidra/Features/Decompiler/src/decompile/zlib/trees.h new file mode 100644 index 00000000000..e5e39af3d50 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/trees.h @@ -0,0 +1,132 @@ +/* ### + * IP: zlib License + * NOTE: from zlib 1.3.1 + */ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/zconf.h b/Ghidra/Features/Decompiler/src/decompile/zlib/zconf.h new file mode 100644 index 00000000000..fea8984d91d --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/zconf.h @@ -0,0 +1,547 @@ +/* ### + * IP: zlib License + * NOTE: from zlib 1.3.1 + */ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols and init macros */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define adler32_z z_adler32_z +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define crc32_combine_gen z_crc32_combine_gen +# define crc32_combine_gen64 z_crc32_combine_gen64 +# define crc32_combine_op z_crc32_combine_op +# define crc32_z z_crc32_z +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateGetDictionary z_deflateGetDictionary +# define deflateInit z_deflateInit +# define deflateInit2 z_deflateInit2 +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzfread z_gzfread +# define gzfwrite z_gzfwrite +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzvprintf z_gzvprintf +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit z_inflateBackInit +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCodesUsed z_inflateCodesUsed +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetDictionary z_inflateGetDictionary +# define inflateGetHeader z_inflateGetHeader +# define inflateInit z_inflateInit +# define inflateInit2 z_inflateInit2 +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateResetKeep z_inflateResetKeep +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateValidate z_inflateValidate +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# define uncompress2 z_uncompress2 +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +#ifdef Z_SOLO +# ifdef _WIN64 + typedef unsigned long long z_size_t; +# else + typedef unsigned long z_size_t; +# endif +#else +# define z_longlong long long +# if defined(NO_SIZE_T) + typedef unsigned NO_SIZE_T z_size_t; +# elif defined(STDC) +# include + typedef size_t z_size_t; +# else + typedef unsigned long z_size_t; +# endif +# undef z_longlong +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#ifndef Z_HAVE_UNISTD_H +# ifdef __WATCOMC__ +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_HAVE_UNISTD_H +# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/zlib.h b/Ghidra/Features/Decompiler/src/decompile/zlib/zlib.h new file mode 100644 index 00000000000..bd0cdf22bf4 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/zlib.h @@ -0,0 +1,1942 @@ +/* ### + * IP: zlib License + * NOTE: from zlib 1.3.1 + */ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.3.1, January 22nd, 2024 + + Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.3.1" +#define ZLIB_VERNUM 0x1310 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 3 +#define ZLIB_VER_REVISION 1 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip and raw deflate streams in + memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in the case of corrupted input. +*/ + +typedef voidpf (*alloc_func)(voidpf opaque, uInt items, uInt size); +typedef void (*free_func)(voidpf opaque, voidpf address); + +struct internal_state; + +typedef struct z_stream_s { + z_const Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total number of input bytes read so far */ + + Bytef *next_out; /* next output byte will go here */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total number of bytes output so far */ + + z_const char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text + for deflate, or the decoding state for inflate */ + uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. In that case, zlib is thread-safe. When zalloc and zfree are + Z_NULL on entry to the initialization function, they are set to internal + routines that use the standard library functions malloc() and free(). + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use by the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field for deflate() */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion(void); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit(z_streamp strm, int level); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. total_in, total_out, adler, and msg are initialized. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate(z_streamp strm, int flush); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary. Some output may be provided even if + flush is zero. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. See deflatePending(), + which can be used if desired to determine whether or not there is more output + in that case. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed + codes block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six when the flush marker begins, in order to avoid + repeated flush markers upon calling deflate() again when avail_out == 0. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this + function must be called again with Z_FINISH and more output space (updated + avail_out) but no more input data, until it returns with Z_STREAM_END or an + error. After deflate has returned Z_STREAM_END, the only possible operations + on the stream are deflateReset or deflateEnd. + + Z_FINISH can be used in the first deflate call after deflateInit if all the + compression is to be done in a single step. In order to complete in one + call, avail_out must be at least the value returned by deflateBound (see + below). Then deflate is guaranteed to return Z_STREAM_END. If not enough + output space is provided, deflate will not return Z_STREAM_END, and it must + be called again as described above. + + deflate() sets strm->adler to the Adler-32 checksum of all input read + so far (that is, total_in bytes). If a gzip stream is being generated, then + strm->adler will be the CRC-32 checksum of the input read so far. (See + deflateInit2 below.) + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is + considered binary. This field is only for information purposes and does not + affect the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL or the state was inadvertently written over + by the application), or Z_BUF_ERROR if no progress is possible (for example + avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and + deflate() can be called again with more input and more output space to + continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd(z_streamp strm); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit(z_streamp strm); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. In the current version of inflate, the provided input is not + read or consumed. The allocation of a sliding window will be deferred to + the first call of inflate (if the decompression does not complete on the + first call). If zalloc and zfree are set to Z_NULL, inflateInit updates + them to use default allocation functions. total_in, total_out, adler, and + msg are initialized. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression. + Actual decompression will be done by inflate(). So next_in, and avail_in, + next_out, and avail_out are unused and unchanged. The current + implementation of inflateInit() does not process any header information -- + that is deferred until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate(z_streamp strm, int flush); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), then next_in and avail_in are updated + accordingly, and processing will resume at this point for the next call of + inflate(). + + - Generate more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. If the + caller of inflate() does not provide both available input and available + output space, it is possible that there will be no progress made. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + To assist in this, on return inflate() always sets strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed Adler-32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained unless inflateGetHeader() is used. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + produced so far. The CRC-32 is checked against the gzip trailer, as is the + uncompressed length, modulo 2^32. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value, in which case strm->msg points to a string with a more specific + error), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL, or the state was inadvertently written over + by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR + if no progress was possible or if there was not enough room in the output + buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is to be attempted. +*/ + + +ZEXTERN int ZEXPORT inflateEnd(z_streamp strm); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state + was inconsistent. +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2(z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy); + + This is another version of deflateInit with more compression options. The + fields zalloc, zfree and opaque must be initialized before by the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + For the current implementation of deflate(), a windowBits value of 8 (a + window size of 256 bytes) is not supported. As a result, a request for 8 + will result in 9 (a 512-byte window). In that case, providing 8 to + inflateInit2() will result in an error when the zlib header with 9 is + checked against the initialization of inflate(). The remedy is to not use 8 + with deflateInit2() with this initialization, or at least in that case use 9 + with inflateInit2(). + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute a check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to the appropriate value, + if the operating system was determined at compile time. If a gzip stream is + being written, strm->adler is a CRC-32 instead of an Adler-32. + + For raw deflate or gzip encoding, a request for a 256-byte window is + rejected as invalid, since only the zlib header provides a means of + transmitting the window size to the decompressor. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary(z_streamp strm, + const Bytef *dictionary, + uInt dictLength); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the Adler-32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler-32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + Adler-32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateGetDictionary(z_streamp strm, + Bytef *dictionary, + uInt *dictLength); +/* + Returns the sliding dictionary being maintained by deflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If deflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similarly, if dictLength is Z_NULL, then it is not set. + + deflateGetDictionary() may return a length less than the window size, even + when more than the window size in input has been provided. It may return up + to 258 bytes less in that case, due to how zlib's implementation of deflate + manages the sliding window and lookahead for matches, where matches can be + up to 258 bytes long. If the application needs the last window-size bytes of + input, then that would need to be saved by the application outside of zlib. + + deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateCopy(z_streamp dest, + z_streamp source); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset(z_streamp strm); +/* + This function is equivalent to deflateEnd followed by deflateInit, but + does not free and reallocate the internal compression state. The stream + will leave the compression level and any other attributes that may have been + set unchanged. total_in, total_out, adler, and msg are initialized. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams(z_streamp strm, + int level, + int strategy); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2(). This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression approach (which is a function of the level) or the + strategy is changed, and if there have been any deflate() calls since the + state was initialized or reset, then the input available so far is + compressed with the old level and strategy using deflate(strm, Z_BLOCK). + There are three approaches for the compression levels 0, 1..3, and 4..9 + respectively. The new level and strategy will take effect at the next call + of deflate(). + + If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does + not have enough output space to complete, then the parameter change will not + take effect. In this case, deflateParams() can be called again with the + same parameters and more output space to try again. + + In order to assure a change in the parameters on the first try, the + deflate stream should be flushed using deflate() with Z_BLOCK or other flush + request until strm.avail_out is not zero, before calling deflateParams(). + Then no more input data should be provided before the deflateParams() call. + If this is done, the old level and strategy will be applied to the data + compressed before deflateParams(), and the new level and strategy will be + applied to the data compressed after deflateParams(). + + deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream + state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if + there was not enough output space to complete the compression of the + available input data before a change in the strategy or approach. Note that + in the case of a Z_BUF_ERROR, the parameters are not changed. A return + value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be + retried with more output space. +*/ + +ZEXTERN int ZEXPORT deflateTune(z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound(z_streamp strm, + uLong sourceLen); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +ZEXTERN int ZEXPORT deflatePending(z_streamp strm, + unsigned *pending, + int *bits); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +ZEXTERN int ZEXPORT deflatePrime(z_streamp strm, + int bits, + int value); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader(z_streamp strm, + gz_headerp head); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to the current operating system, with no + extra, name, or comment fields. The gzip header is returned to the default + state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2(z_streamp strm, + int windowBits); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an Adler-32 or a CRC-32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see + below), inflate() will *not* automatically decode concatenated gzip members. + inflate() will return Z_STREAM_END at the end of the gzip member. The state + would need to be reset to continue decoding a subsequent gzip member. This + *must* be done if there is more data after a gzip member, in order for the + decompression to be compliant with the gzip standard (RFC 1952). + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary(z_streamp strm, + const Bytef *dictionary, + uInt dictLength); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler-32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler-32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateGetDictionary(z_streamp strm, + Bytef *dictionary, + uInt *dictLength); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similarly, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateSync(z_streamp strm); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current value of total_in + which indicates where valid compressed data was found. In the error case, + the application may repeatedly call inflateSync, providing more input each + time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy(z_streamp dest, + z_streamp source); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset(z_streamp strm); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + total_in, total_out, adler, and msg are initialized. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2(z_streamp strm, + int windowBits); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. If the window size is changed, then the + memory allocated for the window is freed, and the window will be reallocated + by inflate() if needed. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime(z_streamp strm, + int bits, + int value); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark(z_streamp strm); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above, or -65536 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader(z_streamp strm, + gz_headerp head); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit(z_streamp strm, int windowBits, + unsigned char FAR *window); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func)(void FAR *, + z_const unsigned char FAR * FAR *); +typedef int (*out_func)(void FAR *, unsigned char FAR *, unsigned); + +ZEXTERN int ZEXPORT inflateBack(z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the default + behavior of inflate(), which expects a zlib header and trailer around the + deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero -- buf is ignored in that + case -- and inflateBack() will return a buffer error. inflateBack() will + call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. + out() should return zero on success, or non-zero on failure. If out() + returns non-zero, inflateBack() will return with an error. Neither in() nor + out() are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd(z_streamp strm); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags(void); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: ZLIB_DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + +#ifndef Z_SOLO + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. compress() is equivalent to compress2() with a level + parameter of Z_DEFAULT_COMPRESSION. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed data. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound(uLong sourceLen); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed data. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + +ZEXTERN int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong *sourceLen); +/* + Same as uncompress, except that sourceLen is a pointer, where the + length of the source is *sourceLen. On return, *sourceLen is the number of + source bytes consumed. +*/ + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode); + + Open the gzip (.gz) file at path for reading and decompressing, or + compressing and writing. The mode parameter is as in fopen ("rb" or "wb") + but can also include a compression level ("wb9") or a strategy: 'f' for + filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", + 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression + as in "wb9F". (See the description of deflateInit2 for more information + about the strategy parameter.) 'T' will request transparent writing or + appending with no compression and not using the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen(int fd, const char *mode); +/* + Associate a gzFile with the file descriptor fd. File descriptors are + obtained from calls like open, dup, creat, pipe or fileno (if the file has + been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer(gzFile file, unsigned size); +/* + Set the internal buffer size used by this library's functions for file to + size. The default buffer size is 8192 bytes. This function must be called + after gzopen() or gzdopen(), and before any other calls that read or write + the file. The buffer memory allocation is always deferred to the first read + or write. Three times that size in buffer space is allocated. A larger + buffer size of, for example, 64K or 128K bytes will noticeably increase the + speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams(gzFile file, int level, int strategy); +/* + Dynamically update the compression level and strategy for file. See the + description of deflateInit2 for the meaning of these parameters. Previously + provided data is flushed before applying the parameter changes. + + gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not + opened for writing, Z_ERRNO if there is an error writing the flushed data, + or Z_MEM_ERROR if there is a memory allocation error. +*/ + +ZEXTERN int ZEXPORT gzread(gzFile file, voidp buf, unsigned len); +/* + Read and decompress up to len uncompressed bytes from file into buf. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. If len is too large to fit in an int, + then nothing is read, -1 is returned, and the error state is set to + Z_STREAM_ERROR. +*/ + +ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, + gzFile file); +/* + Read and decompress up to nitems items of size size from file into buf, + otherwise operating as gzread() does. This duplicates the interface of + stdio's fread(), with size_t request and return types. If the library + defines size_t, then z_size_t is identical to size_t. If not, then z_size_t + is an unsigned integer type that can contain a pointer. + + gzfread() returns the number of full items read of size size, or zero if + the end of the file was reached and a full item could not be read, or if + there was an error. gzerror() must be consulted if zero is returned in + order to determine if there was an error. If the multiplication of size and + nitems overflows, i.e. the product does not fit in a z_size_t, then nothing + is read, zero is returned, and the error state is set to Z_STREAM_ERROR. + + In the event that the end of file is reached and only a partial item is + available at the end, i.e. the remaining uncompressed data length is not a + multiple of size, then the final partial item is nevertheless read into buf + and the end-of-file flag is set. The length of the partial item read is not + provided, but could be inferred from the result of gztell(). This behavior + is the same as the behavior of fread() implementations in common libraries, + but it prevents the direct use of gzfread() to read a concurrently written + file, resetting and retrying on end-of-file, when size is not 1. +*/ + +ZEXTERN int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len); +/* + Compress and write the len uncompressed bytes at buf to file. gzwrite + returns the number of uncompressed bytes written or 0 in case of error. +*/ + +ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, + z_size_t nitems, gzFile file); +/* + Compress and write nitems items of size size from buf to file, duplicating + the interface of stdio's fwrite(), with size_t request and return types. If + the library defines size_t, then z_size_t is identical to size_t. If not, + then z_size_t is an unsigned integer type that can contain a pointer. + + gzfwrite() returns the number of full items written of size size, or zero + if there was an error. If the multiplication of size and nitems overflows, + i.e. the product does not fit in a z_size_t, then nothing is written, zero + is returned, and the error state is set to Z_STREAM_ERROR. +*/ + +ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...); +/* + Convert, format, compress, and write the arguments (...) to file under + control of the string format, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or a negative zlib error code in case + of error. The number of uncompressed bytes written is limited to 8191, or + one less than the buffer size given to gzbuffer(). The caller should assure + that this limit is not exceeded. If it is exceeded, then gzprintf() will + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf(), + because the secure snprintf() or vsnprintf() functions were not available. + This can be determined using zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs(gzFile file, const char *s); +/* + Compress and write the given null-terminated string s to file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len); +/* + Read and decompress bytes from file into buf, until len-1 characters are + read, or until a newline character is read and transferred to buf, or an + end-of-file condition is encountered. If any characters are read or if len + is one, the string is terminated with a null character. If no characters + are read due to an end-of-file or len is less than one, then the buffer is + left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc(gzFile file, int c); +/* + Compress and write c, converted to an unsigned char, into file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc(gzFile file); +/* + Read and decompress one byte from file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +ZEXTERN int ZEXPORT gzungetc(int c, gzFile file); +/* + Push c back onto the stream for file to be read as the first character on + the next read. At least one character of push-back is always allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush(gzFile file, int flush); +/* + Flush all pending output to file. The parameter flush is as in the + deflate() function. The return value is the zlib error number (see function + gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatenated gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek(gzFile file, + z_off_t offset, int whence); + + Set the starting position to offset relative to whence for the next gzread + or gzwrite on file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind(gzFile file); +/* + Rewind file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET). +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell(gzFile file); + + Return the starting position for the next gzread or gzwrite on file. + This position represents a number of bytes in the uncompressed data stream, + and is zero when starting, even if appending or reading a gzip stream from + the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset(gzFile file); + + Return the current compressed (actual) read or write offset of file. This + offset includes the count of bytes that precede the gzip stream, for example + when appending or when using gzdopen() for reading. When reading, the + offset does not include as yet unused buffered input. This information can + be used for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof(gzFile file); +/* + Return true (1) if the end-of-file indicator for file has been set while + reading, false (0) otherwise. Note that the end-of-file indicator is set + only if the read tried to go past the end of the input, but came up short. + Therefore, just like feof(), gzeof() may return false even if there is no + more data to read, in the event that the last read request was for the exact + number of bytes remaining in the input file. This will happen if the input + file size is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect(gzFile file); +/* + Return true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +ZEXTERN int ZEXPORT gzclose(gzFile file); +/* + Flush all pending output for file, if necessary, close file and + deallocate the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r(gzFile file); +ZEXTERN int ZEXPORT gzclose_w(gzFile file); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror(gzFile file, int *errnum); +/* + Return the error message for the last error which occurred on file. + errnum is set to zlib error number. If an error occurred in the file system + and not in the compression library, errnum is set to Z_ERRNO and the + application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr(gzFile file); +/* + Clear the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif /* !Z_SOLO */ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. An Adler-32 value is in the range of a 32-bit + unsigned integer. If buf is Z_NULL, this function returns the required + initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, + z_size_t len); +/* + Same as adler32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, + z_off_t len2); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +ZEXTERN uLong ZEXPORT crc32(uLong crc, const Bytef *buf, uInt len); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer. + If buf is Z_NULL, this function returns the required initial value for the + crc. Pre- and post-conditioning (one's complement) is performed within this + function so it shouldn't be done by the application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_z(uLong crc, const Bytef *buf, + z_size_t len); +/* + Same as crc32(), but with a size_t length. +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. len2 must be non-negative. +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2); + + Return the operator corresponding to length len2, to be used with + crc32_combine_op(). len2 must be non-negative. +*/ + +ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op); +/* + Give the same result as crc32_combine(), using op in place of len2. op is + is generated from len2 by crc32_combine_gen(). This will be faster than + crc32_combine() if the generated op is used more than once. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_(z_streamp strm, int level, + const char *version, int stream_size); +ZEXTERN int ZEXPORT inflateInit_(z_streamp strm, + const char *version, int stream_size); +ZEXTERN int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size); +ZEXTERN int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, + const char *version, int stream_size); +ZEXTERN int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size); +#ifdef Z_PREFIX_SET +# define z_deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define z_inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#else +# define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#endif + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_(gzFile file); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) +#endif + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#ifdef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int); + ZEXTERN z_off64_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t); +#endif + +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# define z_crc32_combine_gen z_crc32_combine_gen64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# define crc32_combine_gen crc32_combine_gen64 +# endif +# ifndef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off_t ZEXPORT gzseek64(gzFile, z_off_t, int); + ZEXTERN z_off_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off_t ZEXPORT gzoffset64(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen(const char *, const char *); + ZEXTERN z_off_t ZEXPORT gzseek(gzFile, z_off_t, int); + ZEXTERN z_off_t ZEXPORT gztell(gzFile); + ZEXTERN z_off_t ZEXPORT gzoffset(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t); +#endif + +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t); + +#endif /* !Z_SOLO */ + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError(int); +ZEXTERN int ZEXPORT inflateSyncPoint(z_streamp); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table(void); +ZEXTERN int ZEXPORT inflateUndermine(z_streamp, int); +ZEXTERN int ZEXPORT inflateValidate(z_streamp, int); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed(z_streamp); +ZEXTERN int ZEXPORT inflateResetKeep(z_streamp); +ZEXTERN int ZEXPORT deflateResetKeep(z_streamp); +#if defined(_WIN32) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w(const wchar_t *path, + const char *mode); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf(gzFile file, + const char *format, + va_list va); +# endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/zutil.c b/Ghidra/Features/Decompiler/src/decompile/zlib/zutil.c new file mode 100644 index 00000000000..6bbf499ce72 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/zutil.c @@ -0,0 +1,303 @@ +/* ### + * IP: zlib License + * NOTE: from zlib 1.3.1 + */ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2017 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" +#ifndef Z_SOLO +# include "gzguts.h" +#endif + +z_const char * const z_errmsg[10] = { + (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ + (z_const char *)"stream end", /* Z_STREAM_END 1 */ + (z_const char *)"", /* Z_OK 0 */ + (z_const char *)"file error", /* Z_ERRNO (-1) */ + (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ + (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ + (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ + (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ + (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ + (z_const char *)"" +}; + + +const char * ZEXPORT zlibVersion(void) { + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags(void) { + uLong flags; + + flags = 0; + switch ((int)(sizeof(uInt))) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch ((int)(sizeof(uLong))) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch ((int)(sizeof(voidpf))) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch ((int)(sizeof(z_off_t))) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef ZLIB_DEBUG + flags += 1 << 8; +#endif + /* +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif + */ +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef ZLIB_DEBUG +#include +# ifndef verbose +# define verbose 0 +# endif +int ZLIB_INTERNAL z_verbose = verbose; + +void ZLIB_INTERNAL z_error(char *m) { + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(int err) { + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 + /* The older Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len) { + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len) { + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len) { + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + +#ifndef Z_SOLO + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { + voidpf buf; + ulg bsize = (ulg)items*size; + + (void)opaque; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { + int n; + + (void)opaque; + + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) { + (void)opaque; + return _halloc((long)items, size); +} + +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { + (void)opaque; + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc(uInt size); +extern voidp calloc(uInt items, uInt size); +extern void free(voidpf ptr); +#endif + +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { + (void)opaque; + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { + (void)opaque; + free(ptr); +} + +#endif /* MY_ZCALLOC */ + +#endif /* !Z_SOLO */ diff --git a/Ghidra/Features/Decompiler/src/decompile/zlib/zutil.h b/Ghidra/Features/Decompiler/src/decompile/zlib/zutil.h new file mode 100644 index 00000000000..b7318cef883 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/zlib/zutil.h @@ -0,0 +1,258 @@ +/* ### + * IP: zlib License + * NOTE: from zlib 1.3.1 + */ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include "zlib.h" + +#if defined(STDC) && !defined(Z_SOLO) +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif +# include +# include +#endif + +#ifndef local +# define local static +#endif +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +#if !defined(Z_U8) && !defined(Z_SOLO) && defined(STDC) +# include +# if (ULONG_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned long +# elif (ULLONG_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned long long +# elif (UINT_MAX == 0xffffffffffffffff) +# define Z_U8 unsigned +# endif +#endif + +extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[(err) < -6 || (err) > 2 ? 9 : 2 - (err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# ifndef Z_SOLO +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 1 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 2 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef __370__ +# if __TARGET_LIB__ < 0x20000000 +# define OS_CODE 4 +# elif __TARGET_LIB__ < 0x40000000 +# define OS_CODE 11 +# else +# define OS_CODE 8 +# endif +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 5 +#endif + +#ifdef OS2 +# define OS_CODE 6 +# if defined(M_I86) && !defined(Z_SOLO) +# include +# endif +#endif + +#if defined(MACOS) +# define OS_CODE 7 +#endif + +#ifdef __acorn +# define OS_CODE 13 +#endif + +#if defined(WIN32) && !defined(__CYGWIN__) +# define OS_CODE 10 +#endif + +#ifdef _BEOS_ +# define OS_CODE 16 +#endif + +#ifdef __TOS_OS400__ +# define OS_CODE 18 +#endif + +#ifdef __APPLE__ +# define OS_CODE 19 +#endif + +#if defined(__BORLANDC__) && !defined(MSDOS) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_WIN32) && \ + (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t); +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 3 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(pyr) || defined(Z_SOLO) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len); + int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len); + void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len); +#endif + +/* Diagnostic functions */ +#ifdef ZLIB_DEBUG +# include + extern int ZLIB_INTERNAL z_verbose; + extern void ZLIB_INTERNAL z_error(char *m); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +#ifndef Z_SOLO + voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, + unsigned size); + void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr); +#endif + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +/* Reverse the bytes in a 32-bit value */ +#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +#endif /* ZUTIL_H */ diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompInterface.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompInterface.java index 3ab6647a510..33ff0fa92a4 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompInterface.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompInterface.java @@ -84,10 +84,10 @@ public class DecompInterface { public static class EncodeDecodeSet { public OverlayAddressSpace overlay; // Active overlay space or null - public Encoder mainQuery; // Encoder for main query to decompiler process + public CachedEncoder mainQuery; // Encoder for main query to decompiler process public PackedDecode mainResponse; // Decoder for main response from the decompiler process public PackedDecode callbackQuery; // Decoder for queries from the decompiler process - public PackedEncode callbackResponse; // Encode for response to decompiler queries + public PatchPackedEncode callbackResponse; // Encode for response to decompiler queries /** * Set up encoders and decoders for functions that are not in overlay address spaces @@ -95,10 +95,10 @@ public static class EncodeDecodeSet { */ public EncodeDecodeSet(Program program) { overlay = null; - mainQuery = new PackedEncode(); + mainQuery = new PatchPackedEncode(); mainResponse = new PackedDecode(program.getAddressFactory()); callbackQuery = new PackedDecode(program.getAddressFactory()); - callbackResponse = new PackedEncode(); + callbackResponse = new PatchPackedEncode(); } /** @@ -272,7 +272,7 @@ else if (!decompProcess.isReady()) { decompProcess = DecompileProcessFactory.get(); } long uniqueBase = UniqueLayout.SLEIGH_BASE.getOffset(pcodelanguage); - XmlEncode xmlEncode = new XmlEncode(); + XmlEncode xmlEncode = new XmlEncode(false); pcodelanguage.encodeTranslator(xmlEncode, program.getAddressFactory(), uniqueBase); String tspec = xmlEncode.toString(); xmlEncode.clear(); diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java index 9e46e05f448..fa841b195e1 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java @@ -208,7 +208,7 @@ public void getComments(Address addr, int types, Encoder resultEncoder) throws I * @param addr is the given address * @param resultEncoder will contain the generated p-code ops */ - public void getPcode(Address addr, PackedEncode resultEncoder) { + public void getPcode(Address addr, PatchEncoder resultEncoder) { try { Instruction instr = getInstruction(addr); if (instr == null) { diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileProcess.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileProcess.java index 48f31122ff9..985c81296a0 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileProcess.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileProcess.java @@ -77,7 +77,7 @@ public class DecompileProcess { private int maxResultSizeMBYtes = 50; // maximum result size in MBytes to allow from decompiler private PackedDecode paramDecoder; // Decoder to use for queries from the decompiler - private PackedEncode resultEncoder; // Encoder to use for query responses + private PatchPackedEncode resultEncoder; // Encoder to use for query responses private StringIngest stringDecoder; // Ingest of exception and status messages public enum DisposeState { @@ -202,7 +202,7 @@ private void readToResponse() throws IOException, DecompileException { private int readToBuffer(ByteIngest buf) throws IOException { int cur; for (;;) { - buf.ingestStream(nativeIn); + buf.ingestStreamToNextTerminator(nativeIn); do { cur = nativeIn.read(); } @@ -239,7 +239,7 @@ private void writeString(String msg) throws IOException { write(string_end); } - private void writeString(Encoder byteResult) throws IOException { + private void writeString(CachedEncoder byteResult) throws IOException { if (nativeOut == null) { return; } @@ -426,7 +426,7 @@ public synchronized void registerProgram(DecompileCallback cback, String pspecxm // Decompiler process may callback during the registerProgram operation // so provide query/reponse decoding/encoding paramDecoder = new PackedDecode(program.getAddressFactory()); - resultEncoder = new PackedEncode(); + resultEncoder = new PatchPackedEncode(); StringIngest response = new StringIngest(); // Don't use stringDecoder @@ -605,8 +605,8 @@ public void setMaxResultSize(int maxResultSizeMBytes) { * @throws IOException for problems with the pipe to the decompiler process * @throws DecompileException for problems executing the command */ - public synchronized void sendCommand1Param(String command, Encoder param1, ByteIngest response) - throws IOException, DecompileException { + public synchronized void sendCommand1Param(String command, CachedEncoder param1, + ByteIngest response) throws IOException, DecompileException { if (!statusGood) { throw new IOException(command + " called on bad process"); } diff --git a/Ghidra/Framework/Emulation/src/test/java/ghidra/app/plugin/processors/sleigh/SleighLanguageHelper.java b/Ghidra/Framework/Emulation/src/test/java/ghidra/app/plugin/processors/sleigh/SleighLanguageHelper.java index 8b69b7d6331..7bc039a498e 100644 --- a/Ghidra/Framework/Emulation/src/test/java/ghidra/app/plugin/processors/sleigh/SleighLanguageHelper.java +++ b/Ghidra/Framework/Emulation/src/test/java/ghidra/app/plugin/processors/sleigh/SleighLanguageHelper.java @@ -15,20 +15,19 @@ */ package ghidra.app.plugin.processors.sleigh; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.*; import java.io.IOException; import java.net.URL; import java.util.*; import org.antlr.runtime.RecognitionException; -import org.jdom.JDOMException; import org.xml.sax.SAXException; import generic.jar.ResourceFile; import ghidra.pcodeCPort.slgh_compile.SleighCompileLauncher; import ghidra.program.model.lang.*; +import ghidra.program.model.pcode.DecoderException; import ghidra.util.Msg; import resources.ResourceManager; @@ -42,7 +41,7 @@ private static ResourceFile getResourceFile(String name) { } public static SleighLanguage getMockBE64Language() - throws UnknownInstructionException, SAXException, IOException { + throws DecoderException, UnknownInstructionException, SAXException, IOException { ResourceFile cSpecFile = getResourceFile("mock.cpsec"); CompilerSpecDescription cSpecDesc = @@ -59,7 +58,7 @@ public static SleighLanguage getMockBE64Language() assertEquals("Failed to compile mock.slaspec", 0, SleighCompileLauncher.runMain(new String[] { slaSpecFile.getAbsolutePath() })); } - catch (JDOMException | IOException | RecognitionException e) { + catch (IOException | RecognitionException e) { throw new AssertionError(e); } slaFile = getResourceFile("mock.sla"); @@ -67,19 +66,15 @@ public static SleighLanguage getMockBE64Language() } SleighLanguageDescription langDesc = new SleighLanguageDescription( - new LanguageID("Mock:BE:64:default"), - "Mock language (64-bit BE)", - Processor.findOrPossiblyCreateProcessor("Mock"), - Endian.BIG, // endian + new LanguageID("Mock:BE:64:default"), "Mock language (64-bit BE)", + Processor.findOrPossiblyCreateProcessor("Mock"), Endian.BIG, // endian Endian.BIG, // instructionEndian - 64, - "default", // variant + 64, "default", // variant 0, // major version 0, // minor version false, // deprecated new HashMap<>(), // truncatedSpaceMap - new ArrayList<>(List.of(cSpecDesc)), - new HashMap<>() // externalNames + new ArrayList<>(List.of(cSpecDesc)), new HashMap<>() // externalNames ); langDesc.setDefsFile(lDefsFile); langDesc.setSpecFile(pSpecFile); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/Constructor.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/Constructor.java index f2893f9b753..6d40cd0495e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/Constructor.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/Constructor.java @@ -19,21 +19,18 @@ */ package ghidra.app.plugin.processors.sleigh; +import static ghidra.pcode.utils.SlaFormat.*; + import java.util.*; import ghidra.app.plugin.processors.sleigh.symbol.*; import ghidra.app.plugin.processors.sleigh.template.ConstructTpl; import ghidra.app.plugin.processors.sleigh.template.HandleTpl; -import ghidra.program.model.lang.UnknownInstructionException; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.util.Msg; -import ghidra.util.xml.SpecXmlUtils; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * The primary sleigh concept representing a semantic action * taking operands (semantic values) as input * producing a semantic value as output @@ -313,65 +310,59 @@ public ConstructTpl getNamedTempl(int secnum) { return null; } - public void restoreXml(XmlPullParser parser, SleighLanguage sleigh) - throws UnknownInstructionException { - XmlElement el = parser.start("constructor"); + public void decode(Decoder decoder, SleighLanguage sleigh) throws DecoderException { + int el = decoder.openElement(ELEM_CONSTRUCTOR); SymbolTable symtab = sleigh.getSymbolTable(); - int myId = SpecXmlUtils.decodeInt(el.getAttribute("parent")); + int myId = (int) decoder.readUnsignedInteger(ATTRIB_PARENT); parent = (SubtableSymbol) symtab.findSymbol(myId); - firstwhitespace = SpecXmlUtils.decodeInt(el.getAttribute("first")); - minimumlength = SpecXmlUtils.decodeInt(el.getAttribute("length")); - String sourceAndLine = el.getAttribute("line"); - String[] parts = sourceAndLine.split(":"); - if (parts.length != 2) { - Msg.error(this, "Bad line attribute in .sla file"); - lineno = -1; - sourceFile = "UNKNOWN"; - } - else { - lineno = Integer.parseInt(parts[1].trim()); - sourceFile = sleigh.getSourceFileIndexer().getFileName(Integer.parseInt(parts[0].trim())); - } + firstwhitespace = (int) decoder.readSignedInteger(ATTRIB_FIRST); + minimumlength = (int) decoder.readSignedInteger(ATTRIB_LENGTH); + int srcLine = (int) decoder.readSignedInteger(ATTRIB_SOURCE); + lineno = (int) decoder.readSignedInteger(ATTRIB_LINE); + sourceFile = sleigh.getSourceFileIndexer().getFileName(srcLine); ArrayList oplist = new ArrayList<>(); ArrayList piecelist = new ArrayList<>(); ArrayList coplist = new ArrayList<>(); - XmlElement subel = parser.peek(); - while (!subel.getName().equals("constructor")) { - if (subel.getName().equals("oper")) { - myId = SpecXmlUtils.decodeInt(subel.getAttribute("id")); + int subel = decoder.peekElement(); + while (subel != 0) { + if (subel == ELEM_OPER.id()) { + decoder.openElement(); + myId = (int) decoder.readUnsignedInteger(ATTRIB_ID); oplist.add(symtab.findSymbol(myId)); - parser.discardSubTree(); + decoder.closeElementSkipping(subel); } - else if (subel.getName().equals("print")) { - piecelist.add(subel.getAttribute("piece")); - parser.discardSubTree(); + else if (subel == ELEM_PRINT.id()) { + decoder.openElement(); + piecelist.add(decoder.readString(ATTRIB_PIECE)); + decoder.closeElementSkipping(subel); } - else if (subel.getName().equals("opprint")) { - myId = SpecXmlUtils.decodeInt(subel.getAttribute("id")); + else if (subel == ELEM_OPPRINT.id()) { + decoder.openElement(); + myId = (int) decoder.readSignedInteger(ATTRIB_ID); String operstring = "\n"; char ind = (char) ('A' + myId); operstring += ind; piecelist.add(operstring); - parser.discardSubTree(); + decoder.closeElementSkipping(subel); } - else if (subel.getName().equals("context_op")) { + else if (subel == ELEM_CONTEXT_OP.id()) { ContextOp c_op = new ContextOp(); - c_op.restoreXml(parser, sleigh); + c_op.decode(decoder, sleigh); coplist.add(c_op); } - else if (subel.getName().equals("commit")) { + else if (subel == ELEM_COMMIT.id()) { ContextCommit c_op = new ContextCommit(); - c_op.restoreXml(parser, sleigh); + c_op.decode(decoder, sleigh); coplist.add(c_op); } else { ConstructTpl curtempl = new ConstructTpl(); - int sectionid = curtempl.restoreXml(parser, sleigh.getAddressFactory()); + int sectionid = curtempl.decode(decoder); if (sectionid < 0) { if (templ != null) { - throw new UnknownInstructionException("Duplicate main template section"); + throw new DecoderException("Duplicate main template section"); } templ = curtempl; } @@ -383,12 +374,12 @@ else if (subel.getName().equals("commit")) { namedtempl.add(null); } if (namedtempl.get(sectionid) != null) { - throw new UnknownInstructionException("Duplicate named template section"); + throw new DecoderException("Duplicate named template section"); } namedtempl.set(sectionid, curtempl); } } - subel = parser.peek(); + subel = decoder.peekElement(); } operands = new OperandSymbol[oplist.size()]; separators = new String[operands.length + 1]; @@ -404,7 +395,7 @@ else if (subel.getName().equals("commit")) { else { flowthruindex = -1; } - parser.end(el); + decoder.closeElement(el); } /** @@ -432,10 +423,6 @@ public int[] getOpsPrintOrder() { return res; } - /* ***************************** * - * Get these working as map keys * - * ***************************** */ - @Override public int compareTo(Constructor that) { int result; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/ContextChange.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/ContextChange.java index c7bb8404f2a..a51f7e5fd7e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/ContextChange.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/ContextChange.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +16,11 @@ package ghidra.app.plugin.processors.sleigh; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; public interface ContextChange { void apply(ParserWalker walker, SleighDebugLogger debug) throws MemoryAccessException; - void restoreXml(XmlPullParser parser,SleighLanguage lang); + + void decode(Decoder decoder, SleighLanguage lang) throws DecoderException; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/ContextCommit.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/ContextCommit.java index 95c3389d5b7..c24f3680c8a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/ContextCommit.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/ContextCommit.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +15,12 @@ */ package ghidra.app.plugin.processors.sleigh; +import static ghidra.pcode.utils.SlaFormat.*; + import ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.util.xml.SpecXmlUtils; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; public class ContextCommit implements ContextChange { @@ -32,6 +32,7 @@ public ContextCommit() { sym = null; } + @Override public void apply(ParserWalker walker, SleighDebugLogger debug) throws MemoryAccessException { walker.getParserContext().addCommit(walker.getState(), sym, num, mask); if (debug != null) { @@ -40,13 +41,14 @@ public void apply(ParserWalker walker, SleighDebugLogger debug) throws MemoryAcc } } - public void restoreXml(XmlPullParser parser, SleighLanguage lang) { - XmlElement el = parser.start("commit"); - int id = SpecXmlUtils.decodeInt(el.getAttribute("id")); + @Override + public void decode(Decoder decoder, SleighLanguage lang) throws DecoderException { + int el = decoder.openElement(ELEM_COMMIT); + int id = (int) decoder.readUnsignedInteger(ATTRIB_ID); sym = (TripleSymbol) lang.getSymbolTable().findSymbol(id); - num = SpecXmlUtils.decodeInt(el.getAttribute("num")); - mask = SpecXmlUtils.decodeInt(el.getAttribute("mask")); - parser.end(el); + num = (int) decoder.readSignedInteger(ATTRIB_NUMBER); + mask = (int) decoder.readUnsignedInteger(ATTRIB_MASK); + decoder.closeElement(el); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/ContextOp.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/ContextOp.java index 09461ec7193..80c502facb4 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/ContextOp.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/ContextOp.java @@ -19,16 +19,15 @@ */ package ghidra.app.plugin.processors.sleigh; +import static ghidra.pcode.utils.SlaFormat.*; + import ghidra.app.plugin.processors.sleigh.expression.PatternExpression; import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; import ghidra.util.NumericUtilities; -import ghidra.util.xml.SpecXmlUtils; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; /** - * - * * An operation on the context (bit-packed form) of an instruction */ public class ContextOp implements ContextChange { @@ -51,13 +50,13 @@ public void apply(ParserWalker walker, SleighDebugLogger debug) throws MemoryAcc } @Override - public void restoreXml(XmlPullParser parser, SleighLanguage lang) { - XmlElement el = parser.start("context_op"); - num = SpecXmlUtils.decodeInt(el.getAttribute("i")); - shift = SpecXmlUtils.decodeInt(el.getAttribute("shift")); - mask = SpecXmlUtils.decodeInt(el.getAttribute("mask")); - patexp = PatternExpression.restoreExpression(parser, lang); - parser.end(el); + public void decode(Decoder decoder, SleighLanguage lang) throws DecoderException { + int el = decoder.openElement(ELEM_CONTEXT_OP); + num = (int) decoder.readSignedInteger(ATTRIB_I); + shift = (int) decoder.readSignedInteger(ATTRIB_SHIFT); + mask = (int) decoder.readUnsignedInteger(ATTRIB_MASK); + patexp = PatternExpression.decodeExpression(decoder, lang); + decoder.closeElement(el); } public PatternExpression getPatternExpression() { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/DecisionNode.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/DecisionNode.java index 944bbfbabcb..a4445a5e09c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/DecisionNode.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/DecisionNode.java @@ -19,11 +19,9 @@ */ package ghidra.app.plugin.processors.sleigh; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.util.*; import ghidra.app.plugin.processors.sleigh.pattern.DisjointPattern; import ghidra.app.plugin.processors.sleigh.pattern.PatternBlock; @@ -31,13 +29,10 @@ import ghidra.program.model.lang.UnknownInstructionException; import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.util.xml.SpecXmlUtils; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * A node in the decision tree for resolving a Constructor in * a SubtableSymbol based on the InstructionContext */ @@ -224,33 +219,33 @@ private void dumpDecendentConstructors(List clist) { // } // } - public void restoreXml(XmlPullParser parser, DecisionNode par, SubtableSymbol sub) { - XmlElement el = parser.start("decision"); -// parent = par; -// num = SpecXmlUtils.decodeInt(el.getAttributeValue("number")); - contextdecision = SpecXmlUtils.decodeBoolean(el.getAttribute("context")); - startbit = SpecXmlUtils.decodeInt(el.getAttribute("start")); - bitsize = SpecXmlUtils.decodeInt(el.getAttribute("size")); + public void decode(Decoder decoder, DecisionNode par, SubtableSymbol sub) + throws DecoderException { + int el = decoder.openElement(ELEM_DECISION); + + contextdecision = decoder.readBool(ATTRIB_CONTEXT); + startbit = (int) decoder.readSignedInteger(ATTRIB_STARTBIT); + bitsize = (int) decoder.readSignedInteger(ATTRIB_SIZE); ArrayList patlist = new ArrayList<>(); ArrayList conlist = new ArrayList<>(); ArrayList childlist = new ArrayList<>(); // num = 0; - XmlElement subel = parser.peek(); - while (!subel.isEnd()) { - if (subel.getName().equals("pair")) { - XmlElement start = parser.start(); - int id = SpecXmlUtils.decodeInt(subel.getAttribute("id")); + int subel = decoder.peekElement(); + while (subel != 0) { + if (subel == ELEM_PAIR.id()) { + decoder.openElement(); + int id = (int) decoder.readSignedInteger(ATTRIB_ID); conlist.add(sub.getConstructor(id)); - patlist.add(DisjointPattern.restoreDisjoint(parser)); - parser.end(start); + patlist.add(DisjointPattern.decodeDisjoint(decoder)); + decoder.closeElement(subel); } - else if (subel.getName().equals("decision")) { + else if (subel == ELEM_DECISION.id()) { DecisionNode subnode = new DecisionNode(); - subnode.restoreXml(parser, this, sub); + subnode.decode(decoder, this, sub); childlist.add(subnode); } - subel = parser.peek(); + subel = decoder.peekElement(); } patternlist = new DisjointPattern[patlist.size()]; patlist.toArray(patternlist); @@ -258,7 +253,7 @@ else if (subel.getName().equals("decision")) { conlist.toArray(constructlist); children = new DecisionNode[childlist.size()]; childlist.toArray(children); - parser.end(el); + decoder.closeElement(el); unmodifiablePatternList = Collections.unmodifiableList(Arrays.asList(patternlist)); unmodifiableConstructorList = Collections.unmodifiableList(Arrays.asList(constructlist)); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java index c2b79418d7f..9d777e90b1c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java @@ -15,8 +15,7 @@ */ package ghidra.app.plugin.processors.sleigh; -import static ghidra.program.model.pcode.AttributeId.*; -import static ghidra.program.model.pcode.ElementId.*; +import static ghidra.pcode.utils.SlaFormat.*; import java.io.*; import java.math.BigInteger; @@ -26,7 +25,6 @@ import java.util.regex.Pattern; import org.antlr.runtime.RecognitionException; -import org.jdom.JDOMException; import org.xml.sax.*; import generic.jar.ResourceFile; @@ -36,15 +34,14 @@ import ghidra.app.plugin.processors.sleigh.expression.PatternValue; import ghidra.app.plugin.processors.sleigh.symbol.*; import ghidra.framework.Application; -import ghidra.pcodeCPort.sleighbase.SleighBase; +import ghidra.pcode.utils.SlaFormat; import ghidra.pcodeCPort.slgh_compile.SleighCompileLauncher; import ghidra.program.model.address.*; import ghidra.program.model.lang.*; import ghidra.program.model.listing.DefaultProgramContext; import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.program.model.pcode.ElementId; -import ghidra.program.model.pcode.Encoder; +import ghidra.program.model.pcode.*; import ghidra.program.model.util.ProcessorSymbolType; import ghidra.sleigh.grammar.SleighPreprocessor; import ghidra.sleigh.grammar.SourceFileIndexer; @@ -57,15 +54,6 @@ public class SleighLanguage implements Language { - /** - * SLA_FORMAT_VERSION will be incremented whenever the format of the .sla - * files change. - *

- * Version 3: January 2021: added source file information for each constructor.
- * Version 2: April 2019: Changed numbering of Overlay spaces.
- * Version 1: Initial version.
- */ - public static final int SLA_FORMAT_VERSION = SleighBase.SLA_FORMAT_VERSION; private Map compilerSpecDescriptions; private HashMap compilerSpecs; private List additionalInject = null; @@ -112,7 +100,7 @@ public class SleighLanguage implements Language { SortedMap manual = null; SleighLanguage(SleighLanguageDescription description) - throws SAXException, IOException, UnknownInstructionException { + throws DecoderException, SAXException, IOException { initialize(description); } @@ -124,7 +112,7 @@ private void addAdditionInject(InjectPayloadSleigh payload) { } private void initialize(SleighLanguageDescription langDescription) - throws SAXException, IOException, UnknownInstructionException { + throws DecoderException, SAXException, IOException { this.defaultSymbols = new ArrayList<>(); this.compilerSpecDescriptions = new LinkedHashMap<>(); for (CompilerSpecDescription compilerSpecDescription : langDescription @@ -151,7 +139,8 @@ private void initialize(SleighLanguageDescription langDescription) } // Read in the sleigh specification - readSpecification(slaFile); + PackedDecode decoder = SlaFormat.buildDecoder(slaFile); + decode(decoder); registerBuilder = new RegisterBuilder(); loadRegisters(registerBuilder); @@ -177,42 +166,12 @@ private void buildVolatileSymbolAddresses() { } private boolean isSLAWrongVersion(ResourceFile slaFile) { - XmlPullParser parser = null; - try { - parser = XmlPullParserFactory.create(slaFile, new ErrorHandler() { - - @Override - public void warning(SAXParseException exception) throws SAXException { - // ignore - } - - @Override - public void fatalError(SAXParseException exception) throws SAXException { - throw exception; - } - - @Override - public void error(SAXParseException exception) throws SAXException { - throw exception; - } - }, false); - - XmlElement e = parser.peek(); - if (!"sleigh".equals(e.getName())) { - return true; - } - - int version = SpecXmlUtils.decodeInt(e.getAttribute("version")); - return (version != SLA_FORMAT_VERSION); + try (InputStream stream = slaFile.getInputStream()) { + return !SlaFormat.isSlaFormat(stream); } - catch (SAXException | IOException e) { + catch (Exception e) { return true; } - finally { - if (parser != null) { - parser.dispose(); - } - } } private boolean isSLAStale(ResourceFile slaFile) { @@ -521,9 +480,6 @@ private void reloadLanguage(TaskMonitor monitor, boolean calledFromInitialize) " -- please check log messages for details"); } } - catch (JDOMException e) { - throw new IOException("JDOMException error recompiling: " + e.getMessage()); - } catch (RecognitionException e) { throw new IOException("RecognitionException error recompiling: " + e.getMessage()); } @@ -533,10 +489,10 @@ private void reloadLanguage(TaskMonitor monitor, boolean calledFromInitialize) try { initialize(description); } - catch (SAXException e) { + catch (DecoderException e) { throw new IOException(e.getMessage()); } - catch (UnknownInstructionException e) { + catch (SAXException e) { throw new IOException(e.getMessage()); } } @@ -907,96 +863,104 @@ private void readRemainingSpecification() throws SAXException, IOException { } } - private void readSpecification(final ResourceFile sleighfile) - throws SAXException, IOException, UnknownInstructionException { - ErrorHandler errHandler = new ErrorHandler() { - @Override - public void error(SAXParseException exception) throws SAXException { - Msg.error(SleighLanguage.this, "Error parsing " + sleighfile, exception); + private void decode(Decoder decoder) throws DecoderException { + int el = decoder.openElement(ELEM_SLEIGH); + int version = 0; + uniqueBase = 0; + alignment = 1; + uniqueAllocateMask = 0; // Default mask is 0 + numSections = 0; + boolean isBigEndian = false; + int attrib = decoder.getNextAttributeId(); + while (attrib != 0) { + if (attrib == ATTRIB_VERSION.id()) { + version = (int) decoder.readSignedInteger(); } - - @Override - public void fatalError(SAXParseException exception) throws SAXException { - Msg.error(SleighLanguage.this, "Fatal error parsing " + sleighfile, exception); + else if (attrib == ATTRIB_BIGENDIAN.id()) { + isBigEndian = decoder.readBool(); } - - @Override - public void warning(SAXParseException exception) throws SAXException { - Msg.warn(SleighLanguage.this, "Warning parsing " + sleighfile, exception); + else if (attrib == ATTRIB_UNIQBASE.id()) { + uniqueBase = decoder.readUnsignedInteger(); } - }; - XmlPullParser parser = XmlPullParserFactory.create(sleighfile, errHandler, false); - try { - restoreXml(parser); - } - finally { - parser.dispose(); + else if (attrib == ATTRIB_ALIGN.id()) { + alignment = (int) decoder.readSignedInteger(); + } + else if (attrib == ATTRIB_UNIQMASK.id()) { + uniqueAllocateMask = (int) decoder.readUnsignedInteger(); + } + else if (attrib == ATTRIB_NUMSECTIONS.id()) { + numSections = (int) decoder.readUnsignedInteger(); + } + attrib = decoder.getNextAttributeId(); } - } - - private void restoreXml(XmlPullParser parser) throws UnknownInstructionException { - XmlElement el = parser.start("sleigh"); - int version = SpecXmlUtils.decodeInt(el.getAttribute("version")); - if (version != SLA_FORMAT_VERSION) { + if (version != FORMAT_VERSION) { throw new SleighException(".sla file for " + getLanguageID() + " has the wrong format"); } - String endianAttr = el.getAttribute("bigendian"); - Endian slaEndian = SpecXmlUtils.decodeBoolean(endianAttr) ? Endian.BIG : Endian.LITTLE; + Endian slaEndian = isBigEndian ? Endian.BIG : Endian.LITTLE; Endian ldefEndian = description.getEndian(); Endian instEndian = description.getInstructionEndian(); if (slaEndian != ldefEndian && instEndian == ldefEndian) { throw new SleighException(".ldefs says " + getLanguageID() + " is " + ldefEndian + " but .sla says " + slaEndian); } - uniqueBase = SpecXmlUtils.decodeLong(el.getAttribute("uniqbase")); - alignment = SpecXmlUtils.decodeInt(el.getAttribute("align")); - uniqueAllocateMask = 0; // Default mask is 0 - String uniqmaskstr = el.getAttribute("uniqmask"); - if (uniqmaskstr != null) { - uniqueAllocateMask = SpecXmlUtils.decodeInt(uniqmaskstr); - } - String numsecstr = el.getAttribute("numsections"); - if (numsecstr != null) { - numSections = SpecXmlUtils.decodeInt(numsecstr); - } indexer = new SourceFileIndexer(); - indexer.restoreXml(parser); - parseSpaces(parser); + indexer.decode(decoder); + parseSpaces(decoder); symtab = new SymbolTable(); - symtab.restoreXml(parser, this); + symtab.decode(decoder, this); root = ((SubtableSymbol) symtab.getGlobalScope().findSymbol("instruction")).getDecisionNode(); - parser.end(el); + decoder.closeElement(el); } - private void parseSpaces(XmlPullParser parser) { + private void parseSpaces(Decoder decoder) throws DecoderException { Set truncatedSpaceNames = description.getTruncatedSpaceNames(); int truncatedSpaceCnt = truncatedSpaceNames.size(); - XmlElement el = parser.start("spaces"); - String defname = el.getAttribute("defaultspace"); + int el = decoder.openElement(ELEM_SPACES); + String defname = decoder.readString(ATTRIB_DEFAULTSPACE); spacetable = new LinkedHashMap<>(); // Slot zero is always the constant space AddressSpace constspc = new GenericAddressSpace(SpaceNames.CONSTANT_SPACE_NAME, 64, AddressSpace.TYPE_CONSTANT, SpaceNames.CONSTANT_SPACE_INDEX); spacetable.put(SpaceNames.CONSTANT_SPACE_NAME, constspc); default_space = null; - XmlElement subel = parser.peek(); - if (subel.getName().equals("space_other")) { // tag must be present - parser.discardSubTree(); // We don't process it + int subel = decoder.peekElement(); + if (subel == ELEM_SPACE_OTHER.id()) { // tag must be present + decoder.openElement(); + decoder.closeElementSkipping(subel); // We don't process it // Instead the ProgramAddressFactory maps in the static OTHER_SPACE automatically } else { throw new SleighException(".sla file missing required OTHER space tag"); } - while ((subel = parser.softStart("space", "space_unique")) != null) { - String name = subel.getAttribute("name"); - int index = SpecXmlUtils.decodeInt(subel.getAttribute("index")); - String typename = subel.getName(); - int delay = SpecXmlUtils.decodeInt(subel.getAttribute("delay")); - int size = SpecXmlUtils.decodeInt(subel.getAttribute("size")); - - int type = AddressSpace.TYPE_UNKNOWN; - if (typename.equals("space")) { + while (decoder.peekElement() != 0) { + int wordsize = 1; + String name = null; + int index = 0; + int delay = -1; + int size = 0; + subel = decoder.openElement(); + int attrib = decoder.getNextAttributeId(); + while (attrib != 0) { + if (attrib == ATTRIB_NAME.id()) { + name = decoder.readString(); + } + else if (attrib == ATTRIB_INDEX.id()) { + index = (int) decoder.readSignedInteger(); + } + else if (attrib == ATTRIB_DELAY.id()) { + delay = (int) decoder.readSignedInteger(); + } + else if (attrib == ATTRIB_SIZE.id()) { + size = (int) decoder.readSignedInteger(); + } + else if (attrib == ATTRIB_WORDSIZE.id()) { + wordsize = (int) decoder.readSignedInteger(); + } + attrib = decoder.getNextAttributeId(); + } + int type; + if (subel == ELEM_SPACE.id()) { if (delay > 0) { type = AddressSpace.TYPE_RAM; } @@ -1004,19 +968,13 @@ private void parseSpaces(XmlPullParser parser) { type = AddressSpace.TYPE_REGISTER; } } - else if (typename.equals("space_unique")) { + else if (subel == ELEM_SPACE_UNIQUE.id()) { type = AddressSpace.TYPE_UNIQUE; } - if (type == AddressSpace.TYPE_UNKNOWN) { + else { throw new SleighException("Sleigh cannot match new space definition to old type"); } - String wSizeString = subel.getAttribute("wordsize"); - int wordsize = 1; - if (wSizeString != null) { - wordsize = SpecXmlUtils.decodeInt(wSizeString); - } - boolean truncateSpace = truncatedSpaceNames.contains(name); if (truncateSpace && type != AddressSpace.TYPE_RAM) { throw new SleighException("Non-ram space does not support truncation: " + name); @@ -1048,7 +1006,7 @@ else if (typename.equals("space_unique")) { spc = new GenericAddressSpace(name, 8 * size, wordsize, type, index); } spacetable.put(name, spc); - parser.end(subel); + decoder.closeElement(subel); } if (truncatedSpaceCnt > 0) { throw new SleighException( @@ -1058,7 +1016,8 @@ else if (typename.equals("space_unique")) { defaultDataSpace = default_space; defaultPointerWordSize = defaultDataSpace.getAddressableUnitSize(); buildAddressSpaceFactory(); - parser.end(el); + decoder.closeElement(el); + decoder.setAddressFactory(addressFactory); } void buildAddressSpaceFactory() { @@ -1454,11 +1413,16 @@ public void encodeTranslator(Encoder encoder, AddressFactory factory, long uniqu throws IOException { AddressSpace[] spclist = factory.getAllAddressSpaces(); - encoder.openElement(ELEM_SLEIGH); - encoder.writeBool(ATTRIB_BIGENDIAN, isBigEndian()); - encoder.writeUnsignedInteger(ATTRIB_UNIQBASE, uniqueOffset); - encoder.openElement(ELEM_SPACES); - encoder.writeString(ATTRIB_DEFAULTSPACE, factory.getDefaultAddressSpace().getName()); + // WARNING + // ELEM_ and ATTRIB_ symbols in this method all come from the AttributeId and ElementId + // namespace, some of which conflict with other ELEM_ and ATTRIB_ symbols used in this file + + encoder.openElement(ElementId.ELEM_SLEIGH); + encoder.writeBool(AttributeId.ATTRIB_BIGENDIAN, isBigEndian()); + encoder.writeUnsignedInteger(AttributeId.ATTRIB_UNIQBASE, uniqueOffset); + encoder.openElement(ElementId.ELEM_SPACES); + encoder.writeString(AttributeId.ATTRIB_DEFAULTSPACE, + factory.getDefaultAddressSpace().getName()); ElementId tag; int delay; @@ -1467,31 +1431,31 @@ public void encodeTranslator(Encoder encoder, AddressFactory factory, long uniqu for (AddressSpace element : spclist) { if ((element instanceof OverlayAddressSpace)) { OverlayAddressSpace ospace = (OverlayAddressSpace) element; - encoder.openElement(ELEM_SPACE_OVERLAY); - encoder.writeString(ATTRIB_NAME, ospace.getName()); - encoder.writeSignedInteger(ATTRIB_INDEX, ospace.getUnique()); - encoder.writeSpace(ATTRIB_BASE, ospace.getOverlayedSpace()); - encoder.closeElement(ELEM_SPACE_OVERLAY); + encoder.openElement(ElementId.ELEM_SPACE_OVERLAY); + encoder.writeString(AttributeId.ATTRIB_NAME, ospace.getName()); + encoder.writeSignedInteger(AttributeId.ATTRIB_INDEX, ospace.getUnique()); + encoder.writeSpace(AttributeId.ATTRIB_BASE, ospace.getOverlayedSpace()); + encoder.closeElement(ElementId.ELEM_SPACE_OVERLAY); continue; } switch (element.getType()) { case AddressSpace.TYPE_RAM: - tag = ELEM_SPACE; + tag = ElementId.ELEM_SPACE; delay = 1; physical = true; break; case AddressSpace.TYPE_REGISTER: - tag = ELEM_SPACE; + tag = ElementId.ELEM_SPACE; delay = 0; physical = true; break; case AddressSpace.TYPE_UNIQUE: - tag = ELEM_SPACE_UNIQUE; + tag = ElementId.ELEM_SPACE_UNIQUE; delay = 0; physical = true; break; case AddressSpace.TYPE_OTHER: - tag = ELEM_SPACE_OTHER; + tag = ElementId.ELEM_SPACE_OTHER; delay = 0; physical = true; break; @@ -1499,8 +1463,8 @@ public void encodeTranslator(Encoder encoder, AddressFactory factory, long uniqu continue; } encoder.openElement(tag); - encoder.writeString(ATTRIB_NAME, element.getName()); - encoder.writeSignedInteger(ATTRIB_INDEX, element.getUnique()); + encoder.writeString(AttributeId.ATTRIB_NAME, element.getName()); + encoder.writeSignedInteger(AttributeId.ATTRIB_INDEX, element.getUnique()); int size = element.getSize(); // Size in bits if (element instanceof SegmentedAddressSpace) { @@ -1511,18 +1475,19 @@ public void encodeTranslator(Encoder encoder, AddressFactory factory, long uniqu size = 64; } int bytesize = (size + 7) / 8; // Convert bits to bytes - encoder.writeSignedInteger(ATTRIB_SIZE, bytesize); + encoder.writeSignedInteger(AttributeId.ATTRIB_SIZE, bytesize); if (element.getAddressableUnitSize() > 1) { - encoder.writeUnsignedInteger(ATTRIB_WORDSIZE, element.getAddressableUnitSize()); + encoder.writeUnsignedInteger(AttributeId.ATTRIB_WORDSIZE, + element.getAddressableUnitSize()); } - encoder.writeBool(ATTRIB_BIGENDIAN, isBigEndian()); - encoder.writeSignedInteger(ATTRIB_DELAY, delay); - encoder.writeBool(ATTRIB_PHYSICAL, physical); + encoder.writeBool(AttributeId.ATTRIB_BIGENDIAN, isBigEndian()); + encoder.writeSignedInteger(AttributeId.ATTRIB_DELAY, delay); + encoder.writeBool(AttributeId.ATTRIB_PHYSICAL, physical); encoder.closeElement(tag); } - encoder.closeElement(ELEM_SPACES); + encoder.closeElement(ElementId.ELEM_SPACES); SleighLanguageDescription sleighDescription = (SleighLanguageDescription) getLanguageDescription(); @@ -1530,13 +1495,13 @@ public void encodeTranslator(Encoder encoder, AddressFactory factory, long uniqu if (!truncatedSpaceNames.isEmpty()) { for (String spaceName : truncatedSpaceNames) { int sz = sleighDescription.getTruncatedSpaceSize(spaceName); - encoder.openElement(ELEM_TRUNCATE_SPACE); - encoder.writeString(ATTRIB_SPACE, spaceName); - encoder.writeSignedInteger(ATTRIB_SIZE, sz); - encoder.closeElement(ELEM_TRUNCATE_SPACE); + encoder.openElement(ElementId.ELEM_TRUNCATE_SPACE); + encoder.writeString(AttributeId.ATTRIB_SPACE, spaceName); + encoder.writeSignedInteger(AttributeId.ATTRIB_SIZE, sz); + encoder.closeElement(ElementId.ELEM_TRUNCATE_SPACE); } } - encoder.closeElement(ELEM_SLEIGH); + encoder.closeElement(ElementId.ELEM_SLEIGH); } private void initParallelHelper() { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguageProvider.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguageProvider.java index 3f0f64d3550..b14f20e98ce 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguageProvider.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguageProvider.java @@ -27,6 +27,7 @@ import generic.jar.ResourceFile; import ghidra.framework.Application; import ghidra.program.model.lang.*; +import ghidra.program.model.pcode.DecoderException; import ghidra.util.Msg; import ghidra.util.SystemUtilities; import ghidra.util.xml.SpecXmlUtils; @@ -137,17 +138,16 @@ public Language getLanguage(LanguageID languageId) { "Can't read language spec " + description.getSlaFile().getAbsolutePath(), e); throw e; } - catch (FileNotFoundException e) { + catch (DecoderException e) { Msg.showError(this, null, "Error", "Can't read language spec " + description.getSlaFile().getAbsolutePath(), e); - throw new SleighException( - "File not found - language probably did not compile properly", e); + throw new SleighException("Format violation in the .sla file", e); } - catch (UnknownInstructionException e) { + catch (FileNotFoundException e) { Msg.showError(this, null, "Error", "Can't read language spec " + description.getSlaFile().getAbsolutePath(), e); throw new SleighException( - "Unknown instruction - language probably did not compile properly", e); + "File not found - language probably did not compile properly", e); } catch (SAXException e) { Msg.showError(this, null, "Error", diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/BinaryExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/BinaryExpression.java index 0c8e8e21d1d..6595cb0a458 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/BinaryExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/BinaryExpression.java @@ -20,12 +20,10 @@ package ghidra.app.plugin.processors.sleigh.expression; import ghidra.app.plugin.processors.sleigh.SleighLanguage; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * Base class for binary operators that combine PatternExpressions */ public abstract class BinaryExpression extends PatternExpression { @@ -69,10 +67,10 @@ public PatternExpression getRight() { } @Override - public void restoreXml(XmlPullParser parser, SleighLanguage lang) { - XmlElement el = parser.start(); - left = PatternExpression.restoreExpression(parser, lang); - right = PatternExpression.restoreExpression(parser, lang); - parser.end(el); + public void decode(Decoder decoder, SleighLanguage lang) throws DecoderException { + int el = decoder.openElement(); + left = PatternExpression.decodeExpression(decoder, lang); + right = PatternExpression.decodeExpression(decoder, lang); + decoder.closeElement(el); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/ConstantValue.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/ConstantValue.java index adb3e52e9e0..a731d01d305 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/ConstantValue.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/ConstantValue.java @@ -19,19 +19,17 @@ */ package ghidra.app.plugin.processors.sleigh.expression; +import static ghidra.pcode.utils.SlaFormat.*; + import ghidra.app.plugin.processors.sleigh.ParserWalker; import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.util.xml.SpecXmlUtils; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * A constant value associated with an alwaysTrue pattern */ - public class ConstantValue extends PatternValue { private long val; // The constant value @@ -61,25 +59,16 @@ public ConstantValue(long b) { val = b; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.expression.PatternValue#minValue() - */ @Override public long minValue() { return val; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.expression.PatternValue#maxValue() - */ @Override public long maxValue() { return val; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.expression.PatternExpression#getValue(ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override public long getValue(ParserWalker walker) throws MemoryAccessException { return val; @@ -89,14 +78,11 @@ public long getValue() { return val; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.PatternExpression#restoreXml(org.jdom.Element) - */ @Override - public void restoreXml(XmlPullParser parser, SleighLanguage lang) { - XmlElement el = parser.start("intb"); - val = SpecXmlUtils.decodeLong(el.getAttribute("val")); - parser.end(el); + public void decode(Decoder decoder, SleighLanguage lang) throws DecoderException { + int el = decoder.openElement(ELEM_INTB); + val = decoder.readSignedInteger(ATTRIB_VAL); + decoder.closeElement(el); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/ContextField.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/ContextField.java index 3b34aa8eae1..e5b562afd3a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/ContextField.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/ContextField.java @@ -19,16 +19,15 @@ */ package ghidra.app.plugin.processors.sleigh.expression; +import static ghidra.pcode.utils.SlaFormat.*; + import ghidra.app.plugin.processors.sleigh.ParserWalker; import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.util.xml.SpecXmlUtils; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * Contiguous bits in the non-instruction part of the context interpreted * as an integer value */ @@ -81,17 +80,11 @@ public boolean getSignBit() { return signbit; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.expression.PatternValue#minValue() - */ @Override public long minValue() { return 0; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.expression.PatternValue#maxValue() - */ @Override public long maxValue() { long res = -1; @@ -100,39 +93,35 @@ public long maxValue() { return ~res; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.PatternExpression#getValue(ghidra.app.plugin.processors.sleigh.InstructionContext) - */ @Override public long getValue(ParserWalker walker) throws MemoryAccessException { long res = getContextBytes(walker); res >>= shift; - if (signbit) + if (signbit) { res = TokenField.signExtend(res, endbit - startbit); - else + } + else { res = TokenField.zeroExtend(res, endbit - startbit); + } return res; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.PatternExpression#restoreXml(org.jdom.Element) - */ @Override - public void restoreXml(XmlPullParser parser, SleighLanguage lang) { - XmlElement el = parser.start("contextfield"); - signbit = SpecXmlUtils.decodeBoolean(el.getAttribute("signbit")); - startbit = SpecXmlUtils.decodeInt(el.getAttribute("startbit")); - endbit = SpecXmlUtils.decodeInt(el.getAttribute("endbit")); - startbyte = SpecXmlUtils.decodeInt(el.getAttribute("startbyte")); - endbyte = SpecXmlUtils.decodeInt(el.getAttribute("endbyte")); - shift = SpecXmlUtils.decodeInt(el.getAttribute("shift")); - parser.end(el); + public void decode(Decoder decoder, SleighLanguage lang) throws DecoderException { + int el = decoder.openElement(ELEM_CONTEXTFIELD); + signbit = decoder.readBool(ATTRIB_SIGNBIT); + startbit = (int) decoder.readSignedInteger(ATTRIB_STARTBIT); + endbit = (int) decoder.readSignedInteger(ATTRIB_ENDBIT); + startbyte = (int) decoder.readSignedInteger(ATTRIB_STARTBYTE); + endbyte = (int) decoder.readSignedInteger(ATTRIB_ENDBYTE); + shift = (int) decoder.readSignedInteger(ATTRIB_SHIFT); + decoder.closeElement(el); } /** - * Build a long from the context bytes in pos - * @param pos - * @return + * Build a long from the context bytes at the current point in the instruction parse + * @param walker is the parsing state + * @return the recover value */ private long getContextBytes(ParserWalker walker) { long res = 0; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/EndInstructionValue.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/EndInstructionValue.java index 03ed689f829..737a893850e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/EndInstructionValue.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/EndInstructionValue.java @@ -19,15 +19,16 @@ */ package ghidra.app.plugin.processors.sleigh.expression; +import static ghidra.pcode.utils.SlaFormat.*; + import ghidra.app.plugin.processors.sleigh.ParserWalker; import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.program.model.address.Address; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * The integer offset of the address following the current instruction */ public class EndInstructionValue extends PatternValue { @@ -43,37 +44,26 @@ public boolean equals(Object obj) { return obj instanceof EndInstructionValue; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.expression.PatternValue#minValue() - */ @Override public long minValue() { return 0; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.expression.PatternValue#maxValue() - */ @Override public long maxValue() { return 0; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.expression.PatternExpression#getValue(ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override public long getValue(ParserWalker walker) throws MemoryAccessException { Address addr = walker.getNaddr(); return addr.getAddressableWordOffset(); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.PatternExpression#restoreXml(org.jdom.Element) - */ @Override - public void restoreXml(XmlPullParser parser, SleighLanguage lang) { - parser.discardSubTree("end_exp"); + public void decode(Decoder decoder, SleighLanguage lang) throws DecoderException { + int el = decoder.openElement(ELEM_END_EXP); + decoder.closeElement(el); // Nothing to do } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/Next2InstructionValue.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/Next2InstructionValue.java index 58608dd6c00..55f18ed9a6b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/Next2InstructionValue.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/Next2InstructionValue.java @@ -15,15 +15,16 @@ */ package ghidra.app.plugin.processors.sleigh.expression; +import static ghidra.pcode.utils.SlaFormat.*; + import ghidra.app.plugin.processors.sleigh.ParserWalker; import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.program.model.address.Address; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * The integer offset of the address following the current instruction */ public class Next2InstructionValue extends PatternValue { @@ -56,8 +57,9 @@ public long getValue(ParserWalker walker) throws MemoryAccessException { } @Override - public void restoreXml(XmlPullParser parser, SleighLanguage lang) { - parser.discardSubTree("next2_exp"); + public void decode(Decoder decoder, SleighLanguage lang) throws DecoderException { + int el = decoder.openElement(ELEM_NEXT2_EXP); + decoder.closeElement(el); // Nothing to do } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/OperandValue.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/OperandValue.java index 88081b3d040..d32b894e79b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/OperandValue.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/OperandValue.java @@ -19,16 +19,15 @@ */ package ghidra.app.plugin.processors.sleigh.expression; +import static ghidra.pcode.utils.SlaFormat.*; + import ghidra.app.plugin.processors.sleigh.*; import ghidra.app.plugin.processors.sleigh.symbol.*; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.util.xml.SpecXmlUtils; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * An Expression representing the value of a Constructor operand */ public class OperandValue extends PatternValue { @@ -75,25 +74,16 @@ public Constructor getConstructor() { return ct; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.expression.PatternValue#minValue() - */ @Override public long minValue() { throw new SleighException("Operand used in pattern expression"); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.expression.PatternValue#maxValue() - */ @Override public long maxValue() { throw new SleighException("Operand used in pattern expression"); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.expression.PatternExpression#getValue(ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override public long getValue(ParserWalker walker) throws MemoryAccessException { OperandSymbol sym = ct.getOperand(index); @@ -114,18 +104,15 @@ public long getValue(ParserWalker walker) throws MemoryAccessException { return res; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.PatternExpression#restoreXml(org.jdom.Element) - */ @Override - public void restoreXml(XmlPullParser parser, SleighLanguage lang) { - XmlElement el = parser.start("operand_exp"); - index = SpecXmlUtils.decodeInt(el.getAttribute("index")); - int tabid = SpecXmlUtils.decodeInt(el.getAttribute("table")); - int ctid = SpecXmlUtils.decodeInt(el.getAttribute("ct")); + public void decode(Decoder decoder, SleighLanguage lang) throws DecoderException { + int el = decoder.openElement(ELEM_OPERAND_EXP); + index = (int) decoder.readSignedInteger(ATTRIB_INDEX); + int tabid = (int) decoder.readUnsignedInteger(ATTRIB_TABLE); + int ctid = (int) decoder.readUnsignedInteger(ATTRIB_CT); SubtableSymbol sym = (SubtableSymbol) lang.getSymbolTable().findSymbol(tabid); ct = sym.getConstructor(ctid); - parser.end(el); + decoder.closeElement(el); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/PatternExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/PatternExpression.java index 69b6f9c3cbf..3818f96ee1d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/PatternExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/PatternExpression.java @@ -19,66 +19,85 @@ */ package ghidra.app.plugin.processors.sleigh.expression; +import static ghidra.pcode.utils.SlaFormat.*; + import ghidra.app.plugin.processors.sleigh.ParserWalker; import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * An expression which results in a pattern for a specific InstructionContext */ public abstract class PatternExpression { public abstract long getValue(ParserWalker walker) throws MemoryAccessException; - public abstract void restoreXml(XmlPullParser parser, SleighLanguage lang); + public abstract void decode(Decoder decoder, SleighLanguage lang) throws DecoderException; - public static PatternExpression restoreExpression(XmlPullParser parser, SleighLanguage lang) { - XmlElement el = parser.peek(); + public static PatternExpression decodeExpression(Decoder decoder, SleighLanguage lang) + throws DecoderException { + int el = decoder.peekElement(); PatternExpression res; - String nm = el.getName(); - if (nm.equals("tokenfield")) + if (el == ELEM_TOKENFIELD.id()) { res = new TokenField(); - else if (nm.equals("contextfield")) + } + else if (el == ELEM_CONTEXTFIELD.id()) { res = new ContextField(); - else if (nm.equals("intb")) + } + else if (el == ELEM_INTB.id()) { res = new ConstantValue(); - else if (nm.equals("operand_exp")) + } + else if (el == ELEM_OPERAND_EXP.id()) { res = new OperandValue(); - else if (nm.equals("start_exp")) + } + else if (el == ELEM_START_EXP.id()) { res = new StartInstructionValue(); - else if (nm.equals("end_exp")) + } + else if (el == ELEM_END_EXP.id()) { res = new EndInstructionValue(); - else if (nm.equals("next2_exp")) + } + else if (el == ELEM_NEXT2_EXP.id()) { res = new Next2InstructionValue(); - else if (nm.equals("plus_exp")) + } + else if (el == ELEM_PLUS_EXP.id()) { res = new PlusExpression(); - else if (nm.equals("sub_exp")) + } + else if (el == ELEM_SUB_EXP.id()) { res = new SubExpression(); - else if (nm.equals("mult_exp")) + } + else if (el == ELEM_MULT_EXP.id()) { res = new MultExpression(); - else if (nm.equals("lshift_exp")) + } + else if (el == ELEM_LSHIFT_EXP.id()) { res = new LeftShiftExpression(); - else if (nm.equals("rshift_exp")) + } + else if (el == ELEM_RSHIFT_EXP.id()) { res = new RightShiftExpression(); - else if (nm.equals("and_exp")) + } + else if (el == ELEM_AND_EXP.id()) { res = new AndExpression(); - else if (nm.equals("or_exp")) + } + else if (el == ELEM_OR_EXP.id()) { res = new OrExpression(); - else if (nm.equals("xor_exp")) + } + else if (el == ELEM_XOR_EXP.id()) { res = new XorExpression(); - else if (nm.equals("div_exp")) + } + else if (el == ELEM_DIV_EXP.id()) { res = new DivExpression(); - else if (nm.equals("minus_exp")) + } + else if (el == ELEM_MINUS_EXP.id()) { res = new MinusExpression(); - else if (nm.equals("not_exp")) + } + else if (el == ELEM_NOT_EXP.id()) { res = new NotExpression(); - else + } + else { return null; + } - res.restoreXml(parser, lang); + res.decode(decoder, lang); return res; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/StartInstructionValue.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/StartInstructionValue.java index 53afe1159c3..86281e4b802 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/StartInstructionValue.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/StartInstructionValue.java @@ -19,15 +19,16 @@ */ package ghidra.app.plugin.processors.sleigh.expression; +import static ghidra.pcode.utils.SlaFormat.*; + import ghidra.app.plugin.processors.sleigh.ParserWalker; import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.program.model.address.Address; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * The offset value of the current instructions address */ public class StartInstructionValue extends PatternValue { @@ -43,37 +44,26 @@ public boolean equals(Object obj) { return obj instanceof StartInstructionValue; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.expression.PatternValue#minValue() - */ @Override public long minValue() { return 0; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.expression.PatternValue#maxValue() - */ @Override public long maxValue() { return 0; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.expression.PatternExpression#getValue(ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override public long getValue(ParserWalker walker) throws MemoryAccessException { Address addr = walker.getAddr(); return addr.getAddressableWordOffset(); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.PatternExpression#restoreXml(org.jdom.Element) - */ @Override - public void restoreXml(XmlPullParser parser, SleighLanguage lang) { - parser.discardSubTree("start_exp"); + public void decode(Decoder decoder, SleighLanguage lang) throws DecoderException { + int el = decoder.openElement(ELEM_START_EXP); + decoder.closeElement(el); // Nothing to do } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/TokenField.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/TokenField.java index ecd259e1314..c56ba44e933 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/TokenField.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/TokenField.java @@ -19,16 +19,15 @@ */ package ghidra.app.plugin.processors.sleigh.expression; +import static ghidra.pcode.utils.SlaFormat.*; + import ghidra.app.plugin.processors.sleigh.ParserWalker; import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.util.xml.SpecXmlUtils; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * A contiguous set of bits within instruction stream, interpreted * as an integer value */ @@ -75,17 +74,11 @@ public boolean equals(Object obj) { return true; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.expression.PatternValue#minValue() - */ @Override public long minValue() { return 0; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.expression.PatternValue#maxValue() - */ @Override public long maxValue() { long res = -1; @@ -94,18 +87,17 @@ public long maxValue() { return ~res; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.PatternExpression#getValue(ghidra.app.plugin.processors.sleigh.InstructionContext) - */ @Override public long getValue(ParserWalker walker) throws MemoryAccessException { long res = getInstructionBytes(walker); res >>= shift; - if (signbit) + if (signbit) { res = signExtend(res, bitend - bitstart); - else + } + else { res = zeroExtend(res, bitend - bitstart); + } return res; } @@ -125,20 +117,17 @@ public int getByteEnd() { return byteend; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.PatternExpression#restoreXml(org.jdom.Element) - */ @Override - public void restoreXml(XmlPullParser parser, SleighLanguage lang) { - XmlElement el = parser.start("tokenfield"); - bigendian = SpecXmlUtils.decodeBoolean(el.getAttribute("bigendian")); - signbit = SpecXmlUtils.decodeBoolean(el.getAttribute("signbit")); - bitstart = SpecXmlUtils.decodeInt(el.getAttribute("bitstart")); - bitend = SpecXmlUtils.decodeInt(el.getAttribute("bitend")); - bytestart = SpecXmlUtils.decodeInt(el.getAttribute("bytestart")); - byteend = SpecXmlUtils.decodeInt(el.getAttribute("byteend")); - shift = SpecXmlUtils.decodeInt(el.getAttribute("shift")); - parser.end(el); + public void decode(Decoder decoder, SleighLanguage lang) throws DecoderException { + int el = decoder.openElement(ELEM_TOKENFIELD); + bigendian = decoder.readBool(ATTRIB_BIGENDIAN); + signbit = decoder.readBool(ATTRIB_SIGNBIT); + bitstart = (int) decoder.readSignedInteger(ATTRIB_STARTBIT); + bitend = (int) decoder.readSignedInteger(ATTRIB_ENDBIT); + bytestart = (int) decoder.readSignedInteger(ATTRIB_STARTBYTE); + byteend = (int) decoder.readSignedInteger(ATTRIB_ENDBYTE); + shift = (int) decoder.readSignedInteger(ATTRIB_SHIFT); + decoder.closeElement(el); } public boolean hasSignbit() { @@ -146,10 +135,10 @@ public boolean hasSignbit() { } /** - * Build a long from the instruction bytes in pos - * @param pos Current instruction - * @return - * @throws MemoryAccessException + * Build a long from the instruction bytes at the current point in the parse + * @param walker is the instruction parse state + * @return the recovered value + * @throws MemoryAccessException for problems reading the bytes */ private long getInstructionBytes(ParserWalker walker) throws MemoryAccessException { long res = 0; @@ -171,8 +160,9 @@ private long getInstructionBytes(ParserWalker walker) throws MemoryAccessExcepti res = res << (8 * tmpsize); res |= (tmp & 0xffffffffl); } - if (!bigendian) + if (!bigendian) { res = byteSwap(res, size); + } return res; } @@ -180,15 +170,17 @@ private long getInstructionBytes(ParserWalker walker) throws MemoryAccessExcepti * Sign extend -val- above -bit- * @param val value to extend * @param bit bit specifying sign - * @return + * @return the extended value */ public static long signExtend(long val, int bit) { long mask = 0; mask = (~mask) << bit; - if (((val >> bit) & 1) != 0) + if (((val >> bit) & 1) != 0) { val |= mask; - else + } + else { val &= (~mask); + } return val; } @@ -196,7 +188,7 @@ public static long signExtend(long val, int bit) { * Clear all bits in -val- above -bit- * @param val value to zero extend * @param bit bit above which to zero extend - * @return + * @return the extended value */ public static long zeroExtend(long val, int bit) { long mask = 0; @@ -210,7 +202,7 @@ public static long zeroExtend(long val, int bit) { * Swap the least sig -size- bytes in -val- * @param val value to be byte swapped * @param size number of bytes involved in swap - * @return + * @return the byte swapped value */ public static long byteSwap(long val, int size) { long res = 0; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/UnaryExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/UnaryExpression.java index 65e4b6b4a20..68a3341d8b4 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/UnaryExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/UnaryExpression.java @@ -21,12 +21,10 @@ package ghidra.app.plugin.processors.sleigh.expression; import ghidra.app.plugin.processors.sleigh.SleighLanguage; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * Base class for unary operators on PatternExpressions */ @@ -59,10 +57,10 @@ public PatternExpression getUnary() { } @Override - public void restoreXml(XmlPullParser parser, SleighLanguage lang) { - XmlElement el = parser.start(); + public void decode(Decoder decoder, SleighLanguage lang) throws DecoderException { + int el = decoder.openElement(); - unary = PatternExpression.restoreExpression(parser, lang); - parser.end(el); + unary = PatternExpression.decodeExpression(decoder, lang); + decoder.closeElement(el); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/CombinePattern.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/CombinePattern.java index ad1f72ba1dd..44c0258f1cd 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/CombinePattern.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/CombinePattern.java @@ -19,15 +19,15 @@ */ package ghidra.app.plugin.processors.sleigh.pattern; +import static ghidra.pcode.utils.SlaFormat.*; + import ghidra.app.plugin.processors.sleigh.ParserWalker; import ghidra.app.plugin.processors.sleigh.SleighDebugLogger; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * A pattern that has both an instruction part and non-instruction part */ public class CombinePattern extends DisjointPattern { @@ -35,9 +35,6 @@ public class CombinePattern extends DisjointPattern { private ContextPattern context; // Context piece private InstructionPattern instr; // Instruction piece - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.DisjointPattern#getBlock(boolean) - */ @Override public PatternBlock getBlock(boolean cont) { return cont ? context.getBlock() : instr.getBlock(); @@ -53,55 +50,50 @@ public CombinePattern(ContextPattern con, InstructionPattern in) { instr = in; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#simplifyClone() - */ @Override public Pattern simplifyClone() { - if (context.alwaysTrue()) + if (context.alwaysTrue()) { return instr.simplifyClone(); - if (instr.alwaysTrue()) + } + if (instr.alwaysTrue()) { return context.simplifyClone(); - if (context.alwaysFalse() || instr.alwaysFalse()) + } + if (context.alwaysFalse() || instr.alwaysFalse()) { return new InstructionPattern(false); + } return new CombinePattern((ContextPattern) context.simplifyClone(), (InstructionPattern) instr.simplifyClone()); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#shiftInstruction(int) - */ @Override public void shiftInstruction(int sa) { instr.shiftInstruction(sa); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#doOr(ghidra.app.plugin.processors.sleigh.Pattern, int) - */ @Override public Pattern doOr(Pattern b, int sa) { - if (b.numDisjoint() != 0) + if (b.numDisjoint() != 0) { return b.doOr(this, -sa); + } DisjointPattern res1 = (DisjointPattern) simplifyClone(); DisjointPattern res2 = (DisjointPattern) b.simplifyClone(); - if (sa < 0) + if (sa < 0) { res1.shiftInstruction(-sa); - else + } + else { res2.shiftInstruction(sa); + } OrPattern tmp = new OrPattern(res1, res2); return tmp; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#doAnd(ghidra.app.plugin.processors.sleigh.Pattern, int) - */ @Override public Pattern doAnd(Pattern b, int sa) { - if (b.numDisjoint() != 0) + if (b.numDisjoint() != 0) { return b.doAnd(this, -sa); + } CombinePattern tmp; if (b instanceof CombinePattern) { @@ -117,17 +109,15 @@ public Pattern doAnd(Pattern b, int sa) { else { // Must be a ContextPattern ContextPattern c = (ContextPattern) context.doAnd(b, 0); InstructionPattern newpat = (InstructionPattern) instr.simplifyClone(); - if (sa < 0) + if (sa < 0) { newpat.shiftInstruction(-sa); + } tmp = new CombinePattern(c, newpat); } } return tmp; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.pattern.Pattern#isMatch(ghidra.app.plugin.processors.sleigh.ParserWalker, ghidra.app.plugin.processors.sleigh.SleighDebugLogger) - */ @Override public boolean isMatch(ParserWalker walker, SleighDebugLogger debug) throws MemoryAccessException { @@ -167,41 +157,29 @@ private void debugNextMatch(SleighDebugLogger debug, boolean isFirst) { debug.indent(); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#alwaysTrue() - */ @Override public boolean alwaysTrue() { return (context.alwaysTrue() && instr.alwaysTrue()); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#alwaysFalse() - */ @Override public boolean alwaysFalse() { return (context.alwaysFalse() || instr.alwaysFalse()); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#alwaysInstructionTrue() - */ @Override public boolean alwaysInstructionTrue() { return instr.alwaysInstructionTrue(); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#restoreXml(org.jdom.Element) - */ @Override - public void restoreXml(XmlPullParser parser) { - XmlElement el = parser.start("combine_pat"); + public void decode(Decoder decoder) throws DecoderException { + int el = decoder.openElement(ELEM_COMBINE_PAT); context = new ContextPattern(); - context.restoreXml(parser); + context.decode(decoder); instr = new InstructionPattern(); - instr.restoreXml(parser); - parser.end(el); + instr.decode(decoder); + decoder.closeElement(el); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/ContextPattern.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/ContextPattern.java index a5ec209d61d..0833e52aedb 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/ContextPattern.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/ContextPattern.java @@ -19,16 +19,16 @@ */ package ghidra.app.plugin.processors.sleigh.pattern; +import static ghidra.pcode.utils.SlaFormat.*; + import ghidra.app.plugin.processors.sleigh.ParserWalker; import ghidra.app.plugin.processors.sleigh.SleighDebugLogger; import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; import ghidra.util.StringUtilities; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; /** - * - * * Pattern which depends only on the non-instruction stream bits * of the context */ @@ -36,9 +36,6 @@ public class ContextPattern extends DisjointPattern { private PatternBlock maskvalue; - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.DisjointPattern#getBlock(boolean) - */ @Override public PatternBlock getBlock(boolean context) { return context ? maskvalue : null; @@ -56,49 +53,36 @@ public PatternBlock getBlock() { return maskvalue; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#simplifyClone() - */ @Override public Pattern simplifyClone() { return new ContextPattern((PatternBlock) maskvalue.clone()); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#shiftInstruction(int) - */ @Override public void shiftInstruction(int sa) { // do nothing } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#doOr(ghidra.app.plugin.processors.sleigh.Pattern, int) - */ @Override public Pattern doOr(Pattern b, int sa) { - if (!(b instanceof ContextPattern)) + if (!(b instanceof ContextPattern)) { return b.doOr(this, -sa); + } return new OrPattern((DisjointPattern) simplifyClone(), (DisjointPattern) b.simplifyClone()); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#doAnd(ghidra.app.plugin.processors.sleigh.Pattern, int) - */ @Override public Pattern doAnd(Pattern b, int sa) { - if (!(b instanceof ContextPattern)) + if (!(b instanceof ContextPattern)) { return b.doAnd(this, -sa); + } PatternBlock resblock = maskvalue.andBlock(((ContextPattern) b).maskvalue); return new ContextPattern(resblock); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.pattern.Pattern#isMatch(ghidra.app.plugin.processors.sleigh.ParserWalker, ghidra.app.plugin.processors.sleigh.SleighDebugLogger) - */ @Override public boolean isMatch(ParserWalker walker, SleighDebugLogger debug) throws MemoryAccessException { @@ -149,39 +133,27 @@ else if (alwaysFalse()) { } } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#alwaysTrue() - */ @Override public boolean alwaysTrue() { return maskvalue.alwaysTrue(); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#alwaysFalse() - */ @Override public boolean alwaysFalse() { return maskvalue.alwaysFalse(); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#alwaysInstructionTrue() - */ @Override public boolean alwaysInstructionTrue() { return true; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#restoreXml(org.jdom.Element) - */ @Override - public void restoreXml(XmlPullParser parser) { - XmlElement el = parser.start("context_pat"); + public void decode(Decoder decoder) throws DecoderException { + int el = decoder.openElement(ELEM_CONTEXT_PAT); maskvalue = new PatternBlock(true); - maskvalue.restoreXml(parser); - parser.end(el); + maskvalue.decode(decoder); + decoder.closeElement(el); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/DisjointPattern.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/DisjointPattern.java index 6ff93d0c769..2ed50101241 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/DisjointPattern.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/DisjointPattern.java @@ -19,12 +19,12 @@ */ package ghidra.app.plugin.processors.sleigh.pattern; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import static ghidra.pcode.utils.SlaFormat.*; + +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * A pattern with no ORs in it */ public abstract class DisjointPattern extends Pattern { @@ -55,22 +55,25 @@ public DisjointPattern getDisjoint(int i) { public int getMask(int startbit, int size, boolean context) { PatternBlock block = getBlock(context); - if (block != null) + if (block != null) { return block.getMask(startbit, size); + } return 0; } public int getValue(int startbit, int size, boolean context) { PatternBlock block = getBlock(context); - if (block != null) + if (block != null) { return block.getValue(startbit, size); + } return 0; } public int getLength(boolean context) { PatternBlock block = getBlock(context); - if (block != null) + if (block != null) { return block.getLength(); + } return 0; } @@ -80,18 +83,22 @@ public boolean specializes(DisjointPattern op2) { a = getBlock(false); b = op2.getBlock(false); if (b != null) { // a must match existing block - if (a == null) + if (a == null) { return false; - if (!a.specializes(b)) + } + if (!a.specializes(b)) { return false; + } } a = getBlock(true); b = op2.getBlock(true); if (b != null) { // a must match existing block - if (a == null) + if (a == null) { return false; - if (!a.specializes(b)) + } + if (!a.specializes(b)) { return false; + } } return true; } @@ -102,32 +109,39 @@ public boolean identical(DisjointPattern op2) { a = getBlock(false); b = op2.getBlock(false); if (b != null) { // a must match existing block - if (a == null) + if (a == null) { return false; - if (!a.identical(b)) + } + if (!a.identical(b)) { return false; + } } a = getBlock(true); b = op2.getBlock(true); if (b != null) { // a must match existing block - if (a == null) + if (a == null) { return false; - if (!a.identical(b)) + } + if (!a.identical(b)) { return false; + } } return true; } - static public DisjointPattern restoreDisjoint(XmlPullParser parser) { - XmlElement el = parser.peek(); + static public DisjointPattern decodeDisjoint(Decoder decoder) throws DecoderException { + int el = decoder.peekElement(); DisjointPattern res; - if (el.getName().equals("instruct_pat")) + if (el == ELEM_INSTRUCT_PAT.id()) { res = new InstructionPattern(); - else if (el.getName().equals("context_pat")) + } + else if (el == ELEM_CONTEXT_PAT.id()) { res = new ContextPattern(); - else + } + else { res = new CombinePattern(); - res.restoreXml(parser); + } + res.decode(decoder); return res; } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/InstructionPattern.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/InstructionPattern.java index 2533cbef0f0..c65fc9d2570 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/InstructionPattern.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/InstructionPattern.java @@ -19,26 +19,23 @@ */ package ghidra.app.plugin.processors.sleigh.pattern; +import static ghidra.pcode.utils.SlaFormat.*; + import ghidra.app.plugin.processors.sleigh.ParserWalker; import ghidra.app.plugin.processors.sleigh.SleighDebugLogger; import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; import ghidra.util.StringUtilities; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; /** - * - * * Matches against the actual instruction bit stream */ public class InstructionPattern extends DisjointPattern { private PatternBlock maskvalue; - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.DisjointPattern#getBlock(boolean) - */ @Override public PatternBlock getBlock(boolean context) { return context ? null : maskvalue; @@ -60,56 +57,51 @@ public PatternBlock getBlock() { return maskvalue; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#simplifyClone() - */ @Override public Pattern simplifyClone() { return new InstructionPattern((PatternBlock) maskvalue.clone()); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#shiftInstruction() - */ @Override public void shiftInstruction(int sa) { maskvalue.shift(sa); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#doOr(ghidra.app.plugin.processors.sleigh.Pattern, int) - */ @Override public Pattern doOr(Pattern b, int sa) { - if (b.numDisjoint() > 0) + if (b.numDisjoint() > 0) { return b.doOr(this, -sa); + } - if (b instanceof CombinePattern) + if (b instanceof CombinePattern) { return b.doOr(this, -sa); + } DisjointPattern res1, res2; res1 = (DisjointPattern) simplifyClone(); res2 = (DisjointPattern) b.simplifyClone(); - if (sa < 0) + if (sa < 0) { res1.shiftInstruction(-sa); - else + } + else { res2.shiftInstruction(sa); + } return new OrPattern(res1, res2); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#doAnd(ghidra.app.plugin.processors.sleigh.Pattern, int) - */ @Override public Pattern doAnd(Pattern b, int sa) { - if (b.numDisjoint() > 0) + if (b.numDisjoint() > 0) { return b.doAnd(this, -sa); - if (b instanceof CombinePattern) + } + if (b instanceof CombinePattern) { return b.doAnd(this, -sa); + } if (b instanceof ContextPattern) { InstructionPattern newpat = (InstructionPattern) simplifyClone(); - if (sa < 0) + if (sa < 0) { newpat.shiftInstruction(-sa); + } return new CombinePattern((ContextPattern) b.simplifyClone(), newpat); } // b must be an InstructionPattern if it reaches here @@ -127,9 +119,6 @@ public Pattern doAnd(Pattern b, int sa) { return new InstructionPattern(respattern); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.pattern.Pattern#isMatch(ghidra.app.plugin.processors.sleigh.ParserWalker, ghidra.app.plugin.processors.sleigh.SleighDebugLogger) - */ @Override public boolean isMatch(ParserWalker walker, SleighDebugLogger debug) throws MemoryAccessException { @@ -176,39 +165,27 @@ else if (alwaysFalse()) { } } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#alwaysTrue() - */ @Override public boolean alwaysTrue() { return maskvalue.alwaysTrue(); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#alwaysFalse() - */ @Override public boolean alwaysFalse() { return maskvalue.alwaysFalse(); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#alwaysInstructionTrue() - */ @Override public boolean alwaysInstructionTrue() { return maskvalue.alwaysTrue(); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Pattern#restoreXml(org.jdom.Element) - */ @Override - public void restoreXml(XmlPullParser parser) { - XmlElement el = parser.start("instruct_pat"); + public void decode(Decoder decoder) throws DecoderException { + int el = decoder.openElement(ELEM_INSTRUCT_PAT); maskvalue = new PatternBlock(true); - maskvalue.restoreXml(parser); - parser.end(el); + maskvalue.decode(decoder); + decoder.closeElement(el); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/OrPattern.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/OrPattern.java index 01c3a3de6d1..f8699624711 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/OrPattern.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/OrPattern.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,127 +19,127 @@ */ package ghidra.app.plugin.processors.sleigh.pattern; -import ghidra.app.plugin.processors.sleigh.*; -import ghidra.program.model.mem.*; -import ghidra.xml.*; +import static ghidra.pcode.utils.SlaFormat.*; -import java.util.*; +import java.util.ArrayList; + +import ghidra.app.plugin.processors.sleigh.ParserWalker; +import ghidra.app.plugin.processors.sleigh.SleighDebugLogger; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * A pattern that can be matched by matching any of a list of subpatterns */ public class OrPattern extends Pattern { private DisjointPattern[] orlist; - - public OrPattern() { orlist = null; } // For use with restoreXml - - public OrPattern(DisjointPattern a,DisjointPattern b) { + + public OrPattern() { + orlist = null; + } + + public OrPattern(DisjointPattern a, DisjointPattern b) { orlist = new DisjointPattern[2]; orlist[0] = a; orlist[1] = b; } - + public OrPattern(ArrayList list) { orlist = new DisjointPattern[list.size()]; - for(int i=0;i newlist = new ArrayList(); - for(int i=0;i newlist = new ArrayList(); - - for(int i=0;i 0) { - for(int i=0;i newlist = new ArrayList(); if (b instanceof OrPattern) { - OrPattern b2 = (OrPattern)b; - for(int i=0;i ors = new ArrayList(); - XmlElement peek = parser.peek(); - while (!peek.isEnd()) { - ors.add(DisjointPattern.restoreDisjoint(parser)); - } + public void decode(Decoder decoder) throws DecoderException { + int el = decoder.openElement(ELEM_OR_PAT); + ArrayList ors = new ArrayList(); + int peek = decoder.peekElement(); + while (peek != 0) { + ors.add(DisjointPattern.decodeDisjoint(decoder)); + } orlist = new DisjointPattern[ors.size()]; int i = 0; for (DisjointPattern pat : ors) { orlist[i++] = pat; } - parser.end(el); + decoder.closeElement(el); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/Pattern.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/Pattern.java index 8b7d9707634..9b349e5e721 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/Pattern.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/Pattern.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,13 +19,13 @@ */ package ghidra.app.plugin.processors.sleigh.pattern; -import ghidra.app.plugin.processors.sleigh.*; -import ghidra.program.model.mem.*; -import ghidra.xml.*; +import ghidra.app.plugin.processors.sleigh.ParserWalker; +import ghidra.app.plugin.processors.sleigh.SleighDebugLogger; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * A pattern which either matches or doesnt match a particular * InstructionContext. In particular, the bits comprising the * current instruction in the executable, and possible other @@ -34,14 +33,25 @@ */ public abstract class Pattern { public abstract Pattern simplifyClone(); + public abstract void shiftInstruction(int sa); - public abstract Pattern doOr(Pattern b,int sa); - public abstract Pattern doAnd(Pattern b,int sa); - public abstract boolean isMatch(ParserWalker walker, SleighDebugLogger debug) throws MemoryAccessException; + + public abstract Pattern doOr(Pattern b, int sa); + + public abstract Pattern doAnd(Pattern b, int sa); + + public abstract boolean isMatch(ParserWalker walker, SleighDebugLogger debug) + throws MemoryAccessException; + public abstract int numDisjoint(); + public abstract DisjointPattern getDisjoint(int i); + public abstract boolean alwaysTrue(); + public abstract boolean alwaysFalse(); + public abstract boolean alwaysInstructionTrue(); - public abstract void restoreXml(XmlPullParser parser); + + public abstract void decode(Decoder decoder) throws DecoderException; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/PatternBlock.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/PatternBlock.java index 1a6c44bed2f..2433f55a94a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/PatternBlock.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/pattern/PatternBlock.java @@ -19,18 +19,17 @@ */ package ghidra.app.plugin.processors.sleigh.pattern; +import static ghidra.pcode.utils.SlaFormat.*; + import java.util.ArrayList; import ghidra.app.plugin.processors.sleigh.ParserWalker; import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; import ghidra.util.NumericUtilities; -import ghidra.util.xml.SpecXmlUtils; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; /** - * - * * A mask/value pair viewed as two bitstreams */ public class PatternBlock { @@ -43,10 +42,12 @@ private static int[] eraseArray(int[] array, int start, int end) { int delsize = end - start; int newsize = array.length - delsize; int[] res = new int[newsize]; - for (int i = 0; i < start; ++i) + for (int i = 0; i < start; ++i) { res[i] = array[i]; - for (int i = end; i < array.length; ++i) + } + for (int i = end; i < array.length; ++i) { res[i - delsize] = array[i]; + } return res; } @@ -104,8 +105,9 @@ private void normalize() { while (iter1 != 0) { --iter1; --iter2; - if (maskvec[iter1] != 0) + if (maskvec[iter1] != 0) { break; // Find last non-zero + } } if (iter1 != maskvec.length) { iter1++; // Find first zero,in last zero chain @@ -142,10 +144,12 @@ public PatternBlock(int off, int msk, int val) { public PatternBlock(boolean tf) { offset = 0; - if (tf) + if (tf) { nonzerosize = 0; - else + } + else { nonzerosize = -1; + } maskvec = null; valvec = null; } @@ -193,8 +197,9 @@ public PatternBlock andBlock(PatternBlock b) { int maxlength = (getLength() > b.getLength()) ? getLength() : b.getLength(); int asize = maxlength / 4; - if (maxlength % 4 != 0) + if (maxlength % 4 != 0) { asize += 1; + } res.maskvec = new int[asize]; res.valvec = new int[asize]; res.offset = 0; @@ -206,17 +211,20 @@ public PatternBlock andBlock(PatternBlock b) { val1 = getValue(offset1 * 8, 32); mask2 = b.getMask(offset1 * 8, 32); val2 = b.getValue(offset1 * 8, 32); - if (((mask2 & mask1) & val2) != ((mask2 & mask1) & val1)) + if (((mask2 & mask1) & val2) != ((mask2 & mask1) & val1)) { break; // Impossible pattern + } res.maskvec[i] = mask1 | mask2; res.valvec[i] = val1 | val2; offset1 += 4; i += 1; } - if (offset1 < maxlength) // If pattern is impossible + if (offset1 < maxlength) { // If pattern is impossible res.nonzerosize = -1; - else + } + else { // If pattern is impossible res.nonzerosize = maxlength; + } res.normalize(); return res; } @@ -228,16 +236,19 @@ public boolean specializes(PatternBlock op2) { int sbit = 0; while (sbit < length) { tmplength = length - sbit; - if (tmplength > 32) + if (tmplength > 32) { tmplength = 32; + } mask1 = getMask(sbit, tmplength); value1 = getValue(sbit, tmplength); mask2 = op2.getMask(sbit, tmplength); value2 = op2.getValue(sbit, tmplength); - if ((mask1 & mask2) != mask2) + if ((mask1 & mask2) != mask2) { return false; - if ((value1 & mask2) != (value2 & mask2)) + } + if ((value1 & mask2) != (value2 & mask2)) { return false; + } sbit += tmplength; } return true; @@ -250,16 +261,19 @@ public boolean identical(PatternBlock op2) { int sbit = 0; while (sbit < length) { tmplength = length - sbit; - if (tmplength > 32) + if (tmplength > 32) { tmplength = 32; + } mask1 = getMask(sbit, tmplength); value1 = getValue(sbit, tmplength); mask2 = op2.getMask(sbit, tmplength); value2 = op2.getValue(sbit, tmplength); - if (mask1 != mask2) + if (mask1 != mask2) { return false; - if ((mask1 & value1) != (mask2 & value2)) + } + if ((mask1 & value1) != (mask2 & value2)) { return false; + } sbit += tmplength; } return true; @@ -281,17 +295,21 @@ public int getMask(int startbit, int size) { int wordnum2 = (startbit + size - 1) / 32; int res; - if ((wordnum1 < 0) || (wordnum1 >= maskvec.length)) + if ((wordnum1 < 0) || (wordnum1 >= maskvec.length)) { res = 0; - else + } + else { res = maskvec[wordnum1]; + } res <<= shift; if (wordnum1 != wordnum2) { int tmp; - if ((wordnum2 < 0) || (wordnum2 >= maskvec.length)) + if ((wordnum2 < 0) || (wordnum2 >= maskvec.length)) { tmp = 0; - else + } + else { tmp = maskvec[wordnum2]; + } res |= (tmp >>> (32 - shift)); } res >>>= 32 - size; @@ -305,17 +323,21 @@ public int getValue(int startbit, int size) { int wordnum2 = (startbit + size - 1) / 32; int res; - if ((wordnum1 < 0) || (wordnum1 >= valvec.length)) + if ((wordnum1 < 0) || (wordnum1 >= valvec.length)) { res = 0; - else + } + else { res = valvec[wordnum1]; + } res <<= shift; if (wordnum1 != wordnum2) { int tmp; - if ((wordnum2 < 0) || (wordnum2 >= valvec.length)) + if ((wordnum2 < 0) || (wordnum2 >= valvec.length)) { tmp = 0; - else + } + else { tmp = valvec[wordnum2]; + } res |= (tmp >>> (32 - shift)); } res >>>= 32 - size; @@ -331,14 +353,16 @@ public boolean alwaysFalse() { } public boolean isInstructionMatch(ParserWalker walker) { - if (nonzerosize <= 0) + if (nonzerosize <= 0) { return (nonzerosize == 0); + } int off = offset; try { for (int i = 0; i < maskvec.length; ++i) { int data = walker.getInstructionBytes(off, 4); - if ((maskvec[i] & data) != valvec[i]) + if ((maskvec[i] & data) != valvec[i]) { return false; + } off += 4; } return true; @@ -349,37 +373,39 @@ public boolean isInstructionMatch(ParserWalker walker) { } public boolean isContextMatch(ParserWalker walker) { - if (nonzerosize <= 0) + if (nonzerosize <= 0) { return (nonzerosize == 0); + } int off = offset; for (int i = 0; i < maskvec.length; ++i) { int data = walker.getContextBytes(off, 4); - if ((maskvec[i] & data) != valvec[i]) + if ((maskvec[i] & data) != valvec[i]) { return false; + } off += 4; } return true; } - public void restoreXml(XmlPullParser parser) { - XmlElement el = parser.start("pat_block"); - offset = SpecXmlUtils.decodeInt(el.getAttribute("offset")); - nonzerosize = SpecXmlUtils.decodeInt(el.getAttribute("nonzero")); - ArrayList masks = new ArrayList<>(); - ArrayList vals = new ArrayList<>(); - XmlElement subel; - while ((subel = parser.softStart("mask_word")) != null) { - masks.add(subel.getAttribute("mask")); - vals.add(subel.getAttribute("val")); - parser.end(subel); + public void decode(Decoder decoder) throws DecoderException { + int el = decoder.openElement(ELEM_PAT_BLOCK); + offset = (int) decoder.readSignedInteger(ATTRIB_OFF); + nonzerosize = (int) decoder.readSignedInteger(ATTRIB_NONZERO); + ArrayList masks = new ArrayList<>(); + ArrayList vals = new ArrayList<>(); + while (decoder.peekElement() == ELEM_MASK_WORD.id()) { + decoder.openElement(); + masks.add((int) decoder.readUnsignedInteger(ATTRIB_MASK)); + vals.add((int) decoder.readUnsignedInteger(ATTRIB_VAL)); + decoder.closeElement(ELEM_MASK_WORD.id()); } maskvec = new int[masks.size()]; valvec = new int[vals.size()]; for (int i = 0; i < maskvec.length; ++i) { - maskvec[i] = SpecXmlUtils.decodeInt(masks.get(i)); - valvec[i] = SpecXmlUtils.decodeInt(vals.get(i)); + maskvec[i] = masks.get(i); + valvec[i] = vals.get(i); } - parser.end(el); + decoder.closeElement(el); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/ContextSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/ContextSymbol.java index 99c4e5ef5ea..c9847df013b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/ContextSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/ContextSymbol.java @@ -19,15 +19,14 @@ */ package ghidra.app.plugin.processors.sleigh.symbol; +import static ghidra.pcode.utils.SlaFormat.*; + import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.app.plugin.processors.sleigh.expression.*; -import ghidra.util.xml.SpecXmlUtils; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * A ValueSymbol that gets its semantic value from contiguous bits * in a VarnodeSymbol. This serves as an embedding of a ContextOp * into an actual Varnode and is probably only relevant at compile time @@ -35,11 +34,13 @@ public class ContextSymbol extends ValueSymbol { private VarnodeSymbol vn; - private int low,high; // Bit range of context value + private int low, high; // Bit range of context value private boolean flow = true; // indicates that context should follow flow - - public VarnodeSymbol getVarnode() { return vn; } - + + public VarnodeSymbol getVarnode() { + return vn; + } + /** * Get starting bit of context value within its context register. * @return the starting bit @@ -74,20 +75,39 @@ public int getInternalLow() { public int getInternalHigh() { return ((ContextField) patval).getEndBit(); } - public boolean followsFlow() { return flow; } - + + public boolean followsFlow() { + return flow; + } + @Override - public void restoreXml(XmlPullParser parser,SleighLanguage sleigh) { - XmlElement el = parser.start("context_sym"); - int id = SpecXmlUtils.decodeInt(el.getAttribute("varnode")); + public void decode(Decoder decoder, SleighLanguage sleigh) throws DecoderException { +// int el = decoder.openElement(ELEM_CONTEXT_SYM); + flow = false; + int id = (int) decoder.readUnsignedInteger(ATTRIB_VARNODE); SymbolTable symtab = sleigh.getSymbolTable(); - vn = (VarnodeSymbol)symtab.findSymbol(id); - low = SpecXmlUtils.decodeInt(el.getAttribute("low")); - if (el.hasAttribute("flow")) { - flow = SpecXmlUtils.decodeBoolean(el.getAttribute("flow")); + vn = (VarnodeSymbol) symtab.findSymbol(id); + int attrib = decoder.getNextAttributeId(); + boolean lowMissing = true; + boolean highMissing = true; + while (attrib != 0) { + if (attrib == ATTRIB_LOW.id()) { + low = (int) decoder.readSignedInteger(); + lowMissing = false; + } + else if (attrib == ATTRIB_HIGH.id()) { + high = (int) decoder.readSignedInteger(); + highMissing = false; + } + else if (attrib == ATTRIB_FLOW.id()) { + flow = decoder.readBool(); + } + attrib = decoder.getNextAttributeId(); + } + if (lowMissing || highMissing) { + throw new DecoderException("Missing high/low attributes"); } - high = SpecXmlUtils.decodeInt(el.getAttribute("high")); - patval = (PatternValue)PatternExpression.restoreExpression(parser,sleigh); - parser.end(el); + patval = (PatternValue) PatternExpression.decodeExpression(decoder, sleigh); + decoder.closeElement(ELEM_CONTEXT_SYM.id()); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/EndSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/EndSymbol.java index 8ac601cad09..9999a95b1a2 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/EndSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/EndSymbol.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,63 +19,54 @@ */ package ghidra.app.plugin.processors.sleigh.symbol; -import ghidra.app.plugin.processors.sleigh.*; -import ghidra.app.plugin.processors.sleigh.expression.*; -import ghidra.program.model.mem.*; -import ghidra.xml.*; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.util.ArrayList; -import java.util.*; +import ghidra.app.plugin.processors.sleigh.*; +import ghidra.app.plugin.processors.sleigh.expression.EndInstructionValue; +import ghidra.app.plugin.processors.sleigh.expression.PatternExpression; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * Symbol with semantic value equal to offset of address immediately * after current instruction */ public class EndSymbol extends SpecificSymbol { private PatternExpression patexp; - - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#getPatternExpression() - */ + @Override - public PatternExpression getPatternExpression() { + public PatternExpression getPatternExpression() { return patexp; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#getFixedHandle(ghidra.app.plugin.processors.sleigh.FixedHandle, ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override - public void getFixedHandle(FixedHandle hand, ParserWalker walker) { + public void getFixedHandle(FixedHandle hand, ParserWalker walker) { hand.space = walker.getCurSpace(); hand.offset_space = null; hand.offset_offset = walker.getNaddr().getOffset(); hand.size = hand.space.getPointerSize(); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#print(ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override - public String print(ParserWalker walker) throws MemoryAccessException { + public String print(ParserWalker walker) throws MemoryAccessException { long val = walker.getNaddr().getOffset(); - return "0x"+Long.toHexString(val); + return "0x" + Long.toHexString(val); } @Override - public void printList(ParserWalker walker, ArrayList list) { + public void printList(ParserWalker walker, ArrayList list) { list.add(walker.getParentHandle()); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.Symbol#restoreXml(org.jdom.Element, ghidra.app.plugin.processors.sleigh.SleighLanguage) - */ + @Override - public void restoreXml(XmlPullParser parser, SleighLanguage sleigh) { - XmlElement element = parser.start("end_sym"); + public void decode(Decoder decoder, SleighLanguage sleigh) throws DecoderException { +// int el = decoder.openElement(ELEM_END_SYM); patexp = new EndInstructionValue(); - parser.end(element); + decoder.closeElement(ELEM_END_SYM.id()); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/EpsilonSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/EpsilonSymbol.java index 08a559c649b..0f892a60935 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/EpsilonSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/EpsilonSymbol.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,50 +19,43 @@ */ package ghidra.app.plugin.processors.sleigh.symbol; -import ghidra.app.plugin.processors.sleigh.*; -import ghidra.xml.*; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.util.ArrayList; -import java.util.*; +import ghidra.app.plugin.processors.sleigh.*; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * A pattern with no semantic or printing content, that will match * any pattern. */ public class EpsilonSymbol extends PatternlessSymbol { - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#getFixedHandle(ghidra.app.plugin.processors.sleigh.FixedHandle, ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override - public void getFixedHandle(FixedHandle hand, ParserWalker walker) { + public void getFixedHandle(FixedHandle hand, ParserWalker walker) { hand.space = walker.getConstSpace(); hand.offset_space = null; // Not a dynamic value hand.offset_offset = 0; hand.size = 0; // Cannot provide size } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#print(ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override - public String print(ParserWalker walker) { + public String print(ParserWalker walker) { return "0"; } @Override - public void printList(ParserWalker walker, ArrayList list) { + public void printList(ParserWalker walker, ArrayList list) { list.add(walker.getParentHandle()); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Symbol#restoreXml(org.jdom.Element, ghidra.program.model.address.AddressFactory) - */ + @Override - public void restoreXml(XmlPullParser parser,SleighLanguage sleigh) { - XmlElement element = parser.start("epsilon_sym"); + public void decode(Decoder decoder, SleighLanguage sleigh) throws DecoderException { +// int element = decoder.openElement(ELEM_EPSILON_SYM); + decoder.closeElement(ELEM_EPSILON_SYM.id()); // Nothing to do - parser.end(element); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/NameSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/NameSymbol.java index c110cd581c6..dd605fd3411 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/NameSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/NameSymbol.java @@ -19,6 +19,8 @@ */ package ghidra.app.plugin.processors.sleigh.symbol; +import static ghidra.pcode.utils.SlaFormat.*; + import java.util.*; import ghidra.app.plugin.processors.sleigh.*; @@ -26,12 +28,10 @@ import ghidra.app.plugin.processors.sleigh.expression.PatternValue; import ghidra.program.model.lang.UnknownInstructionException; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * A ValueSymbol whose printing aspect is determined by looking * up the context value of the symbol in a table of strings */ @@ -55,9 +55,6 @@ private void checkTableFill() { } } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#resolve(ghidra.app.plugin.processors.sleigh.ParserWalker, ghidra.app.plugin.processors.sleigh.SleighDebugLogger) - */ @Override public Constructor resolve(ParserWalker walker, SleighDebugLogger debug) throws MemoryAccessException, UnknownInstructionException { @@ -75,42 +72,43 @@ public Constructor resolve(ParserWalker walker, SleighDebugLogger debug) return null; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#print(ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override public String print(ParserWalker walker) throws MemoryAccessException { int ind = (int) getPatternValue().getValue(walker); return nametable[ind]; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#printList(ghidra.app.plugin.processors.sleigh.ParserWalker, java.util.ArrayList) - */ @Override public void printList(ParserWalker walker, ArrayList list) throws MemoryAccessException { int ind = (int) getPatternValue().getValue(walker); String token = nametable[ind]; - for (int i = 0; i < token.length(); ++i) + for (int i = 0; i < token.length(); ++i) { list.add(Character.valueOf(token.charAt(i))); + } } @Override - public void restoreXml(XmlPullParser parser, SleighLanguage sleigh) { - XmlElement el = parser.start("name_sym"); - patval = (PatternValue) PatternExpression.restoreExpression(parser, sleigh); + public void decode(Decoder decoder, SleighLanguage sleigh) throws DecoderException { +// int el = decoder.openElement(ELEM_NAME_SYM); + patval = (PatternValue) PatternExpression.decodeExpression(decoder, sleigh); ArrayList names = new ArrayList<>(); - XmlElement nametab; - while ((nametab = parser.softStart("nametab")) != null) { - names.add(nametab.getAttribute("name")); - parser.end(nametab); + while (decoder.peekElement() == ELEM_NAMETAB.id()) { + decoder.openElement(); + int attrib = decoder.getNextAttributeId(); + if (attrib == ATTRIB_NAME.id()) { + names.add(decoder.readString()); + } + else { + names.add(null); + } + decoder.closeElement(ELEM_NAMETAB.id()); } nametable = new String[names.size()]; for (int i = 0; i < nametable.length; ++i) { nametable[i] = names.get(i); } checkTableFill(); - parser.end(el); + decoder.closeElement(ELEM_NAME_SYM.id()); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/Next2Symbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/Next2Symbol.java index 5c2660f02c8..661cc57e87c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/Next2Symbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/Next2Symbol.java @@ -15,32 +15,32 @@ */ package ghidra.app.plugin.processors.sleigh.symbol; +import static ghidra.pcode.utils.SlaFormat.*; + import java.util.ArrayList; import ghidra.app.plugin.processors.sleigh.*; import ghidra.app.plugin.processors.sleigh.expression.Next2InstructionValue; import ghidra.app.plugin.processors.sleigh.expression.PatternExpression; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * Symbol with semantic value equal to offset of address immediately * after the next instruction (inst_next2) */ public class Next2Symbol extends SpecificSymbol { private PatternExpression patexp; - + @Override - public PatternExpression getPatternExpression() { + public PatternExpression getPatternExpression() { return patexp; } @Override - public void getFixedHandle(FixedHandle hand, ParserWalker walker) { + public void getFixedHandle(FixedHandle hand, ParserWalker walker) { hand.space = walker.getCurSpace(); hand.offset_space = null; hand.offset_offset = walker.getN2addr().getOffset(); @@ -48,21 +48,21 @@ public void getFixedHandle(FixedHandle hand, ParserWalker walker) { } @Override - public String print(ParserWalker walker) throws MemoryAccessException { + public String print(ParserWalker walker) throws MemoryAccessException { long val = walker.getN2addr().getOffset(); - return "0x"+Long.toHexString(val); + return "0x" + Long.toHexString(val); } @Override - public void printList(ParserWalker walker, ArrayList list) { + public void printList(ParserWalker walker, ArrayList list) { list.add(walker.getParentHandle()); } @Override - public void restoreXml(XmlPullParser parser, SleighLanguage sleigh) { - XmlElement element = parser.start("next2_sym"); + public void decode(Decoder decoder, SleighLanguage sleigh) throws DecoderException { +// int element = decoder.openElement(ELEM_NEXT2_SYM); patexp = new Next2InstructionValue(); - parser.end(element); + decoder.closeElement(ELEM_NEXT2_SYM.id()); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/OperandSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/OperandSymbol.java index f7074b3a270..02680346d4a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/OperandSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/OperandSymbol.java @@ -19,21 +19,18 @@ */ package ghidra.app.plugin.processors.sleigh.symbol; +import static ghidra.pcode.utils.SlaFormat.*; + import java.util.ArrayList; -import ghidra.app.plugin.processors.sleigh.FixedHandle; -import ghidra.app.plugin.processors.sleigh.ParserWalker; -import ghidra.app.plugin.processors.sleigh.SleighLanguage; +import ghidra.app.plugin.processors.sleigh.*; import ghidra.app.plugin.processors.sleigh.expression.OperandValue; import ghidra.app.plugin.processors.sleigh.expression.PatternExpression; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.util.xml.SpecXmlUtils; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * Variable representing an operand to a specific Constructor */ public class OperandSymbol extends SpecificSymbol { @@ -77,17 +74,11 @@ public boolean isCodeAddress() { return codeaddress; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#getPatternExpression() - */ @Override public PatternExpression getPatternExpression() { return localexp; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#getFixedHandle(ghidra.app.plugin.processors.sleigh.FixedHandle, ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override public void getFixedHandle(FixedHandle hnd, ParserWalker walker) { FixedHandle h = walker.getFixedHandle(hand); @@ -100,25 +91,26 @@ public void getFixedHandle(FixedHandle hnd, ParserWalker walker) { hnd.temp_offset = h.temp_offset; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#print(ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override public String print(ParserWalker walker) throws MemoryAccessException { String res; walker.pushOperand(hand); if (triple != null) { - if (triple instanceof SubtableSymbol) + if (triple instanceof SubtableSymbol) { res = walker.getConstructor().print(walker); - else + } + else { res = triple.print(walker); + } } else { // Must be expression resulting in a constant long val = defexp.getValue(walker); - if (val >= 0) + if (val >= 0) { res = "0x" + Long.toHexString(val); - else + } + else { res = "-0x" + Long.toHexString(-val); + } } walker.popOperand(); return res; @@ -129,10 +121,12 @@ public void printList(ParserWalker walker, ArrayList list) throws MemoryAccessException { walker.pushOperand(hand); if (triple != null) { - if (triple instanceof SubtableSymbol) + if (triple instanceof SubtableSymbol) { walker.getConstructor().printList(walker, list); - else + } + else { triple.printList(walker, list); + } } else { FixedHandle handle = walker.getParentHandle(); @@ -144,32 +138,41 @@ public void printList(ParserWalker walker, ArrayList list) walker.popOperand(); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.Symbol#restoreXml(org.jdom.Element, ghidra.app.plugin.processors.sleigh.SleighLanguage) - */ @Override - public void restoreXml(XmlPullParser parser, SleighLanguage lang) { - XmlElement el = parser.start("operand_sym"); + public void decode(Decoder decoder, SleighLanguage lang) throws DecoderException { +// int el = decoder.openElement(ELEM_OPERAND_SYM); defexp = null; triple = null; codeaddress = false; - - hand = SpecXmlUtils.decodeInt(el.getAttribute("index")); - - reloffset = SpecXmlUtils.decodeInt(el.getAttribute("off")); - offsetbase = SpecXmlUtils.decodeInt(el.getAttribute("base")); - minimumlength = SpecXmlUtils.decodeInt(el.getAttribute("minlen")); - String attrstr = el.getAttribute("subsym"); - if (attrstr != null) { - int id = SpecXmlUtils.decodeInt(attrstr); - triple = (TripleSymbol) lang.getSymbolTable().findSymbol(id); + int attrib = decoder.getNextAttributeId(); + while (attrib != 0) { + if (attrib == ATTRIB_INDEX.id()) { + hand = (int) decoder.readSignedInteger(); + } + else if (attrib == ATTRIB_OFF.id()) { + reloffset = (int) decoder.readSignedInteger(); + } + else if (attrib == ATTRIB_BASE.id()) { + offsetbase = (int) decoder.readSignedInteger(); + } + else if (attrib == ATTRIB_MINLEN.id()) { + minimumlength = (int) decoder.readSignedInteger(); + } + else if (attrib == ATTRIB_SUBSYM.id()) { + int id = (int) decoder.readUnsignedInteger(); + triple = (TripleSymbol) lang.getSymbolTable().findSymbol(id); + } + else if (attrib == ATTRIB_CODE.id()) { + codeaddress = decoder.readBool(); + } + attrib = decoder.getNextAttributeId(); } - codeaddress = SpecXmlUtils.decodeBoolean(el.getAttribute("code")); - localexp = (OperandValue) PatternExpression.restoreExpression(parser, lang); - if (!parser.peek().isEnd()) - defexp = PatternExpression.restoreExpression(parser, lang); - parser.end(el); + localexp = (OperandValue) PatternExpression.decodeExpression(decoder, lang); + if (decoder.peekElement() != 0) { + defexp = PatternExpression.decodeExpression(decoder, lang); + } + decoder.closeElement(ELEM_OPERAND_SYM.id()); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/StartSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/StartSymbol.java index a3cf4f8f2b3..60f0c354812 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/StartSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/StartSymbol.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,63 +19,54 @@ */ package ghidra.app.plugin.processors.sleigh.symbol; -import ghidra.app.plugin.processors.sleigh.*; -import ghidra.app.plugin.processors.sleigh.expression.*; -import ghidra.program.model.mem.*; -import ghidra.xml.*; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.util.ArrayList; -import java.util.*; +import ghidra.app.plugin.processors.sleigh.*; +import ghidra.app.plugin.processors.sleigh.expression.PatternExpression; +import ghidra.app.plugin.processors.sleigh.expression.StartInstructionValue; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * TripleSymbol with semantic value equal to offset of instruction's * current address */ public class StartSymbol extends SpecificSymbol { private PatternExpression patexp; - - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#getPatternExpression() - */ + @Override - public PatternExpression getPatternExpression() { + public PatternExpression getPatternExpression() { return patexp; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#getFixedHandle(ghidra.app.plugin.processors.sleigh.FixedHandle, ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override - public void getFixedHandle(FixedHandle hand, ParserWalker walker) { + public void getFixedHandle(FixedHandle hand, ParserWalker walker) { hand.space = walker.getCurSpace(); hand.offset_space = null; hand.offset_offset = walker.getAddr().getOffset(); hand.size = hand.space.getPointerSize(); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#print(ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override - public String print(ParserWalker walker) throws MemoryAccessException { + public String print(ParserWalker walker) throws MemoryAccessException { long val = walker.getAddr().getOffset(); return "0x" + Long.toHexString(val); } @Override - public void printList(ParserWalker walker, ArrayList list) { + public void printList(ParserWalker walker, ArrayList list) { list.add(walker.getParentHandle()); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.Symbol#restoreXml(org.jdom.Element, ghidra.app.plugin.processors.sleigh.SleighLanguage) - */ + @Override - public void restoreXml(XmlPullParser parser, SleighLanguage sleigh) { - XmlElement element = parser.start("start_sym"); + public void decode(Decoder decoder, SleighLanguage sleigh) throws DecoderException { +// int element = decoder.openElement(ELEM_START_SYM); patexp = new StartInstructionValue(); - parser.end(element); + decoder.closeElement(ELEM_START_SYM.id()); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/SubtableSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/SubtableSymbol.java index 62f1497ef0b..e98cac30eb7 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/SubtableSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/SubtableSymbol.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,18 +19,18 @@ */ package ghidra.app.plugin.processors.sleigh.symbol; -import ghidra.app.plugin.processors.sleigh.*; -import ghidra.app.plugin.processors.sleigh.expression.*; -import ghidra.program.model.lang.*; -import ghidra.program.model.mem.*; -import ghidra.util.xml.*; -import ghidra.xml.*; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.util.ArrayList; -import java.util.*; +import ghidra.app.plugin.processors.sleigh.*; +import ghidra.app.plugin.processors.sleigh.expression.PatternExpression; +import ghidra.program.model.lang.UnknownInstructionException; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * A collection of Constructors or a Symbol representing * one out of a family of Constructors, choosen based on InstructionContext */ @@ -40,67 +39,61 @@ public class SubtableSymbol extends TripleSymbol { private Constructor[] construct; // All the constructors in this table private DecisionNode decisiontree; // The decision tree for this table - public DecisionNode getDecisionNode() { return decisiontree; } - - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#resolve(ghidra.app.plugin.processors.sleigh.ParserWalker, ghidra.app.plugin.processors.sleigh.SleighDebugLogger) - */ + public DecisionNode getDecisionNode() { + return decisiontree; + } + @Override - public Constructor resolve(ParserWalker walker, SleighDebugLogger debug) throws MemoryAccessException, UnknownInstructionException { + public Constructor resolve(ParserWalker walker, SleighDebugLogger debug) + throws MemoryAccessException, UnknownInstructionException { return decisiontree.resolve(walker, debug); } - - public int getNumConstructors() { return construct.length; } - public Constructor getConstructor(int i) { return construct[i]; } - - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#getPatternExpression() - */ + + public int getNumConstructors() { + return construct.length; + } + + public Constructor getConstructor(int i) { + return construct[i]; + } + @Override - public PatternExpression getPatternExpression() { + public PatternExpression getPatternExpression() { throw new SleighException("Cannot use subtable in expression"); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#getFixedHandle(ghidra.app.plugin.processors.sleigh.FixedHandle, ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override - public void getFixedHandle(FixedHandle hand, ParserWalker walker) { + public void getFixedHandle(FixedHandle hand, ParserWalker walker) { throw new SleighException("Cannot use subtable in expression"); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#print(ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override - public String print(ParserWalker walker) throws MemoryAccessException { + public String print(ParserWalker walker) throws MemoryAccessException { throw new SleighException("Cannot use subtable in expression"); } @Override - public void printList(ParserWalker walker, ArrayList list) { + public void printList(ParserWalker walker, ArrayList list) { throw new SleighException("Cannot use subtable in expression"); } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.Symbol#restoreXml(org.jdom.Element, ghidra.app.plugin.processors.sleigh.SleighLanguage) - */ + @Override - public void restoreXml(XmlPullParser parser, SleighLanguage sleigh) throws UnknownInstructionException { - XmlElement el = parser.start("subtable_sym"); - int numct = SpecXmlUtils.decodeInt(el.getAttribute("numct")); + public void decode(Decoder decoder, SleighLanguage sleigh) throws DecoderException { +// int el = decoder.openElement(ELEM_SUBTABLE_SYM); + int numct = (int) decoder.readSignedInteger(ATTRIB_NUMCT); construct = new Constructor[numct]; // Array must be built - // before restoring constructors - for(int i=0;i0) { - if (res.getParent() == null) + while (i > 0) { + if (res.getParent() == null) { return res; + } res = res.getParent(); --i; } return res; } - - private Symbol findSymbolInternal(SymbolScope scope,String nm) { - while(scope != null) { + + private Symbol findSymbolInternal(SymbolScope scope, String nm) { + while (scope != null) { Symbol res = scope.findSymbol(nm); - if (res != null) + if (res != null) { return res; + } scope = scope.getParent(); } return null; } - - public SymbolTable() { curscope = null; } - - public SymbolScope getCurrentScope() { return curscope; } - - public SymbolScope getGlobalScope() { return table[0]; } - - public void setCurrentScope(SymbolScope scope) { curscope = scope; } - + + public SymbolTable() { + curscope = null; + } + + public SymbolScope getCurrentScope() { + return curscope; + } + + public SymbolScope getGlobalScope() { + return table[0]; + } + + public void setCurrentScope(SymbolScope scope) { + curscope = scope; + } + public Symbol findSymbol(String nm) { - return findSymbolInternal(curscope,nm); + return findSymbolInternal(curscope, nm); } - public Symbol findSymbol(String nm,int skip) { - return findSymbolInternal(skipScope(skip),nm); + public Symbol findSymbol(String nm, int skip) { + return findSymbolInternal(skipScope(skip), nm); } - + public Symbol findGlobalSymbol(String nm) { - return findSymbolInternal(table[0],nm); + return findSymbolInternal(table[0], nm); + } + + public Symbol[] getSymbolList() { + return symbollist; } - public Symbol[] getSymbolList() { return symbollist; } - public Symbol findSymbol(int id) { return symbollist[id]; } - - public void restoreXml(XmlPullParser parser, SleighLanguage sleigh) throws UnknownInstructionException { - XmlElement el = parser.start("symbol_table"); - int scopesize = SpecXmlUtils.decodeInt(el.getAttribute("scopesize")); + + public void decode(Decoder decoder, SleighLanguage sleigh) throws DecoderException { + int el = decoder.openElement(ELEM_SYMBOL_TABLE); + int scopesize = (int) decoder.readSignedInteger(ATTRIB_SCOPESIZE); table = new SymbolScope[scopesize]; - int symsize = SpecXmlUtils.decodeInt(el.getAttribute("symbolsize")); + int symsize = (int) decoder.readSignedInteger(ATTRIB_SYMBOLSIZE); symbollist = new Symbol[symsize]; - - // Restore the scopes - for(int i=0;i userops = new ArrayList(); - XmlElement subel = parser.peek(); - while(!subel.getName().equals("symbol_table")) { // Restore the symbol content - int id = SpecXmlUtils.decodeInt(subel.getAttribute("id")); + while (decoder.peekElement() != 0) { // Decode the symbol content + decoder.openElement(); + int id = (int) decoder.readUnsignedInteger(ATTRIB_ID); Symbol sym = findSymbol(id); - sym.restoreXml(parser,sleigh); - if (sym instanceof UseropSymbol) - userops.add((UseropSymbol)sym); - subel = parser.peek(); + sym.decode(decoder, sleigh); + // Tag closed by decode method +// decoder.closeElement(subel); + if (sym instanceof UseropSymbol) { + userops.add((UseropSymbol) sym); + } } userOps = new UseropSymbol[userops.size()]; userops.toArray(userOps); - parser.end(el); + decoder.closeElement(el); } - - public void restoreSymbolHeader(XmlPullParser parser) { + + public void decodeSymbolHeader(Decoder decoder) throws DecoderException { Symbol sym; - XmlElement el = parser.peek(); - if (el.getName().equals("userop_head")) + int el = decoder.peekElement(); + if (el == ELEM_USEROP_HEAD.id()) { sym = new UseropSymbol(); - else if (el.getName().equals("epsilon_sym_head")) + } + else if (el == ELEM_EPSILON_SYM_HEAD.id()) { sym = new EpsilonSymbol(); - else if (el.getName().equals("value_sym_head")) + } + else if (el == ELEM_VALUE_SYM_HEAD.id()) { sym = new ValueSymbol(); - else if (el.getName().equals("valuemap_sym_head")) + } + else if (el == ELEM_VALUEMAP_SYM_HEAD.id()) { sym = new ValueMapSymbol(); - else if (el.getName().equals("name_sym_head")) + } + else if (el == ELEM_NAME_SYM_HEAD.id()) { sym = new NameSymbol(); - else if (el.getName().equals("varnode_sym_head")) + } + else if (el == ELEM_VARNODE_SYM_HEAD.id()) { sym = new VarnodeSymbol(); - else if (el.getName().equals("context_sym_head")) + } + else if (el == ELEM_CONTEXT_SYM_HEAD.id()) { sym = new ContextSymbol(); - else if (el.getName().equals("varlist_sym_head")) + } + else if (el == ELEM_VARLIST_SYM_HEAD.id()) { sym = new VarnodeListSymbol(); - else if (el.getName().equals("operand_sym_head")) + } + else if (el == ELEM_OPERAND_SYM_HEAD.id()) { sym = new OperandSymbol(); - else if (el.getName().equals("start_sym_head")) + } + else if (el == ELEM_START_SYM_HEAD.id()) { sym = new StartSymbol(); - else if (el.getName().equals("end_sym_head")) + } + else if (el == ELEM_END_SYM_HEAD.id()) { sym = new EndSymbol(); - else if (el.getName().equals("next2_sym_head")) + } + else if (el == ELEM_NEXT2_SYM_HEAD.id()) { sym = new Next2Symbol(); - else if (el.getName().equals("subtable_sym_head")) + } + else if (el == ELEM_SUBTABLE_SYM_HEAD.id()) { sym = new SubtableSymbol(); - else - throw new SleighException("Bad symbol xml"); - sym.restoreHeaderXml(parser); // Restore basic elements of symbol + } + else { + throw new SleighException("Bad symbol encoding"); + } + sym.decodeHeader(decoder); // Decode basic elements of symbol symbollist[sym.getId()] = sym; table[sym.getScopeId()].addSymbol(sym); } @@ -166,10 +194,11 @@ else if (el.getName().equals("subtable_sym_head")) public int getNumberOfUserDefinedOpNames() { return userOps.length; } - + public String getUserDefinedOpName(int index) { - if (index < userOps.length) + if (index < userOps.length) { return userOps[index].getName(); + } return null; } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/UseropSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/UseropSymbol.java index 15a5a5e7523..d2d7bb38a75 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/UseropSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/UseropSymbol.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,26 +19,28 @@ */ package ghidra.app.plugin.processors.sleigh.symbol; -import ghidra.app.plugin.processors.sleigh.*; -import ghidra.util.xml.*; -import ghidra.xml.*; +import static ghidra.pcode.utils.SlaFormat.*; + +import ghidra.app.plugin.processors.sleigh.SleighLanguage; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * A user-defined pcode operation (PcodeOp) * This is implemented as a name and a unique id which is passed * as the first parameter to a PcodeOp with the opcode = "CALLOTHER". */ public class UseropSymbol extends Symbol { private int index; // Unique id for this userop - - public int getIndex() { return index; } - + + public int getIndex() { + return index; + } + @Override - public void restoreXml(XmlPullParser parser,SleighLanguage sleigh) { - XmlElement el = parser.start("userop"); - index = SpecXmlUtils.decodeInt(el.getAttribute("index")); - parser.end(el); + public void decode(Decoder decoder, SleighLanguage sleigh) throws DecoderException { +// int el = decoder.openElement(ELEM_USEROP); + index = (int) decoder.readSignedInteger(ATTRIB_INDEX); + decoder.closeElement(ELEM_USEROP.id()); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/ValueMapSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/ValueMapSymbol.java index 087750b643e..c4ee351f436 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/ValueMapSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/ValueMapSymbol.java @@ -15,6 +15,8 @@ */ package ghidra.app.plugin.processors.sleigh.symbol; +import static ghidra.pcode.utils.SlaFormat.*; + import java.util.*; import ghidra.app.plugin.processors.sleigh.*; @@ -22,9 +24,8 @@ import ghidra.app.plugin.processors.sleigh.expression.PatternValue; import ghidra.program.model.lang.UnknownInstructionException; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.util.xml.SpecXmlUtils; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; public class ValueMapSymbol extends ValueSymbol { private long[] valuetable; // Map from natural encoding to attached values @@ -43,14 +44,12 @@ private void checkTableFill() { long max = getPatternValue().maxValue(); tableisfilled = (min >= 0) && (max < valuetable.length); for (long element : valuetable) { - if (element == 0xBADBEEF) + if (element == 0xBADBEEF) { tableisfilled = false; + } } } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#resolve(ghidra.app.plugin.processors.sleigh.ParserWalker, ghidra.app.plugin.processors.sleigh.SleighDebugLogger) - */ @Override public Constructor resolve(ParserWalker walker, SleighDebugLogger debug) throws MemoryAccessException, UnknownInstructionException { @@ -68,9 +67,6 @@ public Constructor resolve(ParserWalker walker, SleighDebugLogger debug) return null; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#getFixedHandle(ghidra.app.plugin.processors.sleigh.FixedHandle, ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override public void getFixedHandle(FixedHandle hand, ParserWalker walker) throws MemoryAccessException { int ind = (int) getPatternValue().getValue(walker); @@ -87,28 +83,30 @@ public String print(ParserWalker walker) throws MemoryAccessException { // ind is already known to be a valid array index via resolve long val = valuetable[ind]; String res; - if (val >= 0) + if (val >= 0) { res = "0x" + Long.toHexString(val); - else + } + else { res = "-0x" + Long.toHexString(-val); + } return res; } @Override - public void restoreXml(XmlPullParser parser, SleighLanguage sleigh) { - XmlElement el = parser.start("valuemap_sym"); - patval = (PatternValue) PatternExpression.restoreExpression(parser, sleigh); - ArrayList values = new ArrayList<>(); - XmlElement valuetab; - while ((valuetab = parser.softStart("valuetab")) != null) { - values.add(valuetab.getAttribute("val")); - parser.end(valuetab); + public void decode(Decoder decoder, SleighLanguage sleigh) throws DecoderException { +// int el = decoder.openElement(ELEM_VALUEMAP_SYM); + patval = (PatternValue) PatternExpression.decodeExpression(decoder, sleigh); + ArrayList values = new ArrayList<>(); + while (decoder.peekElement() == ELEM_VALUETAB.id()) { + decoder.openElement(); + values.add(decoder.readSignedInteger(ATTRIB_VAL)); + decoder.closeElement(ELEM_VALUETAB.id()); } valuetable = new long[values.size()]; for (int i = 0; i < valuetable.length; ++i) { - valuetable[i] = SpecXmlUtils.decodeLong(values.get(i)); + valuetable[i] = values.get(i); } checkTableFill(); - parser.end(el); + decoder.closeElement(ELEM_VALUEMAP_SYM.id()); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/ValueSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/ValueSymbol.java index 6c28b134a7d..a264e7b20d4 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/ValueSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/ValueSymbol.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,80 +19,67 @@ */ package ghidra.app.plugin.processors.sleigh.symbol; -import ghidra.app.plugin.processors.sleigh.*; -import ghidra.app.plugin.processors.sleigh.expression.*; -import ghidra.program.model.mem.*; -import ghidra.xml.*; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.util.ArrayList; -import java.util.*; +import ghidra.app.plugin.processors.sleigh.*; +import ghidra.app.plugin.processors.sleigh.expression.PatternExpression; +import ghidra.app.plugin.processors.sleigh.expression.PatternValue; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * A variable with its semantic (and printing) value equal to a fixed * mapping of its pattern */ public class ValueSymbol extends FamilySymbol { protected PatternValue patval; - - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.FamilySymbol#getPatternValue() - */ + @Override - public PatternValue getPatternValue() { + public PatternValue getPatternValue() { return patval; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.TripleSymbol#getPatternExpression() - */ @Override - public PatternExpression getPatternExpression() { + public PatternExpression getPatternExpression() { return patval; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#getFixedHandle(ghidra.app.plugin.processors.sleigh.FixedHandle, ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override - public void getFixedHandle(FixedHandle hand, ParserWalker walker) throws MemoryAccessException { + public void getFixedHandle(FixedHandle hand, ParserWalker walker) throws MemoryAccessException { hand.space = walker.getConstSpace(); hand.offset_space = null; hand.offset_offset = patval.getValue(walker); hand.size = 0; // Cannot provide size } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#print(ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override - public String print(ParserWalker walker) throws MemoryAccessException { + public String print(ParserWalker walker) throws MemoryAccessException { long val = patval.getValue(walker); String res; - if (val >= 0) + if (val >= 0) { res = "0x" + Long.toHexString(val); - else + } + else { res = "-0x" + Long.toHexString(-val); + } return res; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#printList(ghidra.app.plugin.processors.sleigh.ParserWalker, java.util.ArrayList) - */ @Override - public void printList(ParserWalker walker, ArrayList list) throws MemoryAccessException { + public void printList(ParserWalker walker, ArrayList list) + throws MemoryAccessException { list.add(walker.getParentHandle()); } - - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.Symbol#restoreXml(org.jdom.Element, ghidra.program.model.address.AddressFactory) - */ + @Override - public void restoreXml(XmlPullParser parser,SleighLanguage sleigh) { - XmlElement el = parser.start("value_sym"); - patval = (PatternValue)PatternExpression.restoreExpression(parser,sleigh); - parser.end(el); + public void decode(Decoder decoder, SleighLanguage sleigh) throws DecoderException { +// int el = decoder.openElement(ELEM_VALUE_SYM); + patval = (PatternValue) PatternExpression.decodeExpression(decoder, sleigh); + decoder.closeElementSkipping(ELEM_VALUE_SYM.id()); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/VarnodeListSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/VarnodeListSymbol.java index 9d2911ac61f..27443618f47 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/VarnodeListSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/VarnodeListSymbol.java @@ -19,28 +19,19 @@ */ package ghidra.app.plugin.processors.sleigh.symbol; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; +import static ghidra.pcode.utils.SlaFormat.*; -import ghidra.app.plugin.processors.sleigh.Constructor; -import ghidra.app.plugin.processors.sleigh.FixedHandle; -import ghidra.app.plugin.processors.sleigh.ParserWalker; -import ghidra.app.plugin.processors.sleigh.SleighDebugLogger; -import ghidra.app.plugin.processors.sleigh.SleighLanguage; -import ghidra.app.plugin.processors.sleigh.VarnodeData; +import java.util.*; + +import ghidra.app.plugin.processors.sleigh.*; import ghidra.app.plugin.processors.sleigh.expression.PatternExpression; import ghidra.app.plugin.processors.sleigh.expression.PatternValue; import ghidra.program.model.lang.UnknownInstructionException; import ghidra.program.model.mem.MemoryAccessException; -import ghidra.util.xml.SpecXmlUtils; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * A ValueSymbol where the semantic context is obtained by looking * up the value in a table of VarnodeSymbols */ @@ -58,14 +49,12 @@ private void checkTableFill() { long max = getPatternValue().maxValue(); tableisfilled = (min >= 0) && (max < varnode_table.length); for (int i = 0; i < varnode_table.length; ++i) { - if (varnode_table[i] == null) + if (varnode_table[i] == null) { tableisfilled = false; + } } } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#resolve(ghidra.app.plugin.processors.sleigh.ParserWalker, ghidra.app.plugin.processors.sleigh.SleighDebugLogger) - */ @Override public Constructor resolve(ParserWalker walker, SleighDebugLogger debug) throws MemoryAccessException, UnknownInstructionException { @@ -102,20 +91,21 @@ public String print(ParserWalker walker) throws MemoryAccessException { } @Override - public void restoreXml(XmlPullParser parser, SleighLanguage sleigh) { - XmlElement el = parser.start("varlist_sym"); - patval = (PatternValue) PatternExpression.restoreExpression(parser, sleigh); + public void decode(Decoder decoder, SleighLanguage sleigh) throws DecoderException { +// int el = decoder.openElement(ELEM_VARLIST_SYM); + patval = (PatternValue) PatternExpression.decodeExpression(decoder, sleigh); ArrayList varnodes = new ArrayList<>(); SymbolTable symtab = sleigh.getSymbolTable(); - while (!parser.peek().isEnd()) { - XmlElement subel = parser.start(); - if (subel.getName().equals("var")) { - int id = SpecXmlUtils.decodeInt(subel.getAttribute("id")); + while (decoder.peekElement() != 0) { + int subel = decoder.openElement(); + if (subel == ELEM_VAR.id()) { + int id = (int) decoder.readUnsignedInteger(ATTRIB_ID); varnodes.add((VarnodeSymbol) symtab.findSymbol(id)); } - else + else { varnodes.add(null); - parser.end(subel); + } + decoder.closeElement(subel); } varnode_table = new VarnodeSymbol[varnodes.size()]; @@ -123,6 +113,6 @@ public void restoreXml(XmlPullParser parser, SleighLanguage sleigh) { varnode_table[i] = varnodes.get(i); } checkTableFill(); - parser.end(el); + decoder.closeElement(ELEM_VARLIST_SYM.id()); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/VarnodeSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/VarnodeSymbol.java index 635e0b88853..536c16cd6cb 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/VarnodeSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/VarnodeSymbol.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,61 +19,51 @@ */ package ghidra.app.plugin.processors.sleigh.symbol; -import ghidra.app.plugin.processors.sleigh.*; -import ghidra.program.model.address.*; -import ghidra.util.xml.*; -import ghidra.xml.*; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.util.ArrayList; -import java.util.*; +import ghidra.app.plugin.processors.sleigh.*; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * A symbol representing a global varnode, i.e. a named memory location */ public class VarnodeSymbol extends PatternlessSymbol { private VarnodeData fix; - - public VarnodeData getFixedVarnode() { return fix; } - - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#getFixedHandle(ghidra.app.plugin.processors.sleigh.FixedHandle, ghidra.app.plugin.processors.sleigh.ParserWalker) - */ + + public VarnodeData getFixedVarnode() { + return fix; + } + @Override - public void getFixedHandle(FixedHandle hand, ParserWalker walker) { + public void getFixedHandle(FixedHandle hand, ParserWalker walker) { hand.space = fix.space; hand.offset_space = null; // Not a dynamic variable hand.offset_offset = fix.offset; hand.size = fix.size; } - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol#print(ghidra.app.plugin.processors.sleigh.ParserWalker) - */ @Override - public String print(ParserWalker walker) { + public String print(ParserWalker walker) { return getName(); // Use the symbol name for printing } @Override - public void printList(ParserWalker walker, ArrayList list) { + public void printList(ParserWalker walker, ArrayList list) { list.add(walker.getParentHandle()); } - - /* (non-Javadoc) - * @see ghidra.app.plugin.processors.sleigh.symbol.Symbol#restoreXml(org.jdom.Element, ghidra.program.model.address.AddressFactory) - */ + @Override - public void restoreXml(XmlPullParser parser,SleighLanguage sleigh) { - XmlElement el = parser.start("varnode_sym"); + public void decode(Decoder decoder, SleighLanguage sleigh) throws DecoderException { +// int el = decoder.openElement(ELEM_VARNODE_SYM); fix = new VarnodeData(); - AddressFactory factory = sleigh.getAddressFactory(); - fix.space = factory.getAddressSpace(el.getAttribute("space")); - fix.offset = SpecXmlUtils.decodeLong(el.getAttribute("offset")); - fix.size = SpecXmlUtils.decodeInt(el.getAttribute("size")); - // PatternlessSymbol does not need to be restored - parser.end(el); + fix.space = decoder.readSpace(ATTRIB_SPACE); + fix.offset = decoder.readUnsignedInteger(ATTRIB_OFF); + fix.size = (int) decoder.readSignedInteger(ATTRIB_SIZE); + decoder.closeElement(ELEM_VARNODE_SYM.id()); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/ConstTpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/ConstTpl.java index 1df3ea70968..75cc37f1e27 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/ConstTpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/ConstTpl.java @@ -19,16 +19,14 @@ */ package ghidra.app.plugin.processors.sleigh.template; +import static ghidra.pcode.utils.SlaFormat.*; + import ghidra.app.plugin.processors.sleigh.*; -import ghidra.program.model.address.AddressFactory; import ghidra.program.model.address.AddressSpace; -import ghidra.util.xml.SpecXmlUtils; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * A placeholder for what will resolve to a field of a Varnode * (an AddressSpace or integer offset or integer size) * given a particular InstructionContext @@ -284,73 +282,62 @@ public void fillinOffset(FixedHandle hand, ParserWalker walker) { } } - public void restoreXml(XmlPullParser parser, AddressFactory factory) { - XmlElement el = parser.start("const_tpl"); - String typestr = el.getAttribute("type"); - if (typestr.equals("real")) { + public void decode(Decoder decoder) throws DecoderException { + int el = decoder.openElement(); + if (el == ELEM_CONST_REAL.id()) { type = REAL; - value_real = SpecXmlUtils.decodeLong(el.getAttribute("val")); + value_real = decoder.readUnsignedInteger(ATTRIB_VAL); } - else if (typestr.equals("handle")) { + else if (el == ELEM_CONST_HANDLE.id()) { type = HANDLE; - handle_index = (short) SpecXmlUtils.decodeInt(el.getAttribute("val")); - String selstr = el.getAttribute("s"); - if (selstr.equals("space")) { - select = V_SPACE; - } - else if (selstr.equals("offset")) { - select = V_OFFSET; - } - else if (selstr.equals("size")) { - select = V_SIZE; - } - else if (selstr.equals("offset_plus")) { - select = V_OFFSET_PLUS; - value_real = SpecXmlUtils.decodeLong(el.getAttribute("plus")); + handle_index = (short) decoder.readSignedInteger(ATTRIB_VAL); + select = (short) decoder.readSignedInteger(ATTRIB_S); + if (select < 0 || select > V_OFFSET_PLUS) { + throw new DecoderException("Bad handle selector encoding"); } - else { - throw new SleighException("Bad handle selector"); + if (select == V_OFFSET_PLUS) { + value_real = decoder.readUnsignedInteger(ATTRIB_PLUS); } } - else if (typestr.equals("start")) { + else if (el == ELEM_CONST_START.id()) { type = J_START; } - else if (typestr.equals("next")) { + else if (el == ELEM_CONST_NEXT.id()) { type = J_NEXT; } - else if (typestr.equals("next2")) { + else if (el == ELEM_CONST_NEXT2.id()) { type = J_NEXT2; } - else if (typestr.equals("curspace")) { + else if (el == ELEM_CONST_CURSPACE.id()) { type = J_CURSPACE; } - else if (typestr.equals("curspace_size")) { + else if (el == ELEM_CONST_CURSPACE_SIZE.id()) { type = J_CURSPACE_SIZE; } - else if (typestr.equals("spaceid")) { + else if (el == ELEM_CONST_SPACEID.id()) { type = SPACEID; - value_spaceid = factory.getAddressSpace(el.getAttribute("name")); + value_spaceid = decoder.readSpace(ATTRIB_SPACE); } - else if (typestr.equals("relative")) { + else if (el == ELEM_CONST_RELATIVE.id()) { type = J_RELATIVE; - value_real = SpecXmlUtils.decodeLong(el.getAttribute("val")); + value_real = decoder.readUnsignedInteger(ATTRIB_VAL); } - else if (typestr.equals("flowref")) { + else if (el == ELEM_CONST_FLOWREF.id()) { type = J_FLOWREF; } - else if (typestr.equals("flowref_size")) { + else if (el == ELEM_CONST_FLOWREF_SIZE.id()) { type = J_FLOWREF_SIZE; } - else if (typestr.equals("flowdest")) { + else if (el == ELEM_CONST_FLOWDEST.id()) { type = J_FLOWDEST; } - else if (typestr.equals("flowdest_size")) { + else if (el == ELEM_CONST_FLOWDEST_SIZE.id()) { type = J_FLOWDEST_SIZE; } else { - throw new SleighException("Bad xml for ConstTpl"); + throw new SleighException("Bad encoding for ConstTpl"); } - parser.end(el); + decoder.closeElement(el); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/ConstructTpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/ConstructTpl.java index d3da23393f6..194b68e05ec 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/ConstructTpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/ConstructTpl.java @@ -19,13 +19,12 @@ */ package ghidra.app.plugin.processors.sleigh.template; +import static ghidra.pcode.utils.SlaFormat.*; + import java.util.ArrayList; -import ghidra.program.model.address.AddressFactory; -import ghidra.program.model.lang.UnknownInstructionException; -import ghidra.util.xml.SpecXmlUtils; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** * A constructor template, representing the semantic action of a SLEIGH constructor, without @@ -40,7 +39,6 @@ * The final PcodeOps are produced by handing this to the build() method of PcodeEmit which has * the InstructionContext necessary for final resolution. */ - public class ConstructTpl { private int numlabels = 0; // Number of relative-offset labels in this template @@ -48,7 +46,7 @@ public class ConstructTpl { private HandleTpl result; // The final semantic value /** - * Constructor for use with restoreXML + * Constructor for use with decode */ public ConstructTpl() { } @@ -98,42 +96,44 @@ public HandleTpl getResult() { } /** - * Restore this template from a \ tag in an XML stream. - * @param parser is the XML stream - * @param factory is for manufacturing Address objects + * Decode this template from a \ tag in the stream. + * @param decoder is the stream * @return the constructor section id described by the tag - * @throws UnknownInstructionException if the p-code templates contain unknown op-codes + * @throws DecoderException for errors in the encoding */ - public int restoreXml(XmlPullParser parser, AddressFactory factory) - throws UnknownInstructionException { + public int decode(Decoder decoder) throws DecoderException { int sectionid = -1; - XmlElement el = parser.start("construct_tpl"); - String nmlabelstr = el.getAttribute("labels"); - if (nmlabelstr != null) { - numlabels = SpecXmlUtils.decodeInt(nmlabelstr); - } - String sectionidstr = el.getAttribute("section"); - if (sectionidstr != null) { - sectionid = SpecXmlUtils.decodeInt(sectionidstr); + numlabels = 0; + int el = decoder.openElement(ELEM_CONSTRUCT_TPL); + int attrib = decoder.getNextAttributeId(); + while (attrib != 0) { + if (attrib == ATTRIB_LABELS.id()) { + numlabels = (int) decoder.readSignedInteger(); + } + else if (attrib == ATTRIB_SECTION.id()) { + sectionid = (int) decoder.readSignedInteger(); + } + attrib = decoder.getNextAttributeId(); } - XmlElement handel = parser.peek(); - if (handel.getName().equals("null")) { + int handel = decoder.peekElement(); + if (handel == ELEM_NULL.id()) { + decoder.openElement(); + decoder.closeElement(handel); result = null; - parser.discardSubTree(); } else { result = new HandleTpl(); - result.restoreXml(parser, factory); + result.decode(decoder); } ArrayList oplist = new ArrayList<>(); - while (!parser.peek().isEnd()) { + while (decoder.peekElement() != 0) { OpTpl op = new OpTpl(); - op.restoreXml(parser, factory); + op.decode(decoder); oplist.add(op); } vec = new OpTpl[oplist.size()]; oplist.toArray(vec); - parser.end(el); + decoder.closeElement(el); return sectionid; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/HandleTpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/HandleTpl.java index 8a88b03576d..34e4f205c32 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/HandleTpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/HandleTpl.java @@ -19,12 +19,13 @@ */ package ghidra.app.plugin.processors.sleigh.template; +import static ghidra.pcode.utils.SlaFormat.*; + import ghidra.app.plugin.processors.sleigh.*; -import ghidra.program.model.address.AddressFactory; import ghidra.program.model.address.AddressSpace; import ghidra.program.model.lang.InstructionContext; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** * Placeholder that resolves for a specific {@link InstructionContext} into a {@link FixedHandle} @@ -104,23 +105,23 @@ public void fixPrintPiece(FixedHandle hand, ParserWalker walker, int handleIndex } } - public void restoreXml(XmlPullParser parser, AddressFactory factory) { - XmlElement el = parser.start("handle_tpl"); + public void decode(Decoder decoder) throws DecoderException { + int el = decoder.openElement(ELEM_HANDLE_TPL); space = new ConstTpl(); - space.restoreXml(parser, factory); + space.decode(decoder); size = new ConstTpl(); - size.restoreXml(parser, factory); + size.decode(decoder); ptrspace = new ConstTpl(); - ptrspace.restoreXml(parser, factory); + ptrspace.decode(decoder); ptroffset = new ConstTpl(); - ptroffset.restoreXml(parser, factory); + ptroffset.decode(decoder); ptrsize = new ConstTpl(); - ptrsize.restoreXml(parser, factory); + ptrsize.decode(decoder); temp_space = new ConstTpl(); - temp_space.restoreXml(parser, factory); + temp_space.decode(decoder); temp_offset = new ConstTpl(); - temp_offset.restoreXml(parser, factory); - parser.end(el); + temp_offset.decode(decoder); + decoder.closeElement(el); } public int getOffsetOperandIndex() { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/OpTpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/OpTpl.java index 339ca4cf779..975a6708f02 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/OpTpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/OpTpl.java @@ -19,17 +19,13 @@ */ package ghidra.app.plugin.processors.sleigh.template; +import static ghidra.pcode.utils.SlaFormat.*; + import java.util.ArrayList; -import ghidra.program.model.address.AddressFactory; -import ghidra.program.model.lang.UnknownInstructionException; -import ghidra.program.model.pcode.PcodeOp; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.*; /** - * - * * Placeholder for what will resolve to a PcodeOp * for a specific InstructionContext */ @@ -60,28 +56,28 @@ public int getOpcode() { return opcode; } - public void restoreXml(XmlPullParser parser, AddressFactory factory) - throws UnknownInstructionException { - XmlElement el = parser.start("op_tpl"); - opcode = PcodeOp.getOpcode(el.getAttribute("code")); - XmlElement outel = parser.peek(); - if (outel.getName().equals("null")) { + public void decode(Decoder decoder) throws DecoderException { + int el = decoder.openElement(ELEM_OP_TPL); + opcode = decoder.readOpcode(ATTRIB_CODE); + int outel = decoder.peekElement(); + if (outel == ELEM_NULL.id()) { + decoder.openElement(); + decoder.closeElement(outel); output = null; - parser.discardSubTree(); } else { output = new VarnodeTpl(); - output.restoreXml(parser, factory); + output.decode(decoder); } ArrayList inputlist = new ArrayList<>(); - while (!parser.peek().isEnd()) { + while (decoder.peekElement() != 0) { VarnodeTpl vn = new VarnodeTpl(); - vn.restoreXml(parser, factory); + vn.decode(decoder); inputlist.add(vn); } input = new VarnodeTpl[inputlist.size()]; inputlist.toArray(input); - parser.end(el); + decoder.closeElement(el); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/VarnodeTpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/VarnodeTpl.java index a2b84c74982..07cc3d32a44 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/VarnodeTpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/VarnodeTpl.java @@ -19,14 +19,13 @@ */ package ghidra.app.plugin.processors.sleigh.template; +import static ghidra.pcode.utils.SlaFormat.*; + import ghidra.app.plugin.processors.sleigh.ParserWalker; -import ghidra.program.model.address.AddressFactory; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; /** - * - * * Placeholder for what will resolve to a Varnode instance given * a specific InstructionContext */ @@ -57,8 +56,9 @@ public ConstTpl getSize() { } public boolean isDynamic(ParserWalker walker) { - if (offset.getType() != ConstTpl.HANDLE) + if (offset.getType() != ConstTpl.HANDLE) { return false; + } // Technically we should probably check all three ConstTpls // for dynamic handles, but in all cases, if there is any // dynamic piece, then the offset is dynamic @@ -70,15 +70,15 @@ public boolean isRelative() { return (offset.getType() == ConstTpl.J_RELATIVE); } - public void restoreXml(XmlPullParser parser, AddressFactory factory) { - XmlElement el = parser.start("varnode_tpl"); + public void decode(Decoder decoder) throws DecoderException { + int el = decoder.openElement(ELEM_VARNODE_TPL); space = new ConstTpl(); - space.restoreXml(parser, factory); + space.decode(decoder); offset = new ConstTpl(); - offset.restoreXml(parser, factory); + offset.decode(decoder); size = new ConstTpl(); - size.restoreXml(parser, factory); - parser.end(el); + size.decode(decoder); + decoder.closeElement(el); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/utils/SlaFormat.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/utils/SlaFormat.java new file mode 100644 index 00000000000..742341daa63 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/utils/SlaFormat.java @@ -0,0 +1,268 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.pcode.utils; + +import java.io.*; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.InflaterInputStream; + +import generic.jar.ResourceFile; +import ghidra.program.model.pcode.*; + +/** + * Encoding values for the .sla file format + */ +public class SlaFormat { + + /** + * FORMAT_VERSION will be incremented whenever the format of the .sla + * files change. + *

+ * Version 4: Compressed and packed file format + * Version 3: January 2021: added source file information for each constructor.
+ * Version 2: April 2019: Changed numbering of Overlay spaces.
+ * Version 1: Initial version.
+ */ + public static final int FORMAT_VERSION = 4; + + /** + * Absolute limit on the number of bytes in a .sla file + */ + public static final int MAX_FILE_SIZE = 1 << 24; // 16 Megabytes + // Attributes + + // ATTRIB_CONTENT = 1 is reserved + public static final AttributeId ATTRIB_VAL = new AttributeId("val", 2); + public static final AttributeId ATTRIB_ID = new AttributeId("id", 3); + public static final AttributeId ATTRIB_SPACE = new AttributeId("space", 4); + public static final AttributeId ATTRIB_S = new AttributeId("s", 5); + public static final AttributeId ATTRIB_OFF = new AttributeId("off", 6); + public static final AttributeId ATTRIB_CODE = new AttributeId("code", 7); + public static final AttributeId ATTRIB_MASK = new AttributeId("mask", 8); + public static final AttributeId ATTRIB_INDEX = new AttributeId("index", 9); + public static final AttributeId ATTRIB_NONZERO = new AttributeId("nonzero", 10); + public static final AttributeId ATTRIB_PIECE = new AttributeId("piece", 11); + public static final AttributeId ATTRIB_NAME = new AttributeId("name", 12); + public static final AttributeId ATTRIB_SCOPE = new AttributeId("scope", 13); + public static final AttributeId ATTRIB_STARTBIT = new AttributeId("startbit", 14); + public static final AttributeId ATTRIB_SIZE = new AttributeId("size", 15); + public static final AttributeId ATTRIB_TABLE = new AttributeId("table", 16); + public static final AttributeId ATTRIB_CT = new AttributeId("ct", 17); + public static final AttributeId ATTRIB_MINLEN = new AttributeId("minlen", 18); + public static final AttributeId ATTRIB_BASE = new AttributeId("base", 19); + public static final AttributeId ATTRIB_NUMBER = new AttributeId("number", 20); + public static final AttributeId ATTRIB_CONTEXT = new AttributeId("context", 21); + public static final AttributeId ATTRIB_PARENT = new AttributeId("parent", 22); + public static final AttributeId ATTRIB_SUBSYM = new AttributeId("subsym", 23); + public static final AttributeId ATTRIB_LINE = new AttributeId("line", 24); + public static final AttributeId ATTRIB_SOURCE = new AttributeId("source", 25); + public static final AttributeId ATTRIB_LENGTH = new AttributeId("length", 26); + public static final AttributeId ATTRIB_FIRST = new AttributeId("first", 27); + public static final AttributeId ATTRIB_PLUS = new AttributeId("plus", 28); + public static final AttributeId ATTRIB_SHIFT = new AttributeId("shift", 29); + public static final AttributeId ATTRIB_ENDBIT = new AttributeId("endbit", 30); + public static final AttributeId ATTRIB_SIGNBIT = new AttributeId("signbit", 31); + public static final AttributeId ATTRIB_ENDBYTE = new AttributeId("endbyte", 32); + public static final AttributeId ATTRIB_STARTBYTE = new AttributeId("startbyte", 33); + public static final AttributeId ATTRIB_VERSION = new AttributeId("version", 34); + public static final AttributeId ATTRIB_BIGENDIAN = new AttributeId("bigendian", 35); + public static final AttributeId ATTRIB_ALIGN = new AttributeId("align", 36); + public static final AttributeId ATTRIB_UNIQBASE = new AttributeId("uniqbase", 37); + public static final AttributeId ATTRIB_MAXDELAY = new AttributeId("maxdelay", 38); + public static final AttributeId ATTRIB_UNIQMASK = new AttributeId("uniqmask", 39); + public static final AttributeId ATTRIB_NUMSECTIONS = new AttributeId("numsections", 40); + public static final AttributeId ATTRIB_DEFAULTSPACE = new AttributeId("defaultspace", 41); + public static final AttributeId ATTRIB_DELAY = new AttributeId("delay", 42); + public static final AttributeId ATTRIB_WORDSIZE = new AttributeId("wordsize", 43); + public static final AttributeId ATTRIB_PHYSICAL = new AttributeId("physical", 44); + public static final AttributeId ATTRIB_SCOPESIZE = new AttributeId("scopesize", 45); + public static final AttributeId ATTRIB_SYMBOLSIZE = new AttributeId("symbolsize", 46); + public static final AttributeId ATTRIB_VARNODE = new AttributeId("varnode", 47); + public static final AttributeId ATTRIB_LOW = new AttributeId("low", 48); + public static final AttributeId ATTRIB_HIGH = new AttributeId("high", 49); + public static final AttributeId ATTRIB_FLOW = new AttributeId("flow", 50); + public static final AttributeId ATTRIB_CONTAIN = new AttributeId("contain", 51); + public static final AttributeId ATTRIB_I = new AttributeId("i", 52); + public static final AttributeId ATTRIB_NUMCT = new AttributeId("numct", 53); + public static final AttributeId ATTRIB_SECTION = new AttributeId("section", 54); + public static final AttributeId ATTRIB_LABELS = new AttributeId("labels", 55); + + public static final ElementId ELEM_CONST_REAL = new ElementId("const_real", 1); + public static final ElementId ELEM_VARNODE_TPL = new ElementId("varnode_tpl", 2); + public static final ElementId ELEM_CONST_SPACEID = new ElementId("const_spaceid", 3); + public static final ElementId ELEM_CONST_HANDLE = new ElementId("const_handle", 4); + public static final ElementId ELEM_OP_TPL = new ElementId("op_tpl", 5); + public static final ElementId ELEM_MASK_WORD = new ElementId("mask_word", 6); + public static final ElementId ELEM_PAT_BLOCK = new ElementId("pat_block", 7); + public static final ElementId ELEM_PRINT = new ElementId("print", 8); + public static final ElementId ELEM_PAIR = new ElementId("pair", 9); + public static final ElementId ELEM_CONTEXT_PAT = new ElementId("context_pat", 10); + public static final ElementId ELEM_NULL = new ElementId("null", 11); + public static final ElementId ELEM_OPERAND_EXP = new ElementId("operand_exp", 12); + public static final ElementId ELEM_OPERAND_SYM = new ElementId("operand_sym", 13); + public static final ElementId ELEM_OPERAND_SYM_HEAD = new ElementId("operand_sym_head", 14); + public static final ElementId ELEM_OPER = new ElementId("oper", 15); + public static final ElementId ELEM_DECISION = new ElementId("decision", 16); + public static final ElementId ELEM_OPPRINT = new ElementId("opprint", 17); + public static final ElementId ELEM_INSTRUCT_PAT = new ElementId("instruct_pat", 18); + public static final ElementId ELEM_COMBINE_PAT = new ElementId("combine_pat", 19); + public static final ElementId ELEM_CONSTRUCTOR = new ElementId("constructor", 20); + public static final ElementId ELEM_CONSTRUCT_TPL = new ElementId("construct_tpl", 21); + public static final ElementId ELEM_SCOPE = new ElementId("scope", 22); + public static final ElementId ELEM_VARNODE_SYM = new ElementId("varnode_sym", 23); + public static final ElementId ELEM_VARNODE_SYM_HEAD = new ElementId("varnode_sym_head", 24); + public static final ElementId ELEM_USEROP = new ElementId("userop", 25); + public static final ElementId ELEM_USEROP_HEAD = new ElementId("userop_head", 26); + public static final ElementId ELEM_TOKENFIELD = new ElementId("tokenfield", 27); + public static final ElementId ELEM_VAR = new ElementId("var", 28); + public static final ElementId ELEM_CONTEXTFIELD = new ElementId("contextfield", 29); + public static final ElementId ELEM_HANDLE_TPL = new ElementId("handle_tpl", 30); + public static final ElementId ELEM_CONST_RELATIVE = new ElementId("const_relative", 31); + public static final ElementId ELEM_CONTEXT_OP = new ElementId("context_op", 32); + + public static final ElementId ELEM_SLEIGH = new ElementId("sleigh", 33); + public static final ElementId ELEM_SPACES = new ElementId("spaces", 34); + public static final ElementId ELEM_SOURCEFILES = new ElementId("sourcefiles", 35); + public static final ElementId ELEM_SOURCEFILE = new ElementId("sourcefile", 36); + public static final ElementId ELEM_SPACE = new ElementId("space", 37); + public static final ElementId ELEM_SYMBOL_TABLE = new ElementId("symbol_table", 38); + public static final ElementId ELEM_VALUE_SYM = new ElementId("value_sym", 39); + public static final ElementId ELEM_VALUE_SYM_HEAD = new ElementId("value_sym_head", 40); + public static final ElementId ELEM_CONTEXT_SYM = new ElementId("context_sym", 41); + public static final ElementId ELEM_CONTEXT_SYM_HEAD = new ElementId("context_sym_head", 42); + public static final ElementId ELEM_END_SYM = new ElementId("end_sym", 43); + public static final ElementId ELEM_END_SYM_HEAD = new ElementId("end_sym_head", 44); + public static final ElementId ELEM_SPACE_OTHER = new ElementId("space_other", 45); + public static final ElementId ELEM_SPACE_UNIQUE = new ElementId("space_unique", 46); + public static final ElementId ELEM_AND_EXP = new ElementId("and_exp", 47); + public static final ElementId ELEM_DIV_EXP = new ElementId("div_exp", 48); + public static final ElementId ELEM_LSHIFT_EXP = new ElementId("lshift_exp", 49); + public static final ElementId ELEM_MINUS_EXP = new ElementId("minus_exp", 50); + public static final ElementId ELEM_MULT_EXP = new ElementId("mult_exp", 51); + public static final ElementId ELEM_NOT_EXP = new ElementId("not_exp", 52); + public static final ElementId ELEM_OR_EXP = new ElementId("or_exp", 53); + public static final ElementId ELEM_PLUS_EXP = new ElementId("plus_exp", 54); + public static final ElementId ELEM_RSHIFT_EXP = new ElementId("rshift_exp", 55); + public static final ElementId ELEM_SUB_EXP = new ElementId("sub_exp", 56); + public static final ElementId ELEM_XOR_EXP = new ElementId("xor_exp", 57); + public static final ElementId ELEM_INTB = new ElementId("intb", 58); + public static final ElementId ELEM_END_EXP = new ElementId("end_exp", 59); + public static final ElementId ELEM_NEXT2_EXP = new ElementId("next2_exp", 60); + public static final ElementId ELEM_START_EXP = new ElementId("start_exp", 61); + public static final ElementId ELEM_EPSILON_SYM = new ElementId("epsilon_sym", 62); + public static final ElementId ELEM_EPSILON_SYM_HEAD = new ElementId("epsilon_sym_head", 63); + public static final ElementId ELEM_NAME_SYM = new ElementId("name_sym", 64); + public static final ElementId ELEM_NAME_SYM_HEAD = new ElementId("name_sym_head", 65); + public static final ElementId ELEM_NAMETAB = new ElementId("nametab", 66); + public static final ElementId ELEM_NEXT2_SYM = new ElementId("next2_sym", 67); + public static final ElementId ELEM_NEXT2_SYM_HEAD = new ElementId("next2_sym_head", 68); + public static final ElementId ELEM_START_SYM = new ElementId("start_sym", 69); + public static final ElementId ELEM_START_SYM_HEAD = new ElementId("start_sym_head", 70); + public static final ElementId ELEM_SUBTABLE_SYM = new ElementId("subtable_sym", 71); + public static final ElementId ELEM_SUBTABLE_SYM_HEAD = new ElementId("subtable_sym_head", 72); + public static final ElementId ELEM_VALUEMAP_SYM = new ElementId("valuemap_sym", 73); + public static final ElementId ELEM_VALUEMAP_SYM_HEAD = new ElementId("valuemap_sym_head", 74); + public static final ElementId ELEM_VALUETAB = new ElementId("valuetab", 75); + public static final ElementId ELEM_VARLIST_SYM = new ElementId("varlist_sym", 76); + public static final ElementId ELEM_VARLIST_SYM_HEAD = new ElementId("varlist_sym_head", 77); + public static final ElementId ELEM_OR_PAT = new ElementId("or_pat", 78); + public static final ElementId ELEM_COMMIT = new ElementId("commit", 79); + public static final ElementId ELEM_CONST_START = new ElementId("const_start", 80); + public static final ElementId ELEM_CONST_NEXT = new ElementId("const_next", 81); + public static final ElementId ELEM_CONST_NEXT2 = new ElementId("const_next2", 82); + public static final ElementId ELEM_CONST_CURSPACE = new ElementId("const_curspace", 83); + public static final ElementId ELEM_CONST_CURSPACE_SIZE = + new ElementId("const_curspace_size", 84); + public static final ElementId ELEM_CONST_FLOWREF = new ElementId("const_flowref", 85); + public static final ElementId ELEM_CONST_FLOWREF_SIZE = new ElementId("const_flowref_size", 86); + public static final ElementId ELEM_CONST_FLOWDEST = new ElementId("const_flowdest", 87); + public static final ElementId ELEM_CONST_FLOWDEST_SIZE = + new ElementId("const_flowdest_size", 88); + + /** + * Try to read the header bytes of the .sla format from the given stream. If the header bytes + * and the version byte match, \b true is returned, and the stream can be passed to the decoder. + * @param stream is the given stream + * @return true if the .sla header bytes are found + * @throws IOException for any errors reading from the stream + */ + public static boolean isSlaFormat(InputStream stream) throws IOException { + byte[] header = new byte[4]; + int readLen = stream.read(header); + if (readLen < 4) { + return false; + } + if (header[0] != 's' || header[1] != 'l' || header[2] != 'a') { + return false; + } + if (header[3] != FORMAT_VERSION) { + return false; + } + return true; + } + + /** + * Write a .sla file header,including the format version number to the given stream. + * @param stream is the given stream + * @throws IOException for problems writing to the stream + */ + public static void writeSlaHeader(OutputStream stream) throws IOException { + stream.write("sla".getBytes()); + stream.write(FORMAT_VERSION); + } + + /** + * Build the encoder for compressing and encoding a .sla file (as a stream). + * The given file is opened and a header is immediately written. The returned + * encoder is ready immediately to receive the .sla elements and attributes. + * @param sleighFile is the .sla file (to be created) + * @return the encoder + * @throws IOException for any problems opening or writing to the file + */ + public static PackedEncode buildEncoder(ResourceFile sleighFile) throws IOException { + OutputStream stream = sleighFile.getOutputStream(); + writeSlaHeader(stream); + OutputStream compStream = new DeflaterOutputStream(stream); + return new PackedEncode(compStream); + } + + /** + * Build the decoder for decompressing and decoding the .sla file (as a stream). + * The given file is opened and the header bytes are checked. The returned + * decoder is immediately ready to read. + * @param sleighFile is the given .sla file + * @return the decoder + * @throws IOException if the header is invalid or there are problems reading the file + */ + public static PackedDecode buildDecoder(ResourceFile sleighFile) throws IOException { + InputStream stream = sleighFile.getInputStream(); + try { + if (!isSlaFormat(stream)) { + throw new IOException("Missing SLA format header"); + } + InflaterInputStream inflaterStream = new InflaterInputStream(stream); + PackedDecode decoder = new PackedDecode(); + decoder.open(MAX_FILE_SIZE, ".sla file loader"); + decoder.ingestStream(inflaterStream); + decoder.endIngest(); + inflaterStream.close(); + return decoder; + } + finally { + stream.close(); + } + } +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/address/Address.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/address/Address.java index f90dfc1d5f5..94963f27ebb 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/address/Address.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/address/Address.java @@ -15,17 +15,11 @@ */ package ghidra.pcodeCPort.address; -import ghidra.pcodeCPort.pcoderaw.*; -import ghidra.pcodeCPort.space.*; -import ghidra.pcodeCPort.translate.*; -import ghidra.pcodeCPort.utils.*; - import java.io.PrintStream; -import org.jdom.Element; - - - +import ghidra.pcodeCPort.space.AddrSpace; +import ghidra.pcodeCPort.space.spacetype; +import ghidra.pcodeCPort.utils.AddrSpaceToIdSymmetryMap; //For specifying a storage space. Could be RAM, ROM, cpu register, data //segment, coprocessor, stack, nvram, etc. @@ -39,7 +33,7 @@ //a translation from a real machine language will typically simulate registers //by placing them in their own space, separate from RAM. Indirection //(i.e. pointers) must be simulated through the LOAD and STORE ops. -public class Address implements Comparable

{ +public class Address implements Comparable
{ public enum mach_extreme { m_minimal, m_maximal } @@ -53,12 +47,12 @@ public Address() { base = AddrSpace.MIN_SPACE; } - public Address( AddrSpace id, long off ) { + public Address(AddrSpace id, long off) { base = id; - offset = off; + offset = off; } - public Address( Address addr ) { + public Address(Address addr) { base = addr.base; offset = addr.offset; } @@ -68,7 +62,7 @@ public boolean isInvalid() { return (base == AddrSpace.MIN_SPACE || base == AddrSpace.MAX_SPACE); } - void setOffset( long o ) { + void setOffset(long o) { offset = o; } @@ -80,39 +74,35 @@ public boolean isBigEndian() { return base.isBigEndian(); } - void printOffset( PrintStream s ) { - base.printOffset( s, offset ); + void printOffset(PrintStream s) { + base.printOffset(s, offset); } - public int printRaw( PrintStream s ) { - return base.printRaw( s, offset ); + public int printRaw(PrintStream s) { + return base.printRaw(s, offset); } - + // Convert address to most basic physical address // This routine is only present for backward compatibility // with SLED public void toPhysical() { - AddrSpace phys = base.getContain(); - if ((phys != null)&&(base.getType()==spacetype.IPTR_SPACEBASE)) { - base = phys; - } + AddrSpace phys = base.getContain(); + if ((phys != null) && (base.getType() == spacetype.IPTR_SPACEBASE)) { + base = phys; + } } - + @Override - public String toString() { + public String toString() { return base.getName() + ":0x" + base.toString(offset); } + public String toString(boolean showAddressSpace) { if (showAddressSpace) { return base.getName() + ":0x" + base.toString(offset); } return "0x" + base.toString(offset); } - public int read( String s ) { - MutableInt size = new MutableInt( 0 ); - offset = base.read( s, size ); - return size.get(); - } public AddrSpace getSpace() { return base; @@ -127,7 +117,7 @@ public char getShortcut() { } @Override - public boolean equals( Object obj ) { + public boolean equals(Object obj) { if (!(obj instanceof Address)) { return false; } @@ -138,57 +128,43 @@ public boolean equals( Object obj ) { return base == other.base && offset == other.offset; } - public int compareTo( Address other ) { - int result = base.compareTo( other.base ); + @Override + public int compareTo(Address other) { + int result = base.compareTo(other.base); if (result != 0) { return result; } - return AddressUtils.unsignedCompare( offset, other.offset ); + return AddressUtils.unsignedCompare(offset, other.offset); } - public Address add( long off ) { - return new Address( base, (offset + off) & base.getMask() ); + public Address add(long off) { + return new Address(base, (offset + off) & base.getMask()); } - public Address subtract( long off ) { - return sub( off ); + public Address subtract(long off) { + return sub(off); } - - public Address sub( long off ) { - return new Address( base, (offset - off) & base.getMask() ); + + public Address sub(long off) { + return new Address(base, (offset - off) & base.getMask()); } public boolean isConstant() { return (base.getType() == spacetype.IPTR_CONSTANT); } - public void saveXml( PrintStream s ) { - s.append( "" ); - } - - public void saveXml( PrintStream s, int size ) { - s.append( "" ); - } - - public static AddrSpace getSpaceFromConst( Address addr ) { - return (AddrSpace) AddrSpaceToIdSymmetryMap.getSpace( addr.offset ); + public static AddrSpace getSpaceFromConst(Address addr) { + return AddrSpaceToIdSymmetryMap.getSpace(addr.offset); } // Define pseudo-locations that have specific - public Address( mach_extreme ex ) { + public Address(mach_extreme ex) { // properties under comparion if (ex == mach_extreme.m_minimal) { base = AddrSpace.MIN_SPACE; offset = 0; - } else { + } + else { base = AddrSpace.MAX_SPACE; offset = -1; } @@ -196,7 +172,7 @@ public Address( mach_extreme ex ) { // Return true if (op2,sz2) is endian aligned and contained // in (this,sz) - public boolean endianContain( int sz, Address op2, int sz2 ) { + public boolean endianContain(int sz, Address op2, int sz2) { if (base != op2.base) { return false; } @@ -217,7 +193,7 @@ public boolean endianContain( int sz, Address op2, int sz2 ) { return true; } - public int overlap( int skip, Address op, int size ) {// Where does this+skip fall in op to op+size + public int overlap(int skip, Address op, int size) {// Where does this+skip fall in op to op+size if (base != op.base) { return -1; // Must be in same address space to overlap @@ -229,16 +205,10 @@ public int overlap( int skip, Address op, int size ) {// Where does this+skip fa long dist = offset + skip - op.offset; dist &= base.getMask(); - if (dist >= size) + if (dist >= size) { return -1; // but must fall before op+size + } return (int) dist; } - public static VarnodeData restoreXml( Element el, Translate trans ) { - VarnodeData var = new VarnodeData(); - - var.restoreXml( el, trans ); - return var; - } - } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/address/Range.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/address/Range.java index 961fd829d64..5dd461eb530 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/address/Range.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/address/Range.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,15 +17,8 @@ import java.io.PrintStream; -import org.jdom.Element; - - -import ghidra.pcodeCPort.error.*; -import ghidra.pcodeCPort.pcoderaw.*; -import ghidra.pcodeCPort.space.*; -import ghidra.pcodeCPort.translate.*; -import ghidra.pcodeCPort.utils.*; - +import ghidra.pcodeCPort.space.AddrSpace; +import ghidra.pcodeCPort.translate.Translate; public class Range implements Comparable { private AddrSpace spc; // Space containing range @@ -35,14 +27,14 @@ public class Range implements Comparable { private long last; - public Range( AddrSpace s, long f, long l ) { + public Range(AddrSpace s, long f, long l) { spc = s; first = f; last = l; } public Range() { - } // For use with restore_xml + } public AddrSpace getSpace() { return spc; @@ -57,82 +49,46 @@ public long getLast() { } public Address getFirstAddr() { - return new Address( spc, first ); + return new Address(spc, first); } public Address getLastAddr() { - return new Address( spc, last ); + return new Address(spc, last); } - public int compareTo( Range other ) { - int result = spc.compareTo( other.spc ); + @Override + public int compareTo(Range other) { + int result = spc.compareTo(other.spc); if (result != 0) { return result; } - return AddressUtils.unsignedCompare( first, other.first ); - } - - void printBounds( PrintStream s ) { - s.append( spc.getName() ); - s.append( ": " ); - s.append( Long.toHexString( first ) ); - s.append( '-' ); - s.append( Long.toHexString( last ) ); + return AddressUtils.unsignedCompare(first, other.first); } - void saveXml( PrintStream s ) { - s.append( "\n" ); + void printBounds(PrintStream s) { + s.append(spc.getName()); + s.append(": "); + s.append(Long.toHexString(first)); + s.append('-'); + s.append(Long.toHexString(last)); } // Get the last address +1, updating the space, or returning - public Address getLastAddrOpen( Translate trans ) { + public Address getLastAddrOpen(Translate trans) { // the extremal address if necessary AddrSpace curspc = spc; long curlast = last; if (curlast == curspc.getMask()) { - curspc = trans.getNextSpaceInOrder( curspc ); + curspc = trans.getNextSpaceInOrder(curspc); curlast = 0; - } else { + } + else { curlast += 1; } if (curspc == null) { - return new Address( Address.mach_extreme.m_maximal ); - } - return new Address( curspc, curlast ); - } - - public void restoreXml( Element el, Translate trans ) { - spc = null; - first = 0; - last = -1; - String attrvalue = el.getAttributeValue("space"); - if (attrvalue != null) { - spc = trans.getSpaceByName(attrvalue); - if (spc == null) - throw new LowlevelError("Undefined space: "+attrvalue); - } - attrvalue = el.getAttributeValue("first"); - if (attrvalue != null) - first = XmlUtils.decodeUnknownLong(attrvalue); - attrvalue = el.getAttributeValue("last"); - if (attrvalue != null) - last = XmlUtils.decodeUnknownLong(attrvalue); - attrvalue = el.getAttributeValue("name"); - if (attrvalue != null) { - VarnodeData point = trans.getRegister(attrvalue); - spc = point.space; - first = point.offset; - last = (first-1) + point.size; + return new Address(Address.mach_extreme.m_maximal); } - if (spc == null) - throw new LowlevelError( "No address space indicated in range tag"); - first &= spc.getMask(); - last &= spc.getMask(); + return new Address(curspc, curlast); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/address/RangeList.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/address/RangeList.java index 787e1ad1a4e..aba64f4af7d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/address/RangeList.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/address/RangeList.java @@ -16,22 +16,17 @@ package ghidra.pcodeCPort.address; import java.io.PrintStream; -import java.util.List; - -import org.jdom.Element; import generic.stl.*; import ghidra.pcodeCPort.space.AddrSpace; -import ghidra.pcodeCPort.translate.Translate; import ghidra.pcodeCPort.utils.Utils; - public class RangeList { private SetSTL tree; - public RangeList( RangeList rangeList ) { - tree = new SetSTL<>( rangeList.tree ); + public RangeList(RangeList rangeList) { + tree = new SetSTL<>(rangeList.tree); } public RangeList() { @@ -41,9 +36,11 @@ public RangeList() { public void clear() { tree.clear(); } + public IteratorSTL begin() { return tree.begin(); } + public IteratorSTL end() { return tree.end(); } @@ -53,101 +50,101 @@ public boolean empty() { } // tree is disjoint list of ranges - public void insertRange( AddrSpace spc, long first, long last ) { + public void insertRange(AddrSpace spc, long first, long last) { // insert a new range // we must have iter1.first > first - IteratorSTL iter1 = tree.upper_bound( new Range( spc, first, first ) ); + IteratorSTL iter1 = tree.upper_bound(new Range(spc, first, first)); // Set iter1 to first range with range.last >=first // It is either current iter1 or the one before - if ( !iter1.isBegin() ) { + if (!iter1.isBegin()) { iter1.decrement(); - if ( (!iter1.get().getSpace().equals( spc )) - || (Utils.unsignedCompare( iter1.get().getLast(), first ) < 0) ) { + if ((!iter1.get().getSpace().equals(spc)) || + (Utils.unsignedCompare(iter1.get().getLast(), first) < 0)) { iter1.increment(); } } // Set iter2 to first range with range.first > last - IteratorSTL iter2 = tree.upper_bound( new Range( spc, last, last ) ); + IteratorSTL iter2 = tree.upper_bound(new Range(spc, last, last)); - while ( !iter1.equals( iter2 ) ) { - if ( Utils.unsignedCompare( iter1.get().getFirst(), first ) < 0 ) { + while (!iter1.equals(iter2)) { + if (Utils.unsignedCompare(iter1.get().getFirst(), first) < 0) { first = iter1.get().getFirst(); } - if ( Utils.unsignedCompare( iter1.get().getLast(), last ) > 0 ) { + if (Utils.unsignedCompare(iter1.get().getLast(), last) > 0) { last = iter1.get().getLast(); } tree.erase(iter1); iter1.increment(); } - tree.insert( new Range( spc, first, last ) ); + tree.insert(new Range(spc, first, last)); } // remove a range - public void removeRange( AddrSpace spc, long first, long last ) { + public void removeRange(AddrSpace spc, long first, long last) { - if ( tree.isEmpty() ) { + if (tree.isEmpty()) { return; // Nothing to do } // we must have iter1.first > first - IteratorSTL iter1 = tree.upper_bound( new Range( spc, first, first ) ); + IteratorSTL iter1 = tree.upper_bound(new Range(spc, first, first)); // Set iter1 to first range with range.last >=first // It is either current iter1 or the one before - if ( !iter1.isBegin() ) { + if (!iter1.isBegin()) { iter1.decrement(); - if ( (!iter1.get().getSpace().equals( spc )) - || (Utils.unsignedCompare( iter1.get().getLast(), first ) < 0) ) { + if ((!iter1.get().getSpace().equals(spc)) || + (Utils.unsignedCompare(iter1.get().getLast(), first) < 0)) { iter1.increment(); } } // Set iter2 to first range with range.first > last - IteratorSTL iter2 = tree.upper_bound( new Range( spc, last, last ) ); + IteratorSTL iter2 = tree.upper_bound(new Range(spc, last, last)); - while ( !iter1.equals( iter2 ) ) { + while (!iter1.equals(iter2)) { long a = iter1.get().getFirst(); long b = iter1.get().getLast(); tree.erase(iter1); iter1.increment(); - if ( Utils.unsignedCompare( a, first ) < 0 ) { - tree.insert( new Range( spc, a, first - 1 ) ); + if (Utils.unsignedCompare(a, first) < 0) { + tree.insert(new Range(spc, a, first - 1)); } - if ( Utils.unsignedCompare( b, last ) > 0 ) { - tree.insert( new Range( spc, last + 1, b ) ); + if (Utils.unsignedCompare(b, last) > 0) { + tree.insert(new Range(spc, last + 1, b)); } } } // Make sure indicated range is // contained in the rangelist - public boolean inRange( Address addr, int size ) { + public boolean inRange(Address addr, int size) { - if ( addr.isInvalid() ) { + if (addr.isInvalid()) { return true; // We don't really care } - if ( tree.isEmpty() ) { + if (tree.isEmpty()) { return false; } // iter = first range with its first > addr - IteratorSTL iter = tree.upper_bound( new Range( addr.getSpace(), addr.getOffset(), - addr.getOffset() ) ); - if ( iter.isBegin() ) { + IteratorSTL iter = + tree.upper_bound(new Range(addr.getSpace(), addr.getOffset(), addr.getOffset())); + if (iter.isBegin()) { return false; } // Set iter to last range with range.first <= addr iter.decrement(); // if (iter == tree.end()) // iter can't be end if non-empty // return false; - if ( !iter.get().getSpace().equals( addr.getSpace() ) ) { + if (!iter.get().getSpace().equals(addr.getSpace())) { return false; } - if ( Utils.unsignedCompare( iter.get().getLast(), addr.getOffset() + size - 1 ) >= 0 ) { + if (Utils.unsignedCompare(iter.get().getLast(), addr.getOffset() + size - 1) >= 0) { return true; } return false; @@ -155,64 +152,65 @@ public boolean inRange( Address addr, int size ) { // Return size of biggest range (up to maxsize) starting at addr // which is completely covered by this rangelist - public long longestFit( Address addr, long maxsize ) { - if ( addr.isInvalid() ) { + public long longestFit(Address addr, long maxsize) { + if (addr.isInvalid()) { return 0; } - if ( tree.isEmpty() ) { + if (tree.isEmpty()) { return 0; } // iter = first range with its first > addr long offset = addr.getOffset(); - IteratorSTL iter = tree.upper_bound( new Range( addr.getSpace(), offset, offset ) ); - if ( iter.isBegin() ) { + IteratorSTL iter = tree.upper_bound(new Range(addr.getSpace(), offset, offset)); + if (iter.isBegin()) { return 0; } // Set iter to last range with range.first <= addr iter.decrement(); long sizeres = 0; - if ( Utils.unsignedCompare( iter.get().getLast(), offset ) < 0 ) { + if (Utils.unsignedCompare(iter.get().getLast(), offset) < 0) { return sizeres; } do { - if ( !iter.get().getSpace().equals( addr.getSpace() ) ) { + if (!iter.get().getSpace().equals(addr.getSpace())) { break; } - if ( Utils.unsignedCompare( iter.get().getFirst(), offset ) > 0 ) { + if (Utils.unsignedCompare(iter.get().getFirst(), offset) > 0) { break; } sizeres += (iter.get().getLast() + 1 - offset); // Size extends to end of range offset = iter.get().getLast() + 1; // Try to chain on the next range - if ( Utils.unsignedCompare( sizeres, maxsize ) >= 0 ) { + if (Utils.unsignedCompare(sizeres, maxsize) >= 0) { break; // Don't bother if past maxsize } iter.increment(); // Next range in the chain - } while ( !iter.isEnd() ); + } + while (!iter.isEnd()); return sizeres; } public Range getFirstRange() { - if ( tree.isEmpty() ) { + if (tree.isEmpty()) { return null; } return tree.begin().get(); } - public Range getFirstRange( AddrSpace spaceid ) { - Range range = new Range(spaceid,0,0); + public Range getFirstRange(AddrSpace spaceid) { + Range range = new Range(spaceid, 0, 0); IteratorSTL iter = tree.lower_bound(range); - if (iter.equals( tree.end() ) ) { + if (iter.equals(tree.end())) { return null; } - if ( !iter.get().getSpace().equals( spaceid ) ) { + if (!iter.get().getSpace().equals(spaceid)) { return null; } return iter.get(); } public Range getLastRange() { - if ( tree.isEmpty() ) { + if (tree.isEmpty()) { return null; } IteratorSTL iter = tree.end(); @@ -220,49 +218,29 @@ public Range getLastRange() { return iter.get(); } - public Range getLastRange( AddrSpace spaceid ) { - Range range = new Range( spaceid, -1, -1 ); + public Range getLastRange(AddrSpace spaceid) { + Range range = new Range(spaceid, -1, -1); IteratorSTL iter = tree.upper_bound(range); - if (iter.equals( tree.begin() ) ) { + if (iter.equals(tree.begin())) { return null; } iter.decrement(); - if ( !iter.get().getSpace().equals( spaceid ) ) { + if (!iter.get().getSpace().equals(spaceid)) { return null; } return iter.get(); } - public void printBounds( PrintStream s ) { - if ( tree.isEmpty() ) { - s.println( "all" ); - } else { - IteratorSTL it; - for ( it = tree.begin(); !it.isEnd(); it.increment() ) { + public void printBounds(PrintStream s) { + if (tree.isEmpty()) { + s.println("all"); + } + else { + for (IteratorSTL it = tree.begin(); !it.isEnd(); it.increment()) { Range range = it.get(); - range.printBounds( s ); + range.printBounds(s); } } } - public void saveXml( PrintStream s ) { - s.println( "" ); - IteratorSTL it; - for ( it = tree.begin(); !it.isEnd(); it.increment() ) { - Range range = it.get(); - range.saveXml( s ); - } - s.println( "" ); - } - - public void restoreXml( Element el, Translate trans ) { - List children = el.getChildren(); - for ( Object object : children ) { - Element child = (Element) object; - Range range = new Range(); - range.restoreXml( child, trans ); - tree.insert( range ); - } - } - } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/globalcontext/ContextBitRange.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/globalcontext/ContextBitRange.java index e333125f63d..1987dded51d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/globalcontext/ContextBitRange.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/globalcontext/ContextBitRange.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,31 +17,28 @@ public class ContextBitRange { - private int word; - private int startbit; - private int endbit; - private int shift; - private int mask; + private int word; + private int startbit; + private int endbit; + private int shift; + private int mask; - public ContextBitRange() { // For use with restoreXml - } - - public ContextBitRange(int sbit,int ebit) { - word = sbit/(32); - startbit = sbit - word*32; - endbit = ebit - word*32; - shift = 32-endbit-1; - mask = -1 >>> (startbit+shift); - } - - public void setValue(int[] vec, int val) { - int newval = vec[word]; - newval &= ~(mask<>shift)&mask); - } + public ContextBitRange(int sbit, int ebit) { + word = sbit / (32); + startbit = sbit - word * 32; + endbit = ebit - word * 32; + shift = 32 - endbit - 1; + mask = -1 >>> (startbit + shift); + } + + public void setValue(int[] vec, int val) { + int newval = vec[word]; + newval &= ~(mask << shift); + newval |= ((val & mask) << shift); + vec[word] = newval; + } + + public int getValue(int[] vec) { + return ((vec[word] >> shift) & mask); + } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/globalcontext/ContextCache.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/globalcontext/ContextCache.java deleted file mode 100644 index 52945c5a89b..00000000000 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/globalcontext/ContextCache.java +++ /dev/null @@ -1,79 +0,0 @@ -/* ### - * IP: GHIDRA - * REVIEWED: YES - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.pcodeCPort.globalcontext; - -import ghidra.pcodeCPort.address.*; -import ghidra.pcodeCPort.space.*; -import ghidra.pcodeCPort.utils.*; - -public class ContextCache { - - private ContextDatabase database = null; - private boolean allowset; - private AddrSpace curspace = null; - private long first; - private long last; - private int[] context; // Cached context - - public void allowSet( boolean val ) { - allowset = val; - } - - public ContextCache( ContextDatabase db ) { - database = db; - curspace = null; // Mark cache as invalid - allowset = true; - } - - public void dispose() { - } - - public ContextDatabase getDatabase() { - return database; - } - - public void getContext( Address addr, int[] buf ) { - if ( (!addr.getSpace().equals( curspace )) - || (Utils.unsignedCompare( first, addr.getOffset() ) > 0) - || (Utils.unsignedCompare( last, addr.getOffset() ) < 0) ) { - curspace = addr.getSpace(); - - MutableLong firstMutable = new MutableLong( first ); - MutableLong lastMutable = new MutableLong( last ); - context = database.getContext( addr, firstMutable, lastMutable ); - - first = firstMutable.get(); - last = lastMutable.get(); - } - for ( int i = 0; i < database.getContextSize(); ++i ) { - buf[i] = context[i]; - } - } - - public void setContext( Address addr, int num, int mask, int value ) { - if ( !allowset ) { - return; - } - database.setContextRange( addr, num, mask, value ); - if ( (addr.getSpace().equals( curspace )) - && (Utils.unsignedCompare( first, addr.getOffset() ) <= 0) - && (Utils.unsignedCompare( last, addr.getOffset() ) >= 0) ) { - curspace = null; // Invalidate cache - } - } - -} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/globalcontext/ContextDatabase.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/globalcontext/ContextDatabase.java deleted file mode 100644 index 571f2017c07..00000000000 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/globalcontext/ContextDatabase.java +++ /dev/null @@ -1,200 +0,0 @@ -/* ### - * IP: GHIDRA - * REVIEWED: YES - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.pcodeCPort.globalcontext; - -import generic.stl.VectorSTL; -import ghidra.pcodeCPort.address.Address; -import ghidra.pcodeCPort.pcoderaw.VarnodeData; -import ghidra.pcodeCPort.translate.Translate; -import ghidra.pcodeCPort.utils.MutableLong; -import ghidra.pcodeCPort.utils.Utils; - -import java.io.PrintStream; -import java.util.Iterator; -import java.util.List; - -import org.jdom.Element; - -/** - * This is the interface and implementation for a database of memory locations which should be - * treated likeants. These come in two flavors: - *

- * 1) Low-level context variables These can affect instruction decoding. These can be as small as a - * single bit and need to be defined in the sleigh module (so that sleigh knows how they effect - * disassembly). These variables are not mapped to normal memory locations with a space and offset. - * (Although they often have a corresponding embedding into a normal memory location) The model to - * keep in mind is special bitfields within a control register. - *

- * 2) High-level tracked variables These are normal memory locations that are to be treated asants - * across some range of code. These are normally some register that is being kept track of be the - * compiler outside the domain of normal local and global variables. They have a specific value - * established by the compiler coming in to a function but are not supposed to be interpreted as a - * high-level variable. Typical examples are the String instruction direction flag and segment - * registers. These are all interpreted as aant value at the start of a function, but the function - * can recycle the memory location for other calculations once theant has been used. - */ -public abstract class ContextDatabase { - - public void dispose() { - } - - public abstract int getContextSize(); - - public abstract void registerVariable(String nm, int sbit, int ebit); - - public abstract ContextBitRange getVariable(String nm); - - public abstract void getRegion(VectorSTL res, Address addr1, Address addr2); - - public abstract int[] getContext(Address addr); - - public abstract int[] getContext(Address addr, MutableLong first, MutableLong last); - - public abstract int[] getDefaultValue(); - - public abstract int[] createContext(Address addr); - - public abstract VectorSTL getTrackedDefault(); - - public abstract VectorSTL getTrackedSet(Address addr); - - public abstract VectorSTL createSet(Address addr1, Address addr2); - - public abstract void saveXml(PrintStream s); - - public abstract void restoreXml(Element el, Translate translate); - - public abstract void restoreFromSpec(Element el, Translate translate); - - protected void saveTracked(PrintStream s, Address addr, VectorSTL vec) { - if (vec.empty()) { - return; - } - s.append("\n"); - for (int i = 0; i < vec.size(); ++i) { - s.append(" "); - vec.get(i).saveXml(s); - } - s.append("\n"); - } - - public void setVariableDefault(String nm, int val) { - ContextBitRange var = getVariable(nm); - var.setValue(getDefaultValue(), val); - } - - public int getDefaultValue(String nm) { - ContextBitRange var = getVariable(nm); - return var.getValue(getDefaultValue()); - } - - /** Set value of context register, starting at addr */ - public void setVariable(String nm, Address addr, int value) { - ContextBitRange bitrange = getVariable(nm); - - int[] newcontext = createContext(addr); - bitrange.setValue(newcontext, value); - } - - public int getVariable(String nm, Address addr) { - ContextBitRange bitrange = getVariable(nm); - - int[] context = getContext(addr); - return bitrange.getValue(context); - } - - /** Set specific bits in context */ - public void setContextRange(Address addr, int num, int mask, int value) { - int[] newcontext = createContext(addr); - - int val = newcontext[num]; - val &= ~mask; // Clear range to zero - val |= value; - newcontext[num] = val; - } - - /** Set value of context register between begad and endad */ - public void setVariableRegion(String nm, Address begad, Address endad, int value) { - ContextBitRange bitrange = getVariable(nm); - - VectorSTL vec = new VectorSTL(); - getRegion(vec, begad, endad); - for (int i = 0; i < vec.size(); ++i) { - bitrange.setValue(vec.get(i), value); - } - } - - /** - * For a particular tracked memory location, get the value at a particular point. - */ - public long getTrackedValue(VarnodeData mem, Address point) { - VectorSTL tset = getTrackedSet(point); - long endoff = mem.offset + mem.size - 1; - long tendoff; - for (int i = 0; i < tset.size(); ++i) { - TrackedContext tcont = tset.get(i); - if (tcont == null) { - tcont = new TrackedContext(); - tset.set(i, tcont); - } - - // tcont must contain -mem- - if (tcont.loc.space != mem.space) { - continue; - } - if (tcont.loc.offset > mem.offset) { - continue; - } - tendoff = tcont.loc.offset + tcont.loc.size - 1; - if (tendoff < endoff) { - continue; - } - - long res = tcont.val; - // If we have proper containment, trim value based on endianness - if (tcont.loc.space.isBigEndian()) { - if (endoff != tendoff) { - res >>>= (8 * (tendoff - mem.offset)); - } - } - else { - if (mem.offset != tcont.loc.offset) { - res >>>= (8 * (mem.offset - tcont.loc.offset)); - } - } - res &= Utils.calc_mask(mem.size); // Final trim based on size - return res; - } - return 0; - } - - public static void restoreTracked(Element el, Translate trans, VectorSTL vec) { - vec.clear(); - - List list = el.getChildren(); - Iterator iter = list.iterator(); - - while (iter.hasNext()) { - Element subel = (Element) iter.next(); - vec.push_back(new TrackedContext()); - vec.back().restoreXml(subel, trans); - } - } - -} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/globalcontext/TrackedContext.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/globalcontext/TrackedContext.java index 0d5d7969137..100d5d4dd2f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/globalcontext/TrackedContext.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/globalcontext/TrackedContext.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,37 +15,9 @@ */ package ghidra.pcodeCPort.globalcontext; -import ghidra.pcodeCPort.address.*; -import ghidra.pcodeCPort.pcoderaw.*; -import ghidra.pcodeCPort.translate.*; -import ghidra.pcodeCPort.utils.*; - -import java.io.PrintStream; - -import org.jdom.Element; - - +import ghidra.pcodeCPort.pcoderaw.VarnodeData; public class TrackedContext { - public VarnodeData loc = new VarnodeData(); - public long val; - - public void saveXml( PrintStream s ) { - s.append( "\n" ); - } - - public void restoreXml( Element el, Translate trans ) { - VarnodeData varnodeData = Address.restoreXml( el, trans ); - Address addr = varnodeData.getAddress(); - int size = varnodeData.size; - - val = XmlUtils.decodeUnknownLong( el.getAttributeValue( "val" ) ); - - loc.space = addr.getSpace(); - loc.offset = addr.getOffset(); - loc.size = size; - } + public VarnodeData loc = new VarnodeData(); + public long val; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/opcodes/OpCode.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/opcodes/OpCode.java index 4d91cca6b87..d69279a188c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/opcodes/OpCode.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/opcodes/OpCode.java @@ -15,6 +15,7 @@ */ package ghidra.pcodeCPort.opcodes; // Names of ops associated with their opcode number + // Some of the names have been replaced with special placeholder // ops for the sleigh compiler and interpreter these are as follows: // MULTIEQUAL = BUILD @@ -23,7 +24,8 @@ // PTRSUB = CROSSBUILD public enum OpCode { - DO_NOT_USE_ME_I_AM_ENUM_ELEMENT_ZERO, CPUI_COPY, // Copy one operand to another + DO_NOT_USE_ME_I_AM_ENUM_ELEMENT_ZERO, + CPUI_COPY, // Copy one operand to another CPUI_LOAD, // Dereference a pointer into specified space CPUI_STORE, // Store at a pointer into specified space @@ -127,9 +129,9 @@ public String getName() { public OpCode getOpCodeFlip() { // Return the complimentary opcode for boolean operations - // (or CPUI_MAX if not boolean) Set reorder to true if - // the complimentary operation would involve reordering - // the input parameters + // (or CPUI_MAX if not boolean) Set reorder to true if + // the complimentary operation would involve reordering + // the input parameters switch (this) { case CPUI_INT_EQUAL: return CPUI_INT_NOTEQUAL; @@ -162,9 +164,9 @@ public OpCode getOpCodeFlip() public boolean getBooleanFlip() { // Return the complimentary opcode for boolean operations - // (or CPUI_MAX if not boolean) Set reorder to true if - // the complimentary operation would involve reordering - // the input parameters + // (or CPUI_MAX if not boolean) Set reorder to true if + // the complimentary operation would involve reordering + // the input parameters switch (this) { case CPUI_INT_EQUAL: return false; @@ -200,21 +202,20 @@ public boolean getBooleanFlip() "INT_ADD", "INT_SUB", "INT_CARRY", "INT_SCARRY", "INT_SBORROW", "INT_2COMP", "INT_NEGATE", "INT_XOR", "INT_AND", "INT_OR", "INT_LEFT", "INT_RIGHT", "INT_SRIGHT", "INT_MULT", "INT_DIV", "INT_SDIV", "INT_REM", "INT_SREM", "BOOL_NEGATE", "BOOL_XOR", "BOOL_AND", - "BOOL_OR", "FLOAT_EQUAL", "FLOAT_NOTEQUAL", "FLOAT_LESS", "FLOAT_LESSEQUAL", - "UNUSED1", "FLOAT_NAN", "FLOAT_ADD", "FLOAT_DIV", "FLOAT_MULT", "FLOAT_SUB", - "FLOAT_NEG", "FLOAT_ABS", "FLOAT_SQRT", "INT2FLOAT", "FLOAT2FLOAT", "TRUNC", "CEIL", - "FLOOR", "ROUND", "BUILD", "DELAY_SLOT", "PIECE", "SUBPIECE", "CAST", "LABEL", - "CROSSBUILD", "SEGMENTOP", "CPOOLREF", "NEW", "INSERT", "EXTRACT", "POPCOUNT", - "LZCOUNT" }; + "BOOL_OR", "FLOAT_EQUAL", "FLOAT_NOTEQUAL", "FLOAT_LESS", "FLOAT_LESSEQUAL", "UNUSED1", + "FLOAT_NAN", "FLOAT_ADD", "FLOAT_DIV", "FLOAT_MULT", "FLOAT_SUB", "FLOAT_NEG", "FLOAT_ABS", + "FLOAT_SQRT", "INT2FLOAT", "FLOAT2FLOAT", "TRUNC", "CEIL", "FLOOR", "ROUND", "BUILD", + "DELAY_SLOT", "PIECE", "SUBPIECE", "CAST", "LABEL", "CROSSBUILD", "SEGMENTOP", "CPOOLREF", + "NEW", "INSERT", "EXTRACT", "POPCOUNT", "LZCOUNT" }; public static String get_opname(OpCode op) { return opcode_name[op.ordinal()]; } - static final int opcode_indices[] = { 0, 39, 37, 40, 38, 4, 6, 60, 7, 8, 9, 64, 5, 57, 1, 68, 66, - 61, 71, 55, 52, 47, 48, 41, 43, 44, 49, 46, 51, 42, 53, 50, 58, 70, 54, 24, 19, 27, 21, - 33, 11, 29, 15, 16, 32, 25, 12, 28, 35, 30, 23, 22, 34, 18, 13, 14, 36, 31, 20, 26, 17, - 65, 2, 73, 69, 62, 72, 10, 59, 67, 3, 63, 56, 45 }; + static final int opcode_indices[] = { 0, 39, 37, 40, 38, 4, 6, 60, 7, 8, 9, 64, 5, 57, 1, 68, + 66, 61, 71, 55, 52, 47, 48, 41, 43, 44, 49, 46, 51, 42, 53, 50, 58, 70, 54, 24, 19, 27, 21, + 33, 11, 29, 15, 16, 32, 25, 12, 28, 35, 30, 23, 22, 34, 18, 13, 14, 36, 31, 20, 26, 17, 65, + 2, 73, 69, 62, 72, 10, 59, 67, 3, 63, 56, 45 }; public static OpCode get_opcode(String nm) { // Use binary search to find name int min = 1; // Don't include BLANK diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/pcoderaw/VarnodeData.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/pcoderaw/VarnodeData.java index 4b328f7b05d..95db1718cba 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/pcoderaw/VarnodeData.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/pcoderaw/VarnodeData.java @@ -15,12 +15,9 @@ */ package ghidra.pcodeCPort.pcoderaw; -import org.jdom.Element; - -import ghidra.pcodeCPort.address.*; -import ghidra.pcodeCPort.error.*; -import ghidra.pcodeCPort.space.*; -import ghidra.pcodeCPort.translate.*; +import ghidra.pcodeCPort.address.Address; +import ghidra.pcodeCPort.address.AddressUtils; +import ghidra.pcodeCPort.space.AddrSpace; public class VarnodeData { // string name; // This field will be depracated when sleigh comes on line @@ -29,17 +26,18 @@ public class VarnodeData { public long offset; public int size; - // for use before restoreXML - public VarnodeData() { + + public VarnodeData() { } - public VarnodeData( AddrSpace base, long off, int size ) { + + public VarnodeData(AddrSpace base, long off, int size) { space = base; offset = off; this.size = size; } @Override - public boolean equals( Object obj ) { + public boolean equals(Object obj) { if (obj == this) { return true; } @@ -52,53 +50,25 @@ public boolean equals( Object obj ) { @Override public int hashCode() { - return space.hashCode() + (int) offset + size; + return space.hashCode() + (int) offset + size; } - - public int compareTo( VarnodeData other ) { - int result = space.compareTo( other.space ); + + public int compareTo(VarnodeData other) { + int result = space.compareTo(other.space); if (result != 0) { return result; } - result = AddressUtils.unsignedCompare( offset, other.offset ); + result = AddressUtils.unsignedCompare(offset, other.offset); if (result != 0) { return result; } return other.size - size;// BIG sizes come first } - - // Build this VarnodeData from an \b \ tag - // \param el is the parsed tag - // \param trans is the relevant processor translator - public void restoreXml( Element el, Translate trans ) { - String name = el.getAttributeValue( "name" ); - if (name != null) { - VarnodeData vdata = trans.getRegister( name ); - space = vdata.space; - offset = vdata.offset; - size = vdata.size; - return; - } - - - String attributeValue = el.getAttributeValue( "space" ); - if ( attributeValue == null ) { - return; - } - - space = trans.getSpaceByName( attributeValue ); - if (space == null) { - throw new LowlevelError( "Unknown space name: " + attributeValue ); - } - offset = AddrSpace.restore_xml_offset( el ); - size = AddrSpace.restore_xml_size( el ); - } - public Address getAddress() { // if ( space == null ) { // return new Address( AddrSpace.MIN_SPACE, 0 ); // } - return new Address(this.space, this.offset); + return new Address(this.space, this.offset); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/ConstTpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/ConstTpl.java index 341877dae8b..4c84b4d94ec 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/ConstTpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/ConstTpl.java @@ -15,16 +15,15 @@ */ package ghidra.pcodeCPort.semantics; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.error.LowlevelError; import ghidra.pcodeCPort.space.AddrSpace; import ghidra.pcodeCPort.space.spacetype; -import ghidra.pcodeCPort.translate.Translate; -import ghidra.pcodeCPort.utils.XmlUtils; +import ghidra.program.model.pcode.Encoder; public class ConstTpl { @Override @@ -89,8 +88,8 @@ public ConstTpl(const_type tp, int ht, v_field vf) { handle_index = ht; select = vf; } - - public ConstTpl(const_type tp,int ht,v_field vf,long plus) { + + public ConstTpl(const_type tp, int ht, v_field vf, long plus) { type = const_type.handle; handle_index = ht; select = vf; @@ -117,7 +116,7 @@ public int getHandleIndex() { public const_type getType() { return type; } - + public v_field getSelect() { return select; } @@ -224,168 +223,89 @@ public void transfer(VectorSTL params) { case v_offset_plus: long tmp = value_real; copyIntoMe(newhandle.getPtrOffset()); - if (type == const_type.real) + if (type == const_type.real) { value_real += (tmp & 0xffff); - else if ((type == const_type.handle)&&(select == v_field.v_offset)) { + } + else if ((type == const_type.handle) && (select == v_field.v_offset)) { select = v_field.v_offset_plus; value_real = tmp; } - else + else { throw new LowlevelError("Cannot truncate macro input in this way"); + } break; } } - private static void printHandleSelector(PrintStream s, v_field val) { - switch (val) { - case v_space: - s.append("space"); - break; - case v_offset: - s.append("offset"); - break; - case v_size: - s.append("size"); - break; - case v_offset_plus: - s.append("offset_plus"); - break; - } - } - - private static v_field readHandleSelector(String name) { - if (name.equals("space")) { - return v_field.v_space; - } - if (name.equals("offset")) { - return v_field.v_offset; - } - if (name.equals("size")) { - return v_field.v_size; - } - if (name.equals("offset_plus")) { - return v_field.v_offset_plus; - } - throw new LowlevelError("Bad handle selector"); - } - public void changeHandleIndex(VectorSTL handmap) { if (type == const_type.handle) { handle_index = handmap.get(handle_index); } } - public void saveXml(PrintStream s) { - s.append(""); + encoder.openElement(ELEM_CONST_REAL); + encoder.writeUnsignedInteger(ATTRIB_VAL, value_real); + encoder.closeElement(ELEM_CONST_REAL); break; case handle: - s.append("handle\" val=\""); - s.print(handle_index); - s.append("\" "); - s.append("s=\""); - printHandleSelector(s, select); - s.append('\"'); - if (select == v_field.v_offset_plus) - s.append(" plus=\"0x").append(Long.toHexString(value_real)).append('\"'); - s.append("/>"); + encoder.openElement(ELEM_CONST_HANDLE); + encoder.writeSignedInteger(ATTRIB_VAL, handle_index); + encoder.writeSignedInteger(ATTRIB_S, select.ordinal()); + if (select == v_field.v_offset_plus) { + encoder.writeUnsignedInteger(ATTRIB_PLUS, value_real); + } + encoder.closeElement(ELEM_CONST_HANDLE); break; case j_start: - s.append("start\"/>"); + encoder.openElement(ELEM_CONST_START); + encoder.closeElement(ELEM_CONST_START); break; case j_next: - s.append("next\"/>"); + encoder.openElement(ELEM_CONST_NEXT); + encoder.closeElement(ELEM_CONST_NEXT); break; case j_next2: - s.append("next2\"/>"); + encoder.openElement(ELEM_CONST_NEXT2); + encoder.closeElement(ELEM_CONST_NEXT2); break; case j_curspace: - s.append("curspace\"/>"); + encoder.openElement(ELEM_CONST_CURSPACE); + encoder.closeElement(ELEM_CONST_CURSPACE); break; case j_curspace_size: - s.append("curspace_size\"/>"); + encoder.openElement(ELEM_CONST_CURSPACE_SIZE); + encoder.closeElement(ELEM_CONST_CURSPACE_SIZE); break; case spaceid: - s.append("spaceid\" name=\""); - s.append(spaceid.getName()); - s.append("\"/>"); + encoder.openElement(ELEM_CONST_SPACEID); + encoder.writeSpace(ATTRIB_SPACE, spaceid.getIndex(), spaceid.getName()); + encoder.closeElement(ELEM_CONST_SPACEID); break; case j_relative: - s.append("relative\" val=\"0x"); - s.append(Long.toHexString(value_real)); - s.append("\"/>"); + encoder.openElement(ELEM_CONST_RELATIVE); + encoder.writeUnsignedInteger(ATTRIB_VAL, value_real); + encoder.closeElement(ELEM_CONST_RELATIVE); break; case j_flowref: - s.append("flowref\"/>"); + encoder.openElement(ELEM_CONST_FLOWREF); + encoder.closeElement(ELEM_CONST_FLOWREF); break; case j_flowref_size: - s.append("flowref_size\"/>"); + encoder.openElement(ELEM_CONST_FLOWREF_SIZE); + encoder.closeElement(ELEM_CONST_FLOWREF_SIZE); break; case j_flowdest: - s.append("flowdest\"/>"); + encoder.openElement(ELEM_CONST_FLOWDEST); + encoder.closeElement(ELEM_CONST_FLOWDEST); break; case j_flowdest_size: - s.append("flowdest_size\"/>"); + encoder.openElement(ELEM_CONST_FLOWDEST_SIZE); + encoder.closeElement(ELEM_CONST_FLOWDEST_SIZE); break; } } - public void restoreXml(Element el, Translate trans) { - String typestring = el.getAttributeValue("type"); - if (typestring.equals("real")) { - type = const_type.real; - value_real = XmlUtils.decodeUnknownLong(el.getAttributeValue("val")); - } - else if (typestring.equals("handle")) { - type = const_type.handle; - handle_index = XmlUtils.decodeUnknownInt(el.getAttributeValue("val")); - select = readHandleSelector(el.getAttributeValue("s")); - if (select == v_field.v_offset_plus) { - value_real = XmlUtils.decodeUnknownLong(el.getAttributeValue("plus")); - } - } - else if (typestring.equals("start")) { - type = const_type.j_start; - } - else if (typestring.equals("next")) { - type = const_type.j_next; - } - else if (typestring.equals("next2")) { - type = const_type.j_next2; - } - else if (typestring.equals("curspace")) { - type = const_type.j_curspace; - } - else if (typestring.equals("curspace_size")) { - type = const_type.j_curspace_size; - } - else if (typestring.equals("spaceid")) { - type = const_type.spaceid; - spaceid = trans.getSpaceByName(el.getAttributeValue("name")); - } - else if (typestring.equals("relative")) { - type = const_type.j_relative; - value_real = XmlUtils.decodeUnknownLong(el.getAttributeValue("val")); - } - else if (typestring.equals("flowref")) { - type = const_type.j_flowref; - } - else if (typestring.equals("flowref_size")) { - type = const_type.j_flowref_size; - } - else if (typestring.equals("flowdest")) { - type = const_type.j_flowdest; - } - else if (typestring.equals("flowdest_size")) { - type = const_type.j_flowdest_size; - } - else { - throw new LowlevelError("Bad constant type"); - } - } - } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/ConstructTpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/ConstructTpl.java index cf7f9988fe2..de0529db7a3 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/ConstructTpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/ConstructTpl.java @@ -15,16 +15,15 @@ */ package ghidra.pcodeCPort.semantics; -import java.io.PrintStream; -import java.util.*; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; +import java.util.ArrayList; import generic.stl.*; import ghidra.pcodeCPort.opcodes.OpCode; import ghidra.pcodeCPort.space.AddrSpace; -import ghidra.pcodeCPort.translate.Translate; -import ghidra.pcodeCPort.utils.XmlUtils; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; import ghidra.sleigh.grammar.LocationUtil; @@ -49,7 +48,7 @@ public int delaySlot() { public int numLabels() { return numlabels; } - + public void setNumLabels(int val) { numlabels = val; } @@ -57,7 +56,7 @@ public void setNumLabels(int val) { public void setOpvec(VectorSTL opvec) { vec = opvec; } - + public VectorSTL getOpvec() { return vec; } @@ -127,9 +126,9 @@ public Pair fillinBuild(VectorSTL check, AddrSpace c for (int i = 0; i < check.size(); ++i) { if (check.get(i) == 0) { // Didn't see a BUILD statement op = new OpTpl(min, OpCode.CPUI_MULTIEQUAL); - indvn = - new VarnodeTpl(min, new ConstTpl(const_space), new ConstTpl( - ConstTpl.const_type.real, i), new ConstTpl(ConstTpl.const_type.real, 4)); + indvn = new VarnodeTpl(min, new ConstTpl(const_space), + new ConstTpl(ConstTpl.const_type.real, i), + new ConstTpl(ConstTpl.const_type.real, 4)); op.addInput(indvn); vec.insert(vec.begin(), op); } @@ -205,67 +204,28 @@ public void deleteOps(VectorSTL indices) { } } - public void saveXml(PrintStream s, int sectionid) { - s.append("= 0) { - s.append(" section=\""); - s.print(sectionid); - s.append("\""); + encoder.writeSignedInteger(ATTRIB_SECTION, sectionid); } if (delayslot != 0) { - s.append(" delay=\""); - s.print(delayslot); - s.append("\""); + encoder.writeSignedInteger(ATTRIB_DELAY, delayslot); // FIXME: Seems to be unused } if (numlabels != 0) { - s.append(" labels=\""); - s.print(numlabels); - s.append("\""); + encoder.writeSignedInteger(ATTRIB_LABELS, numlabels); } - s.append(">\n"); if (result != null) { - result.saveXml(s); + result.encode(encoder); } else { - s.append(""); + encoder.openElement(ELEM_NULL); + encoder.closeElement(ELEM_NULL); } for (int i = 0; i < vec.size(); ++i) { - vec.get(i).saveXml(s); - } - s.append("\n"); - } - - public int restoreXml(Element el, Translate trans) { - int sectionid = -1; - String str = el.getAttributeValue("delay"); - if (str != null) { - delayslot = XmlUtils.decodeUnknownInt(str); - } - str = el.getAttributeValue("labels"); - if (str != null) { - numlabels = XmlUtils.decodeUnknownInt(str); - } - str = el.getAttributeValue("section"); - if (str != null) { - sectionid = XmlUtils.decodeUnknownInt(str); - } - List list = el.getChildren(); - Iterator it = list.iterator(); - Element child = (Element) it.next(); - if (child.getName().equals("null")) { - result = null; - } - else { - result = new HandleTpl(); - result.restoreXml(child, trans); - } - while (it.hasNext()) { - child = (Element) it.next(); - OpTpl op = new OpTpl(null); - op.restoreXml(child, trans); - vec.push_back(op); + vec.get(i).encode(encoder); } - return sectionid; + encoder.closeElement(ELEM_CONSTRUCT_TPL); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/HandleTpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/HandleTpl.java index 5777ea7d7ec..acc24aab941 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/HandleTpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/HandleTpl.java @@ -15,14 +15,13 @@ */ package ghidra.pcodeCPort.semantics; -import java.io.PrintStream; -import java.util.List; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.space.AddrSpace; -import ghidra.pcodeCPort.translate.Translate; +import ghidra.program.model.pcode.Encoder; public class HandleTpl { @@ -120,27 +119,16 @@ public void changeHandleIndex(VectorSTL handmap) { temp_offset.changeHandleIndex(handmap); } - public void saveXml(PrintStream s) { - s.append(""); - space.saveXml(s); - size.saveXml(s); - ptrspace.saveXml(s); - ptroffset.saveXml(s); - ptrsize.saveXml(s); - temp_space.saveXml(s); - temp_offset.saveXml(s); - s.append("\n"); - } - - public void restoreXml(Element el, Translate trans) { - List list = el.getChildren(); - space.restoreXml((Element) list.get(0), trans); - size.restoreXml((Element) list.get(1), trans); - ptrspace.restoreXml((Element) list.get(2), trans); - ptroffset.restoreXml((Element) list.get(3), trans); - ptrsize.restoreXml((Element) list.get(4), trans); - temp_space.restoreXml((Element) list.get(5), trans); - temp_offset.restoreXml((Element) list.get(6), trans); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_HANDLE_TPL); + space.encode(encoder); + size.encode(encoder); + ptrspace.encode(encoder); + ptroffset.encode(encoder); + ptrsize.encode(encoder); + temp_space.encode(encoder); + temp_offset.encode(encoder); + encoder.closeElement(ELEM_HANDLE_TPL); } public void dispose() { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/OpTpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/OpTpl.java index 5a1edea508d..dcca4e5478c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/OpTpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/OpTpl.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,32 +15,29 @@ */ package ghidra.pcodeCPort.semantics; -import generic.stl.IteratorSTL; -import generic.stl.VectorSTL; -import ghidra.pcodeCPort.opcodes.*; -import ghidra.pcodeCPort.translate.*; -import ghidra.sleigh.grammar.*; - -import java.io.*; -import java.util.*; - +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.*; +import java.io.IOException; +import generic.stl.IteratorSTL; +import generic.stl.VectorSTL; +import ghidra.pcodeCPort.opcodes.OpCode; +import ghidra.program.model.pcode.Encoder; +import ghidra.sleigh.grammar.Location; public class OpTpl { - public final Location location; + public final Location location; private VarnodeTpl output; private OpCode opc; private VectorSTL input = new VectorSTL(); public OpTpl(Location location) { - this.location = location; + this.location = location; } - public OpTpl( Location location, OpCode oc ) { - this.location = location; + public OpTpl(Location location, OpCode oc) { + this.location = location; opc = oc; output = null; } @@ -50,7 +46,7 @@ public OpTpl( Location location, OpCode oc ) { public String toString() { return "OpTpl[opcode=" + opc + "]"; } - + public VarnodeTpl getOut() { return output; } @@ -59,19 +55,19 @@ public int numInput() { return input.size(); } - public VarnodeTpl getIn( int i ) { - return input.get( i ); + public VarnodeTpl getIn(int i) { + return input.get(i); } public OpCode getOpcode() { return opc; } - public void setOpcode( OpCode o ) { + public void setOpcode(OpCode o) { opc = o; } - public void setOutput( VarnodeTpl vt ) { + public void setOutput(VarnodeTpl vt) { output = vt; } @@ -80,82 +76,71 @@ public void clearOutput() { output = null; } - public void addInput( VarnodeTpl vt ) { - input.push_back( vt ); + public void addInput(VarnodeTpl vt) { + input.push_back(vt); } - public void setInput( VarnodeTpl vt, int slot ) { - input.set( slot, vt ); + public void setInput(VarnodeTpl vt, int slot) { + input.set(slot, vt); } // An OpTpl owns its varnode_tpls public void dispose() { - if ( output != null ) { + if (output != null) { output.dispose(); } IteratorSTL iter; - for ( iter = input.begin(); !iter.isEnd(); iter.increment() ) + for (iter = input.begin(); !iter.isEnd(); iter.increment()) { iter.get().dispose(); + } } // Return if any input or output has zero size public boolean isZeroSize() { - if ( output != null ) { - if ( output.isZeroSize() ) + if (output != null) { + if (output.isZeroSize()) { return true; + } } IteratorSTL iter; - for ( iter = input.begin(); !iter.isEnd(); iter.increment() ) - if ( iter.get().isZeroSize() ) + for (iter = input.begin(); !iter.isEnd(); iter.increment()) { + if (iter.get().isZeroSize()) { return true; + } + } return false; } // Remove the indicated input - public void removeInput( int index ) { - input.get( index ).dispose(); - input.erase( index ); + public void removeInput(int index) { + input.get(index).dispose(); + input.erase(index); } - public void changeHandleIndex( VectorSTL handmap ) { - if ( output != null ) { - output.changeHandleIndex( handmap ); + public void changeHandleIndex(VectorSTL handmap) { + if (output != null) { + output.changeHandleIndex(handmap); } IteratorSTL iter; - for ( iter = input.begin(); !iter.isEnd(); iter.increment() ) - iter.get().changeHandleIndex( handmap ); - } - - public void saveXml( PrintStream s ) { - s.append( "" ); - if ( output == null ) - s.append( "\n" ); - else - output.saveXml( s ); - for ( int i = 0; i < input.size(); ++i ) - input.get( i ).saveXml( s ); - s.append( "\n" ); - } - - public void restoreXml( Element el, Translate trans ) { - opc = OpCode.get_opcode( el.getAttributeValue( "code" ) ); - List list = el.getChildren(); - Iterator iter = list.iterator(); - Element child = (Element) iter.next(); - if ( child.getName().equals( "null" ) ) - output = null; + for (iter = input.begin(); !iter.isEnd(); iter.increment()) { + iter.get().changeHandleIndex(handmap); + } + } + + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_OP_TPL); + encoder.writeOpcode(ATTRIB_CODE, opc.ordinal()); + if (output == null) { + encoder.openElement(ELEM_NULL); + encoder.closeElement(ELEM_NULL); + } else { - output = new VarnodeTpl(null); - output.restoreXml( child, trans ); + output.encode(encoder); } - while ( iter.hasNext() ) { - child = (Element) iter.next(); - VarnodeTpl vn = new VarnodeTpl(null); - vn.restoreXml( child, trans ); - input.push_back( vn ); + for (int i = 0; i < input.size(); ++i) { + input.get(i).encode(encoder); } + encoder.closeElement(ELEM_OP_TPL); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/VarnodeTpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/VarnodeTpl.java index dbe481e4082..4e5b2d08fa8 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/VarnodeTpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/VarnodeTpl.java @@ -15,16 +15,15 @@ */ package ghidra.pcodeCPort.semantics; -import java.io.*; -import java.util.List; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.semantics.ConstTpl.const_type; import ghidra.pcodeCPort.semantics.ConstTpl.v_field; import ghidra.pcodeCPort.space.spacetype; -import ghidra.pcodeCPort.translate.Translate; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class VarnodeTpl { @@ -129,22 +128,25 @@ public boolean isLocalTemp() { public int transfer(VectorSTL params) { boolean doesOffsetPlus = false; - int handleIndex=0; - int plus=0; - - if ((offset.getType()==const_type.handle)&&(offset.getSelect()==v_field.v_offset_plus)) { + int handleIndex = 0; + int plus = 0; + + if ((offset.getType() == const_type.handle) && + (offset.getSelect() == v_field.v_offset_plus)) { handleIndex = offset.getHandleIndex(); - plus = (int)offset.getReal(); + plus = (int) offset.getReal(); doesOffsetPlus = true; } space.transfer(params); offset.transfer(params); size.transfer(params); if (doesOffsetPlus) { - if (isLocalTemp()) + if (isLocalTemp()) { return plus; // A positive number indicates truncation of a local temp - if (params.get(handleIndex).getSize().isZero()) + } + if (params.get(handleIndex).getSize().isZero()) { return plus; // or a zerosize object + } } return -1; } @@ -155,60 +157,40 @@ public void changeHandleIndex(VectorSTL handmap) { size.changeHandleIndex(handmap); } - public boolean adjustTruncation(int sz,boolean isbigendian) { + public boolean adjustTruncation(int sz, boolean isbigendian) { // We know this.offset is an v_field.offset_plus, check that the truncation is in bounds (given -sz-) // adjust plus for endianness if necessary // return true if truncation is in bounds - if (size.getType() != const_type.real) + if (size.getType() != const_type.real) { return false; - int numbytes = (int)size.getReal(); + } + int numbytes = (int) size.getReal(); int byteoffset = (int) offset.getReal(); - if (numbytes + byteoffset > sz) return false; - + if (numbytes + byteoffset > sz) { + return false; + } + // Encode the original truncation amount with the plus value long val = byteoffset; val <<= 16; - if (isbigendian) + if (isbigendian) { val |= (sz - (numbytes + byteoffset)); - else - val |= byteoffset; - - offset = new ConstTpl(const_type.handle,offset.getHandleIndex(),v_field.v_offset_plus,val); - return true; - } - - public void saveXml(PrintStream s) { - s.append(""); -// s.append( "" ); - space.saveXml(s); - offset.saveXml(s); - size.saveXml(s); - s.append("\n"); - } - - @Override - public String toString() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos, true); - saveXml(ps); - ps.flush(); - String result = baos.toString(); - ps.close(); - try { - baos.close(); } - catch (IOException e) { - // whatever + else { + val |= byteoffset; } - return result; - } - public void restoreXml(Element el, Translate trans) { - List list = el.getChildren(); + offset = + new ConstTpl(const_type.handle, offset.getHandleIndex(), v_field.v_offset_plus, val); + return true; + } - space.restoreXml((Element) list.get(0), trans); - offset.restoreXml((Element) list.get(1), trans); - size.restoreXml((Element) list.get(2), trans); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_VARNODE_TPL); + space.encode(encoder); + offset.encode(encoder); + size.encode(encoder); + encoder.closeElement(ELEM_VARNODE_TPL); } public int compareTo(VarnodeTpl op2) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/sleighbase/SleighBase.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/sleighbase/SleighBase.java index 89ce3cbccc6..5223f6a466c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/sleighbase/SleighBase.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/sleighbase/SleighBase.java @@ -15,7 +15,9 @@ */ package ghidra.pcodeCPort.sleighbase; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.io.IOException; import java.util.ArrayList; import generic.stl.*; @@ -26,20 +28,15 @@ import ghidra.pcodeCPort.space.AddrSpace; import ghidra.pcodeCPort.space.spacetype; import ghidra.pcodeCPort.translate.Translate; -import ghidra.pcodeCPort.utils.XmlUtils; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.SourceFileIndexer; public abstract class SleighBase extends Translate implements NamedSymbolProvider { - // NOTE: restoreXml method removed as it is only used by the decompiler's - // implementation - /** - * Note: The values of {@link #SLA_FORMAT_VERSION} and {@link #MAX_UNIQUE_SIZE} - * must match the corresponding values defined by sleighbase.cc + * Note: The value of {@link #MAX_UNIQUE_SIZE} must match the corresponding value + * defined by sleighbase.cc */ - public static final int SLA_FORMAT_VERSION = 3; - public static final long MAX_UNIQUE_SIZE = 128; //Maximum size of a varnode in the unique space. //Should match value in sleighbase.cc @@ -181,37 +178,35 @@ public void getUserOpNames(VectorSTL res) { } } - public void saveXml(PrintStream s) { - s.append(" 0) { - XmlUtils.a_v_u(s, "maxdelay", maxdelayslotbytes); + encoder.writeUnsignedInteger(ATTRIB_MAXDELAY, maxdelayslotbytes); } if (unique_allocatemask != 0) { - XmlUtils.a_v_u(s, "uniqmask", unique_allocatemask); + encoder.writeUnsignedInteger(ATTRIB_UNIQMASK, unique_allocatemask); } if (numSections != 0) { - XmlUtils.a_v_u(s, "numsections", numSections); + encoder.writeUnsignedInteger(ATTRIB_NUMSECTIONS, numSections); } - s.append(">\n"); - indexer.saveXml(s); - s.append("\n"); + indexer.encode(encoder); + encoder.openElement(ELEM_SPACES); + encoder.writeString(ATTRIB_DEFAULTSPACE, getDefaultSpace().getName()); for (int i = 0; i < numSpaces(); ++i) { AddrSpace spc = getSpace(i); if ((spc.getType() == spacetype.IPTR_CONSTANT) || (spc.getType() == spacetype.IPTR_FSPEC) || (spc.getType() == spacetype.IPTR_IOP)) { continue; } - spc.saveXml(s); + spc.encode(encoder); } - s.append("\n"); - symtab.saveXml(s); - s.append("\n"); + encoder.closeElement(ELEM_SPACES); + symtab.encode(encoder); + encoder.closeElement(ELEM_SLEIGH); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/SleighCompile.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/SleighCompile.java index 4a8e710b3b6..951c1a3770a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/SleighCompile.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/SleighCompile.java @@ -22,10 +22,11 @@ import org.antlr.runtime.*; import org.antlr.runtime.tree.CommonTreeNodeStream; -import org.jdom.JDOMException; +import generic.jar.ResourceFile; import generic.stl.*; import ghidra.pcode.utils.MessageFormattingUtils; +import ghidra.pcode.utils.SlaFormat; import ghidra.pcodeCPort.address.Address; import ghidra.pcodeCPort.context.SleighError; import ghidra.pcodeCPort.error.LowlevelError; @@ -36,8 +37,9 @@ import ghidra.pcodeCPort.slghsymbol.*; import ghidra.pcodeCPort.space.*; import ghidra.pcodeCPort.utils.Utils; -import ghidra.pcodeCPort.xml.DocumentStorage; import ghidra.program.model.lang.SpaceNames; +import ghidra.program.model.pcode.PackedEncode; +import ghidra.program.model.pcode.XmlEncode; import ghidra.sleigh.grammar.*; import ghidra.util.Msg; import utilities.util.FileResolutionResult; @@ -255,6 +257,7 @@ static SubtableSymbol getCurrentSubtable(Deque stack) { private boolean warnalllocalcollisions; // True if local export collisions generate individual warnings private boolean warnallnops; // True if pcode NOPs generate individual warnings private boolean failinsensitivedups; // True if case insensitive register duplicates cause error + private boolean debugoutput; // True if output .sla is written in XML debug format private VectorSTL noplist = new VectorSTL<>(); private Deque withstack = new LinkedList<>(); @@ -702,6 +705,7 @@ public SleighCompile() { largetemporarywarning = false; warnallnops = false; failinsensitivedups = true; + debugoutput = false; root = null; pcode.resetLabelCount(); } @@ -800,6 +804,11 @@ public void setInsensitiveDuplicateError(boolean val) { failinsensitivedups = val; } + public void setDebugOutput(boolean val) { + entry("setDebugOutput", val); + debugoutput = val; + } + // Do all post processing on the parsed data structures private void process() { entry("process"); @@ -1759,12 +1768,6 @@ public void buildMacro(MacroSymbol sym, ConstructTpl rtl) { macrotable.push_back(rtl); } - // Virtual functions (not used by the compiler) - @Override - public void initialize(DocumentStorage store) { - // do nothing - } - @Override public int instructionLength(Address baseaddr) { return 0; @@ -1778,7 +1781,8 @@ public int printAssembly(PrintStream s, int size, Address baseaddr) { public void setAllOptions(Map preprocs, boolean unnecessaryPcodeWarning, boolean lenientConflict, boolean allCollisionWarning, boolean allNopWarning, boolean deadTempWarning, boolean unusedFieldWarning, boolean enforceLocalKeyWord, - boolean largeTemporaryWarning, boolean caseSensitiveRegisterNames) { + boolean largeTemporaryWarning, boolean caseSensitiveRegisterNames, + boolean debugOutput) { Set> entrySet = preprocs.entrySet(); for (Entry entry : entrySet) { setPreprocValue(entry.getKey(), entry.getValue()); @@ -1792,6 +1796,7 @@ public void setAllOptions(Map preprocs, boolean unnecessaryPcode setEnforceLocalKeyWord(enforceLocalKeyWord); setLargeTemporaryWarning(largeTemporaryWarning); setInsensitiveDuplicateError(!caseSensitiveRegisterNames); + setDebugOutput(debugOutput); } public int run_compilation(String filein, String fileout) @@ -1837,9 +1842,21 @@ public int run_compilation(String filein, String fileout) } if ((parseres == 0) && (numErrors() == 0)) { // If no errors - PrintStream s = new PrintStream(new FileOutputStream(new File(fileout))); - saveXml(s); // Dump output xml - s.close(); + ResourceFile resourceFile = new ResourceFile(fileout); + if (debugoutput) { + // If the debug output format was requested, use XML encoder + XmlEncode encoder = new XmlEncode(); + encode(encoder); + OutputStream stream = resourceFile.getOutputStream(); + encoder.writeTo(stream); + stream.close(); + } + else { + // Use the standard .sla format encoder + PackedEncode encoder = SlaFormat.buildEncoder(resourceFile); + encode(encoder); // Dump compiler output + encoder.getOutputStream().close(); + } } else { Msg.error(SleighCompile.class, "No output produced"); @@ -1867,11 +1884,10 @@ public int run_compilation(String filein, String fileout) * compiler without using the launcher. The full SoftwareModeling classpath * must be established including any dependencies. * @param args compiler command line arguments - * @throws JDOMException for XML errors * @throws IOException for file access errors * @throws RecognitionException for parsing errors */ - public static void main(String[] args) throws JDOMException, IOException, RecognitionException { + public static void main(String[] args) throws IOException, RecognitionException { System.exit(SleighCompileLauncher.runMain(args)); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/SleighCompileLauncher.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/SleighCompileLauncher.java index 014481488a0..7b847279416 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/SleighCompileLauncher.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/SleighCompileLauncher.java @@ -55,12 +55,10 @@ public void launch(GhidraApplicationLayout layout, String[] args) * * @param args sleigh compiler command line arguments * @return exit code (TODO: exit codes are not well defined) - * @throws JDOMException for XML errors * @throws IOException for file access errors * @throws RecognitionException for parse errors */ - public static int runMain(String[] args) - throws JDOMException, IOException, RecognitionException { + public static int runMain(String[] args) throws IOException, RecognitionException { int retval; String filein = null; String fileout = null; @@ -80,6 +78,7 @@ public static int runMain(String[] args) Msg.info(SleighCompile.class, " directory to have all slaspec files compiled"); Msg.info(SleighCompile.class, " options:"); Msg.info(SleighCompile.class, " -x turns on parser debugging"); + Msg.info(SleighCompile.class, " -y write .sla using XML debug format"); Msg.info(SleighCompile.class, " -u print warnings for unnecessary pcode instructions"); Msg.info(SleighCompile.class, " -l report pattern conflicts"); Msg.info(SleighCompile.class, " -n print warnings for all NOP constructors"); @@ -105,6 +104,7 @@ public static int runMain(String[] args) boolean unusedFieldWarning = false; boolean largeTemporaryWarning = false; boolean caseSensitiveRegisterNames = false; + boolean debugOutput = false; int i; for (i = 0; i < args.length; ++i) { @@ -171,6 +171,9 @@ else if (args[i].charAt(1) == 'o') { else if (args[i].charAt(1) == 's') { caseSensitiveRegisterNames = true; } + else if (args[i].charAt(1) == 'y') { + debugOutput = true; + } else if (args[i].charAt(1) == 'x') { SleighCompile.yydebug = true; // Debug option } @@ -205,7 +208,8 @@ else if (args[i].charAt(1) == 'x') { SleighCompile compiler = new SleighCompile(); compiler.setAllOptions(preprocs, unnecessaryPcodeWarning, lenientConflict, allCollisionWarning, allNopWarning, deadTempWarning, unusedFieldWarning, - enforceLocalKeyWord, largeTemporaryWarning, caseSensitiveRegisterNames); + enforceLocalKeyWord, largeTemporaryWarning, caseSensitiveRegisterNames, + debugOutput); String outname = input.getName().replace(".slaspec", ".sla"); File output = new File(input.getParent(), outname); @@ -234,7 +238,7 @@ else if (args[i].charAt(1) == 'x') { SleighCompile compiler = new SleighCompile(); compiler.setAllOptions(preprocs, unnecessaryPcodeWarning, lenientConflict, allCollisionWarning, allNopWarning, deadTempWarning, unusedFieldWarning, - enforceLocalKeyWord, largeTemporaryWarning, caseSensitiveRegisterNames); + enforceLocalKeyWord, largeTemporaryWarning, caseSensitiveRegisterNames, debugOutput); if (i == args.length) { Msg.error(SleighCompile.class, "Missing input file name"); return 1; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/AndExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/AndExpression.java index 0b3fbbdcd7d..fb033d8e623 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/AndExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/AndExpression.java @@ -15,10 +15,13 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.utils.MutableInt; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class AndExpression extends BinaryExpression { @@ -39,10 +42,10 @@ public long getSubValue(VectorSTL replace, MutableInt listpos) { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - super.saveXml(s); - s.append("\n"); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_AND_EXP); + super.encode(encoder); + encoder.closeElement(ELEM_AND_EXP); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/BinaryExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/BinaryExpression.java index 4f06b845fdd..a1eaacefbf9 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/BinaryExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/BinaryExpression.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,26 +15,22 @@ */ package ghidra.pcodeCPort.slghpatexpress; +import java.io.IOException; + import generic.stl.VectorSTL; -import ghidra.pcodeCPort.translate.*; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; -import java.io.PrintStream; -import java.util.List; - -import org.jdom.Element; - - public abstract class BinaryExpression extends PatternExpression { private PatternExpression left; private PatternExpression right; public BinaryExpression(Location location) { - super(location); + super(location); left = null; right = null; - } // For use with restoreXml + } public PatternExpression getLeft() { return left; @@ -46,52 +41,44 @@ public PatternExpression getRight() { } @Override - public TokenPattern genMinPattern( VectorSTL ops ) { + public TokenPattern genMinPattern(VectorSTL ops) { return new TokenPattern(location); } @Override - public void listValues( VectorSTL list ) { - left.listValues( list ); - right.listValues( list ); + public void listValues(VectorSTL list) { + left.listValues(list); + right.listValues(list); } @Override - public void getMinMax( VectorSTL minlist, VectorSTL maxlist ) { - left.getMinMax( minlist, maxlist ); - right.getMinMax( minlist, maxlist ); + public void getMinMax(VectorSTL minlist, VectorSTL maxlist) { + left.getMinMax(minlist, maxlist); + right.getMinMax(minlist, maxlist); } - public BinaryExpression( Location location, PatternExpression l, PatternExpression r ) { - super(location); + public BinaryExpression(Location location, PatternExpression l, PatternExpression r) { + super(location); (left = l).layClaim(); (right = r).layClaim(); } // Delete only non-pattern values @Override - public void dispose() { - if ( left != null ) - PatternExpression.release( left ); - if ( right != null ) - PatternExpression.release( right ); + public void dispose() { + if (left != null) { + PatternExpression.release(left); + } + if (right != null) { + PatternExpression.release(right); + } } // Outer tag is generated by derived classes @Override - public void saveXml( PrintStream s ) { - left.saveXml( s ); - right.saveXml( s ); - } - - @Override - public void restoreXml( Element el, Translate trans ) { - List list = el.getChildren(); - - left = PatternExpression.restoreExpression( (Element) list.get( 0 ), trans ); - right = PatternExpression.restoreExpression( (Element) list.get( 1 ), trans ); - left.layClaim(); - right.layClaim(); + public void encode(Encoder encoder) throws IOException { + left.encode(encoder); + right.encode(encoder); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/ConstantValue.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/ConstantValue.java index 9e8da619c6b..b92c6aa9cad 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/ConstantValue.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/ConstantValue.java @@ -15,13 +15,12 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.VectorSTL; -import ghidra.pcodeCPort.translate.Translate; -import ghidra.pcodeCPort.utils.XmlUtils; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class ConstantValue extends PatternValue { @@ -30,7 +29,7 @@ public class ConstantValue extends PatternValue { public ConstantValue(Location location) { super(location); - } // For use with restoreXml + } public ConstantValue(Location location, long v) { super(location); @@ -58,15 +57,10 @@ public long maxValue() { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - } - - @Override - public void restoreXml(Element el, Translate trans) { - val = XmlUtils.decodeUnknownLong(el.getAttributeValue("val")); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_INTB); + encoder.writeSignedInteger(ATTRIB_VAL, val); + encoder.closeElement(ELEM_INTB); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/ContextField.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/ContextField.java index 6f9f77b4571..53e8f976e32 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/ContextField.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/ContextField.java @@ -15,14 +15,13 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.VectorSTL; -import ghidra.pcodeCPort.translate.Translate; import ghidra.pcodeCPort.utils.Utils; -import ghidra.pcodeCPort.utils.XmlUtils; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class ContextField extends PatternValue { @@ -34,7 +33,7 @@ public class ContextField extends PatternValue { public ContextField(Location location) { super(location); - } // For use with restoreXml + } public int getStartBit() { return startbit; @@ -90,37 +89,15 @@ public TokenPattern genPattern(long val) { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - } - - @Override - public void restoreXml(Element el, Translate trans) { - signbit = XmlUtils.decodeBoolean(el.getAttributeValue("signbit")); - startbit = XmlUtils.decodeUnknownInt(el.getAttributeValue("startbit")); - endbit = XmlUtils.decodeUnknownInt(el.getAttributeValue("endbit")); - startbyte = XmlUtils.decodeUnknownInt(el.getAttributeValue("startbyte")); - endbyte = XmlUtils.decodeUnknownInt(el.getAttributeValue("endbyte")); - shift = XmlUtils.decodeUnknownInt(el.getAttributeValue("shift")); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_CONTEXTFIELD); + encoder.writeBool(ATTRIB_SIGNBIT, signbit); + encoder.writeSignedInteger(ATTRIB_STARTBIT, startbit); + encoder.writeSignedInteger(ATTRIB_ENDBIT, endbit); + encoder.writeSignedInteger(ATTRIB_STARTBYTE, startbyte); + encoder.writeSignedInteger(ATTRIB_ENDBYTE, endbyte); + encoder.writeSignedInteger(ATTRIB_SHIFT, shift); + encoder.closeElement(ELEM_CONTEXTFIELD); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/DivExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/DivExpression.java index 17bd82d9b96..7cd71e01cad 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/DivExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/DivExpression.java @@ -15,10 +15,13 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.utils.MutableInt; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class DivExpression extends BinaryExpression { @@ -39,10 +42,10 @@ public long getSubValue(VectorSTL replace, MutableInt listpos) { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - super.saveXml(s); - s.append("\n"); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_DIV_EXP); + super.encode(encoder); + encoder.closeElement(ELEM_DIV_EXP); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/EndInstructionValue.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/EndInstructionValue.java index ad4b58ed317..4ee28c28842 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/EndInstructionValue.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/EndInstructionValue.java @@ -15,12 +15,12 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.VectorSTL; -import ghidra.pcodeCPort.translate.Translate; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class EndInstructionValue extends PatternValue { @@ -50,12 +50,9 @@ public long maxValue() { } @Override - public void saveXml(PrintStream s) { - s.append(""); - } - - @Override - public void restoreXml(Element el, Translate trans) { + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_END_EXP); + encoder.closeElement(ELEM_END_EXP); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/LeftShiftExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/LeftShiftExpression.java index 947d393efd7..6de53a4f45c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/LeftShiftExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/LeftShiftExpression.java @@ -15,10 +15,13 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.utils.MutableInt; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class LeftShiftExpression extends BinaryExpression { @@ -39,10 +42,10 @@ public long getSubValue(VectorSTL replace, MutableInt listpos) { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - super.saveXml(s); - s.append("\n"); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_LSHIFT_EXP); + super.encode(encoder); + encoder.closeElement(ELEM_LSHIFT_EXP); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/MinusExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/MinusExpression.java index 4f5ba57788e..dce5dd01f18 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/MinusExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/MinusExpression.java @@ -15,10 +15,13 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.utils.MutableInt; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class MinusExpression extends UnaryExpression { @@ -38,10 +41,10 @@ public long getSubValue(VectorSTL replace, MutableInt listpos) { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - super.saveXml(s); - s.append("\n"); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_MINUS_EXP); + super.encode(encoder); + encoder.closeElement(ELEM_MINUS_EXP); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/MultExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/MultExpression.java index 5fff27e07e6..ae451fcf342 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/MultExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/MultExpression.java @@ -15,17 +15,20 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.utils.MutableInt; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class MultExpression extends BinaryExpression { public MultExpression(Location location) { super(location); - } // For use with restoreXml + } public MultExpression(Location location, PatternExpression l, PatternExpression r) { super(location, l, r); @@ -39,10 +42,10 @@ public long getSubValue(VectorSTL replace, MutableInt listpos) { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - super.saveXml(s); - s.append("\n"); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_MULT_EXP); + super.encode(encoder); + encoder.closeElement(ELEM_MULT_EXP); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/Next2InstructionValue.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/Next2InstructionValue.java index 5ac352fb09e..c467da3b8bc 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/Next2InstructionValue.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/Next2InstructionValue.java @@ -15,12 +15,12 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.VectorSTL; -import ghidra.pcodeCPort.translate.Translate; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class Next2InstructionValue extends PatternValue { @@ -50,12 +50,9 @@ public long maxValue() { } @Override - public void saveXml(PrintStream s) { - s.append(""); - } - - @Override - public void restoreXml(Element el, Translate trans) { + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_NEXT2_EXP); + encoder.closeElement(ELEM_NEXT2_EXP); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/NotExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/NotExpression.java index 3c154906b62..c302ef7712c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/NotExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/NotExpression.java @@ -15,10 +15,13 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.utils.MutableInt; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class NotExpression extends UnaryExpression { @@ -38,10 +41,10 @@ public long getSubValue(VectorSTL replace, MutableInt listpos) { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - super.saveXml(s); - s.append("\n"); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_NOT_EXP); + super.encode(encoder); + encoder.closeElement(ELEM_NOT_EXP); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/OperandValue.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/OperandValue.java index c45a9a5f4e9..fd8719d346f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/OperandValue.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/OperandValue.java @@ -15,17 +15,16 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.context.SleighError; -import ghidra.pcodeCPort.sleighbase.SleighBase; -import ghidra.pcodeCPort.slghsymbol.*; -import ghidra.pcodeCPort.translate.Translate; +import ghidra.pcodeCPort.slghsymbol.Constructor; +import ghidra.pcodeCPort.slghsymbol.OperandSymbol; import ghidra.pcodeCPort.utils.MutableInt; -import ghidra.pcodeCPort.utils.XmlUtils; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class OperandValue extends PatternValue { @@ -35,7 +34,7 @@ public class OperandValue extends PatternValue { public OperandValue(Location location) { super(location); - } // For use with restoreXml + } public OperandValue(Location location, int ind, Constructor c) { super(location); @@ -96,29 +95,14 @@ public String getName() { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); // Save id of our constructor - } - - @Override - public void restoreXml(Element el, Translate trans) { - index = XmlUtils.decodeUnknownInt(el.getAttributeValue("index")); - long tabid = XmlUtils.decodeUnknownLong(el.getAttributeValue("table")); - long ctid = XmlUtils.decodeUnknownLong(el.getAttributeValue("ct")); - SleighBase sleigh = (SleighBase) trans; - SubtableSymbol tab = (SubtableSymbol) (sleigh.findSymbol((int) tabid)); - ct = tab.getConstructor((int) ctid); + encoder.writeUnsignedInteger(ATTRIB_CT, ctid); + encoder.closeElement(ELEM_OPERAND_EXP); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/OrExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/OrExpression.java index 524e87b8b45..2801f1ec8b4 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/OrExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/OrExpression.java @@ -15,10 +15,13 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.utils.MutableInt; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class OrExpression extends BinaryExpression { @@ -39,12 +42,12 @@ public long getSubValue(VectorSTL replace, MutableInt listpos) { } @Override - public void saveXml(PrintStream s) + public void encode(Encoder encoder) throws IOException { - s.append("\n"); - super.saveXml(s); - s.append("\n"); + encoder.openElement(ELEM_OR_EXP); + super.encode(encoder); + encoder.closeElement(ELEM_OR_EXP); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/PatternExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/PatternExpression.java index 2842fa83af3..12955493ddf 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/PatternExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/PatternExpression.java @@ -15,13 +15,11 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; - -import org.jdom.Element; +import java.io.IOException; import generic.stl.VectorSTL; -import ghidra.pcodeCPort.translate.Translate; import ghidra.pcodeCPort.utils.MutableInt; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public abstract class PatternExpression { @@ -45,9 +43,7 @@ public PatternExpression(Location location) { public abstract long getSubValue(VectorSTL replace, MutableInt listpos); - public abstract void saveXml(PrintStream s); - - public abstract void restoreXml(Element el, Translate trans); + public abstract void encode(Encoder encoder) throws IOException; public long getSubValue(VectorSTL replace) { MutableInt listpos = new MutableInt(0); @@ -65,70 +61,4 @@ public static void release(PatternExpression p) { } } - public static PatternExpression restoreExpression(Element el, Translate trans) { - PatternExpression res; - String nm = el.getName(); - - if (nm.equals("tokenfield")) { - res = new TokenField(null); - } - else if (nm.equals("contextfield")) { - res = new ContextField(null); - } - else if (nm.equals("intb")) { - res = new ConstantValue(null); - } - else if (nm.equals("operand_exp")) { - res = new OperandValue(null); - } - else if (nm.equals("start_exp")) { - res = new StartInstructionValue(null); - } - else if (nm.equals("end_exp")) { - res = new EndInstructionValue(null); - } - else if (nm.equals("next2_exp")) { - res = new Next2InstructionValue(null); - } - else if (nm.equals("plus_exp")) { - res = new PlusExpression(null); - } - else if (nm.equals("sub_exp")) { - res = new SubExpression(null); - } - else if (nm.equals("mult_exp")) { - res = new MultExpression(null); - } - else if (nm.equals("lshift_exp")) { - res = new LeftShiftExpression(null); - } - else if (nm.equals("rshift_exp")) { - res = new RightShiftExpression(null); - } - else if (nm.equals("and_exp")) { - res = new AndExpression(null); - } - else if (nm.equals("or_exp")) { - res = new OrExpression(null); - } - else if (nm.equals("xor_exp")) { - res = new XorExpression(null); - } - else if (nm.equals("div_exp")) { - res = new DivExpression(null); - } - else if (nm.equals("minus_exp")) { - res = new MinusExpression(null); - } - else if (nm.equals("not_exp")) { - res = new NotExpression(null); - } - else { - return null; - } - - res.restoreXml(el, trans); - return res; - } - } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/PlusExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/PlusExpression.java index 4abad9aa176..506cb24e839 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/PlusExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/PlusExpression.java @@ -15,17 +15,20 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.utils.MutableInt; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class PlusExpression extends BinaryExpression { public PlusExpression(Location location) { super(location); - } // For use by restoreXml + } public PlusExpression(Location location, PatternExpression l, PatternExpression r) { super(location, l, r); @@ -39,10 +42,10 @@ public long getSubValue(VectorSTL replace, MutableInt listpos) { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - super.saveXml(s); - s.append("\n"); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_PLUS_EXP); + super.encode(encoder); + encoder.closeElement(ELEM_PLUS_EXP); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/RightShiftExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/RightShiftExpression.java index e0009fbb96d..821c2394dd4 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/RightShiftExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/RightShiftExpression.java @@ -15,10 +15,13 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.utils.MutableInt; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class RightShiftExpression extends BinaryExpression { @@ -39,10 +42,10 @@ public long getSubValue(VectorSTL replace, MutableInt listpos) { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - super.saveXml(s); - s.append("\n"); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_RSHIFT_EXP); + super.encode(encoder); + encoder.closeElement(ELEM_RSHIFT_EXP); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/StartInstructionValue.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/StartInstructionValue.java index 01331577ff4..ebfe7c8a8d3 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/StartInstructionValue.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/StartInstructionValue.java @@ -15,12 +15,12 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.VectorSTL; -import ghidra.pcodeCPort.translate.Translate; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class StartInstructionValue extends PatternValue { @@ -50,12 +50,9 @@ public long maxValue() { } @Override - public void saveXml(PrintStream s) { - s.append(""); - } - - @Override - public void restoreXml(Element el, Translate trans) { + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_START_EXP); + encoder.closeElement(ELEM_START_EXP); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/SubExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/SubExpression.java index b97da64f480..351085432be 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/SubExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/SubExpression.java @@ -15,17 +15,20 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.utils.MutableInt; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class SubExpression extends BinaryExpression { public SubExpression(Location location) { super(location); - } // For use with restoreXml + } public SubExpression(Location location, PatternExpression l, PatternExpression r) { super(location, l, r); @@ -39,10 +42,10 @@ public long getSubValue(VectorSTL replace, MutableInt listpos) { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - super.saveXml(s); - s.append("\n"); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_SUB_EXP); + super.encode(encoder); + encoder.closeElement(ELEM_SUB_EXP); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/TokenField.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/TokenField.java index ac3f1ab790c..c3ae656d5ff 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/TokenField.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/TokenField.java @@ -15,15 +15,14 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.context.Token; -import ghidra.pcodeCPort.translate.Translate; import ghidra.pcodeCPort.utils.Utils; -import ghidra.pcodeCPort.utils.XmlUtils; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class TokenField extends PatternValue { @@ -37,7 +36,7 @@ public class TokenField extends PatternValue { public TokenField(Location location) { super(location); - } // For use with restoreXml + } @Override public TokenPattern genMinPattern(VectorSTL ops) { @@ -82,44 +81,16 @@ public TokenPattern genPattern(long val) { // Generate corresponding pattern if } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - } - - @Override - public void restoreXml(Element el, Translate trans) { - tok = null; - bigendian = XmlUtils.decodeBoolean(el.getAttributeValue("bigendian")); - signbit = XmlUtils.decodeBoolean(el.getAttributeValue("signbit")); - bitstart = XmlUtils.decodeUnknownInt(el.getAttributeValue("bitstart")); - bitend = XmlUtils.decodeUnknownInt(el.getAttributeValue("bitend")); - bytestart = XmlUtils.decodeUnknownInt(el.getAttributeValue("bytestart")); - byteend = XmlUtils.decodeUnknownInt(el.getAttributeValue("byteend")); - shift = XmlUtils.decodeUnknownInt(el.getAttributeValue("shift")); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_TOKENFIELD); + encoder.writeBool(ATTRIB_BIGENDIAN, bigendian); + encoder.writeBool(ATTRIB_SIGNBIT, signbit); + encoder.writeSignedInteger(ATTRIB_STARTBIT, bitstart); + encoder.writeSignedInteger(ATTRIB_ENDBIT, bitend); + encoder.writeSignedInteger(ATTRIB_STARTBYTE, bytestart); + encoder.writeSignedInteger(ATTRIB_ENDBYTE, byteend); + encoder.writeSignedInteger(ATTRIB_SHIFT, shift); + encoder.closeElement(ELEM_TOKENFIELD); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/UnaryExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/UnaryExpression.java index 410b570c7c8..ed30e028735 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/UnaryExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/UnaryExpression.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,65 +15,55 @@ */ package ghidra.pcodeCPort.slghpatexpress; +import java.io.IOException; + import generic.stl.VectorSTL; -import ghidra.pcodeCPort.translate.*; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; -import java.io.PrintStream; -import java.util.List; - -import org.jdom.Element; - - public abstract class UnaryExpression extends PatternExpression { private PatternExpression unary; public UnaryExpression(Location location) { - super(location); + super(location); unary = null; - } // For use with restoreXml + } public PatternExpression getUnary() { return unary; } @Override - public TokenPattern genMinPattern( VectorSTL ops ) { + public TokenPattern genMinPattern(VectorSTL ops) { return new TokenPattern(location); } @Override - public void listValues( VectorSTL list ) { - unary.listValues( list ); + public void listValues(VectorSTL list) { + unary.listValues(list); } @Override - public void getMinMax( VectorSTL minlist, VectorSTL maxlist ) { - unary.getMinMax( minlist, maxlist ); + public void getMinMax(VectorSTL minlist, VectorSTL maxlist) { + unary.getMinMax(minlist, maxlist); } - public UnaryExpression( Location location, PatternExpression u ) { - super(location); + public UnaryExpression(Location location, PatternExpression u) { + super(location); (unary = u).layClaim(); } @Override - public void dispose() { // Delete only non-pattern values - if ( unary != null ) - PatternExpression.release( unary ); - } - - @Override - public void saveXml( PrintStream s ) { // Outer tag is generated by derived classes - unary.saveXml( s ); + public void dispose() { // Delete only non-pattern values + if (unary != null) { + PatternExpression.release(unary); + } } @Override - public void restoreXml( Element el, Translate trans ) { - List list = el.getChildren(); - unary = PatternExpression.restoreExpression( (Element) list.get( 0 ), trans ); - unary.layClaim(); + public void encode(Encoder encoder) throws IOException { // Outer tag is generated by derived classes + unary.encode(encoder); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/XorExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/XorExpression.java index 5a482aea2fd..9678ea0b1a7 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/XorExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/XorExpression.java @@ -15,10 +15,13 @@ */ package ghidra.pcodeCPort.slghpatexpress; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.utils.MutableInt; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class XorExpression extends BinaryExpression { @@ -39,10 +42,10 @@ public long getSubValue(VectorSTL replace, MutableInt listpos) { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - super.saveXml(s); - s.append("\n"); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_XOR_EXP); + super.encode(encoder); + encoder.closeElement(ELEM_XOR_EXP); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/CombinePattern.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/CombinePattern.java index 9f07b6510a2..fcbbb22dc11 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/CombinePattern.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/CombinePattern.java @@ -15,10 +15,11 @@ */ package ghidra.pcodeCPort.slghpattern; -import java.io.PrintStream; -import java.util.List; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; + +import ghidra.program.model.pcode.Encoder; public class CombinePattern extends DisjointPattern { @@ -162,22 +163,11 @@ public Pattern simplifyClone() { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - context.saveXml(s); - instr.saveXml(s); - s.append("\n"); - } - - @Override - public void restoreXml(Element el) { - List list = el.getChildren(); - Element child = (Element) list.get(0); - context = new ContextPattern(); - context.restoreXml(child); - child = (Element) list.get(1); - instr = new InstructionPattern(); - instr.restoreXml(child); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_COMBINE_PAT); + context.encode(encoder); + instr.encode(encoder); + encoder.closeElement(ELEM_COMBINE_PAT); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/ContextPattern.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/ContextPattern.java index 4318b766a45..65cf597e748 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/ContextPattern.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/ContextPattern.java @@ -15,10 +15,11 @@ */ package ghidra.pcodeCPort.slghpattern; -import java.io.PrintStream; -import java.util.List; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; + +import ghidra.program.model.pcode.Encoder; public class ContextPattern extends DisjointPattern { @@ -31,7 +32,7 @@ protected PatternBlock getBlock(boolean context) { public ContextPattern() { maskvalue = null; - } // For use with restoreXml + } public ContextPattern(PatternBlock mv) { maskvalue = mv; @@ -104,18 +105,10 @@ public Pattern commonSubPattern(Pattern b, int sa) { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - maskvalue.saveXml(s); - s.append("\n"); - } - - @Override - public void restoreXml(Element el) { - List list = el.getChildren(); - Element child = (Element) list.get(0); - maskvalue = new PatternBlock(true); - maskvalue.restoreXml(child); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_CONTEXT_PAT); + maskvalue.encode(encoder); + encoder.closeElement(ELEM_CONTEXT_PAT); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/DisjointPattern.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/DisjointPattern.java index bb975fe61d7..c29a68e4b53 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/DisjointPattern.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/DisjointPattern.java @@ -15,8 +15,6 @@ */ package ghidra.pcodeCPort.slghpattern; -import org.jdom.Element; - public abstract class DisjointPattern extends Pattern { protected abstract PatternBlock getBlock(boolean context); @@ -87,29 +85,35 @@ public boolean identical(DisjointPattern op2) { PatternBlock b = op2.getBlock(false); if (b != null) { // a must match existing block if (a == null) { - if (!b.alwaysTrue()) + if (!b.alwaysTrue()) { return false; + } } - else if (!a.identical(b)) + else if (!a.identical(b)) { return false; + } } else { - if ((a != null) && (!a.alwaysTrue())) + if ((a != null) && (!a.alwaysTrue())) { return false; + } } a = getBlock(true); b = op2.getBlock(true); if (b != null) { // a must match existing block if (a == null) { - if (!b.alwaysTrue()) + if (!b.alwaysTrue()) { return false; + } } - else if (!a.identical(b)) + else if (!a.identical(b)) { return false; + } } else { - if ((a != null) && (!a.alwaysTrue())) + if ((a != null) && (!a.alwaysTrue())) { return false; + } } return true; } @@ -119,45 +123,35 @@ public static boolean resolveIntersectBlock(PatternBlock bl1, PatternBlock bl2, PatternBlock inter; boolean res = true; - if (bl1 == null) + if (bl1 == null) { inter = bl2; - else if (bl2 == null) + } + else if (bl2 == null) { inter = bl1; + } else { inter = bl1.intersect(bl2); } if (inter == null) { - if (thisblock != null) + if (thisblock != null) { res = false; + } } - else if (thisblock == null) + else if (thisblock == null) { res = false; - else + } + else { res = thisblock.identical(inter); + } return res; } public boolean resolvesIntersect(DisjointPattern op1, DisjointPattern op2) { // Is this pattern equal to the intersection of -op1- and -op2- - if (!resolveIntersectBlock(op1.getBlock(false), op2.getBlock(false), getBlock(false))) + if (!resolveIntersectBlock(op1.getBlock(false), op2.getBlock(false), getBlock(false))) { return false; - return resolveIntersectBlock(op1.getBlock(true), op2.getBlock(true), getBlock(true)); - } - - // DisjointPattern factory - public static DisjointPattern restoreDisjoint(Element el) { - DisjointPattern res; - if (el.getName().equals("instruct_pat")) { - res = new InstructionPattern(); - } - else if (el.getName().equals("context_pat")) { - res = new ContextPattern(); } - else { - res = new CombinePattern(); - } - res.restoreXml(el); - return res; + return resolveIntersectBlock(op1.getBlock(true), op2.getBlock(true), getBlock(true)); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/InstructionPattern.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/InstructionPattern.java index c59a9abec0c..3e5a60a9fca 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/InstructionPattern.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/InstructionPattern.java @@ -15,10 +15,11 @@ */ package ghidra.pcodeCPort.slghpattern; -import java.io.PrintStream; -import java.util.List; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; + +import ghidra.program.model.pcode.Encoder; public class InstructionPattern extends DisjointPattern { @@ -36,7 +37,7 @@ protected PatternBlock getBlock(boolean context) { public InstructionPattern() { maskvalue = null; - } // For use with restoreXml + } public InstructionPattern(PatternBlock mv) { maskvalue = mv; @@ -169,18 +170,10 @@ public Pattern doOr(Pattern b, int sa) { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - maskvalue.saveXml(s); - s.append("\n"); - } - - @Override - public void restoreXml(Element el) { - List list = el.getChildren(); - Element child = (Element) list.get(0); - maskvalue = new PatternBlock(true); - maskvalue.restoreXml(child); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_INSTRUCT_PAT); + maskvalue.encode(encoder); + encoder.closeElement(ELEM_INSTRUCT_PAT); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/OrPattern.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/OrPattern.java index dddbf19e370..04c3fbde27d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/OrPattern.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/OrPattern.java @@ -15,21 +15,20 @@ */ package ghidra.pcodeCPort.slghpattern; -import java.io.PrintStream; -import java.util.Iterator; -import java.util.List; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.IteratorSTL; import generic.stl.VectorSTL; +import ghidra.program.model.pcode.Encoder; public class OrPattern extends Pattern { private VectorSTL orlist = new VectorSTL(); public OrPattern() { - } // For use with restoreXml + } @Override public int numDisjoint() { @@ -210,23 +209,11 @@ else if (newlist.size() == 1) { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_OR_PAT); for (int i = 0; i < orlist.size(); ++i) { - orlist.get(i).saveXml(s); - } - s.append("\n"); - } - - @Override - public void restoreXml(Element el) { - List list = el.getChildren(); - Iterator iter = list.iterator(); - while (iter.hasNext()) { - Element element = (Element) iter.next(); - DisjointPattern pat = DisjointPattern.restoreDisjoint(element); - orlist.push_back(pat); + orlist.get(i).encode(encoder); } + encoder.closeElement(ELEM_OR_PAT); } - } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/Pattern.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/Pattern.java index df2197a1c38..eab9a023e7e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/Pattern.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/Pattern.java @@ -15,9 +15,9 @@ */ package ghidra.pcodeCPort.slghpattern; -import java.io.PrintStream; +import java.io.IOException; -import org.jdom.Element; +import ghidra.program.model.pcode.Encoder; public abstract class Pattern { @@ -44,8 +44,6 @@ public void dispose() { public abstract boolean alwaysInstructionTrue(); - public abstract void saveXml(PrintStream s); - - public abstract void restoreXml(Element el); + public abstract void encode(Encoder encoder) throws IOException; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/PatternBlock.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/PatternBlock.java index c6da6a167a8..8bf800a4dc8 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/PatternBlock.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpattern/PatternBlock.java @@ -15,16 +15,14 @@ */ package ghidra.pcodeCPort.slghpattern; -import java.io.PrintStream; -import java.util.Iterator; -import java.util.List; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.IteratorSTL; import generic.stl.VectorSTL; import ghidra.pcodeCPort.utils.Utils; -import ghidra.pcodeCPort.utils.XmlUtils; +import ghidra.program.model.pcode.Encoder; public class PatternBlock { @@ -363,41 +361,17 @@ public int getValue(int startbit, int size) { return res; } - public void saveXml(PrintStream s) { - s.append("\n"); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_PAT_BLOCK); + encoder.writeSignedInteger(ATTRIB_OFF, offset); + encoder.writeSignedInteger(ATTRIB_NONZERO, nonzerosize); for (int i = 0; i < maskvec.size(); ++i) { - s.append(" \n"); + encoder.openElement(ELEM_MASK_WORD); + encoder.writeUnsignedInteger(ATTRIB_MASK, Utils.unsignedInt(maskvec.get(i))); + encoder.writeUnsignedInteger(ATTRIB_VAL, Utils.unsignedInt(valvec.get(i))); + encoder.closeElement(ELEM_MASK_WORD); } - s.append("\n"); - } - - public void restoreXml(Element el) { - offset = XmlUtils.decodeUnknownInt(el.getAttributeValue("offset")); - nonzerosize = XmlUtils.decodeUnknownInt(el.getAttributeValue("nonzero")); - - List list = el.getChildren(); - Iterator it = list.iterator(); - - while (it.hasNext()) { - Element subel = (Element) it.next(); - int mask = XmlUtils.decodeUnknownInt(subel.getAttributeValue("mask")); - int val = XmlUtils.decodeUnknownInt(subel.getAttributeValue("val")); - maskvec.push_back(mask); - valvec.push_back(val); - } - normalize(); + encoder.closeElement(ELEM_PAT_BLOCK); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/BitrangeSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/BitrangeSymbol.java index edba5ab7a98..ba3adf186e2 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/BitrangeSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/BitrangeSymbol.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,11 +25,11 @@ public class BitrangeSymbol extends SleighSymbol { int numbits; // number of bits in the range public BitrangeSymbol(Location location) { - super(location); - } // For use with restoreXml + super(location); + } - public BitrangeSymbol( Location location, String nm, VarnodeSymbol sym, int bitoff, int num ) { - super( location, nm ); + public BitrangeSymbol(Location location, String nm, VarnodeSymbol sym, int bitoff, int num) { + super(location, nm); varsym = sym; bitoffset = bitoff; numbits = num; @@ -49,7 +48,7 @@ public int numBits() { } @Override - public symbol_type getType() { + public symbol_type getType() { return symbol_type.bitrange_symbol; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/Constructor.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/Constructor.java index 5bfd052bbc6..9ba67fc14b3 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/Constructor.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/Constructor.java @@ -15,10 +15,11 @@ */ package ghidra.pcodeCPort.slghsymbol; -import java.io.PrintStream; -import java.util.*; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; import generic.stl.IteratorSTL; import generic.stl.VectorSTL; @@ -26,9 +27,8 @@ import ghidra.pcodeCPort.semantics.ConstTpl.const_type; import ghidra.pcodeCPort.semantics.ConstructTpl; import ghidra.pcodeCPort.semantics.HandleTpl; -import ghidra.pcodeCPort.sleighbase.SleighBase; import ghidra.pcodeCPort.slghpatexpress.*; -import ghidra.pcodeCPort.utils.XmlUtils; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class Constructor { @@ -298,105 +298,46 @@ public void removeTrailingSpace() { // printpiece.pop_back(); } - public void saveXml(PrintStream s) { - s.append("\n"); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_CONSTRUCTOR); + encoder.writeUnsignedInteger(ATTRIB_PARENT, parent.getId()); + encoder.writeSignedInteger(ATTRIB_FIRST, firstwhitespace); + encoder.writeSignedInteger(ATTRIB_LENGTH, minimumlength); + encoder.writeSignedInteger(ATTRIB_SOURCE, sourceFileIndex); + encoder.writeSignedInteger(ATTRIB_LINE, getLineno()); for (int i = 0; i < operands.size(); ++i) { - s.append("\n"); + encoder.openElement(ELEM_OPER); + encoder.writeUnsignedInteger(ATTRIB_ID, operands.get(i).getId()); + encoder.closeElement(ELEM_OPER); } final int printpieces = printpiece.size(); for (int i = 0; i < printpieces; ++i) { String piece = printpiece.get(i); if (piece.length() > 0 && piece.charAt(0) == '\n') { int index = piece.charAt(1) - 'A'; - s.append("\n"); + encoder.openElement(ELEM_OPPRINT); + encoder.writeSignedInteger(ATTRIB_ID, index); + encoder.closeElement(ELEM_OPPRINT); } else { - s.append("\n"); + encoder.openElement(ELEM_PRINT); + encoder.writeString(ATTRIB_PIECE, piece); + encoder.closeElement(ELEM_PRINT); } } for (int i = 0; i < context.size(); ++i) { - context.get(i).saveXml(s); + context.get(i).encode(encoder); } if (templ != null) { - templ.saveXml(s, -1); + templ.encode(encoder, -1); } for (int i = 0; i < namedtempl.size(); ++i) { if (namedtempl.get(i) == null) { continue; } - namedtempl.get(i).saveXml(s, i); - } - s.append("\n"); - } - - public void restoreXml(Element el, SleighBase trans) { - int id = XmlUtils.decodeUnknownInt(el.getAttributeValue("parent")); - parent = (SubtableSymbol) trans.findSymbol(id); - - firstwhitespace = XmlUtils.decodeUnknownInt(el.getAttributeValue("first")); - minimumlength = XmlUtils.decodeUnknownInt(el.getAttributeValue("length")); - int lineno = XmlUtils.decodeUnknownInt(el.getAttributeValue("line")); - - List list = el.getChildren(); - Iterator iter = list.iterator(); - while (iter.hasNext()) { - Element child = (Element) iter.next(); - if (child.getName().equals("oper")) { - id = XmlUtils.decodeUnknownInt(child.getAttributeValue("id")); - OperandSymbol sym = (OperandSymbol) trans.findSymbol(id); - operands.push_back(sym); - } - else if (child.getName().equals("print")) { - printpiece.push_back(child.getAttributeValue("piece")); - } - else if (child.getName().equals("opprint")) { - int index = XmlUtils.decodeUnknownInt(child.getAttributeValue("id")); - char c = (char) ('A' + index); - String operstring = "\n" + c; - printpiece.push_back(operstring); - } - else if (child.getName().equals("context_op")) { - ContextOp c_op = new ContextOp(location); - c_op.restoreXml(child, trans); - context.push_back(c_op); - } - else if (child.getName().equals("commit")) { - ContextCommit c_op = new ContextCommit(); - c_op.restoreXml(child, trans); - context.push_back(c_op); - } - else { - templ = new ConstructTpl(null); - templ.restoreXml(child, trans); - } - } - pattern = null; - if ((printpiece.size() == 1) && (printpiece.get(0).charAt(0) == '\n')) { - flowthruindex = printpiece.get(0).charAt(1) - 'A'; - } - else { - flowthruindex = -1; + namedtempl.get(i).encode(encoder, i); } + encoder.closeElement(ELEM_CONSTRUCTOR); } private void orderOperands() { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ContextChange.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ContextChange.java index 450f510626a..e6bc6262b6d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ContextChange.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ContextChange.java @@ -15,11 +15,9 @@ */ package ghidra.pcodeCPort.slghsymbol; -import java.io.PrintStream; +import java.io.IOException; -import org.jdom.Element; - -import ghidra.pcodeCPort.sleighbase.SleighBase; +import ghidra.program.model.pcode.Encoder; // Change to context command public abstract class ContextChange { @@ -29,9 +27,7 @@ public ContextChange() { public abstract void validate(); - public abstract void saveXml(PrintStream s); - - public abstract void restoreXml(Element el, SleighBase trans); + public abstract void encode(Encoder encoder) throws IOException; public void dispose() { } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ContextCommit.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ContextCommit.java index 5f1dea22427..940448b6d82 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ContextCommit.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ContextCommit.java @@ -15,12 +15,13 @@ */ package ghidra.pcodeCPort.slghsymbol; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; -import ghidra.pcodeCPort.sleighbase.SleighBase; -import ghidra.pcodeCPort.utils.*; +import ghidra.pcodeCPort.utils.MutableInt; +import ghidra.pcodeCPort.utils.Utils; +import ghidra.program.model.pcode.Encoder; public class ContextCommit extends ContextChange { @@ -30,7 +31,7 @@ public class ContextCommit extends ContextChange { private boolean flow; // Whether the context "flows" from the point of change public ContextCommit() { - } // For use with restoreXml + } @Override public void validate() { @@ -48,29 +49,13 @@ public ContextCommit(TripleSymbol s, int sbit, int ebit, boolean fl) { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - } - - @Override - public void restoreXml(Element el, SleighBase trans) { - int id = XmlUtils.decodeUnknownInt(el.getAttributeValue("id")); - sym = (TripleSymbol) trans.findSymbol(id); - - num = XmlUtils.decodeUnknownInt(el.getAttributeValue("num")); - mask = XmlUtils.decodeUnknownInt(el.getAttributeValue("mask")); - String value = el.getAttributeValue("flow"); - if (value != null) { - flow = XmlUtils.decodeBoolean(value); - } - else { - flow = true; - } + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_COMMIT); + encoder.writeUnsignedInteger(ATTRIB_ID, sym.getId()); + encoder.writeSignedInteger(ATTRIB_NUMBER, num); + encoder.writeUnsignedInteger(ATTRIB_MASK, Utils.unsignedInt(mask)); + encoder.writeBool(ATTRIB_FLOW, flow); + encoder.closeElement(ELEM_COMMIT); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ContextOp.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ContextOp.java index 1422e589dfc..7ccaa5894a0 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ContextOp.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ContextOp.java @@ -15,15 +15,16 @@ */ package ghidra.pcodeCPort.slghsymbol; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.context.SleighError; -import ghidra.pcodeCPort.sleighbase.SleighBase; import ghidra.pcodeCPort.slghpatexpress.*; -import ghidra.pcodeCPort.utils.*; +import ghidra.pcodeCPort.utils.MutableInt; +import ghidra.pcodeCPort.utils.Utils; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class ContextOp extends ContextChange { @@ -36,7 +37,7 @@ public class ContextOp extends ContextChange { public ContextOp(Location location) { this.location = location; - } // For use with restoreXml + } @Override public void dispose() { @@ -78,29 +79,13 @@ public void validate() { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - patexp.saveXml(s); - s.append("\n"); - } - - @Override - public void restoreXml(Element el, SleighBase trans) { - num = XmlUtils.decodeUnknownInt(el.getAttributeValue("i")); - shift = XmlUtils.decodeUnknownInt(el.getAttributeValue("shift")); - mask = XmlUtils.decodeUnknownInt(el.getAttributeValue("mask")); - Element child = (Element) el.getChildren().get(0); - patexp = PatternExpression.restoreExpression(child, trans); - patexp.layClaim(); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_CONTEXT_OP); + encoder.writeSignedInteger(ATTRIB_I, num); + encoder.writeSignedInteger(ATTRIB_SHIFT, shift); + encoder.writeUnsignedInteger(ATTRIB_MASK, Utils.unsignedInt(mask)); + patexp.encode(encoder); + encoder.closeElement(ELEM_CONTEXT_OP); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ContextSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ContextSymbol.java index 24ba86b449f..be2c41682db 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ContextSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ContextSymbol.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +15,13 @@ */ package ghidra.pcodeCPort.slghsymbol; -import ghidra.pcodeCPort.sleighbase.*; -import ghidra.pcodeCPort.slghpatexpress.*; -import ghidra.pcodeCPort.utils.*; -import ghidra.sleigh.grammar.Location; - -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; +import ghidra.pcodeCPort.slghpatexpress.ContextField; +import ghidra.program.model.pcode.Encoder; +import ghidra.sleigh.grammar.Location; public class ContextSymbol extends ValueSymbol { @@ -33,8 +30,8 @@ public class ContextSymbol extends ValueSymbol { private boolean flow; public ContextSymbol(Location location) { - super(location); - } // For use with restoreXml + super(location); + } public VarnodeSymbol getVarnode() { return vn; @@ -49,16 +46,17 @@ public int getHigh() { } public boolean isFlow() { - return flow; + return flow; } @Override - public symbol_type getType() { + public symbol_type getType() { return symbol_type.context_symbol; } - public ContextSymbol( Location location, String nm, ContextField pate, VarnodeSymbol v, int l, int h, boolean flow ) { - super( location, nm, pate ); + public ContextSymbol(Location location, String nm, ContextField pate, VarnodeSymbol v, int l, + int h, boolean flow) { + super(location, nm, pate); vn = v; low = l; high = h; @@ -66,39 +64,22 @@ public ContextSymbol( Location location, String nm, ContextField pate, VarnodeSy } @Override - public void saveXml( PrintStream s ) { - s.append( "" ); - patval.saveXml( s ); - s.println( "" ); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_CONTEXT_SYM); + encoder.writeUnsignedInteger(ATTRIB_ID, id); + encoder.writeUnsignedInteger(ATTRIB_VARNODE, vn.getId()); + encoder.writeSignedInteger(ATTRIB_LOW, low); + encoder.writeSignedInteger(ATTRIB_HIGH, high); + encoder.writeBool(ATTRIB_FLOW, flow); + patval.encode(encoder); + encoder.closeElement(ELEM_CONTEXT_SYM); } @Override - public void saveXmlHeader( PrintStream s ) { - s.append( "" ); - } - - @Override - public void restoreXml( Element el, SleighBase trans ) { - super.restoreXml( el, trans ); - - int id = XmlUtils.decodeUnknownInt( el.getAttributeValue( "varnode" ) ); - vn = (VarnodeSymbol) trans.findSymbol( id ); - low = XmlUtils.decodeUnknownInt( el.getAttributeValue( "low" ) ); - high = XmlUtils.decodeUnknownInt( el.getAttributeValue( "high" ) ); + public void encodeHeader(Encoder encoder) throws IOException { + encoder.openElement(ELEM_CONTEXT_SYM_HEAD); + encodeSleighSymbolHeader(encoder); + encoder.closeElement(ELEM_CONTEXT_SYM_HEAD); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/DecisionNode.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/DecisionNode.java index 23142838b93..c17b1ea12e8 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/DecisionNode.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/DecisionNode.java @@ -15,21 +15,18 @@ */ package ghidra.pcodeCPort.slghsymbol; -import java.io.PrintStream; -import java.util.Iterator; -import java.util.List; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.*; import ghidra.pcodeCPort.error.LowlevelError; import ghidra.pcodeCPort.slghpattern.DisjointPattern; -import ghidra.pcodeCPort.utils.XmlUtils; +import ghidra.program.model.pcode.Encoder; public class DecisionNode { - private VectorSTL> list = - new VectorSTL<>(); + private VectorSTL> list = new VectorSTL<>(); private VectorSTL children = new VectorSTL<>(); private int num; // Total number of patterns we distinguish private boolean contextdecision; // True if this is decision based on context @@ -37,7 +34,7 @@ public class DecisionNode { private DecisionNode parent; public DecisionNode() { - } // For use with restoreXml + } public DecisionNode(DecisionNode p) { parent = p; @@ -213,7 +210,7 @@ private void consistentValues(VectorSTL bins, DisjointPattern pat) { long dontCareMask = m ^ commonMask; for (int i = 0; i <= dontCareMask; ++i) { // Iterate over values that contain all don't - // care bits + // care bits if ((i & dontCareMask) != i) { continue; // If all 1 bits in the value are don't cares } @@ -284,8 +281,7 @@ void split(DecisionProperties props) public void orderPatterns(DecisionProperties props) { int i, j, k; VectorSTL> newlist = list.copy(); - VectorSTL> conflictlist = - new VectorSTL<>(); + VectorSTL> conflictlist = new VectorSTL<>(); // Check for identical patterns for (i = 0; i < list.size(); ++i) { @@ -312,10 +308,8 @@ public void orderPatterns(DecisionProperties props) { // So there is no conflict } else { // A true conflict that needs to be resolved - conflictlist.push_back( - new Pair<>(ipat, iconst)); - conflictlist.push_back( - new Pair<>(jpat, jconst)); + conflictlist.push_back(new Pair<>(ipat, iconst)); + conflictlist.push_back(new Pair<>(jpat, jconst)); } } } @@ -354,65 +348,22 @@ public void orderPatterns(DecisionProperties props) { } } - void saveXml(PrintStream s) { - s.append("\n"); + void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_DECISION); + encoder.writeSignedInteger(ATTRIB_NUMBER, num); + encoder.writeBool(ATTRIB_CONTEXT, contextdecision); + encoder.writeSignedInteger(ATTRIB_STARTBIT, startbit); + encoder.writeSignedInteger(ATTRIB_SIZE, bitsize); for (int i = 0; i < list.size(); ++i) { - s.append("\n"); - list.get(i).first.saveXml(s); - s.append("\n"); + encoder.openElement(ELEM_PAIR); + encoder.writeSignedInteger(ATTRIB_ID, list.get(i).second.getId()); + list.get(i).first.encode(encoder); + encoder.closeElement(ELEM_PAIR); } for (int i = 0; i < children.size(); ++i) { - children.get(i).saveXml(s); - } - s.append("\n"); - } - - void restoreXml(Element el, DecisionNode par, SubtableSymbol sub) { - parent = par; - num = XmlUtils.decodeUnknownInt(el.getAttributeValue("number")); - - contextdecision = XmlUtils.decodeBoolean(el.getAttributeValue("context")); - startbit = XmlUtils.decodeUnknownInt(el.getAttributeValue("start")); - bitsize = XmlUtils.decodeUnknownInt(el.getAttributeValue("size")); - - List childlist = el.getChildren(); - Iterator iter = childlist.iterator(); - while (iter.hasNext()) { - Element child = (Element) iter.next(); - if (child.getName().equals("pair")) { - int id = XmlUtils.decodeUnknownInt(child.getAttributeValue("id")); - Constructor ct = sub.getConstructor(id); - DisjointPattern pat = - DisjointPattern.restoreDisjoint((Element) child.getChildren().get(0)); - // This increments num addConstructorPair(pat,ct); - list.push_back(new Pair<>(pat, ct)); - // delete pat; // addConstructorPair makes its own copy - } - else if (child.getName().equals("decision")) { - DecisionNode subnode = new DecisionNode(); - subnode.restoreXml(child, this, sub); - children.push_back(subnode); - } + children.get(i).encode(encoder); } + encoder.closeElement(ELEM_DECISION); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/EndSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/EndSymbol.java index d970ea1b311..13f88729357 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/EndSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/EndSymbol.java @@ -15,16 +15,16 @@ */ package ghidra.pcodeCPort.slghsymbol; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import ghidra.pcodeCPort.semantics.ConstTpl; import ghidra.pcodeCPort.semantics.VarnodeTpl; -import ghidra.pcodeCPort.sleighbase.SleighBase; import ghidra.pcodeCPort.slghpatexpress.EndInstructionValue; import ghidra.pcodeCPort.slghpatexpress.PatternExpression; import ghidra.pcodeCPort.space.AddrSpace; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class EndSymbol extends SpecificSymbol { @@ -34,7 +34,7 @@ public class EndSymbol extends SpecificSymbol { public EndSymbol(Location location) { super(location); patexp = null; - } // For use with restoreXml + } @Override public PatternExpression getPatternExpression() { @@ -70,24 +70,17 @@ public VarnodeTpl getVarnode() { } @Override - public void saveXml(PrintStream s) { - s.append(""); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_END_SYM); + encoder.writeUnsignedInteger(ATTRIB_ID, id); + encoder.closeElement(ELEM_END_SYM); } @Override - public void saveXmlHeader(PrintStream s) { - s.append(""); - } - - @Override - public void restoreXml(Element el, SleighBase trans) { - const_space = trans.getConstantSpace(); - patexp = new EndInstructionValue(null); - patexp.layClaim(); + public void encodeHeader(Encoder encoder) throws IOException { + encoder.openElement(ELEM_END_SYM_HEAD); + encodeSleighSymbolHeader(encoder); + encoder.closeElement(ELEM_END_SYM_HEAD); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/EpsilonSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/EpsilonSymbol.java index 01da1159e96..86f0eebc49e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/EpsilonSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/EpsilonSymbol.java @@ -15,14 +15,14 @@ */ package ghidra.pcodeCPort.slghsymbol; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import ghidra.pcodeCPort.semantics.ConstTpl; import ghidra.pcodeCPort.semantics.VarnodeTpl; -import ghidra.pcodeCPort.sleighbase.SleighBase; import ghidra.pcodeCPort.space.AddrSpace; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; // Another name for zero pattern/value @@ -32,7 +32,7 @@ public class EpsilonSymbol extends PatternlessSymbol { public EpsilonSymbol(Location location) { super(location); - } // For use with restoreXml + } public EpsilonSymbol(Location location, String nm, AddrSpace spc) { super(location, nm); @@ -46,27 +46,22 @@ public symbol_type getType() { @Override public VarnodeTpl getVarnode() { - return new VarnodeTpl(location, new ConstTpl(const_space), new ConstTpl( - ConstTpl.const_type.real, 0), new ConstTpl(ConstTpl.const_type.real, 0)); - } - - @Override - public void saveXml(PrintStream s) { - s.append(""); + return new VarnodeTpl(location, new ConstTpl(const_space), + new ConstTpl(ConstTpl.const_type.real, 0), new ConstTpl(ConstTpl.const_type.real, 0)); } @Override - public void saveXmlHeader(PrintStream s) { - s.append(""); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_EPSILON_SYM); + encoder.writeUnsignedInteger(ATTRIB_ID, id); + encoder.closeElement(ELEM_EPSILON_SYM); } @Override - public void restoreXml(Element el, SleighBase trans) { - const_space = trans.getConstantSpace(); + public void encodeHeader(Encoder encoder) throws IOException { + encoder.openElement(ELEM_EPSILON_SYM_HEAD); + encodeSleighSymbolHeader(encoder); + encoder.closeElement(ELEM_EPSILON_SYM_HEAD); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/NameSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/NameSymbol.java index eb704cb4be9..d48801faf89 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/NameSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/NameSymbol.java @@ -15,16 +15,13 @@ */ package ghidra.pcodeCPort.slghsymbol; -import java.io.PrintStream; -import java.util.Iterator; -import java.util.List; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.VectorSTL; -import ghidra.pcodeCPort.sleighbase.SleighBase; -import ghidra.pcodeCPort.slghpatexpress.PatternExpression; import ghidra.pcodeCPort.slghpatexpress.PatternValue; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class NameSymbol extends ValueSymbol { @@ -34,7 +31,7 @@ public class NameSymbol extends ValueSymbol { public NameSymbol(Location location) { super(location); - } // For use with restoreXml + } public NameSymbol(Location location, String nm, PatternValue pv, VectorSTL nt) { super(location, nm, pv); @@ -60,44 +57,26 @@ public symbol_type getType() { } @Override - public void saveXml(PrintStream s) { - s.append(""); - patval.saveXml(s); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_NAME_SYM); + encoder.writeUnsignedInteger(ATTRIB_ID, id); + patval.encode(encoder); for (int i = 0; i < nametable.size(); ++i) { String name = nametable.get(i); + encoder.openElement(ELEM_NAMETAB); if (name != null) { - s.append(""); - } - else { - s.println(""); + encoder.writeString(ATTRIB_NAME, name); } + encoder.closeElement(ELEM_NAMETAB); } - s.println(""); + encoder.closeElement(ELEM_NAME_SYM); } @Override - public void saveXmlHeader(PrintStream s) { - s.append(""); - } - - @Override - public void restoreXml(Element el, SleighBase trans) { - List list = el.getChildren(); - Iterator iter = list.iterator(); - Element element = (Element) iter.next(); - patval = (PatternValue) PatternExpression.restoreExpression(element, trans); - patval.layClaim(); - while (iter.hasNext()) { - Element child = (Element) iter.next(); - nametable.push_back(child.getAttributeValue("name")); - } - checkTableFill(); + public void encodeHeader(Encoder encoder) throws IOException { + encoder.openElement(ELEM_NAME_SYM_HEAD); + encodeSleighSymbolHeader(encoder); + encoder.closeElement(ELEM_NAME_SYM_HEAD); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/Next2Symbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/Next2Symbol.java index df6cd32a53b..2ce923b268a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/Next2Symbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/Next2Symbol.java @@ -15,16 +15,16 @@ */ package ghidra.pcodeCPort.slghsymbol; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import ghidra.pcodeCPort.semantics.ConstTpl; import ghidra.pcodeCPort.semantics.VarnodeTpl; -import ghidra.pcodeCPort.sleighbase.SleighBase; import ghidra.pcodeCPort.slghpatexpress.Next2InstructionValue; import ghidra.pcodeCPort.slghpatexpress.PatternExpression; import ghidra.pcodeCPort.space.AddrSpace; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class Next2Symbol extends SpecificSymbol { @@ -34,7 +34,7 @@ public class Next2Symbol extends SpecificSymbol { public Next2Symbol(Location location) { super(location); patexp = null; - } // For use with restoreXml + } @Override public PatternExpression getPatternExpression() { @@ -70,24 +70,17 @@ public VarnodeTpl getVarnode() { } @Override - public void saveXml(PrintStream s) { - s.append(""); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_NEXT2_SYM); + encoder.writeUnsignedInteger(ATTRIB_ID, id); + encoder.closeElement(ELEM_NEXT2_SYM); } @Override - public void saveXmlHeader(PrintStream s) { - s.append(""); - } - - @Override - public void restoreXml(Element el, SleighBase trans) { - const_space = trans.getConstantSpace(); - patexp = new Next2InstructionValue(null); - patexp.layClaim(); + public void encodeHeader(Encoder encoder) throws IOException { + encoder.openElement(ELEM_NEXT2_SYM_HEAD); + encodeSleighSymbolHeader(encoder); + encoder.closeElement(ELEM_NEXT2_SYM_HEAD); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/OperandSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/OperandSymbol.java index 139bd799124..80baa5077a7 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/OperandSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/OperandSymbol.java @@ -15,18 +15,16 @@ */ package ghidra.pcodeCPort.slghsymbol; -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.List; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; +import java.util.ArrayList; import ghidra.pcodeCPort.context.SleighError; import ghidra.pcodeCPort.semantics.VarnodeTpl; -import ghidra.pcodeCPort.sleighbase.SleighBase; import ghidra.pcodeCPort.slghpatexpress.OperandValue; import ghidra.pcodeCPort.slghpatexpress.PatternExpression; -import ghidra.pcodeCPort.utils.XmlUtils; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class OperandSymbol extends SpecificSymbol { @@ -47,7 +45,7 @@ public class OperandSymbol extends SpecificSymbol { public OperandSymbol(Location location) { super(location); - } // For use with restoreXml + } public int getRelativeOffset() { return reloffset; @@ -139,8 +137,9 @@ public void defineOperand(PatternExpression pe) { public void defineOperand(TripleSymbol tri) { if ((defexp != null) || (triple != null)) { - throw new SleighError("Redefining operand " + tri.getName() + " from " + - tri.getLocation(), getLocation()); + throw new SleighError( + "Redefining operand " + tri.getName() + " from " + tri.getLocation(), + getLocation()); } triple = tri; } @@ -161,8 +160,8 @@ public VarnodeTpl getVarnode() { if (triple instanceof SpecificSymbol) { return ((SpecificSymbol) triple).getVarnode(); } - else if ((triple != null) && - ((triple.getType() == symbol_type.valuemap_symbol) || (triple.getType() == symbol_type.name_symbol))) { + else if ((triple != null) && ((triple.getType() == symbol_type.valuemap_symbol) || + (triple.getType() == symbol_type.name_symbol))) { return new VarnodeTpl(location, hand, true); // Zero-size symbols } return new VarnodeTpl(location, hand, false); // Possible dynamic handle @@ -184,66 +183,31 @@ public void collectLocalValues(ArrayList results) { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - localexp.saveXml(s); + encoder.writeSignedInteger(ATTRIB_INDEX, hand); + localexp.encode(encoder); if (defexp != null) { - defexp.saveXml(s); + defexp.encode(encoder); } - s.append("\n"); + encoder.closeElement(ELEM_OPERAND_SYM); } @Override - public void saveXmlHeader(PrintStream s) { - s.append("\n"); - } - - @Override - public void restoreXml(Element el, SleighBase trans) { - defexp = null; - triple = null; - flags = 0; - hand = XmlUtils.decodeUnknownInt(el.getAttributeValue("index")); - reloffset = XmlUtils.decodeUnknownInt(el.getAttributeValue("off")); - offsetbase = XmlUtils.decodeUnknownInt(el.getAttributeValue("base")); - minimumlength = XmlUtils.decodeUnknownInt(el.getAttributeValue("minlen")); - String value = el.getAttributeValue("subsym"); - if (value != null) { - int id = XmlUtils.decodeUnknownInt(value); - triple = (TripleSymbol) trans.findSymbol(id); - } - if (XmlUtils.decodeBoolean(el.getAttributeValue("code"))) { - flags |= code_address; - } - List children = el.getChildren(); - Element firstChild = (Element) children.get(0); - localexp = (OperandValue) PatternExpression.restoreExpression(firstChild, trans); - localexp.layClaim(); - if (children.size() > 1) { - Element secondChild = (Element) children.get(1); - defexp = PatternExpression.restoreExpression(secondChild, trans); - defexp.layClaim(); - } + public void encodeHeader(Encoder encoder) throws IOException { + encoder.openElement(ELEM_OPERAND_SYM_HEAD); + encodeSleighSymbolHeader(encoder); + encoder.closeElement(ELEM_OPERAND_SYM_HEAD); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/PatternlessSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/PatternlessSymbol.java index 7603272fbb1..61baf8207fc 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/PatternlessSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/PatternlessSymbol.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,51 +15,36 @@ */ package ghidra.pcodeCPort.slghsymbol; -import ghidra.pcodeCPort.sleighbase.*; -import ghidra.pcodeCPort.slghpatexpress.*; +import ghidra.pcodeCPort.slghpatexpress.ConstantValue; +import ghidra.pcodeCPort.slghpatexpress.PatternExpression; import ghidra.sleigh.grammar.Location; -import java.io.PrintStream; - -import org.jdom.Element; - - // Behaves like constant 0 pattern public abstract class PatternlessSymbol extends SpecificSymbol { private ConstantValue patexp; @Override - public PatternExpression getPatternExpression() { + public PatternExpression getPatternExpression() { return patexp; } - @Override - public void saveXml( PrintStream s ) { - } - - @Override - public void restoreXml( Element el, SleighBase trans ) { - } - - // The void constructor must explicitly build - // the ConstantValue because it is not stored - // or restored via xml + // The constructor must explicitly build the ConstantValue. It is not explicitly + // decoded (or encoded) public PatternlessSymbol(Location location) { - super(location); - patexp = new ConstantValue( location, 0 ); + super(location); + patexp = new ConstantValue(location, 0); patexp.layClaim(); } - public PatternlessSymbol( Location location, String nm ) { - super( location, nm ); - patexp = new ConstantValue( location, 0 ); + public PatternlessSymbol(Location location, String nm) { + super(location, nm); + patexp = new ConstantValue(location, 0); patexp.layClaim(); } @Override - public void dispose() { - PatternExpression.release( patexp ); + public void dispose() { + PatternExpression.release(patexp); } - } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/SectionSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/SectionSymbol.java index 8175831b43b..9737736f75e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/SectionSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/SectionSymbol.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -55,5 +54,5 @@ public int getRefCount() { public symbol_type getType() { return symbol_type.section_symbol; } - // Not saved or restored + // Not encoded } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/SleighSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/SleighSymbol.java index db2c2a95f17..c75010ba818 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/SleighSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/SleighSymbol.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +15,12 @@ */ package ghidra.pcodeCPort.slghsymbol; -import ghidra.pcodeCPort.sleighbase.SleighBase; -import ghidra.pcodeCPort.utils.XmlUtils; -import ghidra.sleigh.grammar.Location; +import static ghidra.pcode.utils.SlaFormat.*; -import java.io.PrintStream; +import java.io.IOException; -import org.jdom.Element; +import ghidra.program.model.pcode.Encoder; +import ghidra.sleigh.grammar.Location; public class SleighSymbol implements Comparable { @Override @@ -49,7 +47,7 @@ public boolean wasSought() { public SleighSymbol(Location location) { this.location = location; - } // For use with restoreXml + } public SleighSymbol(Location location, String nm) { this.location = location; @@ -72,30 +70,19 @@ public symbol_type getType() { return symbol_type.dummy_symbol; } - public void saveXml(PrintStream s) { + public void encode(Encoder encoder) throws IOException { + throw new IOException("Symbol " + name + " cannot be encoded directly"); } - public void restoreXml(Element el, SleighBase trans) { - } - - protected final void saveSleighSymbolXmlHeader(PrintStream s) { - s.append(" name=\"").append(name).append("\""); - s.append(" id=\"0x").print(Long.toHexString(id)); - s.append("\""); - s.append(" scope=\"0x"); - s.print(Long.toHexString(scopeid)); - s.append("\""); + protected final void encodeSleighSymbolHeader(Encoder encoder) throws IOException { + encoder.writeString(ATTRIB_NAME, name); + encoder.writeUnsignedInteger(ATTRIB_ID, id); + encoder.writeUnsignedInteger(ATTRIB_SCOPE, scopeid); } // Save the basic attributes of a symbol - protected void saveXmlHeader(PrintStream s) { - saveSleighSymbolXmlHeader(s); - } - - void restoreXmlHeader(Element el) { - name = el.getAttributeValue("name"); - id = XmlUtils.decodeUnknownInt(el.getAttributeValue("id")); - scopeid = XmlUtils.decodeUnknownInt(el.getAttributeValue("scope")); + protected void encodeHeader(Encoder encoder) throws IOException { + encodeSleighSymbolHeader(encoder); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/StartSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/StartSymbol.java index 0d8cd821d2e..d03995ba90a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/StartSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/StartSymbol.java @@ -15,16 +15,16 @@ */ package ghidra.pcodeCPort.slghsymbol; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import ghidra.pcodeCPort.semantics.ConstTpl; import ghidra.pcodeCPort.semantics.VarnodeTpl; -import ghidra.pcodeCPort.sleighbase.SleighBase; import ghidra.pcodeCPort.slghpatexpress.PatternExpression; import ghidra.pcodeCPort.slghpatexpress.StartInstructionValue; import ghidra.pcodeCPort.space.AddrSpace; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class StartSymbol extends SpecificSymbol { @@ -34,7 +34,7 @@ public class StartSymbol extends SpecificSymbol { StartSymbol(Location location) { super(location); patexp = null; - } // For use with restoreXml + } @Override public PatternExpression getPatternExpression() { @@ -70,24 +70,17 @@ public VarnodeTpl getVarnode() { } @Override - public void saveXml(PrintStream s) { - s.append(""); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_START_SYM); + encoder.writeUnsignedInteger(ATTRIB_ID, id); + encoder.closeElement(ELEM_START_SYM); } @Override - public void saveXmlHeader(PrintStream s) { - s.append("\n"); - } - - @Override - public void restoreXml(Element el, SleighBase trans) { - const_space = trans.getConstantSpace(); - patexp = new StartInstructionValue(null); - patexp.layClaim(); + public void encodeHeader(Encoder encoder) throws IOException { + encoder.openElement(ELEM_START_SYM_HEAD); + encodeSleighSymbolHeader(encoder); + encoder.closeElement(ELEM_START_SYM_HEAD); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/SubtableSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/SubtableSymbol.java index 604c0194ac9..6ba5a9c2602 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/SubtableSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/SubtableSymbol.java @@ -15,20 +15,20 @@ */ package ghidra.pcodeCPort.slghsymbol; -import java.io.PrintStream; -import java.util.*; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; import generic.stl.IteratorSTL; import generic.stl.VectorSTL; import ghidra.pcodeCPort.context.SleighError; -import ghidra.pcodeCPort.sleighbase.SleighBase; import ghidra.pcodeCPort.slghpatexpress.PatternExpression; import ghidra.pcodeCPort.slghpatexpress.TokenPattern; import ghidra.pcodeCPort.slghpattern.DisjointPattern; import ghidra.pcodeCPort.slghpattern.Pattern; -import ghidra.pcodeCPort.utils.XmlUtils; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class SubtableSymbol extends TripleSymbol { @@ -43,7 +43,7 @@ public SubtableSymbol(Location location) { super(location); pattern = null; decisiontree = null; - } // For use with restoreXml + } public boolean isBeingBuilt() { return beingbuilt; @@ -114,50 +114,25 @@ public void dispose() { } @Override - public void saveXml(PrintStream s) { + public void encode(Encoder encoder) throws IOException { if (decisiontree == null) { return; // Not fully formed } - s.append("\n"); + encoder.openElement(ELEM_SUBTABLE_SYM); + encoder.writeUnsignedInteger(ATTRIB_ID, id); + encoder.writeSignedInteger(ATTRIB_NUMCT, construct.size()); for (int i = 0; i < construct.size(); ++i) { - construct.get(i).saveXml(s); + construct.get(i).encode(encoder); } - decisiontree.saveXml(s); - s.append("\n"); - } - - @Override - public void saveXmlHeader(PrintStream s) { - s.append("\n"); + decisiontree.encode(encoder); + encoder.closeElement(ELEM_SUBTABLE_SYM); } @Override - public void restoreXml(Element el, SleighBase trans) { - int numct = XmlUtils.decodeUnknownInt(el.getAttributeValue("numct")); - construct.reserve(numct); - - List children = el.getChildren(); - Iterator iter = children.iterator(); - while (iter.hasNext()) { - Element child = (Element) iter.next(); - if (child.getName().equals("constructor")) { - Constructor ct = new Constructor(null); - addConstructor(ct); - ct.restoreXml(child, trans); - } - else if (child.getName().equals("decision")) { - decisiontree = new DecisionNode(); - decisiontree.restoreXml(child, null, this); - } - } - pattern = null; - beingbuilt = false; - errors = false; + public void encodeHeader(Encoder encoder) throws IOException { + encoder.openElement(ELEM_SUBTABLE_SYM_HEAD); + encodeSleighSymbolHeader(encoder); + encoder.closeElement(ELEM_SUBTABLE_SYM_HEAD); } // Associate pattern disjoints to constructors diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/SymbolTable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/SymbolTable.java index 33fbb65e914..44e9847bd3b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/SymbolTable.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/SymbolTable.java @@ -15,18 +15,14 @@ */ package ghidra.pcodeCPort.slghsymbol; -import java.io.PrintStream; -import java.util.Iterator; -import java.util.List; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.IteratorSTL; import generic.stl.VectorSTL; import ghidra.pcodeCPort.context.SleighError; -import ghidra.pcodeCPort.sleighbase.SleighBase; -import ghidra.pcodeCPort.utils.XmlUtils; -import ghidra.sleigh.grammar.Location; +import ghidra.program.model.pcode.Encoder; public class SymbolTable { @@ -187,131 +183,32 @@ public void replaceSymbol(SleighSymbol a, SleighSymbol b) { } } - public void saveXml(PrintStream s) { - s.append("\n"); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_SYMBOL_TABLE); + encoder.writeSignedInteger(ATTRIB_SCOPESIZE, table.size()); + encoder.writeSignedInteger(ATTRIB_SYMBOLSIZE, symbollist.size()); for (int i = 0; i < table.size(); ++i) { - s.append("\n"); + encoder.closeElement(ELEM_SCOPE); } // First save the headers for (int i = 0; i < symbollist.size(); ++i) { - symbollist.get(i).saveXmlHeader(s); + symbollist.get(i).encodeHeader(encoder); } // Now save the content of each symbol for (int i = 0; i < symbollist.size(); ++i) { // Must save IN ORDER - symbollist.get(i).saveXml(s); + symbollist.get(i).encode(encoder); } - s.append("\n"); - } - - public void restoreXml(Element el, SleighBase trans) { - int size = XmlUtils.decodeUnknownInt(el.getAttributeValue("scopesize")); - for (int i = 0; i < size; i++) { - table.push_back(null); - } - size = XmlUtils.decodeUnknownInt(el.getAttributeValue("symbolsize")); - for (int i = 0; i < size; i++) { - symbollist.push_back(null); - } - - List list = el.getChildren(); - Iterator iter = list.iterator(); - for (int i = 0; i < table.size(); ++i) { // Restore the scopes - Element subel = (Element) iter.next(); - if (!subel.getName().equals("scope")) { - throw new SleighError("Misnumbered symbol scopes", null); - } - int id = XmlUtils.decodeUnknownInt(subel.getAttributeValue("id")); - int parent = XmlUtils.decodeUnknownInt(subel.getAttributeValue("parent")); - SymbolScope parscope = (parent == id) ? null : table.get(parent); - table.set(id, new SymbolScope(parscope, id)); - } - curscope = table.get(0); // Current scope is global - - // Now restore the symbol shells - for (int i = 0; i < symbollist.size(); ++i) { - Element child = (Element) iter.next(); - restoreSymbolHeader(child); - } - // Now restore the symbol content - while (iter.hasNext()) { - Element subel = (Element) iter.next(); - int id = XmlUtils.decodeUnknownInt(subel.getAttributeValue("id")); - SleighSymbol sym = findSymbol(id); - sym.restoreXml(subel, trans); - } - } - - // Put the shell of a symbol in the symbol table - // in order to allow recursion - public void restoreSymbolHeader(Element el) { - SleighSymbol sym; - // this is where you can restore the actual location from in the - // future if you so wish (of course, all the saveXml...need - // to be updated properly too) - Location location = null; - if (el.getName().equals("userop_head")) { - sym = new UserOpSymbol(location); - } - else if (el.getName().equals("epsilon_sym_head")) { - sym = new EpsilonSymbol(location); - } - else if (el.getName().equals("value_sym_head")) { - sym = new ValueSymbol(location); - } - else if (el.getName().equals("valuemap_sym_head")) { - sym = new ValueMapSymbol(location); - } - else if (el.getName().equals("name_sym_head")) { - sym = new NameSymbol(location); - } - else if (el.getName().equals("varnode_sym_head")) { - sym = new VarnodeSymbol(location); - } - else if (el.getName().equals("context_sym_head")) { - sym = new ContextSymbol(location); - } - else if (el.getName().equals("varlist_sym_head")) { - sym = new VarnodeListSymbol(location); - } - else if (el.getName().equals("operand_sym_head")) { - sym = new OperandSymbol(location); - } - else if (el.getName().equals("start_sym_head")) { - sym = new StartSymbol(location); - } - else if (el.getName().equals("end_sym_head")) { - sym = new EndSymbol(location); - } - else if (el.getName().equals("next2_sym_head")) { - sym = new Next2Symbol(location); - } - else if (el.getName().equals("subtable_sym_head")) { - sym = new SubtableSymbol(location); - } - else { - throw new SleighError("Bad symbol xml", null); - } - sym.restoreXmlHeader(el); // Restore basic elements of symbol - symbollist.set(sym.id, sym); // Put the basic symbol in the table - table.get(sym.scopeid).addSymbol(sym); // to allow recursion + encoder.closeElement(ELEM_SYMBOL_TABLE); } // Get rid of unsavable symbols and scopes diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/UserOpSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/UserOpSymbol.java index 703f0e8a8f0..0123268ac9f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/UserOpSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/UserOpSymbol.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +15,12 @@ */ package ghidra.pcodeCPort.slghsymbol; -import ghidra.pcodeCPort.sleighbase.*; -import ghidra.pcodeCPort.utils.*; -import ghidra.sleigh.grammar.Location; - -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; +import ghidra.program.model.pcode.Encoder; +import ghidra.sleigh.grammar.Location; // A user-defined pcode-op public class UserOpSymbol extends SleighSymbol { @@ -31,15 +28,15 @@ public class UserOpSymbol extends SleighSymbol { private int index; public UserOpSymbol(Location location) { - super(location); - } // For use with restoreXml + super(location); + } - public UserOpSymbol( Location location, String nm ) { - super( location, nm ); + public UserOpSymbol(Location location, String nm) { + super(location, nm); index = 0; } - public void setIndex( int ind ) { + public void setIndex(int ind) { index = ind; } @@ -48,30 +45,23 @@ public int getIndex() { } @Override - public symbol_type getType() { + public symbol_type getType() { return symbol_type.userop_symbol; } @Override - public void saveXml( PrintStream s ) { - s.append( "" ); - } - - @Override - public void saveXmlHeader( PrintStream s ) { - s.append( "" ); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_USEROP); + encoder.writeUnsignedInteger(ATTRIB_ID, id); + encoder.writeSignedInteger(ATTRIB_INDEX, index); + encoder.closeElement(ELEM_USEROP); } @Override - public void restoreXml( Element el, SleighBase trans ) { - index = XmlUtils.decodeUnknownInt( el.getAttributeValue( "index" ) ); + public void encodeHeader(Encoder encoder) throws IOException { + encoder.openElement(ELEM_USEROP_HEAD); + encodeSleighSymbolHeader(encoder); + encoder.closeElement(ELEM_USEROP_HEAD); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ValueMapSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ValueMapSymbol.java index 917744de147..025146208b7 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ValueMapSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ValueMapSymbol.java @@ -15,17 +15,13 @@ */ package ghidra.pcodeCPort.slghsymbol; -import java.io.PrintStream; -import java.util.Iterator; -import java.util.List; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.VectorSTL; -import ghidra.pcodeCPort.sleighbase.SleighBase; -import ghidra.pcodeCPort.slghpatexpress.PatternExpression; import ghidra.pcodeCPort.slghpatexpress.PatternValue; -import ghidra.pcodeCPort.utils.XmlUtils; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class ValueMapSymbol extends ValueSymbol { @@ -60,38 +56,23 @@ private void checkTableFill() { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - patval.saveXml(s); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_VALUEMAP_SYM); + encoder.writeUnsignedInteger(ATTRIB_ID, id); + patval.encode(encoder); for (int i = 0; i < valuetable.size(); ++i) { - s.append("\n"); + encoder.openElement(ELEM_VALUETAB); + encoder.writeSignedInteger(ATTRIB_VAL, valuetable.get(i)); + encoder.closeElement(ELEM_VALUETAB); } - s.append("\n"); + encoder.closeElement(ELEM_VALUEMAP_SYM); } @Override - public void saveXmlHeader(PrintStream s) { - s.append("\n"); - } - - @Override - public void restoreXml(Element el, SleighBase trans) { - List list = el.getChildren(); - Iterator iter = list.iterator(); - Element element = (Element) iter.next(); - patval = (PatternValue) PatternExpression.restoreExpression(element, trans); - patval.layClaim(); - while (iter.hasNext()) { - Element child = (Element) iter.next(); - long value = XmlUtils.decodeUnknownLong(child.getAttributeValue("val")); - valuetable.push_back(value); - } - checkTableFill(); - + public void encodeHeader(Encoder encoder) throws IOException { + encoder.openElement(ELEM_VALUEMAP_SYM_HEAD); + encodeSleighSymbolHeader(encoder); + encoder.closeElement(ELEM_VALUEMAP_SYM_HEAD); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ValueSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ValueSymbol.java index 23db19efb8a..9a5c05c2294 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ValueSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/ValueSymbol.java @@ -15,14 +15,13 @@ */ package ghidra.pcodeCPort.slghsymbol; -import java.io.PrintStream; -import java.util.List; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; -import ghidra.pcodeCPort.sleighbase.SleighBase; import ghidra.pcodeCPort.slghpatexpress.PatternExpression; import ghidra.pcodeCPort.slghpatexpress.PatternValue; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class ValueSymbol extends FamilySymbol { @@ -32,7 +31,7 @@ public class ValueSymbol extends FamilySymbol { public ValueSymbol(Location location) { super(location); patval = null; - } // For use with restoreXml + } public ValueSymbol(Location location, String nm, PatternValue pv) { super(location, nm); @@ -63,29 +62,20 @@ public void dispose() { } @Override - public void saveXml(PrintStream s) { - s.append(""); - patval.saveXml(s); - s.println(""); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_VALUE_SYM); + encoder.writeUnsignedInteger(ATTRIB_ID, id); + patval.encode(encoder); + encoder.closeElement(ELEM_VALUE_SYM); } @Override - public void saveXmlHeader(PrintStream s) + public void encodeHeader(Encoder encoder) throws IOException { - s.append(""); - } - - @Override - public void restoreXml(Element el, SleighBase trans) { - List list = el.getChildren(); - Element child = (Element) list.get(0); - patval = (PatternValue) PatternExpression.restoreExpression(child, trans); - patval.layClaim(); + encoder.openElement(ELEM_VALUE_SYM_HEAD); + encodeSleighSymbolHeader(encoder); + encoder.closeElement(ELEM_VALUE_SYM_HEAD); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/VarnodeListSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/VarnodeListSymbol.java index 8d51f901067..eff686c1f0a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/VarnodeListSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/VarnodeListSymbol.java @@ -15,18 +15,14 @@ */ package ghidra.pcodeCPort.slghsymbol; -import java.io.PrintStream; -import java.util.Iterator; -import java.util.List; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; import generic.stl.VectorSTL; import ghidra.pcodeCPort.context.SleighError; -import ghidra.pcodeCPort.sleighbase.SleighBase; -import ghidra.pcodeCPort.slghpatexpress.PatternExpression; import ghidra.pcodeCPort.slghpatexpress.PatternValue; -import ghidra.pcodeCPort.utils.XmlUtils; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class VarnodeListSymbol extends ValueSymbol { @@ -36,7 +32,7 @@ public class VarnodeListSymbol extends ValueSymbol { public VarnodeListSymbol(Location location) { super(location); - } // For use with restoreXml + } @Override public symbol_type getType() { @@ -75,50 +71,29 @@ public int getSize() { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - patval.saveXml(s); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_VARLIST_SYM); + encoder.writeUnsignedInteger(ATTRIB_ID, id); + patval.encode(encoder); for (int i = 0; i < varnode_table.size(); ++i) { if (varnode_table.get(i) == null) { - s.append("\n"); + encoder.openElement(ELEM_NULL); + encoder.closeElement(ELEM_NULL); } else { - s.append("\n"); + encoder.openElement(ELEM_VAR); + encoder.writeUnsignedInteger(ATTRIB_ID, varnode_table.get(i).getId()); + encoder.closeElement(ELEM_VAR); } } - s.append("\n"); + encoder.closeElement(ELEM_VARLIST_SYM); } @Override - public void saveXmlHeader(PrintStream s) { - s.append("\n"); - } - - @Override - public void restoreXml(Element el, SleighBase trans) { - - List children = el.getChildren(); - Iterator iter = children.iterator(); - Element child = (Element) iter.next(); - patval = (PatternValue) PatternExpression.restoreExpression(child, trans); - patval.layClaim(); - while (iter.hasNext()) { - Element subel = (Element) iter.next(); - if (subel.getName().equals("var")) { - int id1 = XmlUtils.decodeUnknownInt(subel.getAttributeValue("id")); - varnode_table.push_back((VarnodeSymbol) trans.findSymbol(id1)); - } - else { - varnode_table.push_back(null); - } - } - checkTableFill(); + public void encodeHeader(Encoder encoder) throws IOException { + encoder.openElement(ELEM_VARLIST_SYM_HEAD); + encodeSleighSymbolHeader(encoder); + encoder.closeElement(ELEM_VARLIST_SYM_HEAD); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/VarnodeSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/VarnodeSymbol.java index 39fc7df72cf..ed7a0d4410f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/VarnodeSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/VarnodeSymbol.java @@ -15,21 +15,19 @@ */ package ghidra.pcodeCPort.slghsymbol; -import java.util.ArrayList; - -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; +import java.util.ArrayList; // A global varnode import ghidra.pcodeCPort.context.SleighError; import ghidra.pcodeCPort.pcoderaw.VarnodeData; import ghidra.pcodeCPort.semantics.ConstTpl; import ghidra.pcodeCPort.semantics.VarnodeTpl; -import ghidra.pcodeCPort.sleighbase.SleighBase; import ghidra.pcodeCPort.space.AddrSpace; import ghidra.pcodeCPort.space.spacetype; -import ghidra.pcodeCPort.utils.XmlUtils; +import ghidra.program.model.pcode.Encoder; import ghidra.sleigh.grammar.Location; public class VarnodeSymbol extends PatternlessSymbol { @@ -38,7 +36,7 @@ public class VarnodeSymbol extends PatternlessSymbol { public VarnodeSymbol(Location location) { super(location); - } // For use with restoreXml + } public void markAsContext() { // note: this value was never read @@ -94,33 +92,22 @@ public VarnodeTpl getVarnode() { } @Override - public void saveXml(PrintStream s) { - s.append("\n"); - super.saveXml(s); - s.append("\n"); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_VARNODE_SYM); + encoder.writeUnsignedInteger(ATTRIB_ID, id); + encoder.writeSpace(ATTRIB_SPACE, fix.space.getIndex(), fix.space.getName()); + encoder.writeUnsignedInteger(ATTRIB_OFF, fix.offset); + encoder.writeSignedInteger(ATTRIB_SIZE, fix.size); + encoder.closeElement(ELEM_VARNODE_SYM); } @Override - public void saveXmlHeader(PrintStream s) + public void encodeHeader(Encoder encoder) throws IOException { - s.append("\n"); - } - - @Override - public void restoreXml(Element el, SleighBase trans) { - fix.space = trans.getSpaceByName(el.getAttributeValue("space")); - fix.offset = XmlUtils.decodeUnknownLong(el.getAttributeValue("offset")); - fix.size = XmlUtils.decodeUnknownInt(el.getAttributeValue("size")); - // PatternlessSymbol does not need restoring + encoder.openElement(ELEM_VARNODE_SYM_HEAD); + encodeSleighSymbolHeader(encoder); + encoder.closeElement(ELEM_VARNODE_SYM_HEAD); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/AddrSpace.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/AddrSpace.java index 8885445ba89..2a4cdae5f59 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/AddrSpace.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/AddrSpace.java @@ -15,15 +15,13 @@ */ package ghidra.pcodeCPort.space; -import java.io.PrintStream; -import java.util.StringTokenizer; +import static ghidra.pcode.utils.SlaFormat.*; -import org.jdom.Element; +import java.io.IOException; +import java.io.PrintStream; -import ghidra.pcodeCPort.error.LowlevelError; -import ghidra.pcodeCPort.pcoderaw.VarnodeData; import ghidra.pcodeCPort.translate.Translate; -import ghidra.pcodeCPort.utils.*; +import ghidra.pcodeCPort.utils.Utils; /// \brief A region where processor data is stored /// /// An AddrSpace (Address Space) is an arbitrary sequence of @@ -54,11 +52,7 @@ /// - \b unique There is always a \e unique address space used /// as a pool for temporary registers. (See UniqueSpace) /// - -import ghidra.pcodeCPort.error.LowlevelError; -import ghidra.pcodeCPort.pcoderaw.VarnodeData; -import ghidra.pcodeCPort.translate.Translate; -import ghidra.pcodeCPort.utils.*; +import ghidra.program.model.pcode.Encoder; public class AddrSpace { @@ -235,18 +229,16 @@ private void calcScaleMask() { // Calculate scale, mask, and shortcut shortcut = trans.assignShortcut(type); } - void save_basic_attributes(PrintStream s) { // write the name, shortcut, - // and index as XML - // attributes - XmlUtils.a_v(s, "name", name); - XmlUtils.a_v_i(s, "index", index); - XmlUtils.a_v_b(s, "bigendian", isBigEndian()); - XmlUtils.a_v_i(s, "delay", delay); - XmlUtils.a_v_i(s, "size", addressSize); + void encode_basic_attributes(Encoder encoder) throws IOException { // write the name, shortcut, and index + encoder.writeString(ATTRIB_NAME, name); + encoder.writeSignedInteger(ATTRIB_INDEX, index); + encoder.writeBool(ATTRIB_BIGENDIAN, isBigEndian()); + encoder.writeSignedInteger(ATTRIB_DELAY, delay); + encoder.writeSignedInteger(ATTRIB_SIZE, addressSize); if (wordsize > 1) { - XmlUtils.a_v_i(s, "wordsize", wordsize); + encoder.writeSignedInteger(ATTRIB_WORDSIZE, wordsize); } - XmlUtils.a_v_b(s, "physical", hasPhysical()); + encoder.writeBool(ATTRIB_PHYSICAL, hasPhysical()); } public boolean contain(AddrSpace id2) { // Does this contain -id2- ? @@ -281,47 +273,6 @@ long data2uintm(byte[] ptr, int size) { // Convert array of bytes to return res; } - public void saveXmlAttributes(PrintStream s, long offset) { // Save address - // as XML - // attributes - XmlUtils.a_v(s, "space", getName()); // Just append the proper - // attributes - s.append(' '); - s.append("offset=\""); - printOffset(s, offset); - s.append("\""); - } - - public void saveXmlAttributes(PrintStream s, long offset, int size) { // Save - // address - // as - // XML - // attributes - XmlUtils.a_v(s, "space", getName()); // Just append the proper - // attributes - s.append(" offset=\""); - printOffset(s, offset); - s.append("\""); - XmlUtils.a_v_i(s, "size", size); - } - - public static long restore_xml_offset(Element el) { - String offsetString = el.getAttributeValue("offset"); - if (offsetString == null) { - throw new LowlevelError("Address missing offset"); - } - return XmlUtils.decodeUnknownLong(offsetString); - - } - - public static int restore_xml_size(Element el) { - String sizeString = el.getAttributeValue("size"); - if (sizeString == null) { - return 0; - } - return XmlUtils.decodeUnknownInt(sizeString); - } - public void printOffset(PrintStream s, long offset) { // Print the offset as // hexidecimal value s.append("0x"); @@ -373,64 +324,10 @@ public String toString(long offset) { return s.toString(); } - public long read(String s, MutableInt size) { // Read string to produce offset value - long offset; - StringTokenizer tokenizzy = new StringTokenizer(s, ":+"); - String frontpart = tokenizzy.nextToken(); - size.set(getAddrSize()); - - try { - VarnodeData point = getTrans().getRegister(frontpart); - offset = point.offset; - size.set(point.size); - return offset; - } - catch (LowlevelError err) { // Name doesn't exist - // not a register; handled below - } - - // value is an address offset and not a register - try { - offset = XmlUtils.decodeUnknownLong(frontpart); - } - catch (NumberFormatException nfe) { - size.set(-1); - return -1; - } - offset <<= scale; - - if (tokenizzy.countTokens() > 1) { // there is a size - try { - size.set(Integer.parseInt(tokenizzy.nextToken())); - } - catch (NumberFormatException nfe) { - // don't update the size - } - } - - return offset; - } - - public void saveXml(PrintStream s) { - s.append(""); - } - - public void restoreXml(Element el) { - name = el.getAttributeValue("name"); - index = XmlUtils.decodeUnknownInt(el.getAttributeValue("index")); - addressSize = XmlUtils.decodeUnknownInt(el.getAttributeValue("size")); - wordsize = XmlUtils.decodeUnknownInt(el.getAttributeValue("wordsize")); - if (XmlUtils.decodeBoolean(el.getAttributeValue("bigendian"))) { - flags |= big_endian; - } - delay = XmlUtils.decodeUnknownInt(el.getAttributeValue("delay")); - if (XmlUtils.decodeBoolean(el.getAttributeValue("physical"))) { - flags |= hasphysical; - } - - calcScaleMask(); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_SPACE); // This implies type=processor + encode_basic_attributes(encoder); + encoder.closeElement(ELEM_SPACE); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/ConstantSpace.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/ConstantSpace.java index 8e98bec1a9d..a15a40de956 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/ConstantSpace.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/ConstantSpace.java @@ -17,11 +17,10 @@ import java.io.PrintStream; -import org.jdom.Element; - import ghidra.pcodeCPort.error.LowlevelError; import ghidra.pcodeCPort.translate.Translate; import ghidra.program.model.lang.SpaceNames; +import ghidra.program.model.pcode.Encoder; public class ConstantSpace extends AddrSpace { public ConstantSpace(Translate t) { @@ -39,13 +38,8 @@ public int printRaw(PrintStream s, long offset) { } @Override - public void saveXml(PrintStream s) { - throw new LowlevelError("Should never save the constant space as XML"); - } - - @Override - public void restoreXml(Element el) { - throw new LowlevelError("Should never restore the constant space from XML"); + public void encode(Encoder encoder) { + throw new LowlevelError("Should never save the constant space"); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/OtherSpace.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/OtherSpace.java index 961773505ca..053189c6a98 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/OtherSpace.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/OtherSpace.java @@ -15,9 +15,13 @@ */ package ghidra.pcodeCPort.space; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.io.IOException; import java.io.PrintStream; import ghidra.pcodeCPort.translate.Translate; +import ghidra.program.model.pcode.Encoder; public class OtherSpace extends AddrSpace { @@ -41,9 +45,9 @@ public int printRaw(PrintStream s, long offset) { } @Override - public void saveXml(PrintStream s) { - s.print(""); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_SPACE_OTHER); + encode_basic_attributes(encoder); + encoder.closeElement(ELEM_SPACE_OTHER); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/SpacebaseSpace.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/SpacebaseSpace.java deleted file mode 100644 index 347488c17f2..00000000000 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/SpacebaseSpace.java +++ /dev/null @@ -1,59 +0,0 @@ -/* ### - * IP: GHIDRA - * REVIEWED: YES - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.pcodeCPort.space; - -import ghidra.pcodeCPort.translate.*; -import ghidra.pcodeCPort.utils.*; - -import java.io.PrintStream; - -import org.jdom.Element; - - - -public class SpacebaseSpace extends AddrSpace { - AddrSpace contain; // Containing space - - @Override - public AddrSpace getContain() { - return contain; - } - - public SpacebaseSpace( String nm, int ind, int sz, AddrSpace base, int dl ) { - super( base.getTrans(), spacetype.IPTR_SPACEBASE, nm, sz, base.getWordSize(), ind, 0, dl ); - contain = base; - } - - public SpacebaseSpace( Translate t ) { - super( t, spacetype.IPTR_SPACEBASE ); - } - - @Override - public void saveXml( PrintStream s ) { - s.print( "" ); - } - - @Override - public void restoreXml( Element el ) { - super.restoreXml( el ); // Restore basic attributes - contain = getTrans().getSpaceByName( el.getAttributeValue( "contain" ) ); - } - -} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/UniqueSpace.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/UniqueSpace.java index f4619cb5ca6..9893fabaf63 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/UniqueSpace.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/space/UniqueSpace.java @@ -15,10 +15,13 @@ */ package ghidra.pcodeCPort.space; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.io.IOException; import ghidra.pcodeCPort.translate.Translate; import ghidra.program.model.lang.SpaceNames; +import ghidra.program.model.pcode.Encoder; public class UniqueSpace extends AddrSpace { public UniqueSpace(Translate t, int ind, int fl) { @@ -35,10 +38,10 @@ public UniqueSpace(Translate t) { } @Override - public void saveXml(PrintStream s) { - s.print(""); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_SPACE_UNIQUE); + encode_basic_attributes(encoder); + encoder.closeElement(ELEM_SPACE_UNIQUE); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/translate/Translate.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/translate/Translate.java index 1ec6aaba277..0926f6c6121 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/translate/Translate.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/translate/Translate.java @@ -19,15 +19,14 @@ import java.util.ArrayList; import java.util.List; -import org.jdom.Element; - import generic.stl.VectorSTL; -import ghidra.pcodeCPort.address.*; +import ghidra.pcodeCPort.address.Address; +import ghidra.pcodeCPort.address.RangeList; import ghidra.pcodeCPort.error.LowlevelError; import ghidra.pcodeCPort.pcoderaw.VarnodeData; -import ghidra.pcodeCPort.space.*; +import ghidra.pcodeCPort.space.AddrSpace; +import ghidra.pcodeCPort.space.spacetype; import ghidra.pcodeCPort.utils.AddrSpaceToIdSymmetryMap; -import ghidra.pcodeCPort.xml.DocumentStorage; import ghidra.program.model.lang.SpaceNames; public abstract class Translate implements BasicSpaceProvider { @@ -212,8 +211,6 @@ public boolean highPtrPossible(Address loc, int size) { return !nohighptr.inRange(loc, size); } - public abstract void initialize(DocumentStorage store); - protected void registerContext(String name, int sbit, int ebit) { // Base implementation (for compiling) doesn't need to keep track of context symbol } @@ -236,44 +233,6 @@ public Translate() { alignment = 1; } - AddrSpace restoreXmlSpace(Element el) { // Factory for spaces - AddrSpace res; - String tp = el.getName(); - if ("space_base".equals(tp)) { - res = new SpacebaseSpace(this); - } - else if ("space_unique".equals(tp)) { - res = new UniqueSpace(this); - } - else if ("space_other".equals(tp)) { - res = new OtherSpace(this); - } - else { - res = new AddrSpace(this, spacetype.IPTR_PROCESSOR); - } - - res.restoreXml(el); - return res; - } - - protected void restoreXmlSpaces(Element el) { - // The first space should always be the constant space - insertSpace(new ConstantSpace(this)); - - // The second space should always be the other space - insertSpace( - new OtherSpace(this, SpaceNames.OTHER_SPACE_NAME, SpaceNames.OTHER_SPACE_INDEX)); - - String defname = el.getAttributeValue("defaultspace"); - List children = el.getChildren(); - for (Object object : children) { - AddrSpace spc = restoreXmlSpace((Element) object); - insertSpace(spc); - } - AddrSpace spc = getSpaceByName(defname); - setDefaultSpace(spc.getIndex()); - } - public AddrSpace getSpaceByName(String nm) { // Convert name to space for (AddrSpace space : baselist) { if (space.getName().equals(nm)) { @@ -469,56 +428,6 @@ public char assignShortcut(spacetype tp) { throw new LowlevelError("Unable to assign shortcut"); } - public void parseStackPointer(Element el) { - int ind = baselist.size(); - - AddrSpace basespace = getSpaceByName(el.getAttributeValue("space")); - if (basespace == null) { - throw new LowlevelError("Unknown space name: " + el.getAttributeValue("space")); - } - AddrSpace spc; - - // Get data for the stackpointer - VarnodeData point = getRegister(el.getAttributeValue("register")); - spc = new SpacebaseSpace(SpaceNames.STACK_SPACE_NAME, ind, point.size, basespace, - point.space.getDelay() + 1); - insertSpace(spc); - addSpacebase(stackspace, point.space, point.offset, point.size); - } - - public void parseSpacebase(Element el) { // Parse a "spacebase" command in configuration file - String namestring = el.getAttributeValue("name"); - VarnodeData point = getRegister(el.getAttributeValue("register")); - AddrSpace spc = getSpaceByName(namestring); - if (spc == null) { // Space not previously defined - int ind = baselist.size(); - - AddrSpace basespace = getSpaceByName(el.getAttributeValue("space")); - if (basespace == null) { - throw new LowlevelError("Unknown space name: " + el.getAttributeValue("space")); - } - spc = new SpacebaseSpace(namestring, ind, point.size, basespace, - point.space.getDelay() + 1); - insertSpace(spc); - } - addSpacebase(spc, point.space, point.offset, point.size); - } - - /** - * This routine is used by the initialization process to add - * address ranges to which there is never an (indirect) pointer - * Should only be called during initialization - * @param el is the parse XML describing the address range - */ - public void parseNoHighPtr(Element el) { - List list = el.getChildren(); - for (Object object : list) { - Range range = new Range(); - range.restoreXml((Element) object, this); - nohighptr.insertRange(range.getSpace(), range.getFirst(), range.getLast()); - } - } - // Get space the next space in the absolute order of addresses public AddrSpace getNextSpaceInOrder(AddrSpace spc) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/translate/XmlError.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/translate/XmlError.java deleted file mode 100644 index e59f41e6b5b..00000000000 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/translate/XmlError.java +++ /dev/null @@ -1,24 +0,0 @@ -/* ### - * IP: GHIDRA - * REVIEWED: YES - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.pcodeCPort.translate; - -public class XmlError extends RuntimeException { - public XmlError(String message) { - super(message); - } - -} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/utils/XmlUtils.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/utils/XmlUtils.java deleted file mode 100644 index 35ab75d3784..00000000000 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/utils/XmlUtils.java +++ /dev/null @@ -1,131 +0,0 @@ -/* ### - * IP: GHIDRA - * REVIEWED: YES - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.pcodeCPort.utils; - -import java.io.PrintStream; -import java.math.BigInteger; - -public class XmlUtils { - - private XmlUtils() { - // utils class - } - - public static void a_v( PrintStream s, String attr, String val ) { - s.append( ' ' ).append( attr ).append( "=\"" ); - xml_escape(s,val); - s.append( "\"" ); - } - - public static void a_v_i( PrintStream s, String attr, long val) { - s.append( ' ' ).append( attr ).append( "=\"" ); - s.append( Long.toString(val, 10) ).append( "\"" ); - } - - public static void a_v_u( PrintStream s, String attr, long val ) { - s.append( ' ' ).append( attr ).append( "=\"0x" ); - s.append( Long.toHexString(val) ).append( "\"" ); - } - - public static void a_v_b( PrintStream s, String attr, boolean val ) { - s.append( ' ' ).append( attr ).append( "=\"" ); - s.append( val ? "true" : "false" ).append( "\"" ); - } - public static boolean decodeBoolean(String boolString) { - if ((boolString == null)||(boolString.length()==0)) { - return false; - } - char firstc = boolString.charAt(0); - if (firstc == 't') return true; - if (firstc == '1') return true; - if (firstc == 'y') return true; - return false; - } - - public static int decodeUnknownInt( String intString ) { - if (intString == null) { - return 0; - } - - // special case - if ( "0".equals( intString ) ) { - return 0; - } - - BigInteger bi = null; - if ( intString.startsWith( "0x" ) ) { - bi = new BigInteger( intString.substring( 2 ), 16 ); - } - else if ( intString.startsWith( "0" ) ) { - bi = new BigInteger( intString.substring( 1 ), 8 ); - } - else { - bi = new BigInteger( intString, 10 ); - } - - return bi.intValue(); - } - - public static long decodeUnknownLong( String longString ) { - if (longString == null) { - return 0; - } - - // special case - if ( "0".equals( longString ) ) { - return 0; - } - - BigInteger bi = null; - if ( longString.startsWith( "0x" ) ) { - bi = new BigInteger( longString.substring( 2 ), 16 ); - } - else if ( longString.startsWith( "0" ) ) { - bi = new BigInteger( longString.substring( 1 ), 8 ); - } - else { - bi = new BigInteger( longString, 10 ); - } - - return bi.longValue(); - } - - // Escape xml tag indicators - public static void xml_escape( PrintStream s, String str ) { - for ( int i = 0; i < str.length(); i++ ) { - char c = str.charAt( i ); - if ( c == '<' ) { - s.append( "<" ); - } - else if ( c == '>' ) { - s.append( ">" ); - } - else if ( c == '"' ) { - s.append( """ ); - } - else if ( c == '\'' ) { - s.append( "'" ); - } - else if ( c == '&' ) { - s.append( "&" ); - } - else { - s.append( c ); - } - } - } -} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/xml/DocumentStorage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/xml/DocumentStorage.java deleted file mode 100644 index 9eecf2fc49d..00000000000 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/xml/DocumentStorage.java +++ /dev/null @@ -1,71 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.pcodeCPort.xml; - -import java.io.*; - -import org.jdom.*; -import org.jdom.input.SAXBuilder; - -import generic.stl.*; -import ghidra.pcodeCPort.translate.XmlError; -import ghidra.util.xml.XmlUtilities; - -// Class for managing xml documents during initialization -public class DocumentStorage { - - VectorSTL doclist = new VectorSTL<>(); - MapSTL tagmap = new ComparableMapSTL(); - - public Document parseDocument(InputStream s) throws JDOMException, IOException { - SAXBuilder builder = XmlUtilities.createSecureSAXBuilder(false, false); - Document document = builder.build(s); - doclist.push_back(document); - return document; - } - - // Open and parse an XML file, return Document object - public Document openDocument(String filename) throws XmlError { - InputStream is = null; - try { - is = new FileInputStream(filename); - return parseDocument(is); - } - catch (Exception e) { - throw new XmlError("Unable to open xml document " + filename); - } - finally { - try { - if (is != null) { - is.close(); - } - } - catch (IOException e) { - } - } - } - - // Register a tag under its name - public void registerTag(Element el) { - tagmap.put(el.getName(), el); - } - - // Retrieve a registered tag by name - public Element getTag(String nm) { - return tagmap.get(nm); - } - -} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PcodeParser.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PcodeParser.java index 19d8622dd6f..8166b87ef8b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PcodeParser.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PcodeParser.java @@ -36,10 +36,10 @@ import ghidra.pcodeCPort.slgh_compile.*; import ghidra.pcodeCPort.slghsymbol.*; import ghidra.pcodeCPort.slghsymbol.EndSymbol; +import ghidra.pcodeCPort.slghsymbol.Next2Symbol; import ghidra.pcodeCPort.slghsymbol.OperandSymbol; import ghidra.pcodeCPort.slghsymbol.StartSymbol; import ghidra.pcodeCPort.space.*; -import ghidra.pcodeCPort.xml.DocumentStorage; import ghidra.program.model.address.*; import ghidra.sleigh.grammar.*; import ghidra.sleigh.grammar.SleighParser_SemanticParser.semantic_return; @@ -322,11 +322,6 @@ public PcodeTranslate(SleighLanguage language, long ubase) { } } - @Override - public void initialize(DocumentStorage store) { - // Unused - } - @Override public int printAssembly(PrintStream s, int size, Address baseaddr) { return 0; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/AttributeId.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/AttributeId.java index a82880f4682..aa3364e86cc 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/AttributeId.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/AttributeId.java @@ -171,7 +171,7 @@ public record AttributeId(String name, int id) { // space public static final AttributeId ATTRIB_BASE = new AttributeId("base", 89); - public static final AttributeId ATTRIB_DEADCODEDELAY = new AttributeId("deadcodedelay", 90); +// public static final AttributeId ATTRIB_DEADCODEDELAY = new AttributeId("deadcodedelay", 90); public static final AttributeId ATTRIB_DELAY = new AttributeId("delay", 91); public static final AttributeId ATTRIB_LOGICALSIZE = new AttributeId("logicalsize", 92); public static final AttributeId ATTRIB_PHYSICAL = new AttributeId("physical", 93); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ByteIngest.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ByteIngest.java index 4570e92d0a1..e10e8ede5a6 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ByteIngest.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ByteIngest.java @@ -32,20 +32,41 @@ public interface ByteIngest { * Open the ingester for receiving bytes. This establishes the description of the source of * the bytes and maximum number of bytes that can be read * @param max is the maximum number of bytes that can be read - * @param source is the description of the byte source + * @param desc is the description of the byte source */ - public void open(int max, String source); + public void open(int max, String desc); /** * Ingest bytes from the stream up to (and including) the first 0 byte. This can be called * multiple times to read in bytes in different chunks. - * An absolute limit is set on the number of bytes that can be ingested via the - * max parameter to a previous call to open(), otherwise an exception is thrown. + * An absolute limit is set on the number of bytes that can be ingested via the max parameter + * to a previous call to open(). If this limit is exceeded, an exception is thrown. + * @param inStream is the input stream to read from + * @throws IOException for errors reading from the stream + */ + public void ingestStreamToNextTerminator(InputStream inStream) throws IOException; + + /** + * Ingest bytes from the stream until the end of stream is encountered. + * An absolute limit is set on the number of bytes that can be ingested via the max parameter + * to a previous call to open(). If this limit is exceeded, an exception is thrown. * @param inStream is the input stream to read from * @throws IOException for errors reading from the stream */ public void ingestStream(InputStream inStream) throws IOException; + /** + * Ingest bytes directly from a byte array. + * If these bytes would cause the total number of bytes ingested to exceed + * the maximum (as set by the call to open()), an exception is thrown. + * This can be called multiple times to read in different chunks. + * @param byteArray is the array of bytes + * @param off is the index of the first byte to ingest + * @param sz is the number of bytes to ingest + * @throws IOException if the max number of bytes to ingest is exceeded + */ + public void ingestBytes(byte[] byteArray, int off, int sz) throws IOException; + /** * Formal indicator that ingesting of bytes is complete and processing can begin * @throws IOException for errors processing the underlying stream diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/CachedEncoder.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/CachedEncoder.java new file mode 100644 index 00000000000..2627feb4fc2 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/CachedEncoder.java @@ -0,0 +1,45 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.program.model.pcode; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * An Encoder that holds its bytes in memory (where they can possibly be edited) and + * can then finally write them all to an OutputStream via a call to writeTo() + */ +public interface CachedEncoder extends Encoder { + + /** + * Clear any state associated with the encoder + * The encoder should be ready to write a new document after this call. + */ + void clear(); + + /** + * The encoder is considered empty if the writeTo() method would output zero bytes + * @return true if there are no bytes in the encoder + */ + public boolean isEmpty(); + + /** + * Dump all the accumulated bytes in this encoder to the stream. + * @param stream is the output stream + * @throws IOException for errors during the write operation + */ + public void writeTo(OutputStream stream) throws IOException; +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/Decoder.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/Decoder.java index 73ed0a8812f..582c3c3c6fe 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/Decoder.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/Decoder.java @@ -37,6 +37,8 @@ public interface Decoder extends ByteIngest { public AddressFactory getAddressFactory(); + public void setAddressFactory(AddressFactory addrFactory); + /** * 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. @@ -243,6 +245,26 @@ public long readSignedIntegerExpectString(AttributeId attribId, String expect, l */ public AddressSpace readSpace(AttributeId attribId) throws DecoderException; + /** + * Parse the current attribute is a p-code opcode + * The last attribute, as returned by getNextAttributeId, is returned as an opcode. + * The opcode is one of the constants specified in {@link PcodeOp} + * @return the opcode associated with the current attribute + * @throws DecoderException if the expected value is not present + */ + public int readOpcode() throws DecoderException; + + /** + * Find the specific attribute in the current element and return it as an opcode + * Search attributes from the current element for a match to the given attribute id. + * Return this attribute as an opcode constant from {@link PcodeOp}. If there is no + * matching attribute id, an exception is thrown. Parse via getNextAttributeId is reset. + * @param attribId is the specific attribute id to match + * @return the opcode associated with the attribute + * @throws DecoderException if the expected value is not present + */ + public int readOpcode(AttributeId attribId) throws DecoderException; + /** * Skip parsing of the next element * The element skipped is the one that would be opened by the next call to openElement. diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/Encoder.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/Encoder.java index 08b185b6427..06fb59019bc 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/Encoder.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/Encoder.java @@ -16,7 +16,6 @@ package ghidra.program.model.pcode; import java.io.IOException; -import java.io.OutputStream; import ghidra.program.model.address.AddressSpace; @@ -35,12 +34,6 @@ */ public interface Encoder { - /** - * Clear any state associated with the encoder - * The encoder should be ready to write a new document after this call. - */ - void clear(); - /** * Begin a new element in the encoding * The element will have the given ElementId annotation and becomes the \e current element. @@ -116,15 +109,22 @@ public interface Encoder { void writeSpace(AttributeId attribId, AddressSpace spc) throws IOException; /** - * Dump all the accumulated bytes in this encoder to the stream. - * @param stream is the output stream - * @throws IOException for errors during the write operation + * Write an address space reference into the encoding. + * An address space identified by its name and unique index is associated with the given + * annotation and the current open element. + * @param attribId is the given annotation + * @param index is the unique index of the address space + * @param name is the name of the address space + * @throws IOException for errors in the underlying stream */ - public void writeTo(OutputStream stream) throws IOException; + void writeSpace(AttributeId attribId, int index, String name) throws IOException; /** - * The encoder is considered empty if the writeTo() method would output zero bytes - * @return true if there are no bytes in the encoder + * Write a p-code operation opcode into the encoding, associating it with the given + * annotation. The opcode is specified based on the constants defined in {@link PcodeOp}. + * @param attribId is the given annotation + * @param opcode is the opcode constant + * @throws IOException for errors in the underlying stream */ - public boolean isEmpty(); + void writeOpcode(AttributeId attribId, int opcode) throws IOException; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/LinkedByteBuffer.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/LinkedByteBuffer.java index 55c826a9c73..3180fff1aba 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/LinkedByteBuffer.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/LinkedByteBuffer.java @@ -18,56 +18,93 @@ import java.io.IOException; import java.io.InputStream; +/** + * A byte buffer that is stored as a linked list of pages. Each page holds BUFFER_SIZE bytes. + * A Position object acts as an iterator over the whole buffer. The buffer can be populated + * from a stream, either all at once or "as needed" when a Position object iterates past + * the current cached set of bytes. + */ public class LinkedByteBuffer { + /** + * An iterator into the byte buffer + */ public static class Position { - public ArrayIter seqIter; - public byte[] array; - public int current; + public LinkedByteBuffer buffer; // The buffer object + public ArrayIter seqIter; // Linked-list node of the current page + public byte[] array; // The byte data of the current page + public int current; // Position within page of current byte + /** + * Set this to be a copy of another Position + * @param pos is the Position being copied + */ public void copy(Position pos) { seqIter = pos.seqIter; array = pos.array; current = pos.current; } + /** + * Return the byte at the current Position. Do not advance the Position. + * @return the byte at this Position + */ public final byte getByte() { return array[current]; } + /** + * Lookahead exactly one byte, without advancing this Position + * @return the byte after the one at this Position + * @throws DecoderException if the end of stream is reached + */ public final byte getBytePlus1() throws DecoderException { int plus1 = current + 1; if (plus1 == array.length) { ArrayIter iter = seqIter.next; if (iter == null) { - throw new DecoderException("Unexpected end of stream"); + iter = buffer.readNextPage(seqIter); } return iter.array[0]; } return array[plus1]; } + /** + * Advance this Position by exactly one byte and return the next byte. + * @return the next byte + * @throws DecoderException if the end of stream is reached + */ public final byte getNextByte() throws DecoderException { byte res = array[current]; current += 1; if (current != array.length) { return res; } - seqIter = seqIter.next; - if (seqIter == null) { - throw new DecoderException("Unexpected end of stream"); + if (seqIter.next == null) { + seqIter = buffer.readNextPage(seqIter); + } + else { + seqIter = seqIter.next; } array = seqIter.array; current = 0; return res; } + /** + * Advance this Position by the specified number of bytes + * @param skip is the specified number of bytes to advance + * @throws DecoderException if the end of stream is reached + */ public final void advancePosition(int skip) throws DecoderException { while (array.length - current <= skip) { skip -= (array.length - current); - seqIter = seqIter.next; - if (seqIter == null) { - throw new DecoderException("Unexpected end of stream"); + if (seqIter.next == null) { + seqIter = buffer.readNextPage(seqIter); + } + else { + seqIter = seqIter.next; } array = seqIter.array; current = 0; @@ -76,39 +113,78 @@ public final void advancePosition(int skip) throws DecoderException { } } + /** + * A linked-list page node + */ public static class ArrayIter { - public ArrayIter next; - public byte[] array; + public ArrayIter next; // The next-node in the list + public byte[] array; // Byte data contained in this page } public final static int BUFFER_SIZE = 1024; - private ArrayIter initialBuffer; - private int byteCount; - private int maxCount; - private ArrayIter currentBuffer; - private int currentPos; - private String source; + private ArrayIter initialBuffer; // The initial page in the linked list + private int byteCount; // Total number of bytes cached + private int maxCount; // Maximum bytes that can be cached + private ArrayIter currentBuffer; // Last page in the linked list + private int currentPos; // Last byte successfully cached in last page + private int padValue; // Padding data + private InputStream asNeededStream = null; // If non-null, a stream that is read as needed + private String description; // Describes source of bytes for use in error messages - public LinkedByteBuffer(int max, String src) { + public LinkedByteBuffer(int max, int pad, String desc) { initialBuffer = new ArrayIter(); currentBuffer = initialBuffer; byteCount = 0; currentPos = 0; + padValue = pad; maxCount = max; initialBuffer.array = new byte[BUFFER_SIZE]; initialBuffer.next = null; - source = src; + description = desc; } - public void ingestStream(InputStream stream) throws IOException { + /** + * Close the "as needed" stream, if configure. + * @throws IOException for problems closing the stream + */ + public void close() throws IOException { + if (asNeededStream != null) { + asNeededStream.close(); + } + } + + /** + * Set up this buffer so that it reads in pages as needed. The initial page is read + * immediately. Additional pages are read via readNextPage() through the Position methods. + * @param stream is the stream to read from + * @param start will hold the initial buffer + * @throws IOException for problems reading data from the stream + */ + public void ingestStreamAsNeeded(InputStream stream, Position start) throws IOException { + asNeededStream = stream; + currentPos = readPage(stream, initialBuffer); + if (currentPos < BUFFER_SIZE) { + pad(); + } + getStartPosition(start); + initialBuffer = null; // Let garbage collection pick up pages that are already parsed + } + + /** + * Ingest stream up to the first 0 byte or until maxCount bytes is reached. + * Store the bytes on the heap in BUFFER_SIZE chunks. + * @param stream is the input + * @throws IOException for errors reading from the stream + */ + public void ingestStreamToNextTerminator(InputStream stream) throws IOException { int tok = stream.read(); if (tok <= 0) { return; } for (;;) { if (byteCount > maxCount) { - throw new IOException("Response buffer size exceded for: " + source); + throw new IOException("Response buffer size exceded for: " + description); } do { if (currentPos == BUFFER_SIZE) { @@ -131,10 +207,85 @@ public void ingestStream(InputStream stream) throws IOException { } /** - * Add a particular byte to the buffer - * @param val is the byte value to add + * Read a page of data into the given buffer. The buffer must already be allocated and + * will be entirely filled, unless end-of-stream is reached. The number of bytes + * actually read into the buffer is returned. + * @param stream is the stream + * @param buffer is the allocated buffer + * @return the number of bytes read + * @throws IOException for problems reading from the stream + */ + private int readPage(InputStream stream, ArrayIter buffer) throws IOException { + int len = maxCount - byteCount; + if (len > BUFFER_SIZE) { + len = BUFFER_SIZE; + } + int pos = 0; + do { + int readLen = stream.read(currentBuffer.array, pos, len - pos); + if (readLen < 0) { + break; + } + pos += readLen; + } + while (pos < len); + byteCount += pos; + return pos; + } + + /** + * Read the stream until the end of stream is encountered or until maxCount bytes is reached. + * Store the bytes on the heap in BUFFER_SIZE chunks. + * @param stream is the input + * @throws IOException for errors reading from the stream */ - public void pad(int val) { + public void ingestStream(InputStream stream) throws IOException { + while (byteCount < maxCount) { + int pos = readPage(stream, currentBuffer); + if (pos < BUFFER_SIZE) { + currentPos += pos; + break; + } + // Set up next buffer + currentBuffer.next = new ArrayIter(); + currentBuffer = currentBuffer.next; + currentBuffer.array = new byte[BUFFER_SIZE]; + currentPos = 0; + } + } + + /** + * Ingest bytes directly from a byte array. + * If these bytes would cause the total number of bytes ingested to exceed + * the maximum (maxCount) bytes set for this buffer, an exception is thrown. + * This can be called multiple times to read in different chunks. + * @param byteArray is the array of bytes + * @param off is the index of the first byte to ingest + * @param sz is the number of bytes to ingest + * @throws IOException if the max number of bytes to ingest is exceeded + */ + public void ingestBytes(byte[] byteArray, int off, int sz) throws IOException { + for (int i = 0; i < sz; ++i) { + byte tok = byteArray[off + i]; + if (currentPos == BUFFER_SIZE) { + // Set up next buffer + currentBuffer.next = new ArrayIter(); + currentBuffer = currentBuffer.next; + currentBuffer.array = new byte[BUFFER_SIZE]; + currentPos = 0; + } + currentBuffer.array[currentPos++] = tok; + byteCount += 1; + if (byteCount > maxCount) { + throw new IOException("Response buffer size exceded for: " + description); + } + } + } + + /** + * Add the padValue to the end of the buffer + */ + public void pad() { if (currentPos == BUFFER_SIZE) { byteCount += currentPos; currentBuffer.next = new ArrayIter(); @@ -143,7 +294,7 @@ public void pad(int val) { currentPos = 0; } - currentBuffer.array[currentPos++] = (byte) val; + currentBuffer.array[currentPos++] = (byte) padValue; } public void getStartPosition(Position position) { @@ -151,4 +302,31 @@ public void getStartPosition(Position position) { position.current = 0; position.seqIter = initialBuffer; } + + /** + * Read the next page of data. The new ArrayIter is added to the linked list, its + * byte buffer is allocated, and data is read into the buffer. + * If the end of stream is reached, padding is added. + * @param buffer is the ArrayIter currently at the end of the linked list + * @return the newly allocated ArrayIter + * @throws DecoderException if there are errors reading from the stream + */ + private ArrayIter readNextPage(ArrayIter buffer) throws DecoderException { + if (asNeededStream == null) { + throw new DecoderException("Unexpected end of stream"); + } + currentBuffer = new ArrayIter(); + buffer.next = currentBuffer; + currentBuffer.array = new byte[BUFFER_SIZE]; + try { + currentPos = readPage(asNeededStream, currentBuffer); + } + catch (IOException e) { + throw new DecoderException(e.getMessage()); + } + if (currentPos < BUFFER_SIZE) { + pad(); + } + return buffer.next; + } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PackedBytes.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PackedBytes.java index 6dbde2b3c08..e026a60b204 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PackedBytes.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PackedBytes.java @@ -24,10 +24,7 @@ * It allows the bytes to be edited in the middle of collection * */ -/** - * - */ -public class PackedBytes { +public class PackedBytes extends OutputStream { private byte[] out; private int bytecnt; @@ -62,6 +59,7 @@ public void insertByte(int streampos, int val) { * Dump a single byte to the packed byte stream * @param val is the byte to be written */ + @Override public void write(int val) { int newcount = bytecnt + 1; if (newcount > out.length) { @@ -75,12 +73,13 @@ public void write(int val) { * Dump an array of bytes to the packed byte stream * @param byteArray is the byte array */ - public void write(byte[] byteArray) { - int newcount = bytecnt + byteArray.length; + @Override + public void write(byte[] byteArray, int off, int len) { + int newcount = bytecnt + len; if (newcount > out.length) { out = Arrays.copyOf(out, Math.max(out.length << 1, newcount)); } - System.arraycopy(byteArray, 0, out, bytecnt, byteArray.length); + System.arraycopy(byteArray, off, out, bytecnt, len); bytecnt = newcount; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PackedDecode.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PackedDecode.java index a5d47ac964b..13df7a0d206 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PackedDecode.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PackedDecode.java @@ -84,6 +84,18 @@ public class PackedDecode implements Decoder { private LinkedByteBuffer.Position endPos; private boolean attributeRead; + /** + * Constructor for formats that do not use the readSpace() methods or use + * setAddressFactory() in the middle of decoding + */ + public PackedDecode() { + addrFactory = null; + inStream = null; + startPos = new LinkedByteBuffer.Position(); + curPos = new LinkedByteBuffer.Position(); + endPos = new LinkedByteBuffer.Position(); + } + public PackedDecode(AddressFactory addrFactory) { this.addrFactory = addrFactory; inStream = null; @@ -93,6 +105,28 @@ public PackedDecode(AddressFactory addrFactory) { buildAddrSpaceArray(); } + /** + * Build a decoder for an input stream, where the decoder is set to read pages from the stream + * "as needed". An initial page is read from the stream by this constructor. But then + * the stream must remain open and additional pages are read during the decoding process. + * Calling close() after decoding, will close the underlying stream. + * @param stream is the stream + * @param desc is a descriptive string for the stream used in error messages + * @throws IOException for problems initially reading from the stream + */ + public PackedDecode(InputStream stream, String desc) throws IOException { + addrFactory = null; + inStream = null; + startPos = new LinkedByteBuffer.Position(); + curPos = new LinkedByteBuffer.Position(); + endPos = new LinkedByteBuffer.Position(); + open(Integer.MAX_VALUE, desc); + startPos.buffer = inStream; + curPos.buffer = inStream; + endPos.buffer = inStream; + inStream.ingestStreamAsNeeded(stream, endPos); + } + private void buildAddrSpaceArray() { ArrayList spaceList = new ArrayList<>(); AddressSpace[] allSpaces = addrFactory.getAllAddressSpaces(); @@ -177,14 +211,34 @@ public AddressFactory getAddressFactory() { return addrFactory; } + @Override + public void setAddressFactory(AddressFactory addrFactory) { + this.addrFactory = addrFactory; + buildAddrSpaceArray(); + } + @Override public void clear() { inStream = null; } @Override - public void open(int max, String source) { - inStream = new LinkedByteBuffer(max, source); + public void open(int max, String desc) { + inStream = new LinkedByteBuffer(max, ELEMENT_END, desc); + } + + /** + * Close stream cached by the ingestStreamAsNeeded method. + * @throws IOException for low-level problems with the stream + */ + public void close() throws IOException { + inStream.close(); + inStream = null; + } + + @Override + public void ingestStreamToNextTerminator(InputStream stream) throws IOException { + inStream.ingestStreamToNextTerminator(stream); } @Override @@ -192,9 +246,14 @@ public void ingestStream(InputStream stream) throws IOException { inStream.ingestStream(stream); } + @Override + public void ingestBytes(byte[] byteArray, int off, int sz) throws IOException { + inStream.ingestBytes(byteArray, off, sz); + } + @Override public void endIngest() { - inStream.pad(ELEMENT_END); + inStream.pad(); inStream.getStartPosition(endPos); } @@ -380,6 +439,7 @@ public long readSignedIntegerExpectString(String expect, long expectval) throws DecoderException { long res; LinkedByteBuffer.Position tmpPos = new LinkedByteBuffer.Position(); + tmpPos.buffer = inStream; tmpPos.copy(curPos); byte header1 = tmpPos.getNextByte(); if ((header1 & HEADEREXTEND_MASK) != 0) { @@ -538,4 +598,20 @@ public AddressSpace readSpace(AttributeId attribId) throws DecoderException { return res; } + @Override + public int readOpcode() throws DecoderException { + int val = (int) readSignedInteger(); + if (val < 0 || val >= PcodeOp.PCODE_MAX) { + throw new DecoderException("Bad OpCode"); + } + return val; + } + + @Override + public int readOpcode(AttributeId attribId) throws DecoderException { + findMatchingAttribute(attribId); + int opcode = readOpcode(); + curPos.copy(startPos); + return opcode; + } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PackedEncode.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PackedEncode.java index 08bb39de21b..ca07bd44c4f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PackedEncode.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PackedEncode.java @@ -26,10 +26,10 @@ * A byte-based encoder designed to marshal to the decompiler efficiently * See {@code PackedDecode} for details of the encoding format */ -public class PackedEncode implements PatchEncoder { - private PackedBytes outStream; +public class PackedEncode implements Encoder { + protected OutputStream outStream; - private void writeHeader(int header, int id) { + protected void writeHeader(int header, int id) throws IOException { if (id > 0x1f) { header |= HEADEREXTEND_MASK; header |= (id >> RAWDATA_BITSPERBYTE); @@ -43,7 +43,7 @@ private void writeHeader(int header, int id) { } } - private void writeInteger(int typeByte, long val) { + protected void writeInteger(int typeByte, long val) throws IOException { byte lenCode; int sa; if (val <= 0) { @@ -113,9 +113,8 @@ public PackedEncode() { outStream = null; } - @Override - public void clear() { - outStream = new PackedBytes(512); + public PackedEncode(OutputStream stream) { + outStream = stream; } @Override @@ -196,106 +195,21 @@ public void writeSpace(AttributeId attribId, AddressSpace spc) throws IOExceptio } @Override - public void writeTo(OutputStream stream) throws IOException { - outStream.writeTo(stream); - } - - @Override - public boolean isEmpty() { - return (outStream.size() == 0); - } - - @Override - public int size() { - return outStream.size(); + public void writeSpace(AttributeId attribId, int index, String name) throws IOException { + writeHeader(ATTRIBUTE, attribId.id()); + writeInteger((TYPECODE_ADDRESSSPACE << TYPECODE_SHIFT), index); } @Override - public void writeSpaceId(AttributeId attribId, long spaceId) { + public void writeOpcode(AttributeId attribId, int opcode) throws IOException { writeHeader(ATTRIBUTE, attribId.id()); - int uniqueId = (int) spaceId >> AddressSpace.ID_UNIQUE_SHIFT; - writeInteger((TYPECODE_ADDRESSSPACE << TYPECODE_SHIFT), uniqueId); + writeInteger((TYPECODE_SIGNEDINT_POSITIVE << TYPECODE_SHIFT), opcode); } /** - * Return the position after the open element directive at the given position. - * @param pos is the given position - * @return the next position or -1 if the current byte is not an open directive + * @return the underlying stream */ - private int skipOpen(int pos) { - int val = outStream.getByte(pos) & (HEADER_MASK | HEADEREXTEND_MASK); - if (val == ELEMENT_START) { - return pos + 1; - } - else if (val == (ELEMENT_START | HEADEREXTEND_MASK)) { - return pos + 2; - } - return -1; - } - - /** - * Read the integer at the given position. - * @param pos is the given position - * @param len is the length of the integer in 7-bit bytes - * @return the integer - */ - private long readInteger(int pos, int len) { - long res = 0; - while (len > 0) { - res <<= RAWDATA_BITSPERBYTE; - res |= (outStream.getByte(pos) & RAWDATA_MASK); - pos += 1; - len -= 1; - } - return res; - } - - @Override - public boolean patchIntegerAttribute(int pos, AttributeId attribId, long val) { - int typeByte; - int length; - - pos = skipOpen(pos); - if (pos < 0) { - return false; - } - for (;;) { - int header1 = outStream.getByte(pos); // Attribute header - if ((header1 & HEADER_MASK) != ATTRIBUTE) { - return false; - } - pos += 1; - int curid = header1 & ELEMENTID_MASK; - if ((header1 & HEADEREXTEND_MASK) != 0) { - curid <<= RAWDATA_BITSPERBYTE; - curid |= outStream.getByte(pos) & RAWDATA_MASK; - pos += 1; // Extra byte for extended id - } - typeByte = outStream.getByte(pos) & 0xff; // Type (and length) byte - pos += 1; - int attribType = typeByte >> TYPECODE_SHIFT; - if (attribType == TYPECODE_BOOLEAN || attribType == TYPECODE_SPECIALSPACE) { - continue; // has no additional data - } - length = typeByte & LENGTHCODE_MASK; // Length of data in bytes - if (attribType == TYPECODE_STRING) { // For a string - length = (int) readInteger(pos, length); // Read length field to get final length of string - } - if (attribId.id() == curid) { - break; - } - pos += length; // Skip -length- data - } - if (length != 10) { - return false; - } - - for (int sa = 9 * RAWDATA_BITSPERBYTE; sa >= 0; sa -= RAWDATA_BITSPERBYTE) { - long piece = (val >>> sa) & RAWDATA_MASK; - piece |= RAWDATA_MARKER; - outStream.insertByte(pos, (int) piece); - pos += 1; - } - return true; + public OutputStream getOutputStream() { + return outStream; } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PackedEncodeOverlay.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PackedEncodeOverlay.java index f8f4afef374..e2b616e3f12 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PackedEncodeOverlay.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PackedEncodeOverlay.java @@ -24,7 +24,7 @@ * Any space that matches the overlay space is encoded as the overlayed space. * This causes addresses in the overlay space to be converted into the underlying space. */ -public class PackedEncodeOverlay extends PackedEncode { +public class PackedEncodeOverlay extends PatchPackedEncode { private OverlayAddressSpace overlay = null; private int overlayId; // Id of the overlay space private int underlyingId; // If of the space underlying the overlay @@ -53,7 +53,7 @@ public void writeSpace(AttributeId attribId, AddressSpace spc) throws IOExceptio } @Override - public void writeSpaceId(AttributeId attribId, long spaceId) { + public void writeSpaceId(AttributeId attribId, long spaceId) throws IOException { if (spaceId == overlayId) { spaceId = underlyingId; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PatchEncoder.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PatchEncoder.java index 86f27755bc3..3cedb4e093e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PatchEncoder.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PatchEncoder.java @@ -15,6 +15,8 @@ */ package ghidra.program.model.pcode; +import java.io.IOException; + /** * This is an encoder that produces encodings that can be retroactively patched. * The contained encoding is expected to be byte based. The user can record a position @@ -22,7 +24,7 @@ * use the returned offset to call the patchIntegerAttribute() method and modify the * encoding at the recorded position. */ -public interface PatchEncoder extends Encoder { +public interface PatchEncoder extends CachedEncoder { /** * Write a given raw spaceid (as returned by AddressSpace.getSpaceID()) as an attribute. @@ -30,8 +32,9 @@ public interface PatchEncoder extends Encoder { * the spaceid, i.e. the decoder will read this as just space attribute. * @param attribId is the attribute * @param spaceId is the given spaceid + * @throws IOException for problems writing to the stream */ - public void writeSpaceId(AttributeId attribId, long spaceId); + public void writeSpaceId(AttributeId attribId, long spaceId) throws IOException; /** * The returned value can be used as a position for later modification diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PatchPackedEncode.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PatchPackedEncode.java new file mode 100644 index 00000000000..867459b65b4 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PatchPackedEncode.java @@ -0,0 +1,143 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.program.model.pcode; + +import static ghidra.program.model.pcode.PackedDecode.*; + +import java.io.IOException; +import java.io.OutputStream; + +import ghidra.program.model.address.AddressSpace; + +public class PatchPackedEncode extends PackedEncode implements PatchEncoder { + + private PackedBytes editStream; + + public PatchPackedEncode() { + editStream = null; + } + + @Override + public int size() { + return editStream.size(); + } + + @Override + public void writeSpaceId(AttributeId attribId, long spaceId) throws IOException { + writeHeader(ATTRIBUTE, attribId.id()); + int uniqueId = (int) spaceId >> AddressSpace.ID_UNIQUE_SHIFT; + writeInteger((TYPECODE_ADDRESSSPACE << TYPECODE_SHIFT), uniqueId); + } + + /** + * Return the position after the open element directive at the given position. + * @param pos is the given position + * @return the next position or -1 if the current byte is not an open directive + */ + private int skipOpen(int pos) { + int val = editStream.getByte(pos) & (HEADER_MASK | HEADEREXTEND_MASK); + if (val == ELEMENT_START) { + return pos + 1; + } + else if (val == (ELEMENT_START | HEADEREXTEND_MASK)) { + return pos + 2; + } + return -1; + } + + /** + * Read the integer at the given position. + * @param pos is the given position + * @param len is the length of the integer in 7-bit bytes + * @return the integer + */ + private long readInteger(int pos, int len) { + long res = 0; + while (len > 0) { + res <<= RAWDATA_BITSPERBYTE; + res |= (editStream.getByte(pos) & RAWDATA_MASK); + pos += 1; + len -= 1; + } + return res; + } + + @Override + public boolean patchIntegerAttribute(int pos, AttributeId attribId, long val) { + int typeByte; + int length; + + pos = skipOpen(pos); + if (pos < 0) { + return false; + } + for (;;) { + int header1 = editStream.getByte(pos); // Attribute header + if ((header1 & HEADER_MASK) != ATTRIBUTE) { + return false; + } + pos += 1; + int curid = header1 & ELEMENTID_MASK; + if ((header1 & HEADEREXTEND_MASK) != 0) { + curid <<= RAWDATA_BITSPERBYTE; + curid |= editStream.getByte(pos) & RAWDATA_MASK; + pos += 1; // Extra byte for extended id + } + typeByte = editStream.getByte(pos) & 0xff; // Type (and length) byte + pos += 1; + int attribType = typeByte >> TYPECODE_SHIFT; + if (attribType == TYPECODE_BOOLEAN || attribType == TYPECODE_SPECIALSPACE) { + continue; // has no additional data + } + length = typeByte & LENGTHCODE_MASK; // Length of data in bytes + if (attribType == TYPECODE_STRING) { // For a string + length = (int) readInteger(pos, length); // Read length field to get final length of string + } + if (attribId.id() == curid) { + break; + } + pos += length; // Skip -length- data + } + if (length != 10) { + return false; + } + + for (int sa = 9 * RAWDATA_BITSPERBYTE; sa >= 0; sa -= RAWDATA_BITSPERBYTE) { + long piece = (val >>> sa) & RAWDATA_MASK; + piece |= RAWDATA_MARKER; + editStream.insertByte(pos, (int) piece); + pos += 1; + } + return true; + } + + @Override + public void clear() { + editStream = new PackedBytes(512); + outStream = editStream; + } + + @Override + public boolean isEmpty() { + return (editStream.size() == 0); + } + + @Override + public void writeTo(OutputStream stream) throws IOException { + editStream.writeTo(stream); + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/StringIngest.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/StringIngest.java index d61661490ea..20183dd05ee 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/StringIngest.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/StringIngest.java @@ -20,38 +20,50 @@ public class StringIngest implements ByteIngest { private ByteArrayOutputStream outStream; - private String source; - private int maxBytes; + private String description; // Describes the source of bytes, for use in error messages + private int maxBytes; // Maximum number of bytes that can be ingested public StringIngest() { outStream = null; - source = null; + description = null; maxBytes = 0; } - public StringIngest(int max, String src) { - open(max, src); - } - @Override - public void open(int max, String src) { + public void open(int max, String desc) { maxBytes = max; - source = src; + description = desc; outStream = new ByteArrayOutputStream(); } @Override - public void ingestStream(InputStream inStream) throws IOException { + public void ingestStreamToNextTerminator(InputStream inStream) throws IOException { int tok = inStream.read(); while (tok > 0) { outStream.write(tok); if (outStream.size() >= maxBytes) { - throw new IOException("Buffer size exceeded: " + source); + throw new IOException("Buffer size exceeded: " + description); } tok = inStream.read(); } } + @Override + public void ingestStream(InputStream inStream) throws IOException { + throw new IOException("Not supported"); + } + + @Override + public void ingestBytes(byte[] byteArray, int off, int sz) throws IOException { + for (int i = 0; i < sz; ++i) { + int tok = byteArray[off + i]; + outStream.write(tok); + if (outStream.size() >= maxBytes) { + throw new IOException("Buffer size exceeded: " + description); + } + } + } + @Override public void endIngest() { // Nothing needs to be done @@ -60,7 +72,7 @@ public void endIngest() { @Override public void clear() { outStream = null; - source = null; + description = null; } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/XmlEncode.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/XmlEncode.java index 34a0fa2cc32..798e7251507 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/XmlEncode.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/XmlEncode.java @@ -29,14 +29,42 @@ * The encoder is initialized with a StringBuilder which will receive the XML document as calls * are made on the encoder. */ -public class XmlEncode implements Encoder { +public class XmlEncode implements CachedEncoder { - private StringBuilder buffer; - private boolean elementTagIsOpen; + private static final int TAG_START = 0; // Tag has been opened, attributes can be written + private static final int TAG_CONTENT = 1; // Opening tag and content have been written + private static final int TAG_STOP = 2; // No tag is currently being written + + private static final char[] spaces = { '\n', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', + ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }; + private StringBuilder buffer; // Buffer accumulating the document characters + private int tagStatus; // Stage of writing an element tag + private int depth; // Depth of open elements + private boolean doFormatting; // true if encoder should indent and emit newlines public XmlEncode() { buffer = new StringBuilder(); - elementTagIsOpen = false; + tagStatus = TAG_STOP; + depth = 0; + doFormatting = true; + } + + public XmlEncode(boolean doFormat) { + buffer = new StringBuilder(); + tagStatus = TAG_STOP; + depth = 0; + doFormatting = doFormat; + } + + private void newLine() { + if (!doFormatting) { + return; + } + int numSpaces = depth * 2 + 1; + if (numSpaces > spaces.length) { + numSpaces = spaces.length; + } + buffer.append(spaces, 0, numSpaces); } @Override @@ -47,42 +75,51 @@ public String toString() { @Override public void clear() { buffer = new StringBuilder(); - elementTagIsOpen = false; + tagStatus = TAG_STOP; + depth = 0; } @Override public void openElement(ElementId elemId) throws IOException { - if (elementTagIsOpen) { + if (tagStatus == TAG_START) { buffer.append('>'); } else { - elementTagIsOpen = true; + tagStatus = TAG_START; } + newLine(); buffer.append('<'); buffer.append(elemId.name()); + depth += 1; } @Override public void closeElement(ElementId elemId) throws IOException { - if (elementTagIsOpen) { + depth -= 1; + if (tagStatus == TAG_START) { buffer.append("/>"); - elementTagIsOpen = false; + tagStatus = TAG_STOP; + return; + } + if (tagStatus != TAG_CONTENT) { + newLine(); } else { - buffer.append("'); + tagStatus = TAG_STOP; } + buffer.append("'); } @Override public void writeBool(AttributeId attribId, boolean val) throws IOException { if (attribId == ATTRIB_CONTENT) { // Special id indicating, text value - if (elementTagIsOpen) { + if (tagStatus == TAG_START) { buffer.append('>'); - elementTagIsOpen = false; } buffer.append(val ? "true" : "false"); + tagStatus = TAG_CONTENT; return; } buffer.append(' '); @@ -95,11 +132,11 @@ public void writeBool(AttributeId attribId, boolean val) throws IOException { @Override public void writeSignedInteger(AttributeId attribId, long val) throws IOException { if (attribId == ATTRIB_CONTENT) { // Special id indicating, text value - if (elementTagIsOpen) { + if (tagStatus == TAG_START) { buffer.append('>'); - elementTagIsOpen = false; } buffer.append(Long.toString(val, 10)); + tagStatus = TAG_CONTENT; return; } buffer.append(' '); @@ -112,12 +149,12 @@ public void writeSignedInteger(AttributeId attribId, long val) throws IOExceptio @Override public void writeUnsignedInteger(AttributeId attribId, long val) throws IOException { if (attribId == ATTRIB_CONTENT) { // Special id indicating, text value - if (elementTagIsOpen) { + if (tagStatus == TAG_START) { buffer.append('>'); - elementTagIsOpen = false; } buffer.append("0x"); buffer.append(Long.toHexString(val)); + tagStatus = TAG_CONTENT; return; } buffer.append(' '); @@ -130,11 +167,11 @@ public void writeUnsignedInteger(AttributeId attribId, long val) throws IOExcept @Override public void writeString(AttributeId attribId, String val) throws IOException { if (attribId == ATTRIB_CONTENT) { // Special id indicating, text value - if (elementTagIsOpen) { + if (tagStatus == TAG_START) { buffer.append('>'); - elementTagIsOpen = false; } SpecXmlUtils.xmlEscape(buffer, val); + tagStatus = TAG_CONTENT; return; } buffer.append(' '); @@ -164,11 +201,11 @@ public void writeSpace(AttributeId attribId, AddressSpace spc) throws IOExceptio spcName = spc.getName(); } if (attribId == ATTRIB_CONTENT) { // Special id indicating, text value - if (elementTagIsOpen) { + if (tagStatus == TAG_START) { buffer.append('>'); - elementTagIsOpen = false; } SpecXmlUtils.xmlEscape(buffer, spcName); + tagStatus = TAG_CONTENT; return; } buffer.append(' '); @@ -178,6 +215,41 @@ public void writeSpace(AttributeId attribId, AddressSpace spc) throws IOExceptio buffer.append("\""); } + @Override + public void writeSpace(AttributeId attribId, int index, String name) throws IOException { + if (attribId == ATTRIB_CONTENT) { + if (tagStatus == TAG_START) { + buffer.append('>'); + } + SpecXmlUtils.xmlEscape(buffer, name); + tagStatus = TAG_CONTENT; + return; + } + buffer.append(' '); + buffer.append(attribId.name()); + buffer.append("=\""); + SpecXmlUtils.xmlEscape(buffer, name); + buffer.append("\""); + } + + @Override + public void writeOpcode(AttributeId attribId, int opcode) throws IOException { + String name = PcodeOp.getMnemonic(opcode); + if (attribId == ATTRIB_CONTENT) { + if (tagStatus == TAG_START) { + buffer.append('>'); + } + buffer.append(name); + tagStatus = TAG_CONTENT; + return; + } + buffer.append(' '); + buffer.append(attribId.name()); + buffer.append("=\""); + buffer.append(name); + buffer.append("\""); + } + @Override public void writeTo(OutputStream stream) throws IOException { byte[] res = buffer.toString().getBytes(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/sleigh/grammar/SourceFileIndexer.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/sleigh/grammar/SourceFileIndexer.java index 00fea56d760..9491980e33e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/sleigh/grammar/SourceFileIndexer.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/sleigh/grammar/SourceFileIndexer.java @@ -15,15 +15,15 @@ */ package ghidra.sleigh.grammar; -import java.io.PrintStream; +import static ghidra.pcode.utils.SlaFormat.*; + +import java.io.IOException; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; -import ghidra.pcodeCPort.utils.XmlUtils; +import ghidra.program.model.pcode.*; import ghidra.util.Msg; -import ghidra.xml.XmlElement; -import ghidra.xml.XmlPullParser; /** * This class is used to index source files in a SLEIGH language module. @@ -86,33 +86,36 @@ public String getFileName(Integer index) { } /** - * Save the index as XML - * @param s stream to write to + * Encode the index to a stream + * @param encoder stream to write to + * @throws IOException for errors writing to the stream */ - public void saveXml(PrintStream s) { - s.append("\n"); + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_SOURCEFILES); for (int i = 0; i < leastUnusedIndex; ++i) { - s.append("\n"); + encoder.openElement(ELEM_SOURCEFILE); + encoder.writeString(ATTRIB_NAME, filenameToIndex.inverse().get(i)); + encoder.writeSignedInteger(ATTRIB_INDEX, i); + encoder.closeElement(ELEM_SOURCEFILE); } - s.append("\n"); + encoder.closeElement(ELEM_SOURCEFILES); } /** - * Restore an index saved as to XML - * @param parser xml parser + * Decode an index from a stream + * @param decoder is the stream + * @throws DecoderException for errors in the encoding */ - public void restoreXml(XmlPullParser parser) { - XmlElement elem = parser.start("sourcefiles"); - XmlElement subElem = null; - while ((subElem = parser.softStart("sourcefile")) != null) { - String filename = subElem.getAttribute("name"); - Integer index = Integer.parseInt(subElem.getAttribute("index")); + public void decode(Decoder decoder) throws DecoderException { + int elem = decoder.openElement(ELEM_SOURCEFILES); + while (decoder.peekElement() == ELEM_SOURCEFILE.id()) { + decoder.openElement(); + String filename = decoder.readString(ATTRIB_NAME); + int index = (int) decoder.readSignedInteger(ATTRIB_INDEX); filenameToIndex.put(filename, index); - parser.end(subElem); + decoder.closeElement(ELEM_SOURCEFILE.id()); } - parser.end(elem); + decoder.closeElement(elem); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/app/plugin/assembler/sleigh/SolverTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/app/plugin/assembler/sleigh/SolverTest.java index 478a553c875..fce092d2dda 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/app/plugin/assembler/sleigh/SolverTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/app/plugin/assembler/sleigh/SolverTest.java @@ -15,13 +15,15 @@ */ package ghidra.app.plugin.assembler.sleigh; +import static ghidra.pcode.utils.SlaFormat.*; import static org.junit.Assert.*; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.util.Collections; import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; -import org.xml.sax.SAXException; import ghidra.GhidraApplicationLayout; import ghidra.app.plugin.assembler.sleigh.expr.*; @@ -37,9 +39,8 @@ import ghidra.framework.Application; import ghidra.framework.ApplicationConfiguration; import ghidra.program.model.lang.LanguageID; +import ghidra.program.model.pcode.*; import ghidra.util.Msg; -import ghidra.xml.XmlPullParser; -import ghidra.xml.XmlPullParserFactory; public class SolverTest { static final DefaultAssemblyResolutionFactory FACTORY = new DefaultAssemblyResolutionFactory(); @@ -164,24 +165,54 @@ public int getWordIndex() { } @Test - public void testCatOrSolver() throws SAXException, NeedsBackfillException { - XmlPullParser parser = XmlPullParserFactory.create(""" - - - - - - - - """, - "Test", null, true); - PatternExpression exp = PatternExpression.restoreExpression(parser, null); + public void testCatOrSolver() throws NeedsBackfillException, DecoderException, IOException { + PatchPackedEncode encode = new PatchPackedEncode(); + encode.clear(); + encode.openElement(ELEM_OR_EXP); + encode.openElement(ELEM_LSHIFT_EXP); + encode.openElement(ELEM_TOKENFIELD); + encode.writeBool(ATTRIB_BIGENDIAN, false); + encode.writeBool(ATTRIB_SIGNBIT, false); + encode.writeSignedInteger(ATTRIB_STARTBIT, 0); + encode.writeSignedInteger(ATTRIB_ENDBIT, 3); + encode.writeSignedInteger(ATTRIB_STARTBYTE, 0); + encode.writeSignedInteger(ATTRIB_ENDBYTE, 0); + encode.writeSignedInteger(ATTRIB_SHIFT, 0); + encode.closeElement(ELEM_TOKENFIELD); + encode.openElement(ELEM_INTB); + encode.writeSignedInteger(ATTRIB_VAL, 4); + encode.closeElement(ELEM_INTB); + encode.closeElement(ELEM_LSHIFT_EXP); + encode.openElement(ELEM_TOKENFIELD); + encode.writeBool(ATTRIB_BIGENDIAN, false); + encode.writeBool(ATTRIB_SIGNBIT, false); + encode.writeSignedInteger(ATTRIB_STARTBIT, 0); + encode.writeSignedInteger(ATTRIB_ENDBIT, 11); + encode.writeSignedInteger(ATTRIB_STARTBYTE, 1); + encode.writeSignedInteger(ATTRIB_ENDBYTE, 1); + encode.writeSignedInteger(ATTRIB_SHIFT, 0); + encode.closeElement(ELEM_TOKENFIELD); + encode.closeElement(ELEM_OR_EXP); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + encode.writeTo(outStream); + byte[] bytes = outStream.toByteArray(); + PackedDecode decoder = new PackedDecode(); + decoder.open(1024, "Test"); + decoder.ingestBytes(bytes, 0, bytes.length); + decoder.endIngest(); +// +// +// +// +// +// +// + PatternExpression exp = PatternExpression.decodeExpression(decoder, null); RecursiveDescentSolver solver = RecursiveDescentSolver.getSolver(); - AssemblyResolution res = - solver.solve(FACTORY, exp, MaskedLong.fromLong(0x78), Collections.emptyMap(), - FACTORY.nop("NOP"), "Test"); + AssemblyResolution res = solver.solve(FACTORY, exp, MaskedLong.fromLong(0x78), + Collections.emptyMap(), FACTORY.nop("NOP"), "Test"); AssemblyResolution e = FACTORY.fromString("ins:X7:X8", "Test", null); assertEquals(e, res); } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/pcode/EncodeDecodeTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/pcode/EncodeDecodeTest.java index 955e81f4b83..45a5b85aeab 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/pcode/EncodeDecodeTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/pcode/EncodeDecodeTest.java @@ -31,7 +31,7 @@ public class EncodeDecodeTest extends AbstractGenericTest { private AddressFactory addrFactory; - private void testSignedAttributes(Encoder encoder, Decoder decoder) + private void testSignedAttributes(CachedEncoder encoder, Decoder decoder) throws DecoderException, IOException { @@ -50,7 +50,7 @@ private void testSignedAttributes(Encoder encoder, Decoder decoder) encoder.writeTo(outStream); ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray()); decoder.open(1 << 20, "testSignedAttributes"); - decoder.ingestStream(inStream); + decoder.ingestStreamToNextTerminator(inStream); decoder.endIngest(); int el = decoder.openElement(ELEM_ADDR); int flags = 0; @@ -109,7 +109,7 @@ else if (attribId == ATTRIB_METATYPE.id()) { assertEquals(flags, 0x1ff); } - private void testUnsignedAttributes(Encoder encoder, Decoder decoder) + private void testUnsignedAttributes(CachedEncoder encoder, Decoder decoder) throws DecoderException, IOException { @@ -129,7 +129,7 @@ private void testUnsignedAttributes(Encoder encoder, Decoder decoder) encoder.writeTo(outStream); ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray()); decoder.open(1 << 20, "testUnsignedAttributes"); - decoder.ingestStream(inStream); + decoder.ingestStreamToNextTerminator(inStream); decoder.endIngest(); int el = decoder.openElement(ELEM_ADDR); long val = decoder.readUnsignedInteger(ATTRIB_ALIGN); @@ -155,7 +155,7 @@ private void testUnsignedAttributes(Encoder encoder, Decoder decoder) decoder.closeElement(el); } - private void testMixedAttributes(Encoder encoder, Decoder decoder) + private void testMixedAttributes(CachedEncoder encoder, Decoder decoder) throws DecoderException, IOException { encoder.openElement(ELEM_ADDR); encoder.writeSignedInteger(ATTRIB_ALIGN, 456); @@ -165,7 +165,7 @@ private void testMixedAttributes(Encoder encoder, Decoder decoder) encoder.writeTo(outStream); ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray()); decoder.open(1 << 20, "testMixedAttributes"); - decoder.ingestStream(inStream); + decoder.ingestStreamToNextTerminator(inStream); decoder.endIngest(); int alignVal = -1; int extrapopVal = -1; @@ -187,7 +187,7 @@ else if (attribId == ATTRIB_EXTRAPOP.id()) { assertEquals(extrapopVal, 800); } - private void testAttributes(Encoder encoder, Decoder decoder) + private void testAttributes(CachedEncoder encoder, Decoder decoder) throws DecoderException, IOException { @@ -209,7 +209,7 @@ private void testAttributes(Encoder encoder, Decoder decoder) encoder.writeTo(outStream); ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray()); decoder.open(1 << 20, "testAttributes"); - decoder.ingestStream(inStream); + decoder.ingestStreamToNextTerminator(inStream); decoder.endIngest(); int el = decoder.openElement(ELEM_DATA); boolean bval = decoder.readBool(ATTRIB_ALIGN); @@ -229,7 +229,7 @@ private void testAttributes(Encoder encoder, Decoder decoder) decoder.closeElement(el); } - private void testHierarchy(Encoder encoder, Decoder decoder) + private void testHierarchy(CachedEncoder encoder, Decoder decoder) throws IOException, DecoderException { @@ -273,7 +273,7 @@ private void testHierarchy(Encoder encoder, Decoder decoder) encoder.writeTo(outStream); ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray()); decoder.open(1 << 20, "testHierarchy"); - decoder.ingestStream(inStream); + decoder.ingestStreamToNextTerminator(inStream); decoder.endIngest(); int el1 = decoder.openElement(ELEM_DATA); // Skip over the bool @@ -303,7 +303,7 @@ private void testHierarchy(Encoder encoder, Decoder decoder) decoder.closeElementSkipping(el1); } - private void testUnexpectedEof(Encoder encoder, Decoder decoder) throws IOException + private void testUnexpectedEof(CachedEncoder encoder, Decoder decoder) throws IOException { encoder.openElement(ELEM_DATA); @@ -316,7 +316,7 @@ private void testUnexpectedEof(Encoder encoder, Decoder decoder) throws IOExcept encoder.writeTo(outStream); ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray()); decoder.open(1 << 20, "testAttributes"); - decoder.ingestStream(inStream); + decoder.ingestStreamToNextTerminator(inStream); decoder.endIngest(); int el1 = decoder.openElement(ELEM_DATA); int el2 = decoder.openElement(ELEM_INPUT); @@ -329,7 +329,7 @@ private void testUnexpectedEof(Encoder encoder, Decoder decoder) throws IOExcept assertTrue(sawUnexpectedError); } - public void testNoremaining(Encoder encoder, Decoder decoder) + public void testNoremaining(CachedEncoder encoder, Decoder decoder) throws IOException, DecoderException { @@ -341,7 +341,7 @@ public void testNoremaining(Encoder encoder, Decoder decoder) encoder.writeTo(outStream); ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray()); decoder.open(1 << 20, "testNoremaining"); - decoder.ingestStream(inStream); + decoder.ingestStreamToNextTerminator(inStream); decoder.endIngest(); decoder.openElement(ELEM_INPUT); int el2 = decoder.openElement(ELEM_OFF); @@ -356,7 +356,7 @@ public void testNoremaining(Encoder encoder, Decoder decoder) assertTrue(sawNoRemaining); } - private void testOpenmismatch(Encoder encoder, Decoder decoder) + private void testOpenmismatch(CachedEncoder encoder, Decoder decoder) throws IOException, DecoderException { @@ -368,7 +368,7 @@ private void testOpenmismatch(Encoder encoder, Decoder decoder) encoder.writeTo(outStream); ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray()); decoder.open(1 << 20, "testOpenmismatch"); - decoder.ingestStream(inStream); + decoder.ingestStreamToNextTerminator(inStream); decoder.endIngest(); decoder.openElement(ELEM_INPUT); boolean sawOpenMismatch = false; @@ -381,7 +381,7 @@ private void testOpenmismatch(Encoder encoder, Decoder decoder) assertTrue(sawOpenMismatch); } - private void testClosemismatch(Encoder encoder, Decoder decoder) + private void testClosemismatch(CachedEncoder encoder, Decoder decoder) throws IOException, DecoderException { @@ -393,7 +393,7 @@ private void testClosemismatch(Encoder encoder, Decoder decoder) encoder.writeTo(outStream); ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray()); decoder.open(1 << 20, "testClosemismatch"); - decoder.ingestStream(inStream); + decoder.ingestStreamToNextTerminator(inStream); decoder.endIngest(); int el1 = decoder.openElement(ELEM_INPUT); boolean sawCloseMismatch = false; @@ -419,7 +419,7 @@ public void setUp() { @Test public void testMarshalSignedPacked() throws DecoderException, IOException { - PackedEncode encoder = new PackedEncode(); + PatchPackedEncode encoder = new PatchPackedEncode(); encoder.clear(); PackedDecode decoder = new PackedDecode(addrFactory); testSignedAttributes(encoder, decoder); @@ -427,7 +427,7 @@ public void testMarshalSignedPacked() throws DecoderException, IOException { @Test public void marshalUnsignedPacked() throws DecoderException, IOException { - PackedEncode encoder = new PackedEncode(); + PatchPackedEncode encoder = new PatchPackedEncode(); encoder.clear(); PackedDecode decoder = new PackedDecode(addrFactory); testUnsignedAttributes(encoder, decoder); @@ -435,7 +435,7 @@ public void marshalUnsignedPacked() throws DecoderException, IOException { @Test public void marshalMixedPacked() throws DecoderException, IOException { - PackedEncode encoder = new PackedEncode(); + PatchPackedEncode encoder = new PatchPackedEncode(); encoder.clear(); PackedDecode decoder = new PackedDecode(addrFactory); testMixedAttributes(encoder, decoder); @@ -443,7 +443,7 @@ public void marshalMixedPacked() throws DecoderException, IOException { @Test public void marshalAttribsPacked() throws DecoderException, IOException { - PackedEncode encoder = new PackedEncode(); + PatchPackedEncode encoder = new PatchPackedEncode(); encoder.clear(); PackedDecode decoder = new PackedDecode(addrFactory); testAttributes(encoder, decoder); @@ -451,7 +451,7 @@ public void marshalAttribsPacked() throws DecoderException, IOException { @Test public void marshalHierarchyPacked() throws DecoderException, IOException { - PackedEncode encoder = new PackedEncode(); + PatchPackedEncode encoder = new PatchPackedEncode(); encoder.clear(); PackedDecode decoder = new PackedDecode(addrFactory); testHierarchy(encoder, decoder); @@ -459,7 +459,7 @@ public void marshalHierarchyPacked() throws DecoderException, IOException { @Test public void marshalUnexpectedPacked() throws IOException { - PackedEncode encoder = new PackedEncode(); + PatchPackedEncode encoder = new PatchPackedEncode(); encoder.clear(); PackedDecode decoder = new PackedDecode(addrFactory); testUnexpectedEof(encoder, decoder); @@ -467,7 +467,7 @@ public void marshalUnexpectedPacked() throws IOException { @Test public void marshalNoremainingPacked() throws IOException, DecoderException { - PackedEncode encoder = new PackedEncode(); + PatchPackedEncode encoder = new PatchPackedEncode(); encoder.clear(); PackedDecode decoder = new PackedDecode(addrFactory); testNoremaining(encoder, decoder); @@ -475,7 +475,7 @@ public void marshalNoremainingPacked() throws IOException, DecoderException { @Test public void marshalOpenmismatchPacked() throws IOException, DecoderException { - PackedEncode encoder = new PackedEncode(); + PatchPackedEncode encoder = new PatchPackedEncode(); encoder.clear(); PackedDecode decoder = new PackedDecode(addrFactory); testOpenmismatch(encoder, decoder); @@ -483,7 +483,7 @@ public void marshalOpenmismatchPacked() throws IOException, DecoderException { @Test public void marshalClosemismatchPacked() throws IOException, DecoderException { - PackedEncode encoder = new PackedEncode(); + PatchPackedEncode encoder = new PatchPackedEncode(); encoder.clear(); PackedDecode decoder = new PackedDecode(addrFactory); testClosemismatch(encoder, decoder); @@ -492,7 +492,7 @@ public void marshalClosemismatchPacked() throws IOException, DecoderException { @Test public void marshalBufferpad() throws IOException, DecoderException { assertEquals(LinkedByteBuffer.BUFFER_SIZE, 1024); - PackedEncode encoder = new PackedEncode(); + PatchPackedEncode encoder = new PatchPackedEncode(); encoder.clear(); encoder.openElement(ELEM_INPUT); // 1-byte for (int i = 0; i < 511; ++i) { @@ -506,7 +506,7 @@ public void marshalBufferpad() throws IOException, DecoderException { ByteArrayInputStream inStream = new ByteArrayInputStream(bytesOut); PackedDecode decoder = new PackedDecode(addrFactory); decoder.open(1 << 20, "marshalBufferpad"); - decoder.ingestStream(inStream); + decoder.ingestStreamToNextTerminator(inStream); decoder.endIngest(); int el = decoder.openElement(ELEM_INPUT); for (int i = 0; i < 511; ++i) {