ghidra/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh
2019-08-23 13:03:26 -04:00

303 lines
16 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 architecture.hh
/// \brief Architecture and associated classes that help manage a single processor architecture and load image
#ifndef __CPUI_ARCHITECTURE__
#define __CPUI_ARCHITECTURE__
#include "capability.hh"
#include "varmap.hh"
#include "action.hh"
#include "database.hh"
#include "pcodeinject.hh"
#include "fspec.hh"
#include "translate.hh"
#include "loadimage.hh"
#include "globalcontext.hh"
#include "comment.hh"
#include "userop.hh"
#include "options.hh"
#include "prefersplit.hh"
#ifdef CPUI_STATISTICS
/// \brief Class for collecting statistics while processing over multiple functions
///
/// As Funcdata objects are transformed, they get fed to the process() method
/// to accumulate statistics over the whole run. Results are printed with printResults()
class Statistics {
uintb numfunc; ///< Number of functions processed
uintb numvar; ///< Number of Varnodes analyzed
uintb coversum; ///< Number of Varnodes with non-empty covers
uintb coversumsq; ///< Internal sum for variance of coversum
uintb lastcastcount; ///< Number of casts since processing last function
uintb castcount; ///< Total number of casts
uintb castcountsq; ///< Internal sum for variance of castcount
//void process_cover(const Funcdata &data);
void process_cast(const Funcdata &data); ///< Count casts for function
public:
Statistics(void); ///< Construct initializing counts
~Statistics(void); ///< Destructor
void countCast(void) { castcount += 1; } ///< Count a single cast
void process(const Funcdata &fd); ///< Accumulate statistics for one function
void printResults(ostream &s); ///< Display accumulated statistics
};
#endif
class Architecture;
/// \brief Abstract extension point for building Architecture objects
///
/// Decompilation hinges on initially recognizing the format of code then
/// bootstrapping into discovering the processor etc. This is the base class
/// for the different extensions that perform this process. Each extension
/// implements the buildArchitecture() method as the formal entry point
/// for the bootstrapping process.
class ArchitectureCapability : public CapabilityPoint {
static const uint4 majorversion; ///< Current major version of decompiler
static const uint4 minorversion; ///< Current minor version of decompiler
static vector<ArchitectureCapability *> thelist; ///< The list of registered extensions
protected:
string name; ///< Identifier for this capability
public:
const string &getName(void) const { return name; } ///< Get the capability identifier
virtual void initialize(void); ///< Do specialized initialization
/// \brief Build an Architecture given a raw file or data
///
/// This is implemented by each separate extension. The method is handed
/// a \e filename and possibly external target information and must build
/// the Architecture object, initializing all the major subcomponents, using just this info.
/// \param filename is the path to the executable file to examine
/// \param target if non-empty is a language id string
/// \param estream is an output stream for error messages
virtual Architecture *buildArchitecture(const string &filename,const string &target,ostream *estream)=0;
/// \brief Determine if this extension can handle this file
///
/// \param filename is the name of the file to examine
/// \return \b true is \b this extension is suitable for analyzing the file
virtual bool isFileMatch(const string &filename) const=0;
/// \brief Determine is this extension can handle this XML document
///
/// If a file to analyze is XML based, this method examines the XML parse
/// to determine if \b this extension can understand the document
/// \param doc is the parsed XML document
/// \return \b true if \b this extension understands the XML
virtual bool isXmlMatch(Document *doc) const=0;
static ArchitectureCapability *findCapability(const string &filename); ///< Find an extension to process a file
static ArchitectureCapability *findCapability(Document *doc); ///< Find an extension to process an XML document
static void sortCapabilities(void); ///< Sort extensions
static uint4 getMajorVersion(void) { return majorversion; } ///< Get \e major decompiler version
static uint4 getMinorVersion(void) { return minorversion; } ///< Get \e minor decompiler version
};
/// \brief Manager for all the major decompiler subsystems
///
/// An instantiation is tailored to a specific LoadImage,
/// processor, and compiler spec. This class is the \e owner of
/// the LoadImage, Translate, symbols (Database), PrintLanguage, etc.
/// This class also holds numerous configuration parameters for the analysis process
class Architecture : public AddrSpaceManager {
public:
string archid; ///< ID string uniquely describing this architecture
// Configuration data
int4 trim_recurse_max; ///< How many levels to let parameter trims recurse
int4 max_implied_ref; ///< Maximum number of references to an implied var
int4 max_term_duplication; ///< Max terms duplicated without a new variable
int4 max_basetype_size; ///< Maximum size of an "integer" type before creating an array type
int4 min_funcsymbol_size; ///< Minimum size of a function symbol
bool aggressive_ext_trim; ///< Aggressively trim inputs that look like they are sign extended
bool readonlypropagate; ///< true if readonly values should be treated as constants
bool infer_pointers; ///< True if we should infer pointers from constants that are likely addresses
uintb pointer_lowerbound; ///< Zero or lowest value that can be inferred as an address
int4 funcptr_align; ///< How many bits of alignment a function ptr has
uint4 flowoptions; ///< options passed to flow following engine
vector<Rule *> extra_pool_rules; ///< Extra rules that go in the main pool (cpu specific, experimental)
Database *symboltab; ///< Memory map of global variables and functions
ContextDatabase *context; ///< Map from addresses to context settings
map<string,ProtoModel *> protoModels; ///< Parsed forms of possible prototypes
ProtoModel *defaultfp; ///< Parsed form of default prototype
VarnodeData defaultReturnAddr; ///< Default storage location of return address (for current function)
ProtoModel *evalfp_current; ///< Function proto to use when evaluating current function
ProtoModel *evalfp_called; ///< Function proto to use when evaluating called functions
TypeFactory *types; ///< List of types for this binary
const Translate *translate; ///< Translation method for this binary
LoadImage *loader; ///< Method for loading portions of binary
PcodeInjectLibrary *pcodeinjectlib; ///< Pcode injection manager
RangeList nohighptr; ///< Ranges for which high-level pointers are not possible
CommentDatabase *commentdb; ///< Comments for this architecture
ConstantPool *cpool; ///< Deferred constant values
PrintLanguage *print; ///< Current high-level language printer
vector<PrintLanguage *> printlist; ///< List of high-level language printers supported
OptionDatabase *options; ///< Options that can be configured
vector<TypeOp *> inst; ///< Registered p-code instructions
UserOpManage userops; ///< Specifically registered user-defined p-code ops
vector<PreferSplitRecord> splitrecords; ///< registers that we would prefer to see split for this processor
ActionDatabase allacts; ///< Actions that can be applied in this architecture
bool loadersymbols_parsed; ///< True if loader symbols have been read
#ifdef CPUI_STATISTICS
Statistics *stats; ///< Statistics collector
#endif
#ifdef OPACTION_DEBUG
ostream *debugstream; ///< The error console
#endif
Architecture(void); ///< Construct an uninitialized Architecture
void init(DocumentStorage &store); ///< Load the image and configure architecture
ProtoModel *getModel(const string &nm) const; ///< Get a specific PrototypeModel
bool hasModel(const string &nm) const; ///< Does this Architecture have a specific PrototypeModel
bool highPtrPossible(const Address &loc,int4 size) const; ///< Are pointers possible to the given location?
AddrSpace *getSpaceBySpacebase(const Address &loc,int4 size) const; ///< Get space associated with a \e spacebase register
void setDefaultModel(const string &nm); ///< Set the default PrototypeModel
void clearAnalysis(Funcdata *fd); ///< Clear analysis specific to a function
void readLoaderSymbols(void); ///< Read any symbols from loader into database
void collectBehaviors(vector<OpBehavior *> &behave) const; ///< Provide a list of OpBehavior objects
bool hasNearPointers(AddrSpace *spc) const; ///< Does the given address space support \e near pointers
void setPrototype(const PrototypePieces &pieces); ///< Set the prototype for a particular function
void setPrintLanguage(const string &nm); ///< Establish a particular output language
void globalify(void); ///< Mark \e all spaces as global
void restoreFlowOverride(const Element *el); ///< Set flow overrides from XML
virtual ~Architecture(void); ///< Destructor
virtual string getDescription(void) const { return archid; } ///< Get a string describing \b this architecture
/// \brief Print an error message to console
///
/// Write the given message to whatever the registered error stream is
/// \param message is the error message
virtual void printMessage(const string &message) const=0;
virtual void saveXml(ostream &s) const; ///< Serialize this architecture to XML
virtual void restoreXml(DocumentStorage &store); ///< Restore the Architecture state from an XML stream
virtual void nameFunction(const Address &addr,string &name) const; ///< Pick a default name for a function
#ifdef OPACTION_DEBUG
void setDebugStream(ostream *s) { debugstream = s; } ///< Establish the debug console stream
void printDebug(const string &message) const { *debugstream << message << endl; } ///< Print message to the debug stream
#endif
protected:
void addSpacebase(AddrSpace *basespace,const string &nm,const VarnodeData &ptrdata,
int4 truncSize,bool isreversejustified,bool stackGrowth); ///< Create a new space and associated pointer
void addNoHighPtr(const Range &rng); ///< Add a new region where pointers do not exist
// Factory routines for building this architecture
virtual Scope *buildGlobalScope(void); ///< Build the global scope for this executable
/// \brief Build the Translator object
///
/// This builds the main disassembly component for the Architecture
/// This does \e not initially the engine for a specific processor.
/// \param store may hold configuration information
/// \return the Translate object
virtual Translate *buildTranslator(DocumentStorage &store)=0;
/// \brief Build the LoadImage object and load the executable image
///
/// \param store may hold configuration information
virtual void buildLoader(DocumentStorage &store)=0;
/// \brief Build the injection library
///
/// This creates the container for p-code injections. It is initially empty.
/// \return the PcodeInjectLibrary object
virtual PcodeInjectLibrary *buildPcodeInjectLibrary(void)=0;
virtual void buildTypegrp(DocumentStorage &store); ///< Build the data-type factory/container
virtual void buildCommentDB(DocumentStorage &store); ///< Build the comment database
virtual void buildConstantPool(DocumentStorage &store); ///< Build the constant pool
virtual void buildInstructions(DocumentStorage &store); ///< Register the p-code operations
virtual void buildAction(DocumentStorage &store); ///< Build the Action framework
virtual void buildContext(DocumentStorage &store); ///< Build the Context database
/// \brief Load any relevant specification files
///
/// Processor/architecture specific configuration files are loaded into the XML store
/// \param store is the document store that will hold the configuration
virtual void buildSpecFile(DocumentStorage &store)=0;
/// \brief Modify address spaces as required by \b this Architecture
///
/// If spaces need to be truncated or otherwise changed from processor defaults,
/// this routine performs the modification.
/// \param trans is the processor disassembly object
virtual void modifySpaces(Translate *trans)=0;
virtual void postSpecFile(void) {} ///< Let components initialize after Translate is built
virtual void resolveArchitecture(void)=0; ///< Figure out the processor and compiler of the target executable
void restoreFromSpec(DocumentStorage &store); ///< Fully initialize the Translate object
void fillinReadOnlyFromLoader(void); ///< Load info about read-only sections
void initializeSegments(); ///< Set up segment resolvers
void parseProcessorConfig(DocumentStorage &store); ///< Apply processor specific configuration
void parseCompilerConfig(DocumentStorage &store); ///< Apply compiler specific configuration
void parseExtraRules(DocumentStorage &store); ///< Apply any Rule tags
void parseDynamicRule(const Element *el); ///< Apply details of a dynamic Rule object
ProtoModel *parseProto(const Element *el); ///< Build a proto-type model from an XML tag
void parseProtoEval(const Element *el); ///< Apply prototype evaluation configuration
void parseDefaultProto(const Element *el); ///< Apply default prototype model configuration
void parseGlobal(const Element *el); ///< Apply global space configuration
void addOtherSpace(void); ////add OTHER space and all of its overlays to the symboltab
void parseReadOnly(const Element *el); ///< Apply read-only region configuration
void parseVolatile(const Element *el); ///< Apply volatile region configuration
void parseReturnAddress(const Element *el); ///< Apply return address configuration
void parseIncidentalCopy(const Element *el); ///< Apply incidental copy configuration
void parseStackPointer(const Element *el); ///< Apply stack pointer configuration
void parseDeadcodeDelay(const Element *el); ///< Apply dead-code delay configuration
void parseFuncPtrAlign(const Element *el); ///< Apply function pointer alignment configuration
void parseSpacebase(const Element *el); ///< Create an additional indexed space
void parseNoHighPtr(const Element *el); ///< Apply memory alias configuration
void parsePreferSplit(const Element *el); ///< Designate registers to be split
void parseAggressiveTrim(const Element *el); ///< Designate how to trim extension p-code ops
};
/// \brief A resolver for segmented architectures
///
/// When the decompiler is attempting to resolve embedded constants as pointers,
/// this class tries to recover segment info for near pointers by looking up
/// tracked registers in context
class SegmentedResolver : public AddressResolver {
Architecture *glb; ///< The architecture owning the segmented space
AddrSpace *spc; ///< The address space being segmented
SegmentOp *segop; ///< The segment operator
public:
/// Construct a segmented resolver
/// \param g is the owning Architecture
/// \param sp is the segmented space
/// \param sop is the segment operator
SegmentedResolver(Architecture *g,AddrSpace *sp,SegmentOp *sop) { glb=g; spc=sp; segop=sop; }
virtual Address resolve(uintb val,int4 sz,const Address &point,uintb &fullEncoding);
};
/// The Translate object keeps track of address ranges for which
/// it is effectively impossible to have a pointer into. This is
/// used for pointer aliasing calculations. This routine returns
/// \b true if it is \e possible to have pointers into the indicated
/// range.
/// \param loc is the starting address of the range
/// \param size is the size of the range in bytes
/// \return \b true if pointers are possible
inline bool Architecture::highPtrPossible(const Address &loc,int4 size) const {
if (loc.getSpace()->getType() == IPTR_INTERNAL) return false;
return !nohighptr.inRange(loc,size);
}
#endif