forked from cseagle/blc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathop.hh
313 lines (292 loc) · 21.3 KB
/
op.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
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
/* ###
* 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 op.hh
/// \brief The PcodeOp and PcodeOpBank classes
#ifndef __CPUI_OP__
#define __CPUI_OP__
#include "typeop.hh"
/// \brief Space for storing internal PcodeOp pointers as addresses
///
/// It is convenient and efficient to replace the formally encoded
/// branch target addresses with a pointer to the actual PcodeOp
/// being branched to. This special \b iop space allows a PcodeOp
/// pointer to be encoded as an address so it can be stored as
/// part of an input varnode, in place of the target address, in
/// a \e branching operation. The pointer is encoded as an offset
/// within the \b fspec space.
class IopSpace : public AddrSpace {
public:
IopSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind);
virtual void saveXmlAttributes(ostream &s,uintb offset) const { s << " space=\"iop\""; }
virtual void saveXmlAttributes(ostream &s,uintb offset,int4 size) const { s << " space=\"iop\""; }
virtual void printRaw(ostream &s,uintb offset) const;
virtual void saveXml(ostream &s) const;
virtual void restoreXml(const Element *el);
};
/// \brief Lowest level operation of the \b p-code language
///
/// The philosophy here is to have only one version of any type of operation,
/// and to be completely explicit about all effects.
/// All operations except the control flow operations have exactly one
/// explicit output. Any given operation can have multiple inputs, but all
/// are listed explicitly.
///
/// Input and output size for an operation are specified explicitly. All
/// inputs must be of the same size.
/// Except for the above restrictions, input and output can be any size
/// in bytes.
///
/// P-code can be either big or little endian, this is determined
/// by the language being translated from
class PcodeOp {
friend class BlockBasic; // Just insert_before, insert_after, setOrder
friend class Funcdata;
friend class PcodeOpBank;
friend class VarnodeBank; // Only uses setInput
public:
/// Boolean attributes (flags) that can be placed on a PcodeOp. Even though this enum is public, these are
/// all set and read internally, although many are read publicly via \e get or \e is methods.
enum {
startbasic = 1, ///< This instruction starts a basic block
branch = 2, ///< This instruction is a branch
call = 4, ///< This instruction calls a subroutine
returns = 0x8, ///< This instruction returns to caller
nocollapse = 0x10, ///< This op cannot be collapsed further
dead = 0x20, ///< This operation is dead
marker = 0x40, ///< special placeholder op (multiequal or indirect)
///< or CPUI_COPY between different copies
///< of same variable
booloutput = 0x80, ///< Boolean operation
boolean_flip = 0x100, ///< Set if condition must be false to take branch
fallthru_true = 0x200, ///< Set if fallthru happens on true condition
indirect_source = 0x400, ///< Op is source of (one or more) CPUI_INDIRECTs
coderef = 0x800, ///< The first parameter to this op is a coderef
startmark = 0x1000, ///< This op is the first in its instruction
mark = 0x2000, ///< Used by many algorithms that need to detect loops or avoid repeats
commutative = 0x4000, ///< Order of input parameters does not matter
unary = 0x8000, ///< Evaluate as unary expression
binary = 0x10000, ///< Evaluate as binary expression
special = 0x20000, ///< Cannot be evaluated (without special processing)
floatingpoint = 0x40000, ///< A floating point operation
splittingbranch = 0x80000, ///< Dead edge cannot be removed as it splits
nonprinting = 0x100000, ///< Op should not be directly printed as source
halt = 0x200000, ///< instruction causes processor or process to halt
badinstruction = 0x400000, ///< placeholder for bad instruction data
unimplemented = 0x800000, ///< placeholder for unimplemented instruction
noreturn = 0x1000000, ///< placeholder for previous call that doesn't exit
missing = 0x2000000, ///< ops at this address were not generated
spacebase_ptr = 0x4000000, ///< Loads or stores from a dynamic pointer into a spacebase
indirect_creation = 0x8000000, ///< Output varnode is created by indirect effect
calculated_bool = 0x10000000, ///< Output has been determined to be a 1-bit boolean value
is_cpool_transformed = 0x20000000, ///< Have we checked for cpool transforms
ptrflow = 0x40000000, ///< Op consumes or produces a ptr
indirect_store = 0x80000000 ///< CPUI_INDIRECT is caused by CPUI_STORE
};
enum {
has_thisptr = 0x1, ///< First parameter ( getIn(1) ) is a this pointer
is_constructor = 0x2, ///< Op is call to a constructor
is_destructor = 0x4, ///< Op is call to a destructor
special_prop = 0x8, ///< Does some special form of datatype propagation
special_print = 0x10, ///< Op is marked for special printing
modified = 0x20, ///< This op has been modified by the current action
warning = 0x40, ///< Warning has been generated for this op
incidental_copy = 0x80 ///< Treat this as \e incidental for parameter recovery algorithms
};
private:
TypeOp *opcode; ///< Pointer to class providing behavioral details of the operation
mutable uint4 flags; ///< Collection of boolean attributes on this op
mutable uint4 addlflags; ///< Additional boolean attributes for this op
SeqNum start; ///< What instruction address is this attached to
BlockBasic *parent; ///< Basic block in which this op is contained
list<PcodeOp *>::iterator basiciter; ///< Iterator within basic block
list<PcodeOp *>::iterator insertiter; ///< Position in alive/dead list
list<PcodeOp *>::iterator codeiter; ///< Position in opcode list
Varnode *output; ///< The one possible output Varnode of this op
vector<Varnode *> inrefs; ///< The ordered list of input Varnodes for this op
// Only used by Funcdata
void setOpcode(TypeOp *t_op); ///< Set the opcode for this PcodeOp
void setOutput(Varnode *vn) { output = vn; } ///< Set the output Varnode of this op
void clearInput(int4 slot) { inrefs[slot] = (Varnode *)0; } ///< Clear a specific input Varnode to \e null
void setInput(Varnode *vn,int4 slot) { inrefs[slot] = vn; } ///< Set a specific input Varnode
void setFlag(uint4 fl) { flags |= fl; } ///< Set specific boolean attribute(s) on this op
void clearFlag(uint4 fl) { flags &= ~fl; } ///< Clear specific boolean attribute(s)
void setAdditionalFlag(uint4 fl) { addlflags |= fl; } ///< Set specific boolean attribute
void clearAdditionalFlag(uint4 fl) { addlflags &= ~fl; } ///< Clear specific boolean atribute
void flipFlag(uint4 fl) { flags ^= fl; } ///< Flip the setting of specific boolean attribute(s)
void setNumInputs(int4 num); ///< Make sure this op has \b num inputs
void removeInput(int4 slot); ///< Eliminate a specific input Varnode
void insertInput(int4 slot); ///< Make room for a new input Varnode at a specific position
void setOrder(uintm ord) { start.setOrder(ord); } ///< Order this op within the ops for a single instruction
void setParent(BlockBasic *p) { parent = p; } ///< Set the parent basic block of this op
void setBasicIter(list<PcodeOp *>::iterator iter) { basiciter = iter; } ///< Store the iterator into this op's basic block
public:
PcodeOp(int4 s,const SeqNum &sq); ///< Construct an unattached PcodeOp
~PcodeOp(void) {} ///< Destructor
int4 numInput(void) const { return inrefs.size(); } ///< Get the number of inputs to this op
Varnode *getOut(void) { return output; } ///< Get the output Varnode of this op or \e null
const Varnode *getOut(void) const { return (const Varnode *) output; } ///< Get the output Varnode of this op or \e null
Varnode *getIn(int4 slot) { return inrefs[slot]; } ///< Get a specific input Varnode to this op
const Varnode *getIn(int4 slot) const { return (const Varnode *) inrefs[slot]; } ///< Get a specific input Varnode to this op
const BlockBasic *getParent(void) const { return (const BlockBasic *) parent; } ///< Get the parent basic block
BlockBasic *getParent(void) { return parent; } ///< Get the parent basic block
const Address &getAddr(void) const { return start.getAddr(); } ///< Get the instruction address associated with this op
uintm getTime(void) const { return start.getTime(); } ///< Get the time index indicating when this op was created
const SeqNum &getSeqNum(void) const { return start; } ///< Get the sequence number associated with this op
list<PcodeOp *>::iterator getInsertIter(void) const { return insertiter; } ///< Get position within alive/dead list
list<PcodeOp *>::iterator getBasicIter(void) const { return basiciter; } ///< Get position within basic block
/// \brief Get the slot number of the indicated input varnode
int4 getSlot(const Varnode *vn) const { int4 i,n; n=inrefs.size(); for(i=0;i<n;++i) if (inrefs[i]==vn) break; return i; }
/// \brief Get the evaluation type of this op
uint4 getEvalType(void) const { return (flags&(PcodeOp::unary|PcodeOp::binary|PcodeOp::special)); }
/// \brief Get type which indicates unusual halt in control-flow
uint4 getHaltType(void) const { return (flags&(PcodeOp::halt|PcodeOp::badinstruction|PcodeOp::unimplemented|
PcodeOp::noreturn|PcodeOp::missing)); }
bool isDead(void) const { return ((flags&PcodeOp::dead)!=0); } ///< Return \b true if this op is dead
bool isAssignment(void) const { return (output!=(Varnode *)0); } ///< Return \b true is this op has an output
bool isCall(void) const { return ((flags&PcodeOp::call)!=0); } ///< Return \b true if this op indicates call semantics
bool isMarker(void) const { return ((flags&PcodeOp::marker)!=0); } ///< Return \b true is a special SSA form op
bool isIndirectCreation(void) const { return ((flags&PcodeOp::indirect_creation)!=0); } ///< Return \b true if op creates a varnode indirectly
bool isIndirectStore(void) const { return ((flags&PcodeOp::indirect_store)!=0); } ///< Return \b true if \b this INDIRECT is caused by STORE
/// \brief Return \b true if this op is not directly represented in C output
bool notPrinted(void) const { return ((flags&(PcodeOp::marker|PcodeOp::nonprinting|PcodeOp::noreturn))!=0); }
/// \brief Return \b true if this op produces a boolean output
bool isBoolOutput(void) const { return ((flags&PcodeOp::booloutput)!=0); }
bool isBranch(void) const { return ((flags&PcodeOp::branch)!=0); } ///< Return \b true if this op is a branch
/// \brief Return \b true if this op is a call or branch
bool isCallOrBranch(void) const { return ((flags&(PcodeOp::branch|PcodeOp::call))!=0); }
/// \brief Return \b true if this op breaks fall-thru flow
bool isFlowBreak(void) const { return ((flags&(PcodeOp::branch|PcodeOp::returns))!=0); }
/// \brief Return \b true if this op flips the true/false meaning of its control-flow branching
bool isBooleanFlip(void) const { return ((flags&PcodeOp::boolean_flip)!=0); }
/// \brief Return \b true if the fall-thru branch is taken when the boolean input is true
bool isFallthruTrue(void) const { return ((flags&PcodeOp::fallthru_true)!=0); }
bool isCodeRef(void) const { return ((flags&PcodeOp::coderef)!=0); } ///< Return \b true if the first input is a code reference
bool isInstructionStart(void) const { return ((flags&PcodeOp::startmark)!=0); } ///< Return \b true if this starts an instruction
bool isBlockStart(void) const { return ((flags&PcodeOp::startbasic)!=0); } ///< Return \b true if this starts a basic block
bool isModified(void) const { return ((addlflags&PcodeOp::modified)!=0); } ///< Return \b true if this is modified by the current action
bool isMark(void) const { return ((flags&PcodeOp::mark)!=0); } ///< Return \b true if this op has been marked
void setMark(void) const { flags |= PcodeOp::mark; } ///< Set the mark on this op
bool isWarning(void) const { return ((addlflags&PcodeOp::warning)!=0); } ///< Return \b true if a warning has been generated for this op
void clearMark(void) const { flags &= ~PcodeOp::mark; } ///< Clear any mark on this op
bool isIndirectSource(void) const { return ((flags&PcodeOp::indirect_source)!=0); } ///< Return \b true if this causes an INDIRECT
void setIndirectSource(void) { flags |= PcodeOp::indirect_source; } ///< Mark this op as source of INDIRECT
void clearIndirectSource(void) { flags &= ~PcodeOp::indirect_source; } ///< Clear INDIRECT source flag
bool isPtrFlow(void) const { return ((flags&PcodeOp::ptrflow)!=0); } ///< Return \b true if this produces/consumes ptrs
void setPtrFlow(void) { flags |= PcodeOp::ptrflow; } ///< Mark this op as consuming/producing ptrs
bool isSplitting(void) const { return ((flags&PcodeOp::splittingbranch)!=0); } ///< Return \b true if this branch splits
bool doesSpecialPropagation(void) const { return ((addlflags&PcodeOp::special_prop)!=0); } ///< Return \b true if this does datatype propagation
bool doesSpecialPrinting(void) const { return ((addlflags&PcodeOp::special_print)!=0); } ///< Return \b true if this needs to special printing
bool hasThisPointer(void) const { return ((addlflags&PcodeOp::has_thisptr)!=0); } ///< Return \b true if this is a call taking 'this' parameter
bool isConstructor(void) const { return ((addlflags&PcodeOp::is_constructor)!=0); } ///< Return \b true if this is call to a constructor
bool isDestructor(void) const { return ((addlflags&PcodeOp::is_destructor)!=0); } ///< Return \b true if this is call to a destructor
bool isIncidentalCopy(void) const { return ((addlflags&PcodeOp::incidental_copy)!=0); } ///< Return \b true if \b this COPY is \e incidental
/// \brief Return \b true if output is 1-bit boolean
bool isCalculatedBool(void) const { return ((flags&(PcodeOp::calculated_bool|PcodeOp::booloutput))!=0); }
/// \brief Return \b true if we have already examined this cpool
bool isCpoolTransformed(void) const { return ((flags&PcodeOp::is_cpool_transformed)!=0); }
bool isCollapsible(void) const; ///< Return \b true if this can be collapsed to a COPY of a constant
/// \brief Return \b true if this LOADs or STOREs from a dynamic \e spacebase pointer
bool usesSpacebasePtr(void) const { return ((flags&PcodeOp::spacebase_ptr)!=0); }
uintm getCseHash(void) const; ///< Return hash indicating possibility of common subexpression elimination
bool isCseMatch(const PcodeOp *op) const; ///< Return \b true if this and \e op represent common subexpressions
TypeOp *getOpcode(void) const { return opcode; } ///< Get the opcode for this op
OpCode code(void) const { return opcode->getOpcode(); } ///< Get the opcode id (enum) for this op
bool isCommutative(void) const { return ((flags & PcodeOp::commutative)!=0); } ///< Return \b true if inputs commute
uintb collapse(bool &markedInput) const; ///< Calculate the constant output produced by this op
void collapseConstantSymbol(Varnode *newConst) const; ///< Propagate constant symbol from inputs to given output
PcodeOp *nextOp(void) const; ///< Return the next op in the control-flow from this or \e null
PcodeOp *previousOp(void) const; ///< Return the previous op within this op's basic block or \e null
PcodeOp *target(void) const; ///< Return starting op for instruction associated with this op
uintb getNZMaskLocal(bool cliploop) const; ///< Calculate known zero bits for output to this op
int4 compareOrder(const PcodeOp *bop) const; ///< Compare the control-flow order of this and \e bop
void push(PrintLanguage *lng) const { opcode->push(lng,this); } ///< Push this op as a display token
void printRaw(ostream &s) const { opcode->printRaw(s,this); } ///< Print raw info about this op to stream
const string &getOpName(void) const { return opcode->getName(); } ///< Return the name of this op
void printDebug(ostream &s) const; ///< Print debug description of this op to stream
void saveXml(ostream &s) const; ///< Write an XML description of this op to stream
/// \brief Retrieve the PcodeOp encoded as the address \e addr
static PcodeOp *getOpFromConst(const Address &addr) { return (PcodeOp *)(uintp)addr.getOffset(); }
Datatype *outputTypeLocal(void) const { return opcode->getOutputLocal(this); } ///< Calculate the local output type
Datatype *inputTypeLocal(int4 slot) const { return opcode->getInputLocal(this,slot); } ///< Calculate the local input type
bool markExplicitUnsigned(int4 slot) { return opcode->markExplicitUnsigned(this,slot); } ///< Decide on unsignedness printing
bool inheritsSign(void) const { return opcode->inheritsSign(); } ///< Does this token inherit its sign from operands
};
/// A map from sequence number (SeqNum) to PcodeOp
typedef map<SeqNum,PcodeOp *> PcodeOpTree;
/// \brief Container class for PcodeOps associated with a single function
///
/// The PcodeOp objects are maintained under multiple different sorting criteria to
/// facilitate quick access in various situations. The main sort (PcodeOpTree) is by
/// sequence number (SeqNum). PcodeOps are also grouped into \e alive and \e dead lists
/// to distinguish between raw p-code ops and those that are fully linked into control-flow.
/// Several lists group PcodeOps with important op-codes (like STORE and RETURN).
class PcodeOpBank {
PcodeOpTree optree; ///< The main sequence number sort
list<PcodeOp *> deadlist; ///< List of \e dead PcodeOps
list<PcodeOp *> alivelist; ///< List of \e alive PcodeOps
list<PcodeOp *> storelist; ///< List of STORE PcodeOps
list<PcodeOp *> returnlist; ///< List of RETURN PcodeOps
list<PcodeOp *> useroplist; ///< List of user-defined PcodeOps
list<PcodeOp *> deadandgone; ///< List of retired PcodeOps
uintm uniqid; ///< Counter for producing unique id's for each op
void addToCodeList(PcodeOp *op); ///< Add given PcodeOp to specific op-code list
void removeFromCodeList(PcodeOp *op); ///< Remove given PcodeOp from specific op-code list
void clearCodeLists(void); ///< Clear all op-code specific lists
public:
void clear(void); ///< Clear all PcodeOps from \b this container
PcodeOpBank(void) { uniqid = 0; } ///< Constructor
~PcodeOpBank(void) { clear(); } ///< Destructor
void setUniqId(uintm val) { uniqid = val; } ///< Set the unique id counter
uintm getUniqId(void) const { return uniqid; } ///< Get the next unique id
PcodeOp *create(int4 inputs,const Address &pc); ///< Create a PcodeOp with at a given Address
PcodeOp *create(int4 inputs,const SeqNum &sq); ///< Create a PcodeOp with a given sequence number
void destroy(PcodeOp *op); ///< Destroy/retire the given PcodeOp
void destroyDead(void); ///< Destroy/retire all PcodeOps in the \e dead list
void changeOpcode(PcodeOp *op,TypeOp *newopc); ///< Change the op-code for the given PcodeOp
void markAlive(PcodeOp *op); ///< Mark the given PcodeOp as \e alive
void markDead(PcodeOp *op); ///< Mark the given PcodeOp as \e dead
void insertAfterDead(PcodeOp *op,PcodeOp *prev); ///< Insert the given PcodeOp after a point in the \e dead list
void moveSequenceDead(PcodeOp *firstop,PcodeOp *lastop,PcodeOp *prev);
void markIncidentalCopy(PcodeOp *firstop,PcodeOp *lastop); ///< Mark any COPY ops in the given range as \e incidental
bool empty(void) const { return optree.empty(); } ///< Return \b true if there are no PcodeOps in \b this container
PcodeOp *target(const Address &addr) const; ///< Find the first executing PcodeOp for a target address
PcodeOp *findOp(const SeqNum &num) const; ///< Find a PcodeOp by sequence number
PcodeOp *fallthru(const PcodeOp *op) const; ///< Find the PcodeOp considered a \e fallthru of the given PcodeOp
/// \brief Start of all PcodeOps in sequence number order
PcodeOpTree::const_iterator beginAll(void) const { return optree.begin(); }
/// \brief End of all PcodeOps in sequence number order
PcodeOpTree::const_iterator endAll(void) const { return optree.end(); }
/// \brief Start of all PcodeOps at one Address
PcodeOpTree::const_iterator begin(const Address &addr) const;
/// \brief End of all PcodeOps at one Address
PcodeOpTree::const_iterator end(const Address &addr) const;
/// \brief Start of all PcodeOps marked as \e alive
list<PcodeOp *>::const_iterator beginAlive(void) const { return alivelist.begin(); }
/// \brief End of all PcodeOps marked as \e alive
list<PcodeOp *>::const_iterator endAlive(void) const { return alivelist.end(); }
/// \brief Start of all PcodeOps marked as \e dead
list<PcodeOp *>::const_iterator beginDead(void) const { return deadlist.begin(); }
/// \brief End of all PcodeOps marked as \e dead
list<PcodeOp *>::const_iterator endDead(void) const { return deadlist.end(); }
/// \brief Start of all PcodeOps sharing the given op-code
list<PcodeOp *>::const_iterator begin(OpCode opc) const;
/// \brief End of all PcodeOps sharing the given op-code
list<PcodeOp *>::const_iterator end(OpCode opc) const;
};
extern int4 functionalEqualityLevel(Varnode *vn1,Varnode *vn2,Varnode **res1,Varnode **res2);
extern bool functionalEquality(Varnode *vn1,Varnode *vn2);
extern bool functionalDifference(Varnode *vn1,Varnode *vn2,int4 depth);
#endif