forked from cseagle/blc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
heritage.hh
293 lines (272 loc) · 16.2 KB
/
heritage.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
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
/* ###
* IP: GHIDRA
* NOTE: Phi placement and renaming based on ACM journal articles
*
* 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 heritage.hh
/// \brief Utilities for building Static Single Assignment (SSA) form
#ifndef __CPUI_HERITAGE__
#define __CPUI_HERITAGE__
#include "block.hh"
/// Container holding the stack system for the renaming algorithm. Every disjoint address
/// range (indexed by its initial address) maps to its own Varnode stack.
typedef map<Address,vector<Varnode *> > VariableStack;
/// \brief Label for describing extent of address range that has been heritaged
struct SizePass {
int4 size; ///< Size of the range (in bytes)
int4 pass; ///< Pass when the range was heritaged
};
/// \brief Map object for keeping track of which address ranges have been heritaged
///
/// We keep track of a fairly fine grained description of when each address range
/// was entered in SSA form, referred to as \b heritaged or, for Varnode objects,
/// no longer \b free. An address range is added using the add() method, which includes
/// the particular pass when it was entered. The map can be queried using findPass()
/// that informs the caller whether the address has been heritaged and if so in which pass.
class LocationMap {
public:
/// Iterator into the main map
typedef map<Address,SizePass>::iterator iterator;
private:
map<Address,SizePass> themap; ///< Heritaged addresses mapped to range size and pass number
public:
iterator add(Address addr,int4 size,int4 pass,int4 &intersect); ///< Mark new address as \b heritaged
iterator find(const Address &addr); ///< Look up if/how given address was heritaged
int4 findPass(const Address &addr) const; ///< Look up if/how given address was heritaged
void erase(iterator iter) { themap.erase(iter); } ///< Remove a particular entry from the map
iterator begin(void) { return themap.begin(); } ///< Get starting iterator over heritaged ranges
iterator end(void) { return themap.end(); } ///< Get ending iterator over heritaged ranges
void clear(void) { themap.clear(); } ///< Clear the map of heritaged ranges
};
/// \brief Priority queue for the phi-node (MULTIEQUAL) placement algorithm
///
/// A \e work-list for basic blocks used during phi-node placement. Implemented as
/// a set of stacks with an associated priority. Blocks are placed in the \e queue
/// with an associated \e priority (or depth) using the insert() method. The current
/// highest priority block is retrieved with the extract() method.
class PriorityQueue {
vector<vector<FlowBlock *> > queue; ///< An array of \e stacks, indexed by priority
int4 curdepth; ///< The current highest priority index with active blocks
public:
PriorityQueue(void) { curdepth = -2; } ///< Constructor
void reset(int4 maxdepth); ///< Reset to an empty queue
void insert(FlowBlock *bl,int4 depth); ///< Insert a block into the queue given its priority
FlowBlock *extract(void); ///< Retrieve the highest priority block
bool empty(void) const { return (curdepth==-1); } ///< Return \b true if \b this queue is empty
};
class Funcdata;
class FuncCallSpecs;
/// \brief Information about heritage passes performed for a specific address space
///
/// For a particular address space, this keeps track of:
/// - how long to delay heritage
/// - how long to delay dead code removal
/// - whether dead code has been removed (for this space)
/// - have warnings been issued
class HeritageInfo {
friend class Heritage;
AddrSpace *space; ///< The address space \b this record describes
int4 delay; ///< How many passes to delay heritage of this space
int4 deadcodedelay; ///< How many passes to delay deadcode removal of this space
int4 deadremoved; ///< >0 if Varnodes in this space have been eliminated
bool loadGuardSearch; ///< \b true if the search for LOAD ops to guard has been performed
bool warningissued; ///< \b true if warning issued previously
void set(AddrSpace *spc,int4 dl,int4 dcdl) {
space=spc; delay=dl; deadcodedelay=dcdl; deadremoved=0; warningissued=false; loadGuardSearch = false; } ///< Set all fields
bool isHeritaged(void) const { return (space != (AddrSpace *)0); } ///< Return \b true if heritage is performed on this space
void reset(void) {
deadremoved = 0; deadcodedelay = delay; warningissued = false; loadGuardSearch = false; } ///< Reset
};
/// \brief Description of a LOAD operation that needs to be guarded
///
/// Heritage maintains a list of CPUI_LOAD ops that reference the stack dynamically. These
/// can potentially alias stack Varnodes, so we maintain what (possibly limited) information
/// we known about the range of stack addresses that can be referenced.
class LoadGuard {
friend class Heritage;
PcodeOp *op; ///< The LOAD op
AddrSpace *spc; ///< The stack space being loaded from
uintb pointerBase; ///< Base offset of the pointer
uintb minimumOffset; ///< Minimum offset of the LOAD
uintb maximumOffset; ///< Maximum offset of the LOAD
int4 step; ///< Step of any access into this range (0=unknown)
int4 analysisState; ///< 0=unanalyzed, 1=analyzed(partial result), 2=analyzed(full result)
void establishRange(const ValueSetRead &valueSet); ///< Convert partial value set analysis into guard range
void finalizeRange(const ValueSetRead &valueSet); ///< Convert value set analysis to final guard range
/// \brief Set a new unanalyzed LOAD guard that initially guards everything
///
/// \param o is the LOAD op
/// \param s is the (stack) space it is loading from
/// \param off is the base offset that is indexed from
void set(PcodeOp *o,AddrSpace *s,uintb off) {
op = o; spc = s; pointerBase=off; minimumOffset=0; maximumOffset=s->getHighest(); step=0; analysisState=0;
}
public:
PcodeOp *getOp(void) const { return op; } ///< Get the PcodeOp being guarded
uintb getMinimum(void) const { return minimumOffset; } ///< Get minimum offset of the guarded range
uintb getMaximum(void) const { return maximumOffset; } ///< Get maximum offset of the guarded range
int4 getStep(void) const { return step; } ///< Get the calculated step associated with the range (or 0)
bool isGuarded(const Address &addr) const; ///< Does \b this guard apply to the given address
bool isRangeLocked(void) const { return (analysisState == 2); } ///< Return \b true if the range is fully determined
bool isValid(OpCode opc) const { return (!op->isDead() && op->code() == opc); } ///< Return \b true if the record still describes an active LOAD
};
/// \brief Manage the construction of Static Single Assignment (SSA) form
///
/// With a specific function (Funcdata), this class links the Varnode and
/// PcodeOp objects into the formal data-flow graph structure, SSA form.
/// The full structure can be built over multiple passes. In particular,
/// this allows register data-flow to be analyzed first, and then stack
/// locations can be discovered and promoted to first-class Varnodes in
/// a second pass.
///
/// Varnodes for which it is not known whether they are written to by a
/// PcodeOp are referred to as \b free. The method heritage() performs
/// a \e single \e pass of constructing SSA form, collecting any \e eligible
/// free Varnodes for the pass and linking them in to the data-flow. A
/// Varnode is considered eligible for a given pass generally based on its
/// address space (see HeritageInfo), which is the main method for delaying
/// linking for stack locations until they are all discovered. In
/// principle a Varnode can be discovered very late and still get linked
/// in on a subsequent pass. Linking causes Varnodes to gain new descendant
/// PcodeOps, which has impact on dead code elimination (see LocationMap).
///
/// The two big aspects of SSA construction are phi-node placement, performed
/// by placeMultiequals(), and the \e renaming algorithm, performed by rename().
/// The various guard* methods are concerned with labeling analyzing
/// data-flow across function calls, STORE, and LOAD operations.
///
/// The phi-node placement algorithm is from (preprint?)
/// "The Static Single Assignment Form and its Computation"
/// by Gianfranco Bilardi and Keshav Pingali, July 22, 1999
///
/// The renaming algorithm taken from
/// "Efficiently computing static single assignment form and the
/// control dependence graph."
/// R. Cytron, J. Ferrante, B. K. Rosen, M. N. Wegman, and F. K. Zadeck
/// ACM Transactions on Programming Languages and Systems,
/// 13(4):451-490, October 1991
class Heritage {
/// Extra boolean properties on basic blocks for the Augmented Dominator Tree
enum heritage_flags {
boundary_node = 1, ///< Augmented Dominator Tree boundary node
mark_node = 2, ///< Node has already been in queue
merged_node = 4 ///< Node has already been merged
};
/// \brief Node for depth-first traversal of stack references
struct StackNode {
enum {
nonconstant_index = 1,
multiequal = 2
};
Varnode *vn; ///< Varnode being traversed
uintb offset; ///< Offset relative to base
uint4 traversals; ///< What kind of operations has this pointer accumulated
list<PcodeOp *>::const_iterator iter; ///< Next PcodeOp to follow
/// \brief Constructor
/// \param v is the Varnode being visited
/// \param o is the current offset from the base pointer
/// \param trav indicates what configurations were seen along the path to this Varnode
StackNode(Varnode *v,uintb o,uint4 trav) {
vn = v;
offset = o;
iter = v->beginDescend();
traversals = trav;
}
};
Funcdata *fd; ///< The function \b this is controlling SSA construction
LocationMap globaldisjoint; ///< Disjoint cover of every heritaged memory location
LocationMap disjoint; ///< Disjoint cover of memory locations currently being heritaged
vector<vector<FlowBlock *> > domchild; ///< Parent->child edges in dominator tree
vector<vector<FlowBlock *> > augment; ///< Augmented edges
vector<uint4> flags; ///< Block properties for phi-node placement algorithm
vector<int4> depth; ///< Dominator depth of individual blocks
int4 maxdepth; ///< Maximum depth of the dominator tree
int4 pass; ///< Current pass being executed
PriorityQueue pq; ///< Priority queue for phi-node placement
vector<FlowBlock *> merge; ///< Calculate merge points (blocks containing phi-nodes)
vector<HeritageInfo> infolist; ///< Heritage status for individual address spaces
list<LoadGuard> loadGuard; ///< List of LOAD operations that need to be guarded
list<LoadGuard> storeGuard; ///< List of STORE operations taking an indexed pointer to the stack
vector<PcodeOp *> loadCopyOps; ///< List of COPY ops generated by load guards
void clearInfoList(void); ///< Reset heritage status for all address spaces
/// \brief Get the heritage status for the given address space
HeritageInfo *getInfo(AddrSpace *spc) { return &(infolist[spc->getIndex()]); }
/// \brief Get the heritage status for the given address space
const HeritageInfo *getInfo(AddrSpace *spc) const { return &(infolist[spc->getIndex()]); }
void splitJoinLevel(vector<Varnode *> &lastcombo,vector<Varnode *> &nextlev,JoinRecord *joinrec);
void splitJoinRead(Varnode *vn,JoinRecord *joinrec);
void splitJoinWrite(Varnode *vn,JoinRecord *joinrec);
void floatExtensionRead(Varnode *vn,JoinRecord *joinrec);
void floatExtensionWrite(Varnode *vn,JoinRecord *joinrec);
void processJoins(void);
void buildADT(void); ///< Build the augmented dominator tree
void removeRevisitedMarkers(const vector<Varnode *> &remove,const Address &addr,int4 size);
int4 collect(Address addr,int4 size,vector<Varnode *> &read,vector<Varnode *> &write,vector<Varnode *> &input,vector<Varnode *> &remove) const;
bool callOpIndirectEffect(const Address &addr,int4 size,PcodeOp *op) const;
Varnode *normalizeReadSize(Varnode *vn,const Address &addr,int4 size);
Varnode *normalizeWriteSize(Varnode *vn,const Address &addr,int4 size);
Varnode *concatPieces(const vector<Varnode *> &vnlist,PcodeOp *insertop,Varnode *finalvn);
void splitPieces(const vector<Varnode *> &vnlist,PcodeOp *insertop,const Address &addr,int4 size,Varnode *startvn);
void findAddressForces(vector<PcodeOp *> ©Sinks,vector<PcodeOp *> &forces);
void propagateCopyAway(PcodeOp *op);
void handleNewLoadCopies(void);
void analyzeNewLoadGuards(void);
void generateLoadGuard(StackNode &node,PcodeOp *op,AddrSpace *spc);
void generateStoreGuard(StackNode &node,PcodeOp *op,AddrSpace *spc);
bool protectFreeStores(AddrSpace *spc,vector<PcodeOp *> &freeStores);
bool discoverIndexedStackPointers(AddrSpace *spc,vector<PcodeOp *> &freeStores,bool checkFreeStores);
void reprocessFreeStores(AddrSpace *spc,vector<PcodeOp *> &freeStores);
void guard(const Address &addr,int4 size,vector<Varnode *> &read,vector<Varnode *> &write,vector<Varnode *> &inputvars);
void guardInput(const Address &addr,int4 size,vector<Varnode *> &input);
void guardCallOverlappingInput(FuncCallSpecs *fc,const Address &addr,const Address &transAddr,int4 size);
void guardCalls(uint4 flags,const Address &addr,int4 size,vector<Varnode *> &write);
void guardStores(const Address &addr,int4 size,vector<Varnode *> &write);
void guardLoads(uint4 flags,const Address &addr,int4 size,vector<Varnode *> &write);
void guardReturns(uint4 flags,const Address &addr,int4 size,vector<Varnode *> &write);
static void buildRefinement(vector<int4> &refine,const Address &addr,int4 size,const vector<Varnode *> &vnlist);
void splitByRefinement(Varnode *vn,const Address &addr,const vector<int4> &refine,vector<Varnode *> &split);
void refineRead(Varnode *vn,const Address &addr,const vector<int4> &refine,vector<Varnode *> &newvn);
void refineWrite(Varnode *vn,const Address &addr,const vector<int4> &refine,vector<Varnode *> &newvn);
void refineInput(Varnode *vn,const Address &addr,const vector<int4> &refine,vector<Varnode *> &newvn);
void remove13Refinement(vector<int4> &refine);
bool refinement(const Address &addr,int4 size,const vector<Varnode *> &readvars,const vector<Varnode *> &writevars,const vector<Varnode *> &inputvars);
void visitIncr(FlowBlock *qnode,FlowBlock *vnode);
void calcMultiequals(const vector<Varnode *> &write);
void renameRecurse(BlockBasic *bl,VariableStack &varstack);
void bumpDeadcodeDelay(Varnode *vn);
void placeMultiequals(void);
void rename(void);
public:
Heritage(Funcdata *data); ///< Constructor
int4 getPass(void) const { return pass; } ///< Get overall count of heritage passes
/// \brief Get the pass number when the given address was heritaged
///
/// \param addr is the given address
/// \return the pass number or -1 if the address has not been heritaged
int4 heritagePass(const Address &addr) const { return globaldisjoint.findPass(addr); }
int4 numHeritagePasses(AddrSpace *spc) const;
void seenDeadCode(AddrSpace *spc); ///< Inform system of dead code removal in given space
int4 getDeadCodeDelay(AddrSpace *spc) const; ///< Get pass delay for heritaging the given space
void setDeadCodeDelay(AddrSpace *spc,int4 delay); ///< Set delay for a specific space
bool deadRemovalAllowed(AddrSpace *spc) const; ///< Return \b true if it is \e safe to remove dead code
bool deadRemovalAllowedSeen(AddrSpace *spc);
void buildInfoList(void); ///< Initialize information for each space
void forceRestructure(void) { maxdepth = -1; } ///< Force regeneration of basic block structures
void clear(void); ///< Reset all analysis of heritage
void heritage(void); ///< Perform one pass of heritage
const list<LoadGuard> &getLoadGuards(void) const { return loadGuard; } ///< Get list of LOAD ops that are guarded
const list<LoadGuard> &getStoreGuards(void) const { return storeGuard; } ///< Get list of STORE ops that are guarded
const LoadGuard *getStoreGuard(PcodeOp *op) const; ///< Get LoadGuard record associated with given PcodeOp
};
#endif