/* ###
* 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 pcodeinject.hh
/// \brief Classes for managing \b p-code \b injection.
#ifndef __PCODEINJECT__
#define __PCODEINJECT__
#include "emulateutil.hh"
class Architecture;
/// \brief An input or output parameter to a p-code injection payload
///
/// Within the chunk of p-code being injected, this is a placeholder for Varnodes
/// that serve as inputs or outputs to the chunk, which are filled-in in the context
/// of the injection. For instance, for a \e call-fixup that injects a user-defined
/// p-code op, the input Varnodes would be substituted with the actual input Varnodes
/// to the user-defined op.
class InjectParameter {
friend class InjectPayload;
string name; ///< Name of the parameter (for use in parsing p-code \e source)
int4 index; ///< Unique index assigned (for cross referencing associated Varnode in the InjectContext)
uint4 size; ///< Size of the parameter Varnode in bytes
public:
InjectParameter(const string &nm,uint4 sz) :name(nm) { index = 0; size = sz; } ///< Constructor
const string &getName(void) const { return name; } ///< Get the parameter name
int4 getIndex(void) const { return index; } ///< Get the assigned index
uint4 getSize(void) const { return size; } ///< Get the size of the parameter in bytes
};
/// \brief Context needed to emit a p-code injection as a full set of p-code operations
///
/// P-code injection works by passing a pre-built template of p-code operations (ConstructTpl)
/// to an emitter (PcodeEmit), which makes the final resolution SLEIGH concepts like \e inst_next to
/// concrete Varnodes. This class contains the context dependent data to resolve:
/// - inst_start -- the address where the injection occurs
/// - inst_next -- the address of the instruction following (the instruction being injected)
/// - inst_dest -- Original destination of CALL being injected
/// - inst_ref -- Target of reference on injected instruction
/// - \ -- Input Varnode of the injection referenced by name
/// - \ -- Output Varnode of the injection referenced by name
class InjectContext {
public:
Architecture *glb; ///< Architecture associated with the injection
Address baseaddr; ///< Address of instruction causing inject
Address nextaddr; ///< Address of following instruction
Address calladdr; ///< If the instruction being injected is a call, this is the address being called
vector inputlist; ///< Storage location for input parameters
vector output; ///< Storage location for output
virtual ~InjectContext(void) {} ///< Destructor
virtual void clear(void) { inputlist.clear(); output.clear(); } ///< Release resources (from last injection)
/// \brief Save \b this context to an XML stream as a \ tag
///
/// \param s is the output stream
virtual void saveXml(ostream &s) const=0;
};
/// \brief An active container for a set of p-code operations that can be injected into data-flow
///
/// This is an abstract base class. Derived classes manage details of how the p-code
/// is stored. The methods provide access to the input/output parameter information,
/// and the main injection is performed with inject().
class InjectPayload {
public:
enum {
CALLFIXUP_TYPE = 1, ///< Injection that replaces a CALL
CALLOTHERFIXUP_TYPE = 2, ///< Injection that replaces a user-defined p-code op, CALLOTHER
CALLMECHANISM_TYPE = 3, ///< Injection to patch up data-flow around the caller/callee boundary
EXECUTABLEPCODE_TYPE = 4 ///< Injection running as a stand-alone p-code script
};
protected:
string name; ///< Formal name of the payload
int4 type; ///< Type of this payload: CALLFIXUP_TYPE, CALLOTHERFIXUP_TYPE, etc.
bool dynamic; ///< True if the injection is generated dynamically
bool incidentalCopy; ///< True if injected COPYs are considered \e incidental
int4 paramshift; ///< Number of parameters shifted in the original call
vector inputlist; ///< List of input parameters to this payload
vector output; ///< List of output parameters
static void readParameter(const Element *el,string &name,uint4 &size);
void orderParameters(void); ///< Assign an index to parameters
public:
InjectPayload(const string &nm,int4 tp) { name=nm; type=tp; paramshift=0; dynamic = false; incidentalCopy = false; } ///< Construct for use with restoreXml
int4 getParamShift(void) const { return paramshift; } ///< Get the number of parameters shifted
bool isDynamic(void) const { return dynamic; } ///< Return \b true if p-code in the injection is generated dynamically
bool isIncidentalCopy(void) const { return incidentalCopy; } ///< Return \b true if any injected COPY is considered \e incidental
int4 sizeInput(void) const { return inputlist.size(); } ///< Return the number of input parameters
int4 sizeOutput(void) const { return output.size(); } ///< Return the number of output parameters
InjectParameter &getInput(int4 i) { return inputlist[i]; } ///< Get the i-th input parameter
InjectParameter &getOutput(int4 i) { return output[i]; } ///< Get the i-th output parameter
virtual ~InjectPayload(void) {} ///< Destructor
/// Perform the injection of \b this payload into data-flow.
///
/// P-code operations representing \b this payload are copied into the
/// controlling analysis context. The provided PcodeEmit object dictates exactly
/// where the PcodeOp and Varnode objects are inserted and to what container.
/// An InjectContext object specifies how placeholder elements become concrete Varnodes
/// in the appropriate context.
/// \param context is the provided InjectConject object
/// \param emit is the provovided PcodeEmit object
virtual void inject(InjectContext &context,PcodeEmit &emit) const=0;
virtual void restoreXml(const Element *el); ///< Restore \b this payload from an XML stream
virtual void printTemplate(ostream &s) const=0; ///< Print the p-code ops of the injection to a stream (for debugging)
string getName(void) const { return name; } ///< Return the name of the injection
int4 getType(void) const { return type; } ///< Return the type of injection (CALLFIXUP_TYPE, CALLOTHERFIXUP_TYPE, etc.)
virtual string getSource(void) const=0; ///< Return a string describing the \e source of the injection (.cspec, prototype model, etc.)
};
/// \brief A snippet of p-code that can be executed outside of normal analysis
///
/// Essentially a p-code script. The p-code contained in this snippet needs to be
/// processor agnostic, so any register Varnodes must be temporary (out of the \e unique space)
/// and any control-flow operations must be contained within the snippet (p-code relative addressing).
/// Input and output to the snippet/script is provided by standard injection parameters.
/// The class contains, as a field, a stripped down emulator to run the script and
/// a convenience method evaluate() to feed in concrete values to the input parameters
/// and return a value from a single output parameter.
class ExecutablePcode : public InjectPayload {
Architecture *glb; ///< The Architecture owning \b this snippet
string source; ///< Description of the source of \b this snippet
bool built; ///< Whether build() method has run, setting up the emulator
EmulateSnippet emulator; ///< The emulator
vector inputList; ///< Temporary ids of input varnodes
vector outputList; ///< Temporary ids of output varnodes
PcodeEmit *emitter; ///< Emitter (allocated temporarily) for initializing the emulator
void build(void); ///< Initialize the Emulate object with the snippet p-code
public:
ExecutablePcode(Architecture *g,const string &src,const string &nm); ///< Constructor
virtual ~ExecutablePcode(void) { if (emitter != (PcodeEmit *)0) delete emitter; }
virtual string getSource(void) const { return source; }
uintb evaluate(const vector &input); ///< Evaluate the snippet on the given inputs
};
/// \brief A collection of p-code injection payloads
///
/// This is a container of InjectPayload objects that can be applied for a
/// specific Architecture. Payloads can be read in via XML (restoreXmlInject()) and manually
/// via manualCallFixup() and manualCallOtherFixup(). Each payload is assigned an integer \e id
/// when it is read in, and getPayload() fetches the payload during analysis. The library
/// also associates the formal names of payloads with the id. Payloads of different types,
/// CALLFIXUP_TYPE, CALLOTHERFIXUP_TYPE, etc., are stored in separate namespaces.
///
/// This is an abstract base class. The derived classes determine the type of storage used
/// by the payloads. The library also provides a reusable InjectContext object to match
/// the payloads, which can be obtained via getCachedContext().
class PcodeInjectLibrary {
protected:
Architecture *glb; ///< The Architecture to which the injection payloads apply
uint4 tempbase; ///< Offset within \e unique space for allocating temporaries within a payload
vector injection; ///< Registered injections
map callFixupMap; ///< Map of registered call-fixup names to injection id
map callOtherFixupMap; ///< Map of registered callother-fixup names to injection id
map callMechFixupMap; ///< Map of registered mechanism names to injection id
map scriptMap; ///< Map of registered script names to ExecutablePcode id
vector callFixupNames; ///< Map from injectid to call-fixup name
vector callOtherTarget; ///< Map from injectid to callother-fixup target-op name
vector callMechTarget; ///< Map from injectid to call-mech name
vector scriptNames; ///< Map from injectid to script name
void registerCallFixup(const string &fixupName,int4 injectid/* , vector targets */);
void registerCallOtherFixup(const string &fixupName,int4 injectid);
void registerCallMechanism(const string &fixupName,int4 injectid);
void registerExeScript(const string &scriptName,int4 injectid);
/// \brief Allocate a new InjectPayload object
///
/// This acts as an InjectPayload factory. The formal name and type of the payload are given,
/// \b this library allocates a new object that fits with its storage scheme and returns the id.
/// \param sourceName is a string describing the source of the new payload
/// \param name is the formal name of the payload
/// \param type is the formal type (CALLFIXUP_TYPE, CALLOTHERFIXUP_TYPE, etc.) of the payload
/// \return the id associated with the new InjectPayload object
virtual int4 allocateInject(const string &sourceName,const string &name,int4 type)=0;
///\brief Finalize a payload within the library, once the payload is initialized
///
/// This provides the derived class the opportunity to add the payload name to the
/// symbol tables or do anything else it needs to once the InjectPayload object
/// has been fully initialized.
/// \param injectid is the id of the InjectPayload to finalize
virtual void registerInject(int4 injectid)=0;
public:
PcodeInjectLibrary(Architecture *g,uint4 tmpbase) { glb = g; tempbase = tmpbase; } ///< Constructor
virtual ~PcodeInjectLibrary(void); ///< Destructor
uint4 getUniqueBase(void) const { return tempbase; } ///< Get the (current) offset for building temporary registers
int4 getPayloadId(int4 type,const string &nm) const; ///< Map name and type to the payload id
InjectPayload *getPayload(int4 id) const { return injection[id]; } ///< Get the InjectPayload by id
string getCallFixupName(int4 injectid) const; ///< Get the call-fixup name associated with an id
string getCallOtherTarget(int4 injectid) const; ///< Get the callother-fixup name associated with an id
string getCallMechanismName(int4 injectid) const; ///< Get the call mechanism name associated with an id
int4 restoreXmlInject(const string &src,const string &nm,int4 tp,const Element *el);
/// \brief A method for reading in p-code generated externally for use in debugging
///
/// Instantiate a special InjectPayloadDynamic object initialized with an
/// \ tag. Within the library, this replaces the original InjectPayload,
/// allowing its p-code to be \e replayed for debugging purposes.
/// \param el is the \ element
virtual void restoreDebug(const Element *el) {}
/// \brief Manually add a call-fixup payload given a compilable snippet of p-code \e source
///
/// The snippet is compiled immediately to produce the payload.
/// \param name is the formal name of the new payload
/// \param snippetstring is the compilable snippet of p-code \e source
/// \return the id of the new payload
virtual int4 manualCallFixup(const string &name,const string &snippetstring)=0;
/// \brief Manually add a callother-fixup payload given a compilable snippet of p-code \e source
///
/// The snippet is compiled immediately to produce the payload. Symbol names for
/// input and output parameters must be provided to the compiler.
/// \param name is the formal name of the new payload
/// \param outname is the name of the output symbol
/// \param inname is the ordered list of input symbol names
/// \param snippet is the compilable snippet of p-code \e source
/// \return the id of the new payload
virtual int4 manualCallOtherFixup(const string &name,const string &outname,const vector &inname,
const string &snippet)=0;
/// \brief Retrieve a reusable context object for \b this library
///
/// The object returned by this method gets passed to the payload inject() method.
/// The clear() method must be called between uses.
/// \return the cached context object
virtual InjectContext &getCachedContext(void)=0;
/// \brief Get the array of op-code behaviors for initializing and emulator
///
/// Behaviors are pulled from the underlying architecture in order to initialize
/// the Emulate object which services the \e p-code \e script payloads.
/// \return the array of OpBehavior objects indexed by op-code
virtual const vector &getBehaviors(void)=0;
};
#endif