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