-
Notifications
You must be signed in to change notification settings - Fork 149
/
DispatcherARM64.h
304 lines (232 loc) · 16.1 KB
/
DispatcherARM64.h
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
#ifndef ROSE_DispatcherARM64_H
#define ROSE_DispatcherARM64_H
#include "BaseSemantics2.h"
#include "../SgAsmArmv8Instruction.h"
#include "external/rose/armv8InstructionEnum.h"
namespace rose {
namespace BinaryAnalysis {
namespace InstructionSemantics2 {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Dispatcher
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** Shared-ownership pointer to an ARM instruction dispatcher. See @ref heap_object_shared_ownership. */
typedef boost::shared_ptr<class DispatcherARM64> DispatcherARM64Ptr;
class DispatcherARM64 : public BaseSemantics::Dispatcher {
protected:
// Prototypical constructor
DispatcherARM64()
: BaseSemantics::Dispatcher(64, RegisterDictionary::dictionary_armv8()) { }
// Prototypical constructor
DispatcherARM64(size_t addrWidth, const RegisterDictionary *regs/*=NULL*/)
: BaseSemantics::Dispatcher(addrWidth, regs ? regs : RegisterDictionary::dictionary_armv8()) { }
// Normal constructor
DispatcherARM64(const BaseSemantics::RiscOperatorsPtr &ops, size_t addrWidth,
const RegisterDictionary *regs)
: BaseSemantics::Dispatcher(ops, addrWidth,
regs ? regs : RegisterDictionary::dictionary_armv8()) {
regcache_init();
iproc_init();
memory_init();
}
public:
/** Loads the iproc table with instruction processing functors. This normally happens from the constructor. */
void iproc_init();
/** Load the cached register descriptors. This happens at construction and on set_register_dictionary() calls. */
void regcache_init();
/** Make sure memory is set up correctly. For instance, byte order should be little endian. */
void memory_init();
public:
/** Cached register. This register is cached so that there are not so many calls to Dispatcher::findRegister(). The
* register descriptor is updated only when the register dictionary is changed (see set_register_dictionary()).
*
* Register names like REG_anyAX have sizes that depend on the architecture: 16 bits for 16-bit architectures, 32 bits for
* 32-bit architectures, etc. The other register names have specific sizes--such as REG_EAX being 32 bits--and are
* defined only on architectures that support them.
*
* @{ */
RegisterDescriptor REG_PC, REG_N, REG_Z, REG_C, REG_V, REG_SP;
/** @}*/
/** Construct a prototypical dispatcher. The only thing this dispatcher can be used for is to create another dispatcher
* with the virtual @ref create method. */
static DispatcherARM64Ptr instance() {
return DispatcherARM64Ptr(new DispatcherARM64);
}
/** Construct a prototyipcal dispatcher. Construct a prototypical dispatcher with a specified address size. The only thing
* this dispatcher can be used for is to create another dispatcher with the virtual @ref create method. */
static DispatcherARM64Ptr instance(size_t addrWidth, const RegisterDictionary *regs = NULL) {
return DispatcherARM64Ptr(new DispatcherARM64(addrWidth, regs));
}
/** Constructor. */
static DispatcherARM64Ptr instance(const BaseSemantics::RiscOperatorsPtr &ops, size_t addrWidth,
const RegisterDictionary *regs = NULL) {
return DispatcherARM64Ptr(new DispatcherARM64(ops, addrWidth, regs));
}
/** Virtual constructor. */
virtual BaseSemantics::DispatcherPtr create(const BaseSemantics::RiscOperatorsPtr &ops,
size_t addrWidth = 0,
const RegisterDictionary *regs = NULL) const {
if (0 == addrWidth) {
//TODO
//addressWidth(64);
addrWidth = 64;//addressWidth();
}
return instance(ops, addrWidth, regs);
}
/** Dynamic cast to a DispatcherARM64Ptr with assertion. */
static DispatcherARM64Ptr promote(const BaseSemantics::DispatcherPtr &d) {
DispatcherARM64Ptr retval = boost::dynamic_pointer_cast<DispatcherARM64>(d);
assert(retval != NULL);
return retval;
}
virtual void set_register_dictionary(const RegisterDictionary *regdict);
/** Get list of common registers. Returns a list of non-overlapping registers composed of the largest registers except
* using individual flags for the fields of the FLAGS/EFLAGS register. */
virtual RegisterDictionary::RegisterDescriptors get_usual_registers() const;
virtual RegisterDescriptor instructionPointerRegister() const;
virtual RegisterDescriptor stackPointerRegister() const;
virtual BaseSemantics::SValuePtr effectiveAddress(SgAsmExpression *, size_t nbits = 0);
virtual int iproc_key(SgAsmInstruction *insn_) const {
SgAsmArmv8Instruction *insn = isSgAsmArmv8Instruction(insn_);
assert(insn != NULL);
return insn->get_kind();
}
virtual void write(SgAsmExpression *e, const BaseSemantics::SValuePtr &value, size_t addr_nbits = 0);
/** Architecture-specific read from register.
*
* Similar to RiscOperators::readRegister, but might do additional architecture-specific things. */
virtual BaseSemantics::SValuePtr readRegister(const RegisterDescriptor &);
/** Architecture-specific write to register.
*
* Similar to RiscOperators::writeRegister, but might do additional architecture-specific things. For instance, writing to
* a 32-bit GPR such as "eax" on x86-64 will write zeros to the upper half of "rax". */
virtual void writeRegister(const RegisterDescriptor &, const BaseSemantics::SValuePtr &result);
/** Set parity, sign, and zero flags appropriate for result value. */
virtual void setFlagsForResult(const BaseSemantics::SValuePtr &result,
const BaseSemantics::SValuePtr &carries,
bool invertCarries, size_t nbits,
BaseSemantics::SValuePtr &n,
BaseSemantics::SValuePtr &z,
BaseSemantics::SValuePtr &c,
BaseSemantics::SValuePtr &v);
/** Returns true if byte @p v has an even number of bits set; false for an odd number */
virtual BaseSemantics::SValuePtr parity(const BaseSemantics::SValuePtr &v);
/** Conditionally invert the bits of @p value. The bits are inverted if @p maybe is true, otherwise @p value is returned. */
virtual BaseSemantics::SValuePtr invertMaybe(const BaseSemantics::SValuePtr &value, bool maybe);
/** Adds two values and adjusts flags. This method can be used for subtraction if @p b is two's complement and @p
* invertCarries is set. If @p cond is supplied, then the addition and flag adjustments are conditional.
* @{ */
virtual BaseSemantics::SValuePtr doAddOperation(BaseSemantics::SValuePtr a, BaseSemantics::SValuePtr b,
bool invertCarries,
const BaseSemantics::SValuePtr &carryIn,
BaseSemantics::SValuePtr &n,
BaseSemantics::SValuePtr &z,
BaseSemantics::SValuePtr &c,
BaseSemantics::SValuePtr &v);
//FIXME
/** Implements the RCL, RCR, ROL, and ROR instructions for various operand sizes. The rotate amount is always 8 bits wide
* in the instruction, but the semantics mask off all but the low-order bits, keeping 5 bits in 32-bit mode and 6 bits in
* 64-bit mode (indicated by the rotateSignificantBits argument). */
/*virtual BaseSemantics::SValuePtr doRotateOperation(ARMv8InstructionKind kind,
const BaseSemantics::SValuePtr &operand,
const BaseSemantics::SValuePtr &total_rotate,
size_t rotateSignificantBits);*/
//FIXME
/** Implements the SHR, SAR, SHL, SAL, SHRD, and SHLD instructions for various operand sizes. The shift amount is always 8
* bits wide in the instruction, but the semantics mask off all but the low-order bits, keeping 5 bits in 32-bit mode and
* 7 bits in 64-bit mode (indicated by the @p shiftSignificantBits argument). The semantics of SHL and SAL are
* identical (in fact, ROSE doesn't even define x86_sal). The @p source_bits argument contains the bits to be shifted into
* the result and is used only for SHRD and SHLD instructions. */
/*virtual BaseSemantics::SValuePtr doShiftOperation(ARMv8InstructionKind kind,
const BaseSemantics::SValuePtr &operand,
const BaseSemantics::SValuePtr &source_bits,
const BaseSemantics::SValuePtr &total_shift,
size_t shiftSignificantBits);*/
/** Extend or truncate value to propert memory address width. */
virtual BaseSemantics::SValuePtr fixMemoryAddress(const BaseSemantics::SValuePtr &address) const;
/** Checks if the supplied value is or isn't equal to zero */
virtual BaseSemantics::SValuePtr isZero(const BaseSemantics::SValuePtr &value);
virtual BaseSemantics::SValuePtr ConditionHolds(const BaseSemantics::SValuePtr &cond);
/** Inverts the passed in expression and returns the result */
virtual BaseSemantics::SValuePtr NOT(const BaseSemantics::SValuePtr &expr);
/** Execute a branch -- equivalent to writing the target address value to the PC */
virtual void BranchTo(const BaseSemantics::SValuePtr &target);
/** Returns a value that equals 0. nbits specifies what should be the bit-length of the value,
* but is irrelevant in practice as a 64-bit zero is returned anyway. */
virtual BaseSemantics::SValuePtr Zeros(const unsigned int nbits);
/** Returns the input value sign extended to the provided length. */
virtual BaseSemantics::SValuePtr SignExtend(const BaseSemantics::SValuePtr &expr, size_t newsize);
/** Returns the input value zero extended to the provided length. */
virtual BaseSemantics::SValuePtr ZeroExtend(const BaseSemantics::SValuePtr &expr, size_t newsize);
/** Returns the input value right rotated by the provided amount. */
virtual BaseSemantics::SValuePtr ROR(const BaseSemantics::SValuePtr &expr, const BaseSemantics::SValuePtr &amt);
/** */
virtual BaseSemantics::SValuePtr Replicate(const BaseSemantics::SValuePtr &expr);
/** */
virtual BaseSemantics::SValuePtr getBitfieldMask(int immr, int imms, int N, bool iswmask, int datasize);
size_t getRegSize(uint32_t raw);
size_t ldStrLiteralAccessSize(uint32_t raw);
bool inzero(uint32_t raw);
bool extend(uint32_t raw);
int op(uint32_t raw);
bool setflags(uint32_t raw);
int getDatasize(uint32_t raw);
int getShiftType(uint32_t raw);
/** */
BaseSemantics::SValuePtr readMemory(const BaseSemantics::SValuePtr &addr, size_t readSize);
/** */
void writeMemory(const BaseSemantics::SValuePtr &addr, size_t writeSize, const BaseSemantics::SValuePtr &data);
/** */
SgAsmExpression *getWriteBackTarget(SgAsmExpression *expr);
/** */
BaseSemantics::SValuePtr UInt(const BaseSemantics::SValuePtr &expr);
/** */
BaseSemantics::SValuePtr ShiftReg(const BaseSemantics::SValuePtr &src, int shiftType, const BaseSemantics::SValuePtr &amount);
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Instruction processors
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace ARM64 {
/** Base class for all x86 instruction processors.
*
* This class provides single-letter names for some types that are used in all instructions: D, I, A, and Ops for the
* dispatcher raw pointer, instruction pointer, argument list pointer, and RISC operators raw pointer. It also takes care
* of advancing the instruction pointer prior to handing the instruction to the subclass, which by the way is done via
* @ref p method (short for "process"). See examples in DispatcherX86.C -- there are <em>lots</em> of them. */
class InsnProcessor : public BaseSemantics::InsnProcessor {
public:
typedef DispatcherARM64 *D;
typedef BaseSemantics::RiscOperators *Ops;
typedef SgAsmArmv8Instruction *I;
typedef const SgAsmExpressionPtrList &A;
typedef uint32_t B;
virtual void p(D, Ops, I, A, B) = 0;
virtual void process(const BaseSemantics::DispatcherPtr &, SgAsmInstruction *);
virtual void assert_args(I insn, A args, size_t nargs);
//void check_arg_width(D d, I insn, A args);
public:
enum MemOp {
MemOp_STORE,
MemOp_LOAD
};
enum MoveWideOp {
MoveWideOp_N,
MoveWideOp_Z,
MoveWideOp_K
};
enum LogicalOp {
LogicalOp_AND,
LogicalOp_ORR,
LogicalOp_EOR
};
enum ShiftType {
ShiftType_LSL,
ShiftType_LSR,
ShiftType_ASR,
ShiftType_ROR
};
};
} // namespace
} // namespace
} // namespace
} // namespace
#endif