ghidra/Ghidra/Features/Decompiler/src/decompile/cpp/cpool.hh
2019-03-26 13:46:51 -04:00

200 lines
10 KiB
C++

/* ###
* 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 {
has_thisptr = 0x1, ///< Referenced method has a \b this pointer
is_constructor = 0x2, ///< Referenced method is a constructor
is_destructor = 0x4 ///< 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 hasThisPointer(void) const { return ((flags & has_thisptr)!=0); } ///< Is object a method with a \b this pointer
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<uintb> &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<uintb> &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<uintb> &refs,uint4 tag,const string &tok,Datatype *ct);
/// \brief Restore a CPoolRecord given a \e reference and an XML stream
///
/// A \<cpoolrec> 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<uintb> &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 \<constantpool> element is written containing \<cpoolrec>
/// 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 \<constantpool> 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<uintb> &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<op2.a);
return (b < op2.b);
}
/// \brief Convert the reference back to a formal array of integers
///
/// \param refs is the provided container of integers
void apply(vector<uintb> &refs) const { refs.push_back(a); refs.push_back(b); }
void 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<CheapSorter,CPoolRecord> cpoolMap; ///< A map from \e reference to constant pool record
virtual CPoolRecord *createRecord(const vector<uintb> &refs);
public:
virtual const CPoolRecord *getRecord(const vector<uintb> &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