mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
178 lines
8.2 KiB
C++
178 lines
8.2 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 emulateutil.hh
|
|
/// \brief (Lightweight) emulation interface for executing PcodeOp objects within a syntax tree
|
|
/// or for executing snippets defined with PcodeOpRaw objects
|
|
#ifndef __EMULATEUTIL_HH__
|
|
#define __EMULATEUTIL_HH__
|
|
|
|
#include "emulate.hh"
|
|
#include "op.hh"
|
|
|
|
namespace ghidra {
|
|
|
|
/// \brief Emulation based on (existing) PcodeOps and Varnodes.
|
|
///
|
|
/// This is still an abstract class. It does most of the work of emulating
|
|
/// p-code using PcodeOp and Varnode objects (as opposed to PcodeOpRaw and VarnodeData).
|
|
/// This class leaves implementation of control-flow to the derived class. This class
|
|
/// implements most operations by going through new virtual methods:
|
|
/// - getVarnodeValue()
|
|
/// - setVarnodeValue()
|
|
/// - getLoadImageValue()
|
|
///
|
|
/// The default executeLoad() implementation pulls values from the underlying LoadImage
|
|
/// object. The following p-code ops are provided \e NULL implementations, as some tasks
|
|
/// don't need hard emulation of them:
|
|
/// - STORE
|
|
/// - CPOOLREF
|
|
/// - NEW
|
|
class EmulatePcodeOp : public Emulate {
|
|
protected:
|
|
Architecture *glb; ///< The underlying Architecture for the program being emulated
|
|
PcodeOp *currentOp; ///< Current PcodeOp being executed
|
|
PcodeOp *lastOp; ///< Last PcodeOp that was executed
|
|
|
|
/// \brief Pull a value from the load-image given a specific address
|
|
///
|
|
/// A contiguous chunk of memory is pulled from the load-image and returned as a
|
|
/// constant value, respecting the endianness of the address space. The default implementation
|
|
/// of this method pulls the value directly from the LoadImage object.
|
|
/// \param spc is the address space to pull the value from
|
|
/// \param offset is the starting address offset (from within the space) to pull the value from
|
|
/// \param sz is the number of bytes to pull from memory
|
|
/// \return indicated bytes arranged as a constant value
|
|
virtual uintb getLoadImageValue(AddrSpace *spc,uintb offset,int4 sz) const;
|
|
virtual void executeUnary(void);
|
|
virtual void executeBinary(void);
|
|
virtual void executeLoad(void);
|
|
virtual void executeStore(void);
|
|
// virtual void executeBranch(void)=0;
|
|
virtual bool executeCbranch(void);
|
|
// virtual void executeBranchind(void)=0;
|
|
// virtual void executeCall(void)=0;
|
|
// virtual void executeCallind(void)=0;
|
|
// virtual void executeCallother(void)=0;
|
|
virtual void executeMultiequal(void);
|
|
virtual void executeIndirect(void);
|
|
virtual void executeSegmentOp(void);
|
|
virtual void executeCpoolRef(void);
|
|
virtual void executeNew(void);
|
|
// virtual void fallthruOp(void)=0;
|
|
public:
|
|
EmulatePcodeOp(Architecture *g); ///< Constructor
|
|
|
|
/// \brief Establish the current PcodeOp being emulated
|
|
///
|
|
/// \param op is the PcodeOp that will next be executed via executeCurrentOp()
|
|
void setCurrentOp(PcodeOp *op) { currentOp = op; currentBehave = op->getOpcode()->getBehavior(); }
|
|
virtual Address getExecuteAddress(void) const { return currentOp->getAddr(); }
|
|
|
|
/// \brief Given a specific Varnode, set the given value for it in the current machine state
|
|
///
|
|
/// This is the placeholder internal operation for setting a Varnode value during emulation.
|
|
/// The value is \e stored using the Varnode as the \e address and \e storage \e size.
|
|
/// \param vn is the specific Varnode
|
|
/// \param val is the constant value to store
|
|
virtual void setVarnodeValue(Varnode *vn,uintb val)=0;
|
|
|
|
/// \brief Given a specific Varnode, retrieve the current value for it from the machine state
|
|
///
|
|
/// This is the placeholder internal operation for obtaining a Varnode value during emulation.
|
|
/// The value is \e loaded using the Varnode as the \e address and \e storage \e size.
|
|
/// \param vn is the specific Varnode
|
|
/// \return the corresponding value from the machine state
|
|
virtual uintb getVarnodeValue(Varnode *vn) const=0;
|
|
};
|
|
|
|
/// \brief Emulate a \e snippet of PcodeOps out of a functional context
|
|
///
|
|
/// Emulation is performed on a short sequence (\b snippet) of PcodeOpRaw objects.
|
|
/// Control-flow emulation is limited to this snippet; BRANCH and CBRANCH operations
|
|
/// can happen using p-code relative branching. Executing BRANCHIND, CALL, CALLIND,
|
|
/// CALLOTHER, STORE, MULTIEQUAL, INDIRECT, SEGMENTOP, CPOOLOP, and NEW
|
|
/// ops is treated as illegal and an exception is thrown.
|
|
/// Expressions can only use temporary registers or read from the LoadImage.
|
|
///
|
|
/// The set of PcodeOpRaw objects in the snippet is provided by emitting p-code to the object
|
|
/// returned by buildEmitter(). This is designed for one-time initialization of this
|
|
/// class, which can be repeatedly used by calling resetMemory() between executions.
|
|
class EmulateSnippet : public Emulate {
|
|
Architecture *glb; ///< The underlying Architecture for the program being emulated
|
|
vector<PcodeOpRaw *> opList; ///< Sequence of p-code ops to be executed
|
|
vector<VarnodeData *> varList; ///< Varnodes allocated for ops
|
|
map<uintb,uintb> tempValues; ///< Values stored in temporary registers
|
|
PcodeOpRaw *currentOp; ///< Current p-code op being executed
|
|
int4 pos; ///< Index of current p-code op being executed
|
|
|
|
/// \brief Pull a value from the load-image given a specific address
|
|
///
|
|
/// A contiguous chunk of memory is pulled from the load-image and returned as a
|
|
/// constant value, respecting the endianness of the address space.
|
|
/// \param spc is the address space to pull the value from
|
|
/// \param offset is the starting address offset (from within the space) to pull the value from
|
|
/// \param sz is the number of bytes to pull from memory
|
|
/// \return indicated bytes arranged as a constant value
|
|
uintb getLoadImageValue(AddrSpace *spc,uintb offset,int4 sz) const;
|
|
virtual void executeUnary(void);
|
|
virtual void executeBinary(void);
|
|
virtual void executeLoad(void);
|
|
virtual void executeStore(void);
|
|
virtual void executeBranch(void);
|
|
virtual bool executeCbranch(void);
|
|
virtual void executeBranchind(void);
|
|
virtual void executeCall(void);
|
|
virtual void executeCallind(void);
|
|
virtual void executeCallother(void);
|
|
virtual void executeMultiequal(void);
|
|
virtual void executeIndirect(void);
|
|
virtual void executeSegmentOp(void);
|
|
virtual void executeCpoolRef(void);
|
|
virtual void executeNew(void);
|
|
virtual void fallthruOp(void);
|
|
public:
|
|
EmulateSnippet(Architecture *g) { glb = g; pos = 0; currentOp = (PcodeOpRaw *)0; } ///< Constructor
|
|
virtual ~EmulateSnippet(void); ///< Destructor
|
|
virtual void setExecuteAddress(const Address &addr) { setCurrentOp(0); }
|
|
virtual Address getExecuteAddress(void) const { return currentOp->getAddr(); }
|
|
Architecture *getArch(void) const { return glb; } ///< Get the underlying Architecture
|
|
|
|
/// \brief Reset the emulation snippet
|
|
///
|
|
/// Reset the memory state, and set the first p-code op as current.
|
|
void resetMemory(void) { tempValues.clear(); setCurrentOp(0); emu_halted = false; }
|
|
|
|
PcodeEmit *buildEmitter(const vector<OpBehavior *> &inst,uintb uniqReserve);
|
|
bool checkForLegalCode(void) const;
|
|
|
|
/// \brief Set the current executing p-code op by index
|
|
///
|
|
/// The i-th p-code op in the snippet sequence is set as the currently executing op.
|
|
/// \param i is the index
|
|
void setCurrentOp(int4 i) { pos = i; currentOp = opList[i]; currentBehave = currentOp->getBehavior(); }
|
|
|
|
/// \brief Set a temporary register value in the machine state
|
|
///
|
|
/// The temporary Varnode's storage offset is used as key into the machine state map.
|
|
/// \param offset is the temporary storage offset
|
|
/// \param val is the value to put into the machine state
|
|
void setVarnodeValue(uintb offset,uintb val) { tempValues[offset] = val; }
|
|
uintb getVarnodeValue(VarnodeData *vn) const;
|
|
uintb getTempValue(uintb offset) const;
|
|
};
|
|
|
|
} // End namespace ghidra
|
|
#endif
|