]> git.saurik.com Git - apple/xnu.git/blame - bsd/dev/arm64/disassembler.c
xnu-4903.221.2.tar.gz
[apple/xnu.git] / bsd / dev / arm64 / disassembler.c
CommitLineData
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
17static uint32_t thumb32_instword_to_arm(uint16_t hw1, uint16_t hw2)
18{
19 return (hw1 << 16) | hw2;
20}
21
22int dtrace_decode_arm(uint32_t instr);
23int dtrace_decode_arm64(uint32_t instr);
24int dtrace_decode_thumb(uint32_t instr);
25
26/*
27 * VFP decoder - shared between ARM and THUMB32 mode
28 */
29
30static
31int 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
39static
40int 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
49static
50int 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
59static
60int 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
79static
80int 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
96static
97int 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
109static
110int 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
144static
145int 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
169static
170int 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
186static
187int 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
203static
204int 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
212static
213int 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
221static
222int 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
273static
274int 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
295static
296int 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
304static
305int 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
323static
324int arm_msr_hints(__unused uint32_t instr)
325{
326 /* These deal with the psr, not instrumented */
327
328 return FASTTRAP_T_INV;
329}
330
331static
332int 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
340static
341int 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
361static
362int 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
381static
382int 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
394static
395int 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
407static
408int 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
417static
418int 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
427static
428int 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
454static
455int 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
510int 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
542static
543int 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
553static
554int 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
574static
575int 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
581static
582int 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
607static
608int thumb16_data_proc(__unused uint16_t instr)
609{
610 /* These all access the low registers only */
611 return FASTTRAP_T_COMMON;
612}
613
614static
615int 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
621static
622int 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
682static
683int 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
723static
724int 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
742static
743int 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
758static
759int 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
767static
768int 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
776static
777int 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
785static
786int 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
812static
813int 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
840static
841int 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
858static
859int 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
873static
874int 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
888static
889int 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
908static
909int 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
916static
917int 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
940static
941int 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
947static
948int thumb32_cps_hints(__unused uint16_t instr1, __unused uint16_t instr2)
949{
950 /* Privileged */
951 return FASTTRAP_T_INV;
952}
953
954static
955int 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
976static
977int 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
994static
995int 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
1017static
1018int 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
1085int 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
1098struct arm64_decode_entry {
1099 uint32_t mask;
1100 uint32_t value;
1101 uint32_t type;
1102};
1103
1104struct 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
1134int 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