ghidra/Ghidra/Features/Decompiler/src/decompile/cpp/transform.hh
2024-08-27 21:03:10 +00:00

256 lines
14 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 transform.hh
/// \brief Classes for building large scale transforms of function data-flow
#ifndef __TRANSFORM_HH__
#define __TRANSFORM_HH__
#include "varnode.hh"
namespace ghidra {
class Funcdata; // Forward declaration
class TransformOp;
extern AttributeId ATTRIB_VECTOR_LANE_SIZES; ///< Marshaling attribute "vector_lane_sizes"
/// \brief Placeholder node for Varnode that will exist after a transform is applied to a function
class TransformVar {
friend class TransformManager;
friend class TransformOp;
public:
/// \brief Types of replacement Varnodes
enum {
piece = 1, ///< New Varnode is a piece of an original Varnode
preexisting = 2, ///< Varnode preexisted in the original data-flow
normal_temp = 3, ///< A new temporary (unique space) Varnode
piece_temp = 4, ///< A temporary representing a piece of an original Varnode
constant = 5, ///< A new constant Varnode
constant_iop = 6, ///< Special iop constant encoding a PcodeOp reference
};
/// \brief Flags for a TransformVar
enum {
split_terminator = 1, ///< The last (most significant piece) of a split array
input_duplicate = 2 ///< This is a piece of an input that has already been visited
};
private:
Varnode *vn; ///< Original \b big Varnode of which \b this is a component
Varnode *replacement; ///< The new explicit lane Varnode
uint4 type; ///< Type of new Varnode
uint4 flags; ///< Boolean properties of the placeholder
int4 byteSize; ///< Size of the lane Varnode in bytes
int4 bitSize; ///< Size of the logical value in bits
uintb val; ///< Value of constant or (bit) position within the original big Varnode
TransformOp *def; ///< Defining op for new Varnode
void createReplacement(Funcdata *fd); ///< Create the new/modified variable this placeholder represents
void initialize(uint4 tp,Varnode *v,int4 bits,int4 bytes,uintb value);
public:
Varnode *getOriginal(void) const { return vn; } ///< Get the original Varnode \b this placeholder models
TransformOp *getDef(void) const { return def; } ///< Get the operator that defines this placeholder variable
};
/// \brief Placeholder node for PcodeOp that will exist after a transform is applied to a function
class TransformOp {
friend class TransformManager;
friend class TransformVar;
public:
/// Special annotations on new pcode ops
enum {
op_replacement = 1, ///< Op replaces an existing op
op_preexisting = 2, ///< Op already exists (but will be transformed)
indirect_creation = 4, ///< Mark op as indirect creation
indirect_creation_possible_out = 8 ///< Mark op as indirect creation and possible call output
};
private:
PcodeOp *op; ///< Original op which \b this is splitting (or null)
PcodeOp *replacement; ///< The new replacement op
OpCode opc; ///< Opcode of the new op
uint4 special; ///< Special handling code when creating
TransformVar *output; ///< Varnode output
vector<TransformVar *> input; ///< Varnode inputs
TransformOp *follow; ///< The following op after \b this (if not null)
void createReplacement(Funcdata *fd); ///< Create the new/modified op this placeholder represents
bool attemptInsertion(Funcdata *fd); ///< Try to put the new PcodeOp into its basic block
public:
TransformVar *getOut(void) const { return output; } ///< Get the output placeholder variable for \b this operator
TransformVar *getIn(int4 i) const { return input[i]; } ///< Get the i-th input placeholder variable for \b this
void inheritIndirect(PcodeOp *indOp); ///< Set \e indirect \e creation flags for \b this based on given INDIRECT
};
/// \brief Describes a (register) storage location and the ways it might be split into lanes
class LanedRegister {
friend class LanedIterator;
public:
/// \brief Class for iterating over possible lane sizes
class LanedIterator {
int4 size; ///< Current lane size
uint4 mask; ///< Collection being iterated over
void normalize(void); ///< Normalize the iterator, after increment or initialization
public:
LanedIterator(const LanedRegister *lanedR) { size = 0; mask = lanedR->sizeBitMask; normalize(); } ///< Constructor
LanedIterator(void) { size = -1; mask = 0; } ///< Constructor for ending iterator
LanedIterator &operator++(void) { size += 1; normalize(); return *this; } ///< Preincrement operator
int4 operator*(void) const { return size; } ///< Dereference operator
LanedIterator &operator=(const LanedIterator &op2) { size = op2.size; mask = op2.mask; return *this; } ///< Assignment
bool operator==(const LanedIterator &op2) const { return (size == op2.size); } ///< Equal operator
bool operator!=(const LanedIterator &op2) const { return (size != op2.size); } ///< Not-equal operator
};
typedef LanedIterator const_iterator; ///< Iterator over possible lane sizes for this register
private:
int4 wholeSize; ///< Size of the whole register
uint4 sizeBitMask; ///< A 1-bit for every permissible lane size
public:
LanedRegister(void) { wholeSize = 0; sizeBitMask = 0; } ///< Constructor for use with decode
LanedRegister(int4 sz,uint4 mask) { wholeSize = sz; sizeBitMask = mask; } ///< Constructor
void parseSizes(int4 registerSize,string laneSizes); ///< Parse a \e vector_lane_sizes attribute
int4 getWholeSize(void) const { return wholeSize; } ///< Get the size in bytes of the whole laned register
uint4 getSizeBitMask(void) const { return sizeBitMask; } ///< Get the bit mask of possible lane sizes
void addLaneSize(int4 size) { sizeBitMask |= ((uint4)1 << size); } ///< Add a new \e size to the allowed list
bool allowedLane(int4 size) const { return (((sizeBitMask >> size) & 1) != 0); } ///< Is \e size among the allowed lane sizes
const_iterator begin(void) const { return LanedIterator(this); } ///< Starting iterator over possible lane sizes
const_iterator end(void) const { return LanedIterator(); } ///< Ending iterator over possible lane sizes
};
/// \brief Description of logical lanes within a \b big Varnode
///
/// A \b lane is a byte offset and size within a Varnode. Lanes within a
/// Varnode are disjoint. In general, we expect a Varnode to be tiled with
/// lanes all of the same size, but the API allows for possibly non-uniform lanes.
class LaneDescription {
int4 wholeSize; ///< Size of the region being split in bytes
vector<int4> laneSize; ///< Size of lanes in bytes
vector<int4> lanePosition; ///< Significance positions of lanes in bytes
public:
LaneDescription(const LaneDescription &op2); ///< Copy constructor
LaneDescription(int4 origSize,int4 sz); ///< Construct uniform lanes
LaneDescription(int4 origSize,int4 lo,int4 hi); ///< Construct two lanes of arbitrary size
bool subset(int4 lsbOffset,int4 size); ///< Trim \b this to a subset of the original lanes
int4 getNumLanes(void) const { return laneSize.size(); } ///< Get the total number of lanes
int4 getWholeSize(void) const { return wholeSize; } ///< Get the size of the region being split
int4 getSize(int4 i) const { return laneSize[i]; } ///< Get the size of the i-th lane
int4 getPosition(int4 i) const { return lanePosition[i]; } ///< Get the significance offset of the i-th lane
int4 getBoundary(int4 bytePos) const; ///< Get index of lane that starts at the given byte position
bool restriction(int4 numLanes,int4 skipLanes,int4 bytePos,int4 size,int4 &resNumLanes,int4 &resSkipLanes) const;
bool extension(int4 numLanes,int4 skipLanes,int4 bytePos,int4 size,int4 &resNumLanes,int4 &resSkipLanes) const;
};
/// \brief Class for splitting larger registers holding smaller logical lanes
///
/// Given a starting Varnode in the data-flow, look for evidence of the Varnode
/// being interpreted as disjoint logical values concatenated together (lanes).
/// If the interpretation is consistent for data-flow involving the Varnode, split
/// Varnode and data-flow into explicit operations on the lanes.
class TransformManager {
Funcdata *fd; ///< Function being operated on
map<int4,TransformVar *> pieceMap; ///< Map from large Varnodes to their new pieces
list<TransformVar> newVarnodes; ///< Storage for Varnode placeholder nodes
list<TransformOp> newOps; ///< Storage for PcodeOp placeholder nodes
void specialHandling(TransformOp &rop);
void createOps(void); ///< Create a new op for each placeholder
void createVarnodes(vector<TransformVar *> &inputList); ///< Create a Varnode for each placeholder
void removeOld(void); ///< Remove old preexisting PcodeOps and Varnodes that are now obsolete
void transformInputVarnodes(vector<TransformVar *> &inputList); ///< Remove old input Varnodes, mark new input Varnodes
void placeInputs(void); ///< Set input Varnodes for all new ops
public:
TransformManager(Funcdata *f) { fd = f; } ///< Constructor
virtual ~TransformManager(void); ///< Destructor
virtual bool preserveAddress(Varnode *vn,int4 bitSize,int4 lsbOffset) const;
Funcdata *getFunction(void) const { return fd; } ///< Get function being transformed
void clearVarnodeMarks(void); ///< Clear mark for all Varnodes in the map
TransformVar *newPreexistingVarnode(Varnode *vn); ///< Make placeholder for preexisting Varnode
TransformVar *newUnique(int4 size); ///< Make placeholder for new unique space Varnode
TransformVar *newConstant(int4 size,int4 lsbOffset,uintb val); ///< Make placeholder for constant Varnode
TransformVar *newIop(Varnode *vn); ///< Make placeholder for special iop constant
TransformVar *newPiece(Varnode *vn,int4 bitSize,int4 lsbOffset); ///< Make placeholder for piece of a Varnode
TransformVar *newSplit(Varnode *vn,const LaneDescription &description);
TransformVar *newSplit(Varnode *vn,const LaneDescription &description,int4 numLanes,int4 startLane);
TransformOp *newOpReplace(int4 numParams,OpCode opc,PcodeOp *replace);
TransformOp *newOp(int4 numParams,OpCode opc,TransformOp *follow);
TransformOp *newPreexistingOp(int4 numParams,OpCode opc,PcodeOp *originalOp);
TransformVar *getPreexistingVarnode(Varnode *vn); ///< Get (or create) placeholder for preexisting Varnode
TransformVar *getPiece(Varnode *vn,int4 bitSize,int4 lsbOffset); ///< Get (or create) placeholder piece
TransformVar *getSplit(Varnode *vn,const LaneDescription &description);
TransformVar *getSplit(Varnode *vn,const LaneDescription &description,int4 numLanes,int4 startLane);
void opSetInput(TransformOp *rop,TransformVar *rvn,int4 slot); ///< Mark given variable as input to given op
void opSetOutput(TransformOp *rop,TransformVar *rvn); ///< Mark given variable as output of given op
static bool preexistingGuard(int4 slot,TransformVar *rvn); ///< Should newPreexistingOp be called
void apply(void); ///< Apply the full transform to the function
};
/// \brief Initialize \b this variable from raw data
///
/// \param tp is the type of variable to create
/// \param v is the underlying Varnode of which this is a piece (may be null)
/// \param bits is the number of bits in the variable
/// \param bytes is the number of bytes in the variable
/// \param value is the associated value
inline void TransformVar::initialize(uint4 tp,Varnode *v,int4 bits,int4 bytes,uintb value)
{
type = tp;
vn = v;
val = value;
bitSize = bits;
byteSize = bytes;
flags = 0;
def = (TransformOp *)0;
replacement = (Varnode *)0;
}
/// \param rop is the given placeholder op whose input is set
/// \param rvn is the placeholder variable to set
/// \param slot is the input position to set
inline void TransformManager::opSetInput(TransformOp *rop,TransformVar *rvn,int4 slot)
{
rop->input[slot] = rvn;
}
/// Establish that the given op produces the given var as output.
/// Mark both the \e output field of the TransformOp and the \e def field of the TransformVar.
/// \param rop is the given op
/// \param rvn is the given variable
inline void TransformManager::opSetOutput(TransformOp *rop,TransformVar *rvn)
{
rop->output = rvn;
rvn->def = rop;
}
/// Varnode marking prevents duplicate TransformOp (and TransformVar) records from getting
/// created, except in the case of a preexisting PcodeOp with 2 (or more) non-constant inputs.
/// Because the op is preexisting the output Varnode doesn't get marked, and the op will
/// be visited for each input. This method determines when the TransformOp object should be
/// created, with the goal of creating it exactly once even though the op is visited more than once.
/// It currently assumes the PcodeOp is binary, and the slot along which the op is
/// currently visited is passed in, along with the TransformVar for the \e other input. It returns
/// \b true if the TransformOp should be created.
/// \param slot is the incoming slot along which the op is visited
/// \param rvn is the other input
inline bool TransformManager::preexistingGuard(int4 slot,TransformVar *rvn)
{
if (slot == 0) return true; // If we came in on the first slot, build the TransformOp
if (rvn->type == TransformVar::piece || rvn->type == TransformVar::piece_temp)
return false; // The op was/will be visited on slot 0, don't create TransformOp now
return true; // The op was not (will not be) visited on slot 0, build now
}
} // End namespace ghidra
#endif