]>
Commit | Line | Data |
---|---|---|
5ba3f43e A |
1 | /* |
2 | * Copyright (c) 2017 Apple Inc. All rights reserved. | |
3 | * | |
4 | * Disassemblers for ARM (arm), Thumb (thumb16), and Thumb2 (thumb32). | |
5 | * | |
6 | * Each disassembly begins with a call to dtrace_decode_arm or dtrace_decode_thumb. The thumb | |
7 | * decoder will then call dtrace_decode_thumb16 or dtrace_decode_thumb32 as appropriate. | |
8 | * | |
9 | * The respective disassembly functions are all of the form {arm,thumb16,thumb32}_type. They | |
10 | * follow the ordering and breakdown in the ARMv7 Architecture Reference Manual. | |
11 | */ | |
12 | ||
13 | #include <sys/fasttrap_isa.h> | |
14 | ||
15 | #define BITS(x,n,mask) (((x) >> (n)) & (mask)) | |
16 | ||
17 | static uint32_t thumb32_instword_to_arm(uint16_t hw1, uint16_t hw2) | |
18 | { | |
19 | return (hw1 << 16) | hw2; | |
20 | } | |
21 | ||
22 | int dtrace_decode_arm(uint32_t instr); | |
23 | int dtrace_decode_arm64(uint32_t instr); | |
24 | int dtrace_decode_thumb(uint32_t instr); | |
25 | ||
26 | /* | |
27 | * VFP decoder - shared between ARM and THUMB32 mode | |
28 | */ | |
29 | ||
30 | static | |
31 | int vfp_struct_loadstore(uint32_t instr) | |
32 | { | |
33 | if (ARM_RM(instr) != REG_PC && ARM_RN(instr) != REG_PC) | |
34 | return FASTTRAP_T_COMMON; | |
35 | ||
36 | return FASTTRAP_T_INV; | |
37 | } | |
38 | ||
39 | static | |
40 | int vfp_64transfer(uint32_t instr) | |
41 | { | |
42 | /* These instructions all use RD and RN */ | |
43 | if (ARM_RD(instr) != REG_PC && ARM_RN(instr) != REG_PC) | |
44 | return FASTTRAP_T_COMMON; | |
45 | ||
46 | return FASTTRAP_T_INV; | |
47 | } | |
48 | ||
49 | static | |
50 | int vfp_transfer(uint32_t instr) | |
51 | { | |
52 | /* These instructions all use RD only */ | |
53 | if (ARM_RD(instr) != REG_PC) | |
54 | return FASTTRAP_T_COMMON; | |
55 | ||
56 | return FASTTRAP_T_INV; | |
57 | } | |
58 | ||
59 | static | |
60 | int vfp_loadstore(uint32_t instr) | |
61 | { | |
62 | int opcode = BITS(instr,20,0x1F); | |
63 | ||
64 | /* Instrument VLDR */ | |
65 | if ((opcode & 0x13) == 0x11 && ARM_RN(instr) == REG_PC) | |
66 | return FASTTRAP_T_VLDR_PC_IMMED; | |
67 | ||
68 | /* These instructions all use RN only */ | |
69 | if (ARM_RN(instr) != REG_PC) | |
70 | return FASTTRAP_T_COMMON; | |
71 | ||
72 | return FASTTRAP_T_INV; | |
73 | } | |
74 | ||
75 | /* | |
76 | * ARM decoder | |
77 | */ | |
78 | ||
79 | static | |
80 | int arm_unconditional_misc(uint32_t instr) | |
81 | { | |
82 | int op = BITS(instr,20,0x7F); | |
83 | ||
84 | if ((op & 0x60) == 0x20) { | |
85 | /* VFP data processing uses its own registers */ | |
86 | return FASTTRAP_T_COMMON; | |
87 | } | |
88 | ||
89 | if ((op & 0x71) == 0x40) { | |
90 | return vfp_struct_loadstore(instr); | |
91 | } | |
92 | ||
93 | return FASTTRAP_T_INV; | |
94 | } | |
95 | ||
96 | static | |
97 | int arm_unconditional(uint32_t instr) | |
98 | { | |
99 | if (BITS(instr,27,0x1) == 0) | |
100 | return arm_unconditional_misc(instr); | |
101 | ||
102 | /* The rest are privileged or BL/BLX, do not instrument */ | |
103 | ||
104 | /* Do not need to instrument BL/BLX either, see comment in arm_misc(uint32_t) */ | |
105 | ||
106 | return FASTTRAP_T_INV; | |
107 | } | |
108 | ||
109 | static | |
110 | int arm_syscall_coproc(uint32_t instr) | |
111 | { | |
112 | /* Instrument any VFP data processing instructions, ignore the rest */ | |
113 | ||
114 | int op1 = BITS(instr,20,0x3F), coproc = BITS(instr,8,0xF), op = BITS(instr,4,0x1); | |
115 | ||
116 | if ((op1 & 0x3E) == 0 || (op1 & 0x30) == 0x30) { | |
117 | /* Undefined or swi */ | |
118 | return FASTTRAP_T_INV; | |
119 | } | |
120 | ||
121 | if ((coproc & 0xE) == 0xA) { | |
122 | /* VFP instruction */ | |
123 | ||
124 | if ((op1 & 0x20) == 0 && (op1 & 0x3A) != 0) | |
125 | return vfp_loadstore(instr); | |
126 | ||
127 | if ((op1 & 0x3E) == 0x04) | |
128 | return vfp_64transfer(instr); | |
129 | ||
130 | if ((op1 & 0x30) == 0x20) { | |
131 | /* VFP data processing or 8, 16, or 32 bit move between ARM reg and VFP reg */ | |
132 | if (op == 0) { | |
133 | /* VFP data processing uses its own registers */ | |
134 | return FASTTRAP_T_COMMON; | |
135 | } else { | |
136 | return vfp_transfer(instr); | |
137 | } | |
138 | } | |
139 | } | |
140 | ||
141 | return FASTTRAP_T_INV; | |
142 | } | |
143 | ||
144 | static | |
145 | int arm_branch_link_blockdata(uint32_t instr) | |
146 | { | |
147 | int branch = BITS(instr,25,0x1), link = BITS(instr,24,0x1), op = BITS(instr,20,0x1F), uses_pc = BITS(instr,15,0x1), uses_lr = BITS(instr,14,0x1); | |
148 | ||
149 | if (branch == 1) { | |
150 | if (link == 0) | |
151 | return FASTTRAP_T_B_COND; | |
152 | return FASTTRAP_T_INV; | |
153 | } else { | |
154 | /* Only emulate a use of the pc if it's a return from function: ldmia sp!, { ... pc } */ | |
155 | if (op == 0x0B && ARM_RN(instr) == REG_SP && uses_pc == 1) | |
156 | return FASTTRAP_T_LDM_PC; | |
157 | ||
158 | /* stmia sp!, { ... lr } doesn't touch the pc, but it is very common, so special case it */ | |
159 | if (op == 0x12 && ARM_RN(instr) == REG_SP && uses_lr == 1) | |
160 | return FASTTRAP_T_STM_LR; | |
161 | ||
162 | if (ARM_RN(instr) != REG_PC && uses_pc == 0) | |
163 | return FASTTRAP_T_COMMON; | |
164 | } | |
165 | ||
166 | return FASTTRAP_T_INV; | |
167 | } | |
168 | ||
169 | static | |
170 | int arm_signed_multiplies(uint32_t instr) | |
171 | { | |
172 | int op1 = BITS(instr,20,0x7), op2 = BITS(instr,5,0x7); | |
173 | ||
174 | /* smlald, smlsld, smmls use RD in addition to RM, RS, and RN */ | |
175 | if ((op1 == 0x4 && (op2 & 0x4) == 0) || (op1 == 0x5 && (op2 & 0x6) == 0x6)) { | |
176 | if (ARM_RD(instr) == REG_PC) | |
177 | return FASTTRAP_T_INV; | |
178 | } | |
179 | ||
180 | if (ARM_RM(instr) != REG_PC && ARM_RS(instr) != REG_PC && ARM_RN(instr) != REG_PC) | |
181 | return FASTTRAP_T_COMMON; | |
182 | ||
183 | return FASTTRAP_T_INV; | |
184 | } | |
185 | ||
186 | static | |
187 | int arm_pack_unpack_sat_reversal(uint32_t instr) | |
188 | { | |
189 | int op1 = BITS(instr,20,0x7), op2 = BITS(instr,5,0x7); | |
190 | ||
191 | /* pkh, sel use RN in addition to RD and RM */ | |
192 | if ((op1 == 0 && (op2 & 0x1) == 0) || (op1 == 0 && op2 == 0x5)) { | |
193 | if (ARM_RN(instr) == REG_PC) | |
194 | return FASTTRAP_T_INV; | |
195 | } | |
196 | ||
197 | if (ARM_RM(instr) != REG_PC && ARM_RD(instr) != REG_PC) | |
198 | return FASTTRAP_T_COMMON; | |
199 | ||
200 | return FASTTRAP_T_INV; | |
201 | } | |
202 | ||
203 | static | |
204 | int arm_parallel_addsub_unsigned(uint32_t instr) | |
205 | { | |
206 | if (ARM_RM(instr) != REG_PC && ARM_RD(instr) != REG_PC && ARM_RN(instr) != REG_PC) | |
207 | return FASTTRAP_T_COMMON; | |
208 | ||
209 | return FASTTRAP_T_INV; | |
210 | } | |
211 | ||
212 | static | |
213 | int arm_parallel_addsub_signed(uint32_t instr) | |
214 | { | |
215 | if (ARM_RM(instr) != REG_PC && ARM_RD(instr) != REG_PC && ARM_RN(instr) != REG_PC) | |
216 | return FASTTRAP_T_COMMON; | |
217 | ||
218 | return FASTTRAP_T_INV; | |
219 | } | |
220 | ||
221 | static | |
222 | int arm_media(uint32_t instr) | |
223 | { | |
224 | int op1 = BITS(instr,20,0x1F), op2 = BITS(instr,5,0x7); | |
225 | ||
226 | if ((op1 & 0x1C) == 0) | |
227 | return arm_parallel_addsub_signed(instr); | |
228 | ||
229 | if ((op1 & 0x1C) == 0x04) | |
230 | return arm_parallel_addsub_unsigned(instr); | |
231 | ||
232 | if ((op1 & 0x18) == 0x08) | |
233 | return arm_pack_unpack_sat_reversal(instr); | |
234 | ||
235 | if ((op1 & 0x18) == 0x10) | |
236 | return arm_signed_multiplies(instr); | |
237 | ||
238 | if (op1 == 0x1F && op2 == 0x7) { | |
239 | /* Undefined instruction */ | |
240 | return FASTTRAP_T_INV; | |
241 | } | |
242 | ||
243 | if (op1 == 0x18 && op2 == 0) { | |
244 | /* usad8 usada8 */ | |
245 | /* The registers are named differently in the reference manual for this instruction | |
246 | * but the following positions are correct */ | |
247 | ||
248 | if (ARM_RM(instr) != REG_PC && ARM_RS(instr) != REG_PC && ARM_RN(instr) != REG_PC) | |
249 | return FASTTRAP_T_COMMON; | |
250 | ||
251 | return FASTTRAP_T_INV; | |
252 | } | |
253 | ||
254 | if ((op1 & 0x1E) == 0x1C && (op2 & 0x3) == 0) { | |
255 | /* bfc bfi */ | |
256 | if (ARM_RD(instr) != REG_PC) | |
257 | return FASTTRAP_T_COMMON; | |
258 | ||
259 | return FASTTRAP_T_INV; | |
260 | } | |
261 | ||
262 | if (((op1 & 0x1E) == 0x1A || (op1 & 0x1E) == 0x1E) && ((op2 & 0x3) == 0x2)) { | |
263 | /* sbfx ubfx */ | |
264 | if (ARM_RM(instr) != REG_PC && ARM_RD(instr) != REG_PC) | |
265 | return FASTTRAP_T_COMMON; | |
266 | ||
267 | return FASTTRAP_T_INV; | |
268 | } | |
269 | ||
270 | return FASTTRAP_T_INV; | |
271 | } | |
272 | ||
273 | static | |
274 | int arm_loadstore_wordbyte(uint32_t instr) | |
275 | { | |
276 | /* Instrument PC relative load with immediate, ignore any other uses of the PC */ | |
277 | int R = BITS(instr,25,0x1), L = BITS(instr,20,0x1); | |
278 | ||
279 | if (R == 1) { | |
280 | /* Three register load/store */ | |
281 | if (ARM_RM(instr) != REG_PC && ARM_RD(instr) != REG_PC && ARM_RN(instr) != REG_PC) | |
282 | return FASTTRAP_T_COMMON; | |
283 | } else { | |
284 | /* Immediate load/store, but still do not support ldr pc, [pc...] */ | |
285 | if (L == 1 && ARM_RN(instr) == REG_PC && ARM_RD(instr) != REG_PC) | |
286 | return FASTTRAP_T_LDR_PC_IMMED; | |
287 | ||
288 | if (ARM_RD(instr) != REG_PC && ARM_RN(instr) != REG_PC) | |
289 | return FASTTRAP_T_COMMON; | |
290 | } | |
291 | ||
292 | return FASTTRAP_T_INV; | |
293 | } | |
294 | ||
295 | static | |
296 | int arm_saturating(uint32_t instr) | |
297 | { | |
298 | if (ARM_RM(instr) != REG_PC && ARM_RD(instr) != REG_PC && ARM_RN(instr) != REG_PC) | |
299 | return FASTTRAP_T_COMMON; | |
300 | ||
301 | return FASTTRAP_T_INV; | |
302 | } | |
303 | ||
304 | static | |
305 | int arm_misc(uint32_t instr) | |
306 | { | |
307 | int op = BITS(instr,21,0x3), __unused op1 = BITS(instr,16,0xF), op2 = BITS(instr,4,0x7); | |
308 | ||
309 | if (op2 == 1 && op == 1) | |
310 | return FASTTRAP_T_BX_REG; | |
311 | ||
312 | /* We do not need to emulate BLX for entry/return probes; if we eventually support full offset | |
313 | * tracing, then we will. This is because BLX overwrites the link register, so a function that | |
314 | * can execute this as its first instruction is a special function indeed. | |
315 | */ | |
316 | ||
317 | if (op2 == 0x5) | |
318 | return arm_saturating(instr); | |
319 | ||
320 | return FASTTRAP_T_INV; | |
321 | } | |
322 | ||
323 | static | |
324 | int arm_msr_hints(__unused uint32_t instr) | |
325 | { | |
326 | /* These deal with the psr, not instrumented */ | |
327 | ||
328 | return FASTTRAP_T_INV; | |
329 | } | |
330 | ||
331 | static | |
332 | int arm_sync_primitive(__unused uint32_t instr) | |
333 | { | |
334 | /* TODO will instrumenting these interfere with any kernel usage of these instructions? */ | |
335 | /* Don't instrument for now */ | |
336 | ||
337 | return FASTTRAP_T_INV; | |
338 | } | |
339 | ||
340 | static | |
341 | int arm_extra_loadstore_unpriv(uint32_t instr) | |
342 | { | |
343 | int op = BITS(instr,20,0x1), __unused op2 = BITS(instr,5,0x3), immed = BITS(instr,22,0x1); | |
344 | ||
345 | if (op == 0 && (op2 & 0x2) == 0x2) { | |
346 | /* Unpredictable or undefined */ | |
347 | return FASTTRAP_T_INV; | |
348 | } | |
349 | ||
350 | if (immed == 1) { | |
351 | if (ARM_RD(instr) != REG_PC && ARM_RN(instr) != REG_PC) | |
352 | return FASTTRAP_T_COMMON; | |
353 | } else { | |
354 | if (ARM_RM(instr) != REG_PC && ARM_RD(instr) != REG_PC && ARM_RN(instr) != REG_PC) | |
355 | return FASTTRAP_T_COMMON; | |
356 | } | |
357 | ||
358 | return FASTTRAP_T_INV; | |
359 | } | |
360 | ||
361 | static | |
362 | int arm_extra_loadstore(uint32_t instr) | |
363 | { | |
364 | int op1 = BITS(instr,20,0x1F); | |
365 | ||
366 | /* There are two variants, and we do not instrument either of them that use the PC */ | |
367 | ||
368 | if ((op1 & 0x4) == 0) { | |
369 | /* Variant 1, register */ | |
370 | if (ARM_RM(instr) != REG_PC && ARM_RD(instr) != REG_PC && ARM_RN(instr) != REG_PC) | |
371 | return FASTTRAP_T_COMMON; | |
372 | } else { | |
373 | /* Variant 2, immediate */ | |
374 | if (ARM_RD(instr) != REG_PC && ARM_RN(instr) != REG_PC) | |
375 | return FASTTRAP_T_COMMON; | |
376 | } | |
377 | ||
378 | return FASTTRAP_T_INV; | |
379 | } | |
380 | ||
381 | static | |
382 | int arm_halfword_multiply(uint32_t instr) | |
383 | { | |
384 | /* Not all multiply instructions use all four registers. The ones that don't should have those | |
385 | * register locations set to 0, so we can test them anyway. | |
386 | */ | |
387 | ||
388 | if (ARM_RN(instr) != REG_PC && ARM_RD(instr) != REG_PC && ARM_RS(instr) != REG_PC && ARM_RM(instr) != REG_PC) | |
389 | return FASTTRAP_T_COMMON; | |
390 | ||
391 | return FASTTRAP_T_INV; | |
392 | } | |
393 | ||
394 | static | |
395 | int arm_multiply(uint32_t instr) | |
396 | { | |
397 | /* Not all multiply instructions use all four registers. The ones that don't should have those | |
398 | * register locations set to 0, so we can test them anyway. | |
399 | */ | |
400 | ||
401 | if (ARM_RN(instr) != REG_PC && ARM_RD(instr) != REG_PC && ARM_RS(instr) != REG_PC && ARM_RM(instr) != REG_PC) | |
402 | return FASTTRAP_T_COMMON; | |
403 | ||
404 | return FASTTRAP_T_INV; | |
405 | } | |
406 | ||
407 | static | |
408 | int arm_dataproc_immed(uint32_t instr) | |
409 | { | |
410 | /* All these instructions are either two registers, or one register and have 0 where the other reg would be used */ | |
411 | if (ARM_RN(instr) != REG_PC && ARM_RD(instr) != REG_PC) | |
412 | return FASTTRAP_T_COMMON; | |
413 | ||
414 | return FASTTRAP_T_INV; | |
415 | } | |
416 | ||
417 | static | |
418 | int arm_dataproc_regshift(uint32_t instr) | |
419 | { | |
420 | /* All these instructions are either four registers, or three registers and have 0 where there last reg would be used */ | |
421 | if (ARM_RN(instr) != REG_PC && ARM_RD(instr) != REG_PC && ARM_RS(instr) != REG_PC && ARM_RM(instr) != REG_PC) | |
422 | return FASTTRAP_T_COMMON; | |
423 | ||
424 | return FASTTRAP_T_INV; | |
425 | } | |
426 | ||
427 | static | |
428 | int arm_dataproc_reg(uint32_t instr) | |
429 | { | |
430 | int op1 = BITS(instr,20,0x1F), op2 = BITS(instr,7,0x1F), op3 = BITS(instr,5,0x3); | |
431 | ||
432 | if (op1 == 0x11 || op1 == 0x13 || op1 == 0x15 || op1 == 0x17) { | |
433 | /* These are comparison flag setting instructions and do not have RD */ | |
434 | if (ARM_RN(instr) != REG_PC && ARM_RM(instr) != REG_PC) | |
435 | return FASTTRAP_T_COMMON; | |
436 | ||
437 | return FASTTRAP_T_INV; | |
438 | } | |
439 | ||
440 | /* The rest can, in theory, write or use the PC. The only one we instrument is mov pc, reg. | |
441 | * movs pc, reg is a privileged instruction so we don't instrument that variant. The s bit | |
442 | * is bit 0 of op1 and should be zero. | |
443 | */ | |
444 | if (op1 == 0x1A && op2 == 0 && op3 == 0 && ARM_RD(instr) == REG_PC) | |
445 | return FASTTRAP_T_MOV_PC_REG; | |
446 | ||
447 | /* Any instruction at this point is a three register instruction or two register instruction with RN = 0 */ | |
448 | if (ARM_RN(instr) != REG_PC && ARM_RD(instr) != REG_PC && ARM_RM(instr) != REG_PC) | |
449 | return FASTTRAP_T_COMMON; | |
450 | ||
451 | return FASTTRAP_T_INV; | |
452 | } | |
453 | ||
454 | static | |
455 | int arm_dataproc_misc(uint32_t instr) | |
456 | { | |
457 | int op = BITS(instr,25,0x1), op1 = BITS(instr,20,0x1F), op2 = BITS(instr,4,0xF); | |
458 | ||
459 | if (op == 0) { | |
460 | if ((op1 & 0x19) != 0x10 && (op2 & 0x1) == 0) | |
461 | return arm_dataproc_reg(instr); | |
462 | ||
463 | if ((op1 & 0x19) != 0x10 && (op2 & 0x9) == 0x1) | |
464 | return arm_dataproc_regshift(instr); | |
465 | ||
466 | if ((op1 & 0x19) == 0x10 && (op2 & 0x8) == 0) | |
467 | return arm_misc(instr); | |
468 | ||
469 | if ((op1 & 0x19) == 0x19 && (op2 & 0x9) == 0x8) | |
470 | return arm_halfword_multiply(instr); | |
471 | ||
472 | if ((op1 & 0x10) == 0 && op2 == 0x9) | |
473 | return arm_multiply(instr); | |
474 | ||
475 | if ((op1 & 0x10) == 0x10 && op2 == 0x9) | |
476 | return arm_sync_primitive(instr); | |
477 | ||
478 | if ((op1 & 0x12) != 0x02 && (op2 == 0xB || (op2 & 0xD) == 0xD)) | |
479 | return arm_extra_loadstore(instr); | |
480 | ||
481 | if ((op1 & 0x12) == 0x02 && (op2 == 0xB || (op2 & 0xD) == 0xD)) | |
482 | return arm_extra_loadstore_unpriv(instr); | |
483 | } else { | |
484 | if ((op1 & 0x19) != 0x10) | |
485 | return arm_dataproc_immed(instr); | |
486 | ||
487 | if (op1 == 0x10) { | |
488 | /* 16 bit immediate load (mov (immed)) [encoding A2] */ | |
489 | if (ARM_RD(instr) != REG_PC) | |
490 | return FASTTRAP_T_COMMON; | |
491 | ||
492 | return FASTTRAP_T_INV; | |
493 | } | |
494 | ||
495 | if (op1 == 0x14) { | |
496 | /* high halfword 16 bit immediate load (movt) [encoding A1] */ | |
497 | if (ARM_RD(instr) != REG_PC) | |
498 | return FASTTRAP_T_COMMON; | |
499 | ||
500 | return FASTTRAP_T_INV; | |
501 | } | |
502 | ||
503 | if ((op1 & 0x1B) == 0x12) | |
504 | return arm_msr_hints(instr); | |
505 | } | |
506 | ||
507 | return FASTTRAP_T_INV; | |
508 | } | |
509 | ||
510 | int dtrace_decode_arm(uint32_t instr) | |
511 | { | |
512 | int cond = BITS(instr,28,0xF), op1 = BITS(instr,25,0x7), op = BITS(instr,4,0x1); | |
513 | ||
514 | if (cond == 0xF) | |
515 | return arm_unconditional(instr); | |
516 | ||
517 | if ((op1 & 0x6) == 0) | |
518 | return arm_dataproc_misc(instr); | |
519 | ||
520 | if (op1 == 0x2) | |
521 | return arm_loadstore_wordbyte(instr); | |
522 | ||
523 | if (op1 == 0x3 && op == 0) | |
524 | return arm_loadstore_wordbyte(instr); | |
525 | ||
526 | if (op1 == 0x3 && op == 1) | |
527 | return arm_media(instr); | |
528 | ||
529 | if ((op1 & 0x6) == 0x4) | |
530 | return arm_branch_link_blockdata(instr); | |
531 | ||
532 | if ((op1 & 0x6) == 0x6) | |
533 | return arm_syscall_coproc(instr); | |
534 | ||
535 | return FASTTRAP_T_INV; | |
536 | } | |
537 | ||
538 | /* | |
539 | * Thumb 16-bit decoder | |
540 | */ | |
541 | ||
542 | static | |
543 | int thumb16_cond_supervisor(uint16_t instr) | |
544 | { | |
545 | int opcode = BITS(instr,8,0xF); | |
546 | ||
547 | if ((opcode & 0xE) != 0xE) | |
548 | return FASTTRAP_T_B_COND; | |
549 | ||
550 | return FASTTRAP_T_INV; | |
551 | } | |
552 | ||
553 | static | |
554 | int thumb16_misc(uint16_t instr) | |
555 | { | |
556 | int opcode = BITS(instr,5,0x7F); | |
557 | ||
558 | if ((opcode & 0x70) == 0x30 || (opcode & 0x70) == 0x70) { | |
559 | /* setend, cps, breakpoint, or if-then, not instrumentable */ | |
560 | return FASTTRAP_T_INV; | |
561 | } else if ((opcode & 0x78) == 0x28) { | |
562 | /* Doesn't modify pc, but this happens a lot so make this a special case for emulation */ | |
563 | return FASTTRAP_T_PUSH_LR; | |
564 | } else if ((opcode & 0x78) == 0x68) { | |
565 | return FASTTRAP_T_POP_PC; | |
566 | } else if ((opcode & 0x28) == 0x08) { | |
567 | return FASTTRAP_T_CB_N_Z; | |
568 | } | |
569 | ||
570 | /* All other instructions work on low regs only and are instrumentable */ | |
571 | return FASTTRAP_T_COMMON; | |
572 | } | |
573 | ||
574 | static | |
575 | int thumb16_loadstore_single(__unused uint16_t instr) | |
576 | { | |
577 | /* These all access the low registers or SP only */ | |
578 | return FASTTRAP_T_COMMON; | |
579 | } | |
580 | ||
581 | static | |
582 | int thumb16_data_special_and_branch(uint16_t instr) | |
583 | { | |
584 | int opcode = BITS(instr,6,0xF); | |
585 | ||
586 | if (opcode == 0x4) { | |
587 | /* Unpredictable */ | |
588 | return FASTTRAP_T_INV; | |
589 | } else if ((opcode & 0xC) == 0xC) { | |
590 | /* bx or blx */ | |
591 | /* Only instrument the bx */ | |
592 | if ((opcode & 0x2) == 0) | |
593 | return FASTTRAP_T_BX_REG; | |
594 | return FASTTRAP_T_INV; | |
595 | } else { | |
596 | /* Data processing on high registers, only instrument mov pc, reg */ | |
597 | if ((opcode & 0xC) == 0x8 && THUMB16_HRD(instr) == REG_PC) | |
598 | return FASTTRAP_T_CPY_PC; | |
599 | ||
600 | if (THUMB16_HRM(instr) != REG_PC && THUMB16_HRD(instr) != REG_PC) | |
601 | return FASTTRAP_T_COMMON; | |
602 | } | |
603 | ||
604 | return FASTTRAP_T_INV; | |
605 | } | |
606 | ||
607 | static | |
608 | int thumb16_data_proc(__unused uint16_t instr) | |
609 | { | |
610 | /* These all access the low registers only */ | |
611 | return FASTTRAP_T_COMMON; | |
612 | } | |
613 | ||
614 | static | |
615 | int thumb16_shift_addsub_move_compare(__unused uint16_t instr) | |
616 | { | |
617 | /* These all access the low registers only */ | |
618 | return FASTTRAP_T_COMMON; | |
619 | } | |
620 | ||
621 | static | |
622 | int dtrace_decode_thumb16(uint16_t instr) | |
623 | { | |
624 | int opcode = BITS(instr,10,0x3F); | |
625 | ||
626 | if ((opcode & 0x30) == 0) | |
627 | return thumb16_shift_addsub_move_compare(instr); | |
628 | ||
629 | if (opcode == 0x10) | |
630 | return thumb16_data_proc(instr); | |
631 | ||
632 | if (opcode == 0x11) | |
633 | return thumb16_data_special_and_branch(instr); | |
634 | ||
635 | if ((opcode & 0x3E) == 0x12) { | |
636 | /* ldr (literal) */ | |
637 | return FASTTRAP_T_LDR_PC_IMMED; | |
638 | } | |
639 | ||
640 | if ((opcode & 0x3C) == 0x14 || (opcode & 0x38) == 0x18 || (opcode & 0x38) == 0x20) | |
641 | return thumb16_loadstore_single(instr); | |
642 | ||
643 | if ((opcode & 0x3E) == 0x28) { | |
644 | /* adr, uses the pc */ | |
645 | return FASTTRAP_T_INV; | |
646 | } | |
647 | ||
648 | if ((opcode & 0x3E) == 0x2A) { | |
649 | /* add (sp plus immediate) */ | |
650 | return FASTTRAP_T_COMMON; | |
651 | } | |
652 | ||
653 | if ((opcode & 0x3C) == 0x2C) | |
654 | return thumb16_misc(instr); | |
655 | ||
656 | if ((opcode & 0x3E) == 0x30) { | |
657 | /* stm - can't access high registers */ | |
658 | return FASTTRAP_T_COMMON; | |
659 | } | |
660 | ||
661 | if ((opcode & 0x3E) == 0x32) { | |
662 | /* ldm - can't access high registers */ | |
663 | return FASTTRAP_T_COMMON; | |
664 | } | |
665 | ||
666 | if ((opcode & 0x3C) == 0x34) { | |
667 | return thumb16_cond_supervisor(instr); | |
668 | } | |
669 | ||
670 | if ((opcode & 0x3E) == 0x38) { | |
671 | /* b unconditional */ | |
672 | return FASTTRAP_T_B_UNCOND; | |
673 | } | |
674 | ||
675 | return FASTTRAP_T_INV; | |
676 | } | |
677 | ||
678 | /* | |
679 | * Thumb 32-bit decoder | |
680 | */ | |
681 | ||
682 | static | |
683 | int thumb32_coproc(uint16_t instr1, uint16_t instr2) | |
684 | { | |
685 | /* Instrument any VFP data processing instructions, ignore the rest */ | |
686 | ||
687 | int op1 = BITS(instr1,4,0x3F), coproc = BITS(instr2,8,0xF), op = BITS(instr2,4,0x1); | |
688 | ||
689 | if ((op1 & 0x3E) == 0) { | |
690 | /* Undefined */ | |
691 | return FASTTRAP_T_INV; | |
692 | } | |
693 | ||
694 | if ((coproc & 0xE) == 0xA || (op1 & 0x30) == 0x30) { | |
695 | /* VFP instruction */ | |
696 | uint32_t instr = thumb32_instword_to_arm(instr1,instr2); | |
697 | ||
698 | if ((op1 & 0x30) == 0x30) { | |
699 | /* VFP data processing uses its own registers */ | |
700 | return FASTTRAP_T_COMMON; | |
701 | } | |
702 | ||
703 | if ((op1 & 0x3A) == 0x02 || (op1 & 0x38) == 0x08 || (op1 & 0x30) == 0x10) | |
704 | return vfp_loadstore(instr); | |
705 | ||
706 | if ((op1 & 0x3E) == 0x04) | |
707 | return vfp_64transfer(instr); | |
708 | ||
709 | if ((op1 & 0x30) == 0x20) { | |
710 | /* VFP data processing or 8, 16, or 32 bit move between ARM reg and VFP reg */ | |
711 | if (op == 0) { | |
712 | /* VFP data processing uses its own registers */ | |
713 | return FASTTRAP_T_COMMON; | |
714 | } else { | |
715 | return vfp_transfer(instr); | |
716 | } | |
717 | } | |
718 | } | |
719 | ||
720 | return FASTTRAP_T_INV; | |
721 | } | |
722 | ||
723 | static | |
724 | int thumb32_longmultiply(uint16_t instr1, uint16_t instr2) | |
725 | { | |
726 | int op1 = BITS(instr1,4,0x7), op2 = BITS(instr2,4,0xF); | |
727 | ||
728 | if ((op1 == 1 && op2 == 0xF) || (op1 == 0x3 && op2 == 0xF)) { | |
729 | /* Three register instruction */ | |
730 | if (THUMB32_RM(instr1,instr2) != REG_PC && THUMB32_RD(instr1,instr2) != REG_PC && THUMB32_RN(instr1,instr2) != REG_PC) | |
731 | return FASTTRAP_T_COMMON; | |
732 | } else { | |
733 | /* Four register instruction */ | |
734 | if (THUMB32_RM(instr1,instr2) != REG_PC && THUMB32_RD(instr1,instr2) != REG_PC && | |
735 | THUMB32_RT(instr1,instr2) != REG_PC && THUMB32_RN(instr1,instr2) != REG_PC) | |
736 | return FASTTRAP_T_COMMON; | |
737 | } | |
738 | ||
739 | return FASTTRAP_T_INV; | |
740 | } | |
741 | ||
742 | static | |
743 | int thumb32_multiply(uint16_t instr1, uint16_t instr2) | |
744 | { | |
745 | int op1 = BITS(instr1,4,0x7), op2 = BITS(instr2,4,0x3); | |
746 | ||
747 | if ((op1 == 0 && op2 == 1) || (op1 == 0x6 && (op2 & 0x2) == 0)) { | |
748 | if (THUMB32_RT(instr1,instr2) == REG_PC) | |
749 | return FASTTRAP_T_INV; | |
750 | } | |
751 | ||
752 | if (THUMB32_RM(instr1,instr2) != REG_PC && THUMB32_RD(instr1,instr2) != REG_PC && THUMB32_RN(instr1,instr2) != REG_PC) | |
753 | return FASTTRAP_T_COMMON; | |
754 | ||
755 | return FASTTRAP_T_INV; | |
756 | } | |
757 | ||
758 | static | |
759 | int thumb32_misc(uint16_t instr1, uint16_t instr2) | |
760 | { | |
761 | if (THUMB32_RM(instr1,instr2) != REG_PC && THUMB32_RD(instr1,instr2) != REG_PC && THUMB32_RN(instr1,instr2) != REG_PC) | |
762 | return FASTTRAP_T_COMMON; | |
763 | ||
764 | return FASTTRAP_T_INV; | |
765 | } | |
766 | ||
767 | static | |
768 | int thumb32_parallel_addsub_unsigned(uint16_t instr1, uint16_t instr2) | |
769 | { | |
770 | if (THUMB32_RM(instr1,instr2) != REG_PC && THUMB32_RD(instr1,instr2) != REG_PC && THUMB32_RN(instr1,instr2) != REG_PC) | |
771 | return FASTTRAP_T_COMMON; | |
772 | ||
773 | return FASTTRAP_T_INV; | |
774 | } | |
775 | ||
776 | static | |
777 | int thumb32_parallel_addsub_signed(uint16_t instr1, uint16_t instr2) | |
778 | { | |
779 | if (THUMB32_RM(instr1,instr2) != REG_PC && THUMB32_RD(instr1,instr2) != REG_PC && THUMB32_RN(instr1,instr2) != REG_PC) | |
780 | return FASTTRAP_T_COMMON; | |
781 | ||
782 | return FASTTRAP_T_INV; | |
783 | } | |
784 | ||
785 | static | |
786 | int thumb32_dataproc_reg(uint16_t instr1, uint16_t instr2) | |
787 | { | |
788 | int op1 = BITS(instr1,4,0xF), op2 = BITS(instr2,4,0xF); | |
789 | ||
790 | if (((0 <= op1) && (op1 <= 5)) && (op2 & 0x8) == 0x8) { | |
791 | if (THUMB32_RM(instr1,instr2) != REG_PC && THUMB32_RD(instr1,instr2) != REG_PC) | |
792 | return FASTTRAP_T_COMMON; | |
793 | } | |
794 | ||
795 | if ((op1 & 0x8) == 0 && op2 == 0) { | |
796 | if (THUMB32_RM(instr1,instr2) != REG_PC && THUMB32_RD(instr1,instr2) != REG_PC && THUMB32_RN(instr1,instr2) != REG_PC) | |
797 | return FASTTRAP_T_COMMON; | |
798 | } | |
799 | ||
800 | if ((op1 & 0x8) == 0x8 && (op2 & 0xC) == 0) | |
801 | return thumb32_parallel_addsub_signed(instr1,instr2); | |
802 | ||
803 | if ((op1 & 0x8) == 0x8 && (op2 & 0xC) == 0x4) | |
804 | return thumb32_parallel_addsub_unsigned(instr1,instr2); | |
805 | ||
806 | if ((op1 & 0xC) == 0x8 && (op2 & 0xC) == 0x8) | |
807 | return thumb32_misc(instr1,instr2); | |
808 | ||
809 | return FASTTRAP_T_INV; | |
810 | } | |
811 | ||
812 | static | |
813 | int thumb32_dataproc_regshift(uint16_t instr1, uint16_t instr2) | |
814 | { | |
815 | int op = BITS(instr1,5,0xF), S = BITS(instr1,4,0x1); | |
816 | ||
817 | if (op == 0 || op == 0x4 || op == 0x8 || op == 0xD) { | |
818 | /* These become test instructions if S is 1 and Rd is PC, otherwise they are data instructions. */ | |
819 | if (S == 1) { | |
820 | if (THUMB32_RM(instr1,instr2) != REG_PC && THUMB32_RN(instr1,instr2) != REG_PC) | |
821 | return FASTTRAP_T_COMMON; | |
822 | } else { | |
823 | if (THUMB32_RM(instr1,instr2) != REG_PC && THUMB32_RD(instr1,instr2) != REG_PC && | |
824 | THUMB32_RN(instr1,instr2) != REG_PC) | |
825 | return FASTTRAP_T_COMMON; | |
826 | } | |
827 | } else if (op == 0x2 || op == 0x3) { | |
828 | /* These become moves if RN is PC, otherwise they are data insts. We don't instrument mov pc, reg here */ | |
829 | if (THUMB32_RM(instr1,instr2) != REG_PC && THUMB32_RD(instr1,instr2) != REG_PC) | |
830 | return FASTTRAP_T_COMMON; | |
831 | } else { | |
832 | /* Normal three register instruction */ | |
833 | if (THUMB32_RM(instr1,instr2) != REG_PC && THUMB32_RD(instr1,instr2) != REG_PC && THUMB32_RN(instr1,instr2) != REG_PC) | |
834 | return FASTTRAP_T_COMMON; | |
835 | } | |
836 | ||
837 | return FASTTRAP_T_INV; | |
838 | } | |
839 | ||
840 | static | |
841 | int thumb32_store_single(uint16_t instr1, uint16_t instr2) | |
842 | { | |
843 | int op1 = BITS(instr1,5,0x7), op2 = BITS(instr2,6,0x3F); | |
844 | ||
845 | /* Do not support any use of the pc yet */ | |
846 | if ((op1 == 0 || op1 == 1 || op1 == 2) && (op2 & 0x20) == 0) { | |
847 | /* str (register) uses RM */ | |
848 | if (THUMB32_RM(instr1,instr2) == REG_PC) | |
849 | return FASTTRAP_T_INV; | |
850 | } | |
851 | ||
852 | if (THUMB32_RT(instr1,instr2) != REG_PC && THUMB32_RN(instr1,instr2) != REG_PC) | |
853 | return FASTTRAP_T_COMMON; | |
854 | ||
855 | return FASTTRAP_T_INV; | |
856 | } | |
857 | ||
858 | static | |
859 | int thumb32_loadbyte_memhint(uint16_t instr1, uint16_t instr2) | |
860 | { | |
861 | int op1 = BITS(instr1,7,0x3), __unused op2 = BITS(instr2,6,0x3F); | |
862 | ||
863 | /* Do not support any use of the pc yet */ | |
864 | if ((op1 == 0 || op1 == 0x2) && THUMB32_RM(instr1,instr2) == REG_PC) | |
865 | return FASTTRAP_T_INV; | |
866 | ||
867 | if (THUMB32_RT(instr1,instr2) != REG_PC && THUMB32_RN(instr1,instr2) != REG_PC) | |
868 | return FASTTRAP_T_COMMON; | |
869 | ||
870 | return FASTTRAP_T_INV; | |
871 | } | |
872 | ||
873 | static | |
874 | int thumb32_loadhalfword_memhint(uint16_t instr1, uint16_t instr2) | |
875 | { | |
876 | int op1 = BITS(instr1,7,0x3), op2 = BITS(instr2,6,0x3F); | |
877 | ||
878 | /* Do not support any use of the PC yet */ | |
879 | if (op1 == 0 && op2 == 0 && THUMB32_RM(inst1,instr2) == REG_PC) | |
880 | return FASTTRAP_T_INV; | |
881 | ||
882 | if (THUMB32_RT(instr1,instr2) != REG_PC && THUMB32_RN(instr1,instr2) != REG_PC) | |
883 | return FASTTRAP_T_COMMON; | |
884 | ||
885 | return FASTTRAP_T_INV; | |
886 | } | |
887 | ||
888 | static | |
889 | int thumb32_loadword(uint16_t instr1, uint16_t instr2) | |
890 | { | |
891 | int op1 = BITS(instr1,7,0x3), op2 = BITS(instr2,6,0x3F); | |
892 | ||
893 | if ((op1 & 0x2) == 0 && THUMB32_RN(instr1,instr2) == REG_PC && THUMB32_RT(instr1,instr2) != REG_PC) | |
894 | return FASTTRAP_T_LDR_PC_IMMED; | |
895 | ||
896 | if (op1 == 0 && op2 == 0) { | |
897 | /* ldr (register) uses an additional reg */ | |
898 | if (THUMB32_RM(instr1,instr2) == REG_PC) | |
899 | return FASTTRAP_T_INV; | |
900 | } | |
901 | ||
902 | if (THUMB32_RT(instr1,instr2) != REG_PC && THUMB32_RN(instr1,instr2) != REG_PC) | |
903 | return FASTTRAP_T_COMMON; | |
904 | ||
905 | return FASTTRAP_T_INV; | |
906 | } | |
907 | ||
908 | static | |
909 | int thumb32_loadstore_double_exclusive_table(__unused uint16_t instr1, __unused uint16_t instr2) | |
910 | { | |
911 | /* Don't instrument any of these */ | |
912 | ||
913 | return FASTTRAP_T_INV; | |
914 | } | |
915 | ||
916 | static | |
917 | int thumb32_loadstore_multiple(uint16_t instr1, uint16_t instr2) | |
918 | { | |
919 | int op = BITS(instr1,7,0x3), L = BITS(instr1,4,0x1), uses_pc = BITS(instr2,15,0x1), uses_lr = BITS(instr2,14,0x1); | |
920 | ||
921 | if (op == 0 || op == 0x3) { | |
922 | /* Privileged instructions: srs, rfe */ | |
923 | return FASTTRAP_T_INV; | |
924 | } | |
925 | ||
926 | /* Only emulate a use of the pc if it's a return from function: ldmia sp!, { ... pc }, aka pop { ... pc } */ | |
927 | if (op == 0x1 && L == 1 && THUMB32_RN(instr1,instr2) == REG_SP && uses_pc == 1) | |
928 | return FASTTRAP_T_LDM_PC; | |
929 | ||
930 | /* stmia sp!, { ... lr }, aka push { ... lr } doesn't touch the pc, but it is very common, so special case it */ | |
931 | if (op == 0x2 && L == 0 && THUMB32_RN(instr1,instr2) == REG_SP && uses_lr == 1) | |
932 | return FASTTRAP_T_STM_LR; | |
933 | ||
934 | if (THUMB32_RN(instr1,instr2) != REG_PC && uses_pc == 0) | |
935 | return FASTTRAP_T_COMMON; | |
936 | ||
937 | return FASTTRAP_T_INV; | |
938 | } | |
939 | ||
940 | static | |
941 | int thumb32_misc_control(__unused uint16_t instr1, __unused uint16_t instr2) | |
942 | { | |
943 | /* Privileged, and instructions dealing with ThumbEE */ | |
944 | return FASTTRAP_T_INV; | |
945 | } | |
946 | ||
947 | static | |
948 | int thumb32_cps_hints(__unused uint16_t instr1, __unused uint16_t instr2) | |
949 | { | |
950 | /* Privileged */ | |
951 | return FASTTRAP_T_INV; | |
952 | } | |
953 | ||
954 | static | |
955 | int thumb32_b_misc_control(uint16_t instr1, uint16_t instr2) | |
956 | { | |
957 | int op = BITS(instr1,4,0x7F), op1 = BITS(instr2,12,0x7), __unused op2 = BITS(instr2,8,0xF); | |
958 | ||
959 | if ((op1 & 0x5) == 0) { | |
960 | if ((op & 0x38) != 0x38) | |
961 | return FASTTRAP_T_B_COND; | |
962 | ||
963 | if (op == 0x3A) | |
964 | return thumb32_cps_hints(instr1,instr2); | |
965 | ||
966 | if (op == 0x3B) | |
967 | return thumb32_misc_control(instr1,instr2); | |
968 | } | |
969 | ||
970 | if ((op1 & 0x5) == 1) | |
971 | return FASTTRAP_T_B_UNCOND; | |
972 | ||
973 | return FASTTRAP_T_INV; | |
974 | } | |
975 | ||
976 | static | |
977 | int thumb32_dataproc_plain_immed(uint16_t instr1, uint16_t instr2) | |
978 | { | |
979 | int op = BITS(instr1,4,0x1F); | |
980 | ||
981 | if (op == 0x04 || op == 0x0C || op == 0x16) { | |
982 | /* mov, movt, bfi, bfc */ | |
983 | /* These use only RD */ | |
984 | if (THUMB32_RD(instr1,instr2) != REG_PC) | |
985 | return FASTTRAP_T_COMMON; | |
986 | } else { | |
987 | if (THUMB32_RD(instr1,instr2) != REG_PC && THUMB32_RN(instr1,instr2) != REG_PC) | |
988 | return FASTTRAP_T_COMMON; | |
989 | } | |
990 | ||
991 | return FASTTRAP_T_INV; | |
992 | } | |
993 | ||
994 | static | |
995 | int thumb32_dataproc_mod_immed(uint16_t instr1, uint16_t instr2) | |
996 | { | |
997 | int op = BITS(instr1,5,0xF), S = BITS(instr1,4,0x1); | |
998 | ||
999 | if (op == 0x2 || op == 0x3) { | |
1000 | /* These allow REG_PC in RN, but it doesn't mean use the PC! */ | |
1001 | if (THUMB32_RD(instr1,instr2) != REG_PC) | |
1002 | return FASTTRAP_T_COMMON; | |
1003 | } | |
1004 | ||
1005 | if (op == 0 || op == 0x4 || op == 0x8 || op == 0xD) { | |
1006 | /* These are test instructions, if the sign bit is set and RD is the PC. */ | |
1007 | if (S && THUMB32_RD(instr1,instr2) == REG_PC) | |
1008 | return FASTTRAP_T_COMMON; | |
1009 | } | |
1010 | ||
1011 | if (THUMB32_RD(instr1,instr2) != REG_PC && THUMB32_RN(instr1,instr2) != REG_PC) | |
1012 | return FASTTRAP_T_COMMON; | |
1013 | ||
1014 | return FASTTRAP_T_INV; | |
1015 | } | |
1016 | ||
1017 | static | |
1018 | int dtrace_decode_thumb32(uint16_t instr1, uint16_t instr2) | |
1019 | { | |
1020 | int op1 = BITS(instr1,11,0x3), op2 = BITS(instr1,4,0x7F), op = BITS(instr2,15,0x1); | |
1021 | ||
1022 | if (op1 == 0x1) { | |
1023 | if ((op2 & 0x64) == 0) | |
1024 | return thumb32_loadstore_multiple(instr1,instr2); | |
1025 | ||
1026 | if ((op2 & 0x64) == 0x04) | |
1027 | return thumb32_loadstore_double_exclusive_table(instr1,instr2); | |
1028 | ||
1029 | if ((op2 & 0x60) == 0x20) | |
1030 | return thumb32_dataproc_regshift(instr1,instr2); | |
1031 | ||
1032 | if ((op2 & 0x40) == 0x40) | |
1033 | return thumb32_coproc(instr1,instr2); | |
1034 | } | |
1035 | ||
1036 | if (op1 == 0x2) { | |
1037 | if ((op2 & 0x20) == 0 && op == 0) | |
1038 | return thumb32_dataproc_mod_immed(instr1,instr2); | |
1039 | ||
1040 | if ((op2 & 0x20) == 0x20 && op == 0) | |
1041 | return thumb32_dataproc_plain_immed(instr1,instr2); | |
1042 | ||
1043 | if (op == 1) | |
1044 | return thumb32_b_misc_control(instr1,instr2); | |
1045 | } | |
1046 | ||
1047 | if (op1 == 0x3) { | |
1048 | if ((op2 & 0x71) == 0) | |
1049 | return thumb32_store_single(instr1,instr2); | |
1050 | ||
1051 | if ((op2 & 0x71) == 0x10) { | |
1052 | return vfp_struct_loadstore(thumb32_instword_to_arm(instr1,instr2)); | |
1053 | } | |
1054 | ||
1055 | if ((op2 & 0x67) == 0x01) | |
1056 | return thumb32_loadbyte_memhint(instr1,instr2); | |
1057 | ||
1058 | if ((op2 & 0x67) == 0x03) | |
1059 | return thumb32_loadhalfword_memhint(instr1,instr2); | |
1060 | ||
1061 | if ((op2 & 0x67) == 0x05) | |
1062 | return thumb32_loadword(instr1,instr2); | |
1063 | ||
1064 | if ((op2 & 0x67) == 0x07) { | |
1065 | /* Undefined instruction */ | |
1066 | return FASTTRAP_T_INV; | |
1067 | } | |
1068 | ||
1069 | if ((op2 & 0x70) == 0x20) | |
1070 | return thumb32_dataproc_reg(instr1,instr2); | |
1071 | ||
1072 | if ((op2 & 0x78) == 0x30) | |
1073 | return thumb32_multiply(instr1,instr2); | |
1074 | ||
1075 | if ((op2 & 0x78) == 0x38) | |
1076 | return thumb32_longmultiply(instr1,instr2); | |
1077 | ||
1078 | if ((op2 & 0x40) == 0x40) | |
1079 | return thumb32_coproc(instr1,instr2); | |
1080 | } | |
1081 | ||
1082 | return FASTTRAP_T_INV; | |
1083 | } | |
1084 | ||
1085 | int dtrace_decode_thumb(uint32_t instr) | |
1086 | { | |
1087 | uint16_t* pInstr = (uint16_t*) &instr; | |
1088 | uint16_t hw1 = pInstr[0], hw2 = pInstr[1]; | |
1089 | ||
1090 | int size = BITS(hw1,11,0x1F); | |
1091 | ||
1092 | if (size == 0x1D || size == 0x1E || size == 0x1F) | |
1093 | return dtrace_decode_thumb32(hw1,hw2); | |
1094 | else | |
1095 | return dtrace_decode_thumb16(hw1); | |
1096 | } | |
1097 | ||
1098 | struct arm64_decode_entry { | |
1099 | uint32_t mask; | |
1100 | uint32_t value; | |
1101 | uint32_t type; | |
1102 | }; | |
1103 | ||
1104 | struct arm64_decode_entry arm64_decode_table[] = { | |
1105 | { .mask = 0xFFFFFFFF, .value = FASTTRAP_ARM64_OP_VALUE_FUNC_ENTRY, .type = FASTTRAP_T_ARM64_STANDARD_FUNCTION_ENTRY }, | |
1106 | { .mask = FASTTRAP_ARM64_OP_MASK_LDR_S_PC_REL, .value = FASTTRAP_ARM64_OP_VALUE_LDR_S_PC_REL, .type = FASTTRAP_T_ARM64_LDR_S_PC_REL }, | |
1107 | { .mask = FASTTRAP_ARM64_OP_MASK_LDR_W_PC_REL, .value = FASTTRAP_ARM64_OP_VALUE_LDR_W_PC_REL, .type = FASTTRAP_T_ARM64_LDR_W_PC_REL }, | |
1108 | { .mask = FASTTRAP_ARM64_OP_MASK_LDR_D_PC_REL, .value = FASTTRAP_ARM64_OP_VALUE_LDR_D_PC_REL, .type = FASTTRAP_T_ARM64_LDR_D_PC_REL }, | |
1109 | { .mask = FASTTRAP_ARM64_OP_MASK_LDR_X_PC_REL, .value = FASTTRAP_ARM64_OP_VALUE_LDR_X_PC_REL, .type = FASTTRAP_T_ARM64_LDR_X_PC_REL }, | |
1110 | { .mask = FASTTRAP_ARM64_OP_MASK_LDR_Q_PC_REL, .value = FASTTRAP_ARM64_OP_VALUE_LDR_Q_PC_REL, .type = FASTTRAP_T_ARM64_LDR_Q_PC_REL }, | |
1111 | { .mask = FASTTRAP_ARM64_OP_MASK_LRDSW_PC_REL, .value = FASTTRAP_ARM64_OP_VALUE_LRDSW_PC_REL, .type = FASTTRAP_T_ARM64_LDRSW_PC_REL }, | |
1112 | { .mask = FASTTRAP_ARM64_OP_MASK_B_COND_PC_REL, .value = FASTTRAP_ARM64_OP_VALUE_B_COND_PC_REL, .type = FASTTRAP_T_ARM64_B_COND }, | |
1113 | { .mask = FASTTRAP_ARM64_OP_MASK_CBNZ_W_PC_REL, .value = FASTTRAP_ARM64_OP_VALUE_CBNZ_W_PC_REL, .type = FASTTRAP_T_ARM64_CBNZ_W }, | |
1114 | { .mask = FASTTRAP_ARM64_OP_MASK_CBNZ_X_PC_REL, .value = FASTTRAP_ARM64_OP_VALUE_CBNZ_X_PC_REL, .type = FASTTRAP_T_ARM64_CBNZ_X }, | |
1115 | { .mask = FASTTRAP_ARM64_OP_MASK_CBZ_W_PC_REL, .value = FASTTRAP_ARM64_OP_VALUE_CBZ_W_PC_REL, .type = FASTTRAP_T_ARM64_CBZ_W }, | |
1116 | { .mask = FASTTRAP_ARM64_OP_MASK_CBZ_X_PC_REL, .value = FASTTRAP_ARM64_OP_VALUE_CBZ_X_PC_REL, .type = FASTTRAP_T_ARM64_CBZ_X }, | |
1117 | { .mask = FASTTRAP_ARM64_OP_MASK_TBNZ_PC_REL, .value = FASTTRAP_ARM64_OP_VALUE_TBNZ_PC_REL, .type = FASTTRAP_T_ARM64_TBNZ }, | |
1118 | { .mask = FASTTRAP_ARM64_OP_MASK_TBZ_PC_REL, .value = FASTTRAP_ARM64_OP_VALUE_TBZ_PC_REL, .type = FASTTRAP_T_ARM64_TBZ }, | |
1119 | { .mask = FASTTRAP_ARM64_OP_MASK_B_PC_REL, .value = FASTTRAP_ARM64_OP_VALUE_B_PC_REL, .type = FASTTRAP_T_ARM64_B }, | |
1120 | { .mask = FASTTRAP_ARM64_OP_MASK_BL_PC_REL, .value = FASTTRAP_ARM64_OP_VALUE_BL_PC_REL, .type = FASTTRAP_T_ARM64_BL }, | |
1121 | { .mask = FASTTRAP_ARM64_OP_MASK_BLR, .value = FASTTRAP_ARM64_OP_VALUE_BLR, .type = FASTTRAP_T_ARM64_BLR }, | |
1122 | { .mask = FASTTRAP_ARM64_OP_MASK_BR, .value = FASTTRAP_ARM64_OP_VALUE_BR, .type = FASTTRAP_T_ARM64_BR }, | |
1123 | { .mask = FASTTRAP_ARM64_OP_MASK_RET, .value = FASTTRAP_ARM64_OP_VALUE_RET, .type = FASTTRAP_T_ARM64_RET }, | |
1124 | { .mask = FASTTRAP_ARM64_OP_MASK_ADRP, .value = FASTTRAP_ARM64_OP_VALUE_ADRP, .type = FASTTRAP_T_ARM64_ADRP }, | |
1125 | { .mask = FASTTRAP_ARM64_OP_MASK_ADR, .value = FASTTRAP_ARM64_OP_VALUE_ADR, .type = FASTTRAP_T_ARM64_ADR }, | |
1126 | { .mask = FASTTRAP_ARM64_OP_MASK_PRFM, .value = FASTTRAP_ARM64_OP_VALUE_PRFM, .type = FASTTRAP_T_ARM64_PRFM }, | |
d9a64523 A |
1127 | { .mask = FASTTRAP_ARM64_OP_MASK_EXCL_MEM, .value = FASTTRAP_ARM64_OP_VALUE_EXCL_MEM, .type = FASTTRAP_T_ARM64_EXCLUSIVE_MEM }, |
1128 | { .mask = FASTTRAP_ARM64_OP_MASK_RETAB, .value = FASTTRAP_ARM64_OP_VALUE_RETAB, .type = FASTTRAP_T_ARM64_RETAB }}; | |
5ba3f43e A |
1129 | |
1130 | #define NUM_DECODE_ENTRIES (sizeof(arm64_decode_table) / sizeof(struct arm64_decode_entry)) | |
1131 | ||
1132 | ||
1133 | ||
1134 | int dtrace_decode_arm64(uint32_t instr) | |
1135 | { | |
1136 | unsigned i; | |
1137 | ||
1138 | for (i = 0; i < NUM_DECODE_ENTRIES; i++) { | |
1139 | if ((instr & arm64_decode_table[i].mask) == arm64_decode_table[i].value) { | |
1140 | return arm64_decode_table[i].type; | |
1141 | } | |
1142 | } | |
1143 | ||
1144 | return FASTTRAP_T_COMMON; | |
1145 | } | |
1146 | ||
1147 |