Home | History | Annotate | Download | only in qtools
      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 
     35 static const char* cond_to_str(int cond) {
     36     return cond_names[cond];
     37 }
     38 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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