/* ### * 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 cpool.hh /// \brief Definitions to support a constant pool for \e deferred compilation languages (i.e. java byte-code) #ifndef __CPOOL__ #define __CPOOL__ #include "type.hh" /// \brief A description of a byte-code object referenced by a constant /// /// Byte-code languages can make use of objects that the \e system knows about /// but which aren't fully embedded in the encoding of instructions that use them. /// Instead the instruction refers to the object via a special encoded reference. This class /// describes one object described by such a reference. In order to provide a concrete /// interpretation of the instruction (i.e. a p-code translation), these objects generally /// resolve to some sort of constant value (hence the term \b constant \b pool). The type /// of constant goes to the formal CPoolRecord \b tag field which can be a: /// - Primitive value (integer, floating-point) /// - String literal (pointer to) /// - Class method (pointer to) /// - Class field (offset of) /// - Array length /// - Data-type (pointer to a descriptor) /// /// For decompilation, knowing the actual \e constant a byte-code interpreter would need /// is secondary to knowing what object is being referenced. So the CPoolRecord can hold a /// constant value, but generally it provides a data-type associated with the object /// and a symbol name or other string token naming the object. class CPoolRecord { public: /// \brief Generic constant pool tag types enum { primitive=0, ///< Constant \b value of data-type \b type, cpool operator can be eliminated string_literal=1, ///< Constant reference to string (passed back as \b byteData) class_reference=2, ///< Reference to (system level) class object, \b token holds class name pointer_method=3, ///< Pointer to a method, name in \b token, signature in \b type pointer_field=4, ///< Pointer to a field, name in \b token, data-type in \b type array_length=5, ///< Integer length, \b token is language specific indicator, \b type is integral data-type instance_of=6, ///< Boolean value, \b token is language specific indicator, \b type is boolean data-type check_cast=7 ///< Pointer to object, new name in \b token, new data-type in \b type }; enum { is_constructor = 0x1, ///< Referenced method is a constructor is_destructor = 0x2 ///< Referenced method is a destructor }; private: friend class ConstantPool; uint4 tag; ///< Descriptor of type of the object uint4 flags; ///< Additional boolean properties on the record string token; ///< Name or token associated with the object uintb value; ///< Constant value of the object (if known) Datatype *type; ///< Data-type associated with the object uint1 *byteData; ///< For string literals, the raw byte data of the string int4 byteDataLen; ///< The number of bytes in the data for a string literal public: CPoolRecord(void) { type = (Datatype *)0; byteData = (uint1 *)0; } ///< Construct an empty record ~CPoolRecord(void) { if (byteData != (uint1 *)0) delete [] byteData; } ///< Destructor uint4 getTag(void) const { return tag; } ///< Get the type of record const string &getToken(void) const { return token; } ///< Get name of method or data-type const uint1 *getByteData(void) const { return byteData; } ///< Get pointer to string literal data int4 getByteDataLength(void) const { return byteDataLen; } ///< Number of bytes of string literal data Datatype *getType(void) const { return type; } ///< Get the data-type associated with \b this uintb getValue(void) const { return value; } ///< Get the constant value associated with \b this bool isConstructor(void) const { return ((flags & is_constructor)!=0); } ///< Is object a constructor method bool isDestructor(void) const { return ((flags & is_destructor)!=0); } ///< Is object a destructor method void saveXml(ostream &s) const; ///< Save object to an XML stream void restoreXml(const Element *el,TypeFactory &typegrp); ///< Restore object from XML stream }; /// \brief An interface to the pool of \b constant objects for byte-code languages /// /// This is an abstract base class that acts as a container for CPoolRecords. /// A \e reference (1 or more integer constants) maps to an individual CPoolRecord. /// A CPoolRecord object can be queried for using getRecord(), and a new object /// can be added with putRecord(). Internally, the actual CPoolRecord object /// is produced by createRecord(). class ConstantPool { /// \brief Allocate a new CPoolRecord object, given a \e reference to it /// /// The object will still need to be initialized but is already associated with the reference. /// Any issue with allocation (like a dupicate reference) causes an exception. /// \param refs is the \e reference of 1 or more identifying integers /// \return the new CPoolRecord virtual CPoolRecord *createRecord(const vector &refs)=0; public: virtual ~ConstantPool() {} ///< Destructor /// \brief Retrieve a constant pool record (CPoolRecord) given a \e reference to it /// /// \param refs is the \e reference (made up of 1 or more identifying integers) /// \return the matching CPoolRecord or NULL if none matches the reference virtual const CPoolRecord *getRecord(const vector &refs) const=0; /// \brief A a new constant pool record to \b this database /// /// Given the basic constituents of the record, type, name, and data-type, create /// a new CPoolRecord object and associate it with the given \e reference. /// \param refs is the \e reference (made up of 1 or more identifying integers) /// \param tag is the type of record to create /// \param tok is the name associated with the object /// \param ct is the data-type associated with the object void putRecord(const vector &refs,uint4 tag,const string &tok,Datatype *ct); /// \brief Restore a CPoolRecord given a \e reference and an XML stream /// /// A \ element initializes the new record which is immediately associated /// with the \e reference. /// \param refs is the \e reference (made up of 1 or more identifying integers) /// \param el is the XML element /// \param typegrp is the TypeFactory used to resolve data-type references in XML /// \return the newly allocated and initialized CPoolRecord const CPoolRecord *restoreXmlRecord(const vector &refs,const Element *el,TypeFactory &typegrp); virtual bool empty(void) const=0; ///< Is the container empty of records virtual void clear(void)=0; ///< Release any (local) resources /// \brief Save all records in this container to an XML stream /// /// (If supported) An \ element is written containing \ /// child elements for each CPoolRecord in the container. /// \param s is the output stream virtual void saveXml(ostream &s) const=0; /// \brief Restore constant pool records from an XML stream /// /// (If supported) The container is populated with CPooLRecords initialized /// from a \ XML tag. /// \param el is the XML element /// \param typegrp is the TypeFactory used to resolve data-type references in the XML virtual void restoreXml(const Element *el,TypeFactory &typegrp)=0; }; /// \brief An implementation of the ConstantPool interface storing records internally in RAM /// /// The CPoolRecord objects are held directly in a map container. This class can be used /// as a stand-alone ConstantPool that holds all its records in RAM. Or, it can act as /// a local CPoolRecord cache for some other implementation. class ConstantPoolInternal : public ConstantPool { /// \brief A cheap (efficient) placeholder for a \e reference to a constant pool record /// /// A \b reference can be an open-ended number of (1 or more) integers. In practice, the /// most integers we see in a reference is two. So this is a slightly more efficient /// container than an open-ended vector. /// The field \b a is the first integer, the field \b b is the second integer, or zero /// if there is no second integer. The references are ordered lexicographically. /// The class also serves to serialize/deserialize references from XML class CheapSorter { public: uintb a; ///< The first integer in a \e reference uintb b; ///< The second integer in a \e reference (or zero) CheapSorter(void) { a = 0; b = 0; } ///< Construct a zero reference CheapSorter(const CheapSorter &op2) { a = op2.a; b = op2.b; } ///< Copy constructor CheapSorter(const vector &refs) { a = refs[0]; b = (refs.size() > 1) ? refs[1] : 0; } ///< Construct from an array of integers /// \brief Lexicographic comparison /// /// \param op2 is the reference to compare with \b this /// \return \b true if \b this should be ordered before the other reference bool operator<(const CheapSorter &op2) const { if (a != op2.a) return (a &refs) const { refs.push_back(a); refs.push_back(b); } void saveXml(ostream &s) const; ///< Serialize the \e reference to an XML element void restoreXml(const Element *el); ///< Deserialize the \e reference from an XML element }; map cpoolMap; ///< A map from \e reference to constant pool record virtual CPoolRecord *createRecord(const vector &refs); public: virtual const CPoolRecord *getRecord(const vector &refs) const; virtual bool empty(void) const { return cpoolMap.empty(); } virtual void clear(void) { cpoolMap.clear(); } virtual void saveXml(ostream &s) const; virtual void restoreXml(const Element *el,TypeFactory &typegrp); }; #endif