1 // Copyright 2006 The Android Open Source Project
2
3 #include <stdio.h>
4 #include <string.h>
5 #include "armdis.h"
6 #include "opcode.h"
7
8 static const char *cond_names[] = {
9 "eq",
10 "ne",
11 "cs",
12 "cc",
13 "mi",
14 "pl",
15 "vs",
16 "vc",
17 "hi",
18 "ls",
19 "ge",
20 "lt",
21 "gt",
22 "le",
23 "",
24 "RESERVED"
25 };
26
27 // Indexed by the shift type (bits 6-5)
28 static const char *shift_names[] = {
29 "LSL",
30 "LSR",
31 "ASR",
32 "ROR"
33 };
34
cond_to_str(int cond)35 static const char* cond_to_str(int cond) {
36 return cond_names[cond];
37 }
38
disasm(uint32_t addr,uint32_t insn,char * result)39 char *Arm::disasm(uint32_t addr, uint32_t insn, char *result)
40 {
41 static char buf[80];
42 char *ptr;
43
44 ptr = result ? result : buf;
45 Opcode opcode = decode(insn);
46 switch (opcode) {
47 case OP_INVALID:
48 sprintf(ptr, "Invalid");
49 return ptr;
50 case OP_UNDEFINED:
51 sprintf(ptr, "Undefined");
52 return ptr;
53 case OP_ADC:
54 case OP_ADD:
55 case OP_AND:
56 case OP_BIC:
57 case OP_CMN:
58 case OP_CMP:
59 case OP_EOR:
60 case OP_MOV:
61 case OP_MVN:
62 case OP_ORR:
63 case OP_RSB:
64 case OP_RSC:
65 case OP_SBC:
66 case OP_SUB:
67 case OP_TEQ:
68 case OP_TST:
69 return disasm_alu(opcode, insn, ptr);
70 case OP_B:
71 case OP_BL:
72 return disasm_branch(addr, opcode, insn, ptr);
73 case OP_BKPT:
74 return disasm_bkpt(insn, ptr);
75 case OP_BLX:
76 // not supported yet
77 break;
78 case OP_BX:
79 return disasm_bx(insn, ptr);
80 case OP_CDP:
81 sprintf(ptr, "cdp");
82 return ptr;
83 case OP_CLZ:
84 return disasm_clz(insn, ptr);
85 case OP_LDC:
86 sprintf(ptr, "ldc");
87 return ptr;
88 case OP_LDM:
89 case OP_STM:
90 return disasm_memblock(opcode, insn, ptr);
91 case OP_LDR:
92 case OP_LDRB:
93 case OP_LDRBT:
94 case OP_LDRT:
95 case OP_STR:
96 case OP_STRB:
97 case OP_STRBT:
98 case OP_STRT:
99 return disasm_mem(insn, ptr);
100 case OP_LDRH:
101 case OP_LDRSB:
102 case OP_LDRSH:
103 case OP_STRH:
104 return disasm_memhalf(insn, ptr);
105 case OP_MCR:
106 case OP_MRC:
107 return disasm_mcr(opcode, insn, ptr);
108 case OP_MLA:
109 return disasm_mla(opcode, insn, ptr);
110 case OP_MRS:
111 return disasm_mrs(insn, ptr);
112 case OP_MSR:
113 return disasm_msr(insn, ptr);
114 case OP_MUL:
115 return disasm_mul(opcode, insn, ptr);
116 case OP_PLD:
117 return disasm_pld(insn, ptr);
118 case OP_STC:
119 sprintf(ptr, "stc");
120 return ptr;
121 case OP_SWI:
122 return disasm_swi(insn, ptr);
123 case OP_SWP:
124 case OP_SWPB:
125 return disasm_swp(opcode, insn, ptr);
126 case OP_UMLAL:
127 case OP_UMULL:
128 case OP_SMLAL:
129 case OP_SMULL:
130 return disasm_umlal(opcode, insn, ptr);
131 default:
132 sprintf(ptr, "Error");
133 return ptr;
134 }
135 return NULL;
136 }
137
disasm_alu(Opcode opcode,uint32_t insn,char * ptr)138 char *Arm::disasm_alu(Opcode opcode, uint32_t insn, char *ptr)
139 {
140 static const uint8_t kNoOperand1 = 1;
141 static const uint8_t kNoDest = 2;
142 static const uint8_t kNoSbit = 4;
143
144 char rn_str[20];
145 char rd_str[20];
146 uint8_t flags = 0;
147 uint8_t cond = (insn >> 28) & 0xf;
148 uint8_t is_immed = (insn >> 25) & 0x1;
149 uint8_t bit_s = (insn >> 20) & 1;
150 uint8_t rn = (insn >> 16) & 0xf;
151 uint8_t rd = (insn >> 12) & 0xf;
152 uint8_t immed = insn & 0xff;
153
154 const char *opname = opcode_names[opcode];
155 switch (opcode) {
156 case OP_CMN:
157 case OP_CMP:
158 case OP_TEQ:
159 case OP_TST:
160 flags = kNoDest | kNoSbit;
161 break;
162 case OP_MOV:
163 case OP_MVN:
164 flags = kNoOperand1;
165 break;
166 default:
167 break;
168 }
169
170 // The "mov" instruction ignores the first operand (rn).
171 rn_str[0] = 0;
172 if ((flags & kNoOperand1) == 0) {
173 sprintf(rn_str, "r%d, ", rn);
174 }
175
176 // The following instructions do not write the result register (rd):
177 // tst, teq, cmp, cmn.
178 rd_str[0] = 0;
179 if ((flags & kNoDest) == 0) {
180 sprintf(rd_str, "r%d, ", rd);
181 }
182
183 const char *sbit_str = "";
184 if (bit_s && !(flags & kNoSbit))
185 sbit_str = "s";
186
187 if (is_immed) {
188 sprintf(ptr, "%s%s%s\t%s%s#%u ; 0x%x",
189 opname, cond_to_str(cond), sbit_str, rd_str, rn_str, immed, immed);
190 return ptr;
191 }
192
193 uint8_t shift_is_reg = (insn >> 4) & 1;
194 uint8_t rotate = (insn >> 8) & 0xf;
195 uint8_t rm = insn & 0xf;
196 uint8_t shift_type = (insn >> 5) & 0x3;
197 uint8_t rs = (insn >> 8) & 0xf;
198 uint8_t shift_amount = (insn >> 7) & 0x1f;
199 uint32_t rotated_val = immed;
200 uint8_t rotate2 = rotate << 1;
201 rotated_val = (rotated_val >> rotate2) | (rotated_val << (32 - rotate2));
202
203 if (!shift_is_reg && shift_type == 0 && shift_amount == 0) {
204 sprintf(ptr, "%s%s%s\t%s%sr%d",
205 opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm);
206 return ptr;
207 }
208
209 const char *shift_name = shift_names[shift_type];
210 if (shift_is_reg) {
211 sprintf(ptr, "%s%s%s\t%s%sr%d, %s r%d",
212 opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm,
213 shift_name, rs);
214 return ptr;
215 }
216 if (shift_amount == 0) {
217 if (shift_type == 3) {
218 sprintf(ptr, "%s%s%s\t%s%sr%d, RRX",
219 opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm);
220 return ptr;
221 }
222 shift_amount = 32;
223 }
224 sprintf(ptr, "%s%s%s\t%s%sr%d, %s #%u",
225 opname, cond_to_str(cond), sbit_str, rd_str, rn_str, rm,
226 shift_name, shift_amount);
227 return ptr;
228 }
229
disasm_branch(uint32_t addr,Opcode opcode,uint32_t insn,char * ptr)230 char *Arm::disasm_branch(uint32_t addr, Opcode opcode, uint32_t insn, char *ptr)
231 {
232 uint8_t cond = (insn >> 28) & 0xf;
233 uint32_t offset = insn & 0xffffff;
234 // Sign-extend the 24-bit offset
235 if ((offset >> 23) & 1)
236 offset |= 0xff000000;
237
238 // Pre-compute the left-shift and the prefetch offset
239 offset <<= 2;
240 offset += 8;
241 addr += offset;
242 const char *opname = opcode_names[opcode];
243 sprintf(ptr, "%s%s\t0x%x", opname, cond_to_str(cond), addr);
244 return ptr;
245 }
246
disasm_bx(uint32_t insn,char * ptr)247 char *Arm::disasm_bx(uint32_t insn, char *ptr)
248 {
249 uint8_t cond = (insn >> 28) & 0xf;
250 uint8_t rn = insn & 0xf;
251 sprintf(ptr, "bx%s\tr%d", cond_to_str(cond), rn);
252 return ptr;
253 }
254
disasm_bkpt(uint32_t insn,char * ptr)255 char *Arm::disasm_bkpt(uint32_t insn, char *ptr)
256 {
257 uint32_t immed = (((insn >> 8) & 0xfff) << 4) | (insn & 0xf);
258 sprintf(ptr, "bkpt\t#%d", immed);
259 return ptr;
260 }
261
disasm_clz(uint32_t insn,char * ptr)262 char *Arm::disasm_clz(uint32_t insn, char *ptr)
263 {
264 uint8_t cond = (insn >> 28) & 0xf;
265 uint8_t rd = (insn >> 12) & 0xf;
266 uint8_t rm = insn & 0xf;
267 sprintf(ptr, "clz%s\tr%d, r%d", cond_to_str(cond), rd, rm);
268 return ptr;
269 }
270
disasm_memblock(Opcode opcode,uint32_t insn,char * ptr)271 char *Arm::disasm_memblock(Opcode opcode, uint32_t insn, char *ptr)
272 {
273 char tmp_reg[10], tmp_list[80];
274
275 uint8_t cond = (insn >> 28) & 0xf;
276 uint8_t write_back = (insn >> 21) & 0x1;
277 uint8_t bit_s = (insn >> 22) & 0x1;
278 uint8_t is_up = (insn >> 23) & 0x1;
279 uint8_t is_pre = (insn >> 24) & 0x1;
280 uint8_t rn = (insn >> 16) & 0xf;
281 uint16_t reg_list = insn & 0xffff;
282
283 const char *opname = opcode_names[opcode];
284
285 const char *bang = "";
286 if (write_back)
287 bang = "!";
288
289 const char *carret = "";
290 if (bit_s)
291 carret = "^";
292
293 const char *comma = "";
294 tmp_list[0] = 0;
295 for (int ii = 0; ii < 16; ++ii) {
296 if (reg_list & (1 << ii)) {
297 sprintf(tmp_reg, "%sr%d", comma, ii);
298 strcat(tmp_list, tmp_reg);
299 comma = ",";
300 }
301 }
302
303 const char *addr_mode = "";
304 if (is_pre) {
305 if (is_up) {
306 addr_mode = "ib";
307 } else {
308 addr_mode = "db";
309 }
310 } else {
311 if (is_up) {
312 addr_mode = "ia";
313 } else {
314 addr_mode = "da";
315 }
316 }
317
318 sprintf(ptr, "%s%s%s\tr%d%s, {%s}%s",
319 opname, cond_to_str(cond), addr_mode, rn, bang, tmp_list, carret);
320 return ptr;
321 }
322
disasm_mem(uint32_t insn,char * ptr)323 char *Arm::disasm_mem(uint32_t insn, char *ptr)
324 {
325 uint8_t cond = (insn >> 28) & 0xf;
326 uint8_t is_reg = (insn >> 25) & 0x1;
327 uint8_t is_load = (insn >> 20) & 0x1;
328 uint8_t write_back = (insn >> 21) & 0x1;
329 uint8_t is_byte = (insn >> 22) & 0x1;
330 uint8_t is_up = (insn >> 23) & 0x1;
331 uint8_t is_pre = (insn >> 24) & 0x1;
332 uint8_t rn = (insn >> 16) & 0xf;
333 uint8_t rd = (insn >> 12) & 0xf;
334 uint16_t offset = insn & 0xfff;
335
336 const char *opname = "ldr";
337 if (!is_load)
338 opname = "str";
339
340 const char *bang = "";
341 if (write_back)
342 bang = "!";
343
344 const char *minus = "";
345 if (is_up == 0)
346 minus = "-";
347
348 const char *byte = "";
349 if (is_byte)
350 byte = "b";
351
352 if (is_reg == 0) {
353 if (is_pre) {
354 if (offset == 0) {
355 sprintf(ptr, "%s%s%s\tr%d, [r%d]",
356 opname, cond_to_str(cond), byte, rd, rn);
357 } else {
358 sprintf(ptr, "%s%s%s\tr%d, [r%d, #%s%u]%s",
359 opname, cond_to_str(cond), byte, rd, rn, minus, offset, bang);
360 }
361 } else {
362 const char *transfer = "";
363 if (write_back)
364 transfer = "t";
365 sprintf(ptr, "%s%s%s%s\tr%d, [r%d], #%s%u",
366 opname, cond_to_str(cond), byte, transfer, rd, rn, minus, offset);
367 }
368 return ptr;
369 }
370
371 uint8_t rm = insn & 0xf;
372 uint8_t shift_type = (insn >> 5) & 0x3;
373 uint8_t shift_amount = (insn >> 7) & 0x1f;
374
375 const char *shift_name = shift_names[shift_type];
376
377 if (is_pre) {
378 if (shift_amount == 0) {
379 if (shift_type == 0) {
380 sprintf(ptr, "%s%s%s\tr%d, [r%d, %sr%d]%s",
381 opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang);
382 return ptr;
383 }
384 if (shift_type == 3) {
385 sprintf(ptr, "%s%s%s\tr%d, [r%d, %sr%d, RRX]%s",
386 opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang);
387 return ptr;
388 }
389 shift_amount = 32;
390 }
391 sprintf(ptr, "%s%s%s\tr%d, [r%d, %sr%d, %s #%u]%s",
392 opname, cond_to_str(cond), byte, rd, rn, minus, rm,
393 shift_name, shift_amount, bang);
394 return ptr;
395 }
396
397 const char *transfer = "";
398 if (write_back)
399 transfer = "t";
400
401 if (shift_amount == 0) {
402 if (shift_type == 0) {
403 sprintf(ptr, "%s%s%s%s\tr%d, [r%d], %sr%d",
404 opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm);
405 return ptr;
406 }
407 if (shift_type == 3) {
408 sprintf(ptr, "%s%s%s%s\tr%d, [r%d], %sr%d, RRX",
409 opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm);
410 return ptr;
411 }
412 shift_amount = 32;
413 }
414
415 sprintf(ptr, "%s%s%s%s\tr%d, [r%d], %sr%d, %s #%u",
416 opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm,
417 shift_name, shift_amount);
418 return ptr;
419 }
420
disasm_memhalf(uint32_t insn,char * ptr)421 char *Arm::disasm_memhalf(uint32_t insn, char *ptr)
422 {
423 uint8_t cond = (insn >> 28) & 0xf;
424 uint8_t is_load = (insn >> 20) & 0x1;
425 uint8_t write_back = (insn >> 21) & 0x1;
426 uint8_t is_immed = (insn >> 22) & 0x1;
427 uint8_t is_up = (insn >> 23) & 0x1;
428 uint8_t is_pre = (insn >> 24) & 0x1;
429 uint8_t rn = (insn >> 16) & 0xf;
430 uint8_t rd = (insn >> 12) & 0xf;
431 uint8_t bits_65 = (insn >> 5) & 0x3;
432 uint8_t rm = insn & 0xf;
433 uint8_t offset = (((insn >> 8) & 0xf) << 4) | (insn & 0xf);
434
435 const char *opname = "ldr";
436 if (is_load == 0)
437 opname = "str";
438
439 const char *width = "";
440 if (bits_65 == 1)
441 width = "h";
442 else if (bits_65 == 2)
443 width = "sb";
444 else
445 width = "sh";
446
447 const char *bang = "";
448 if (write_back)
449 bang = "!";
450 const char *minus = "";
451 if (is_up == 0)
452 minus = "-";
453
454 if (is_immed) {
455 if (is_pre) {
456 if (offset == 0) {
457 sprintf(ptr, "%s%sh\tr%d, [r%d]", opname, cond_to_str(cond), rd, rn);
458 } else {
459 sprintf(ptr, "%s%sh\tr%d, [r%d, #%s%u]%s",
460 opname, cond_to_str(cond), rd, rn, minus, offset, bang);
461 }
462 } else {
463 sprintf(ptr, "%s%sh\tr%d, [r%d], #%s%u",
464 opname, cond_to_str(cond), rd, rn, minus, offset);
465 }
466 return ptr;
467 }
468
469 if (is_pre) {
470 sprintf(ptr, "%s%sh\tr%d, [r%d, %sr%d]%s",
471 opname, cond_to_str(cond), rd, rn, minus, rm, bang);
472 } else {
473 sprintf(ptr, "%s%sh\tr%d, [r%d], %sr%d",
474 opname, cond_to_str(cond), rd, rn, minus, rm);
475 }
476 return ptr;
477 }
478
disasm_mcr(Opcode opcode,uint32_t insn,char * ptr)479 char *Arm::disasm_mcr(Opcode opcode, uint32_t insn, char *ptr)
480 {
481 uint8_t cond = (insn >> 28) & 0xf;
482 uint8_t crn = (insn >> 16) & 0xf;
483 uint8_t crd = (insn >> 12) & 0xf;
484 uint8_t cpnum = (insn >> 8) & 0xf;
485 uint8_t opcode2 = (insn >> 5) & 0x7;
486 uint8_t crm = insn & 0xf;
487
488 const char *opname = opcode_names[opcode];
489 sprintf(ptr, "%s%s\t%d, 0, r%d, cr%d, cr%d, {%d}",
490 opname, cond_to_str(cond), cpnum, crd, crn, crm, opcode2);
491 return ptr;
492 }
493
disasm_mla(Opcode opcode,uint32_t insn,char * ptr)494 char *Arm::disasm_mla(Opcode opcode, uint32_t insn, char *ptr)
495 {
496 uint8_t cond = (insn >> 28) & 0xf;
497 uint8_t rd = (insn >> 16) & 0xf;
498 uint8_t rn = (insn >> 12) & 0xf;
499 uint8_t rs = (insn >> 8) & 0xf;
500 uint8_t rm = insn & 0xf;
501 uint8_t bit_s = (insn >> 20) & 1;
502
503 const char *opname = opcode_names[opcode];
504 sprintf(ptr, "%s%s%s\tr%d, r%d, r%d, r%d",
505 opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs, rn);
506 return ptr;
507 }
508
disasm_umlal(Opcode opcode,uint32_t insn,char * ptr)509 char *Arm::disasm_umlal(Opcode opcode, uint32_t insn, char *ptr)
510 {
511 uint8_t cond = (insn >> 28) & 0xf;
512 uint8_t rdhi = (insn >> 16) & 0xf;
513 uint8_t rdlo = (insn >> 12) & 0xf;
514 uint8_t rs = (insn >> 8) & 0xf;
515 uint8_t rm = insn & 0xf;
516 uint8_t bit_s = (insn >> 20) & 1;
517
518 const char *opname = opcode_names[opcode];
519 sprintf(ptr, "%s%s%s\tr%d, r%d, r%d, r%d",
520 opname, cond_to_str(cond), bit_s ? "s" : "", rdlo, rdhi, rm, rs);
521 return ptr;
522 }
523
disasm_mul(Opcode opcode,uint32_t insn,char * ptr)524 char *Arm::disasm_mul(Opcode opcode, uint32_t insn, char *ptr)
525 {
526 uint8_t cond = (insn >> 28) & 0xf;
527 uint8_t rd = (insn >> 16) & 0xf;
528 uint8_t rs = (insn >> 8) & 0xf;
529 uint8_t rm = insn & 0xf;
530 uint8_t bit_s = (insn >> 20) & 1;
531
532 const char *opname = opcode_names[opcode];
533 sprintf(ptr, "%s%s%s\tr%d, r%d, r%d",
534 opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs);
535 return ptr;
536 }
537
disasm_mrs(uint32_t insn,char * ptr)538 char *Arm::disasm_mrs(uint32_t insn, char *ptr)
539 {
540 uint8_t cond = (insn >> 28) & 0xf;
541 uint8_t rd = (insn >> 12) & 0xf;
542 uint8_t ps = (insn >> 22) & 1;
543
544 sprintf(ptr, "mrs%s\tr%d, %s", cond_to_str(cond), rd, ps ? "spsr" : "cpsr");
545 return ptr;
546 }
547
disasm_msr(uint32_t insn,char * ptr)548 char *Arm::disasm_msr(uint32_t insn, char *ptr)
549 {
550 char flags[8];
551 int flag_index = 0;
552 uint8_t cond = (insn >> 28) & 0xf;
553 uint8_t is_immed = (insn >> 25) & 0x1;
554 uint8_t pd = (insn >> 22) & 1;
555 uint8_t mask = (insn >> 16) & 0xf;
556
557 if (mask & 1)
558 flags[flag_index++] = 'c';
559 if (mask & 2)
560 flags[flag_index++] = 'x';
561 if (mask & 4)
562 flags[flag_index++] = 's';
563 if (mask & 8)
564 flags[flag_index++] = 'f';
565 flags[flag_index] = 0;
566
567 if (is_immed) {
568 uint32_t immed = insn & 0xff;
569 uint8_t rotate = (insn >> 8) & 0xf;
570 uint8_t rotate2 = rotate << 1;
571 uint32_t rotated_val = (immed >> rotate2) | (immed << (32 - rotate2));
572 sprintf(ptr, "msr%s\t%s_%s, #0x%x",
573 cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rotated_val);
574 return ptr;
575 }
576
577 uint8_t rm = insn & 0xf;
578
579 sprintf(ptr, "msr%s\t%s_%s, r%d",
580 cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm);
581 return ptr;
582 }
583
disasm_pld(uint32_t insn,char * ptr)584 char *Arm::disasm_pld(uint32_t insn, char *ptr)
585 {
586 uint8_t is_reg = (insn >> 25) & 0x1;
587 uint8_t is_up = (insn >> 23) & 0x1;
588 uint8_t rn = (insn >> 16) & 0xf;
589
590 const char *minus = "";
591 if (is_up == 0)
592 minus = "-";
593
594 if (is_reg) {
595 uint8_t rm = insn & 0xf;
596 sprintf(ptr, "pld\t[r%d, %sr%d]", rn, minus, rm);
597 return ptr;
598 }
599
600 uint16_t offset = insn & 0xfff;
601 if (offset == 0) {
602 sprintf(ptr, "pld\t[r%d]", rn);
603 } else {
604 sprintf(ptr, "pld\t[r%d, #%s%u]", rn, minus, offset);
605 }
606 return ptr;
607 }
608
disasm_swi(uint32_t insn,char * ptr)609 char *Arm::disasm_swi(uint32_t insn, char *ptr)
610 {
611 uint8_t cond = (insn >> 28) & 0xf;
612 uint32_t sysnum = insn & 0x00ffffff;
613
614 sprintf(ptr, "swi%s 0x%x", cond_to_str(cond), sysnum);
615 return ptr;
616 }
617
disasm_swp(Opcode opcode,uint32_t insn,char * ptr)618 char *Arm::disasm_swp(Opcode opcode, uint32_t insn, char *ptr)
619 {
620 uint8_t cond = (insn >> 28) & 0xf;
621 uint8_t rn = (insn >> 16) & 0xf;
622 uint8_t rd = (insn >> 12) & 0xf;
623 uint8_t rm = insn & 0xf;
624
625 const char *opname = opcode_names[opcode];
626 sprintf(ptr, "%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn);
627 return ptr;
628 }
629
decode(uint32_t insn)630 Opcode Arm::decode(uint32_t insn) {
631 uint32_t bits27_26 = (insn >> 26) & 0x3;
632 switch (bits27_26) {
633 case 0x0:
634 return decode00(insn);
635 case 0x1:
636 return decode01(insn);
637 case 0x2:
638 return decode10(insn);
639 case 0x3:
640 return decode11(insn);
641 }
642 return OP_INVALID;
643 }
644
decode00(uint32_t insn)645 Opcode Arm::decode00(uint32_t insn) {
646 uint8_t bit25 = (insn >> 25) & 0x1;
647 uint8_t bit4 = (insn >> 4) & 0x1;
648 if (bit25 == 0 && bit4 == 1) {
649 if ((insn & 0x0ffffff0) == 0x012fff10) {
650 // Bx instruction
651 return OP_BX;
652 }
653 if ((insn & 0x0ff000f0) == 0x01600010) {
654 // Clz instruction
655 return OP_CLZ;
656 }
657 if ((insn & 0xfff000f0) == 0xe1200070) {
658 // Bkpt instruction
659 return OP_BKPT;
660 }
661 uint32_t bits7_4 = (insn >> 4) & 0xf;
662 if (bits7_4 == 0x9) {
663 if ((insn & 0x0ff00ff0) == 0x01000090) {
664 // Swp instruction
665 uint8_t bit22 = (insn >> 22) & 0x1;
666 if (bit22)
667 return OP_SWPB;
668 return OP_SWP;
669 }
670 // One of the multiply instructions
671 return decode_mul(insn);
672 }
673
674 uint8_t bit7 = (insn >> 7) & 0x1;
675 if (bit7 == 1) {
676 // One of the load/store halfword/byte instructions
677 return decode_ldrh(insn);
678 }
679 }
680
681 // One of the data processing instructions
682 return decode_alu(insn);
683 }
684
decode01(uint32_t insn)685 Opcode Arm::decode01(uint32_t insn) {
686 uint8_t is_reg = (insn >> 25) & 0x1;
687 uint8_t bit4 = (insn >> 4) & 0x1;
688 if (is_reg == 1 && bit4 == 1)
689 return OP_UNDEFINED;
690 uint8_t is_load = (insn >> 20) & 0x1;
691 uint8_t is_byte = (insn >> 22) & 0x1;
692 if ((insn & 0xfd70f000) == 0xf550f000) {
693 // Pre-load
694 return OP_PLD;
695 }
696 if (is_load) {
697 if (is_byte) {
698 // Load byte
699 return OP_LDRB;
700 }
701 // Load word
702 return OP_LDR;
703 }
704 if (is_byte) {
705 // Store byte
706 return OP_STRB;
707 }
708 // Store word
709 return OP_STR;
710 }
711
decode10(uint32_t insn)712 Opcode Arm::decode10(uint32_t insn) {
713 uint8_t bit25 = (insn >> 25) & 0x1;
714 if (bit25 == 0) {
715 // LDM/STM
716 uint8_t is_load = (insn >> 20) & 0x1;
717 if (is_load)
718 return OP_LDM;
719 return OP_STM;
720 }
721 // Branch or Branch with link
722 uint8_t is_link = (insn >> 24) & 1;
723 uint32_t offset = insn & 0xffffff;
724
725 // Sign-extend the 24-bit offset
726 if ((offset >> 23) & 1)
727 offset |= 0xff000000;
728
729 // Pre-compute the left-shift and the prefetch offset
730 offset <<= 2;
731 offset += 8;
732 if (is_link == 0)
733 return OP_B;
734 return OP_BL;
735 }
736
decode11(uint32_t insn)737 Opcode Arm::decode11(uint32_t insn) {
738 uint8_t bit25 = (insn >> 25) & 0x1;
739 if (bit25 == 0) {
740 // LDC, SDC
741 uint8_t is_load = (insn >> 20) & 0x1;
742 if (is_load) {
743 // LDC
744 return OP_LDC;
745 }
746 // STC
747 return OP_STC;
748 }
749
750 uint8_t bit24 = (insn >> 24) & 0x1;
751 if (bit24 == 0x1) {
752 // SWI
753 return OP_SWI;
754 }
755
756 uint8_t bit4 = (insn >> 4) & 0x1;
757 uint8_t cpnum = (insn >> 8) & 0xf;
758
759 if (cpnum == 15) {
760 // Special case for coprocessor 15
761 uint8_t opcode = (insn >> 21) & 0x7;
762 if (bit4 == 0 || opcode != 0) {
763 // This is an unexpected bit pattern. Create an undefined
764 // instruction in case this is ever executed.
765 return OP_UNDEFINED;
766 }
767
768 // MRC, MCR
769 uint8_t is_mrc = (insn >> 20) & 0x1;
770 if (is_mrc)
771 return OP_MRC;
772 return OP_MCR;
773 }
774
775 if (bit4 == 0) {
776 // CDP
777 return OP_CDP;
778 }
779 // MRC, MCR
780 uint8_t is_mrc = (insn >> 20) & 0x1;
781 if (is_mrc)
782 return OP_MRC;
783 return OP_MCR;
784 }
785
decode_mul(uint32_t insn)786 Opcode Arm::decode_mul(uint32_t insn) {
787 uint8_t bit24 = (insn >> 24) & 0x1;
788 if (bit24 != 0) {
789 // This is an unexpected bit pattern. Create an undefined
790 // instruction in case this is ever executed.
791 return OP_UNDEFINED;
792 }
793 uint8_t bit23 = (insn >> 23) & 0x1;
794 uint8_t bit22_U = (insn >> 22) & 0x1;
795 uint8_t bit21_A = (insn >> 21) & 0x1;
796 if (bit23 == 0) {
797 // 32-bit multiply
798 if (bit22_U != 0) {
799 // This is an unexpected bit pattern. Create an undefined
800 // instruction in case this is ever executed.
801 return OP_UNDEFINED;
802 }
803 if (bit21_A == 0)
804 return OP_MUL;
805 return OP_MLA;
806 }
807 // 64-bit multiply
808 if (bit22_U == 0) {
809 // Unsigned multiply long
810 if (bit21_A == 0)
811 return OP_UMULL;
812 return OP_UMLAL;
813 }
814 // Signed multiply long
815 if (bit21_A == 0)
816 return OP_SMULL;
817 return OP_SMLAL;
818 }
819
decode_ldrh(uint32_t insn)820 Opcode Arm::decode_ldrh(uint32_t insn) {
821 uint8_t is_load = (insn >> 20) & 0x1;
822 uint8_t bits_65 = (insn >> 5) & 0x3;
823 if (is_load) {
824 if (bits_65 == 0x1) {
825 // Load unsigned halfword
826 return OP_LDRH;
827 } else if (bits_65 == 0x2) {
828 // Load signed byte
829 return OP_LDRSB;
830 }
831 // Signed halfword
832 if (bits_65 != 0x3) {
833 // This is an unexpected bit pattern. Create an undefined
834 // instruction in case this is ever executed.
835 return OP_UNDEFINED;
836 }
837 // Load signed halfword
838 return OP_LDRSH;
839 }
840 // Store halfword
841 if (bits_65 != 0x1) {
842 // This is an unexpected bit pattern. Create an undefined
843 // instruction in case this is ever executed.
844 return OP_UNDEFINED;
845 }
846 // Store halfword
847 return OP_STRH;
848 }
849
decode_alu(uint32_t insn)850 Opcode Arm::decode_alu(uint32_t insn) {
851 uint8_t is_immed = (insn >> 25) & 0x1;
852 uint8_t opcode = (insn >> 21) & 0xf;
853 uint8_t bit_s = (insn >> 20) & 1;
854 uint8_t shift_is_reg = (insn >> 4) & 1;
855 uint8_t bit7 = (insn >> 7) & 1;
856 if (!is_immed && shift_is_reg && (bit7 != 0)) {
857 // This is an unexpected bit pattern. Create an undefined
858 // instruction in case this is ever executed.
859 return OP_UNDEFINED;
860 }
861 switch (opcode) {
862 case 0x0:
863 return OP_AND;
864 case 0x1:
865 return OP_EOR;
866 case 0x2:
867 return OP_SUB;
868 case 0x3:
869 return OP_RSB;
870 case 0x4:
871 return OP_ADD;
872 case 0x5:
873 return OP_ADC;
874 case 0x6:
875 return OP_SBC;
876 case 0x7:
877 return OP_RSC;
878 case 0x8:
879 if (bit_s)
880 return OP_TST;
881 return OP_MRS;
882 case 0x9:
883 if (bit_s)
884 return OP_TEQ;
885 return OP_MSR;
886 case 0xa:
887 if (bit_s)
888 return OP_CMP;
889 return OP_MRS;
890 case 0xb:
891 if (bit_s)
892 return OP_CMN;
893 return OP_MSR;
894 case 0xc:
895 return OP_ORR;
896 case 0xd:
897 return OP_MOV;
898 case 0xe:
899 return OP_BIC;
900 case 0xf:
901 return OP_MVN;
902 }
903 // Unreachable
904 return OP_INVALID;
905 }
906