forked from cseagle/blc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtransform.hh
255 lines (234 loc) · 13.4 KB
/
transform.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
/* ###
* 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
};
/// \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
bool decode(Decoder &decoder); ///< Parse \<register> elements for lane sizes
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