/* ### * 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 "stringmanage.hh" #include "userop.hh" #include "options.hh" #include "transform.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 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 ArchitectureCapability *getCapability(const string &name); ///< Get a capability by name 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 bool analyze_for_loops; ///< True if we should attempt conversion of \e whiledo loops to \e for loops vector inferPtrSpaces; ///< Set of address spaces in which a pointer constant is inferable int4 funcptr_align; ///< How many bits of alignment a function ptr has uint4 flowoptions; ///< options passed to flow following engine uint4 max_instructions; ///< Maximum instructions that can be processed in one function int4 alias_block_level; ///< Aliases blocked by 0=none, 1=struct, 2=array, 3=all vector 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 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 StringManager *stringManager; ///< Manager of decoded strings ConstantPool *cpool; ///< Deferred constant values PrintLanguage *print; ///< Current high-level language printer vector printlist; ///< List of high-level language printers supported OptionDatabase *options; ///< Options that can be configured vector inst; ///< Registered p-code instructions UserOpManage userops; ///< Specifically registered user-defined p-code ops vector splitrecords; ///< registers that we would prefer to see split for this processor vector lanerecords; ///< Vector registers that have preferred lane sizes 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 void resetDefaultsInternal(void); ///< Reset default values for options specific to Architecture void resetDefaults(void); ///< Reset defaults values for options owned by \b this 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 const LanedRegister *getLanedRegister(const Address &loc,int4 size) const; ///< Get LanedRegister associated with storage int4 getMinimumLanedRegisterSize(void) const; ///< Get the minimum size of a laned register in bytes void setDefaultModel(const string &nm); ///< Set the default PrototypeModel void clearAnalysis(Funcdata *fd); ///< Clear analysis specific to a function void readLoaderSymbols(const string &delim); ///< Read any symbols from loader into database void collectBehaviors(vector &behave) const; ///< Provide a list of OpBehavior objects SegmentOp *getSegmentOp(AddrSpace *spc) const; ///< Retrieve the \e segment op for the given space if any 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 *buildDatabase(DocumentStorage &store); ///< Build the database and 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 buildStringManager(DocumentStorage &store); ///< Build the string manager 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 cacheAddrSpaceProperties(void); ///< Calculate some frequently used space properties and cache them 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 parseLaneSizes(const Element *el); ///< Apply lane size configuration void parseStackPointer(const Element *el); ///< Apply stack pointer configuration void parseDeadcodeDelay(const Element *el); ///< Apply dead-code delay configuration void parseInferPtrBounds(const Element *el); ///< Apply pointer inference bounds 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