1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "disassembler_arm.h" 18 19 #include <inttypes.h> 20 21 #include <iostream> 22 23 #include "base/logging.h" 24 #include "base/stringprintf.h" 25 #include "thread.h" 26 27 namespace art { 28 namespace arm { 29 30 size_t DisassemblerArm::Dump(std::ostream& os, const uint8_t* begin) { 31 if ((reinterpret_cast<intptr_t>(begin) & 1) == 0) { 32 DumpArm(os, begin); 33 return 4; 34 } else { 35 // remove thumb specifier bits 36 begin = reinterpret_cast<const uint8_t*>(reinterpret_cast<uintptr_t>(begin) & ~1); 37 return DumpThumb16(os, begin); 38 } 39 } 40 41 void DisassemblerArm::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) { 42 if ((reinterpret_cast<intptr_t>(begin) & 1) == 0) { 43 for (const uint8_t* cur = begin; cur < end; cur += 4) { 44 DumpArm(os, cur); 45 } 46 } else { 47 // remove thumb specifier bits 48 begin = reinterpret_cast<const uint8_t*>(reinterpret_cast<uintptr_t>(begin) & ~1); 49 end = reinterpret_cast<const uint8_t*>(reinterpret_cast<uintptr_t>(end) & ~1); 50 for (const uint8_t* cur = begin; cur < end;) { 51 cur += DumpThumb16(os, cur); 52 } 53 } 54 } 55 56 static const char* kConditionCodeNames[] = { 57 "eq", // 0000 - equal 58 "ne", // 0001 - not-equal 59 "cs", // 0010 - carry-set, greater than, equal or unordered 60 "cc", // 0011 - carry-clear, less than 61 "mi", // 0100 - minus, negative 62 "pl", // 0101 - plus, positive or zero 63 "vs", // 0110 - overflow 64 "vc", // 0111 - no overflow 65 "hi", // 1000 - unsigned higher 66 "ls", // 1001 - unsigned lower or same 67 "ge", // 1010 - signed greater than or equal 68 "lt", // 1011 - signed less than 69 "gt", // 1100 - signed greater than 70 "le", // 1101 - signed less than or equal 71 "", // 1110 - always 72 "nv", // 1111 - never (mostly obsolete, but might be a clue that we're mistranslating) 73 }; 74 75 void DisassemblerArm::DumpCond(std::ostream& os, uint32_t cond) { 76 if (cond < 15) { 77 os << kConditionCodeNames[cond]; 78 } else { 79 os << "Unexpected condition: " << cond; 80 } 81 } 82 83 void DisassemblerArm::DumpMemoryDomain(std::ostream& os, uint32_t domain) { 84 switch (domain) { 85 case 0b1111: os << "sy"; break; 86 case 0b1110: os << "st"; break; 87 case 0b1011: os << "ish"; break; 88 case 0b1010: os << "ishst"; break; 89 case 0b0111: os << "nsh"; break; 90 case 0b0110: os << "nshst"; break; 91 case 0b0011: os << "osh"; break; 92 case 0b0010: os << "oshst"; break; 93 } 94 } 95 96 void DisassemblerArm::DumpBranchTarget(std::ostream& os, const uint8_t* instr_ptr, int32_t imm32) { 97 os << StringPrintf("%+d (", imm32) << FormatInstructionPointer(instr_ptr + imm32) << ")"; 98 } 99 100 static uint32_t ReadU16(const uint8_t* ptr) { 101 return ptr[0] | (ptr[1] << 8); 102 } 103 104 static uint32_t ReadU32(const uint8_t* ptr) { 105 return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24); 106 } 107 108 static const char* kDataProcessingOperations[] = { 109 "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", 110 "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn", 111 }; 112 113 static const char* kThumbDataProcessingOperations[] = { 114 "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror", 115 "tst", "rsb", "cmp", "cmn", "orr", "mul", "bic", "mvn", 116 }; 117 118 static const char* const kThumb2ShiftOperations[] = { 119 "lsl", "lsr", "asr", "ror" 120 }; 121 122 static const char* kThumbReverseOperations[] = { 123 "rev", "rev16", "rbit", "revsh" 124 }; 125 126 struct ArmRegister { 127 explicit ArmRegister(uint32_t r) : r(r) { CHECK_LE(r, 15U); } 128 ArmRegister(uint32_t instruction, uint32_t at_bit) : r((instruction >> at_bit) & 0xf) { CHECK_LE(r, 15U); } 129 uint32_t r; 130 }; 131 std::ostream& operator<<(std::ostream& os, const ArmRegister& r) { 132 if (r.r == 13) { 133 os << "sp"; 134 } else if (r.r == 14) { 135 os << "lr"; 136 } else if (r.r == 15) { 137 os << "pc"; 138 } else { 139 os << "r" << r.r; 140 } 141 return os; 142 } 143 144 struct ThumbRegister : ArmRegister { 145 ThumbRegister(uint16_t instruction, uint16_t at_bit) : ArmRegister((instruction >> at_bit) & 0x7) {} 146 }; 147 148 struct Rm { 149 explicit Rm(uint32_t instruction) : shift((instruction >> 4) & 0xff), rm(instruction & 0xf) {} 150 uint32_t shift; 151 ArmRegister rm; 152 }; 153 std::ostream& operator<<(std::ostream& os, const Rm& r) { 154 os << r.rm; 155 if (r.shift != 0) { 156 os << "-shift-" << r.shift; // TODO 157 } 158 return os; 159 } 160 161 struct ShiftedImmediate { 162 explicit ShiftedImmediate(uint32_t instruction) { 163 uint32_t rotate = ((instruction >> 8) & 0xf); 164 uint32_t imm = (instruction & 0xff); 165 value = (imm >> (2 * rotate)) | (imm << (32 - (2 * rotate))); 166 } 167 uint32_t value; 168 }; 169 std::ostream& operator<<(std::ostream& os, const ShiftedImmediate& rhs) { 170 os << "#" << rhs.value; 171 return os; 172 } 173 174 struct RegisterList { 175 explicit RegisterList(uint32_t instruction) : register_list(instruction & 0xffff) {} 176 uint32_t register_list; 177 }; 178 std::ostream& operator<<(std::ostream& os, const RegisterList& rhs) { 179 if (rhs.register_list == 0) { 180 os << "<no register list?>"; 181 return os; 182 } 183 os << "{"; 184 bool first = true; 185 for (size_t i = 0; i < 16; i++) { 186 if ((rhs.register_list & (1 << i)) != 0) { 187 if (first) { 188 first = false; 189 } else { 190 os << ", "; 191 } 192 os << ArmRegister(i); 193 } 194 } 195 os << "}"; 196 return os; 197 } 198 199 struct FpRegister { 200 explicit FpRegister(uint32_t instr, uint16_t at_bit, uint16_t extra_at_bit) { 201 size = (instr >> 8) & 1; 202 uint32_t Vn = (instr >> at_bit) & 0xF; 203 uint32_t N = (instr >> extra_at_bit) & 1; 204 r = (size != 0 ? ((N << 4) | Vn) : ((Vn << 1) | N)); 205 } 206 explicit FpRegister(uint32_t instr, uint16_t at_bit, uint16_t extra_at_bit, 207 uint32_t forced_size) { 208 size = forced_size; 209 uint32_t Vn = (instr >> at_bit) & 0xF; 210 uint32_t N = (instr >> extra_at_bit) & 1; 211 r = (size != 0 ? ((N << 4) | Vn) : ((Vn << 1) | N)); 212 } 213 FpRegister(const FpRegister& other, uint32_t offset) 214 : size(other.size), r(other.r + offset) {} 215 216 uint32_t size; // 0 = f32, 1 = f64 217 uint32_t r; 218 }; 219 std::ostream& operator<<(std::ostream& os, const FpRegister& rhs) { 220 return os << ((rhs.size != 0) ? "d" : "s") << rhs.r; 221 } 222 223 struct FpRegisterRange { 224 explicit FpRegisterRange(uint32_t instr) 225 : first(instr, 12, 22), imm8(instr & 0xFF) {} 226 FpRegister first; 227 uint32_t imm8; 228 }; 229 std::ostream& operator<<(std::ostream& os, const FpRegisterRange& rhs) { 230 os << "{" << rhs.first; 231 int count = (rhs.first.size != 0 ? ((rhs.imm8 + 1u) >> 1) : rhs.imm8); 232 if (count > 1) { 233 os << "-" << FpRegister(rhs.first, count - 1); 234 } 235 if (rhs.imm8 == 0) { 236 os << " (EMPTY)"; 237 } else if (rhs.first.size != 0 && (rhs.imm8 & 1) != 0) { 238 os << rhs.first << " (HALF)"; 239 } 240 os << "}"; 241 return os; 242 } 243 244 void DisassemblerArm::DumpArm(std::ostream& os, const uint8_t* instr_ptr) { 245 uint32_t instruction = ReadU32(instr_ptr); 246 uint32_t cond = (instruction >> 28) & 0xf; 247 uint32_t op1 = (instruction >> 25) & 0x7; 248 std::string opcode; 249 std::string suffixes; 250 std::ostringstream args; 251 switch (op1) { 252 case 0: 253 case 1: // Data processing instructions. 254 { 255 if ((instruction & 0x0ff000f0) == 0x01200070) { // BKPT 256 opcode = "bkpt"; 257 uint32_t imm12 = (instruction >> 8) & 0xfff; 258 uint32_t imm4 = (instruction & 0xf); 259 args << '#' << ((imm12 << 4) | imm4); 260 break; 261 } 262 if ((instruction & 0x0fffffd0) == 0x012fff10) { // BX and BLX (register) 263 opcode = (((instruction >> 5) & 1) ? "blx" : "bx"); 264 args << ArmRegister(instruction & 0xf); 265 break; 266 } 267 bool i = (instruction & (1 << 25)) != 0; 268 bool s = (instruction & (1 << 20)) != 0; 269 uint32_t op = (instruction >> 21) & 0xf; 270 opcode = kDataProcessingOperations[op]; 271 bool implicit_s = ((op & ~3) == 8); // TST, TEQ, CMP, and CMN. 272 bool is_mov = op == 0b1101 || op == 0b1111; 273 if (is_mov) { 274 // Show only Rd and Rm. 275 if (s) { 276 suffixes += 's'; 277 } 278 args << ArmRegister(instruction, 12) << ", "; 279 if (i) { 280 args << ShiftedImmediate(instruction); 281 } else { 282 // TODO: Shifted register. 283 args << ArmRegister(instruction, 16) << ", " << ArmRegister(instruction, 0); 284 } 285 } else { 286 if (implicit_s) { 287 // Rd is unused (and not shown), and we don't show the 's' suffix either. 288 } else { 289 if (s) { 290 suffixes += 's'; 291 } 292 args << ArmRegister(instruction, 12) << ", "; 293 } 294 if (i) { 295 args << ArmRegister(instruction, 16) << ", " << ShiftedImmediate(instruction); 296 } else { 297 // TODO: Shifted register. 298 args << ArmRegister(instruction, 16) << ", " << ArmRegister(instruction, 0); 299 } 300 } 301 } 302 break; 303 case 2: // Load/store word and unsigned byte. 304 { 305 bool p = (instruction & (1 << 24)) != 0; 306 bool b = (instruction & (1 << 22)) != 0; 307 bool w = (instruction & (1 << 21)) != 0; 308 bool l = (instruction & (1 << 20)) != 0; 309 opcode = StringPrintf("%s%s", (l ? "ldr" : "str"), (b ? "b" : "")); 310 args << ArmRegister(instruction, 12) << ", "; 311 ArmRegister rn(instruction, 16); 312 if (rn.r == 0xf) { 313 UNIMPLEMENTED(FATAL) << "literals"; 314 } else { 315 bool wback = !p || w; 316 uint32_t offset = (instruction & 0xfff); 317 if (p && !wback) { 318 args << "[" << rn << ", #" << offset << "]"; 319 } else if (p && wback) { 320 args << "[" << rn << ", #" << offset << "]!"; 321 } else if (!p && wback) { 322 args << "[" << rn << "], #" << offset; 323 } else { 324 LOG(FATAL) << p << " " << w; 325 } 326 if (rn.r == 9) { 327 args << " ; "; 328 Thread::DumpThreadOffset<4>(args, offset); 329 } 330 } 331 } 332 break; 333 case 4: // Load/store multiple. 334 { 335 bool p = (instruction & (1 << 24)) != 0; 336 bool u = (instruction & (1 << 23)) != 0; 337 bool w = (instruction & (1 << 21)) != 0; 338 bool l = (instruction & (1 << 20)) != 0; 339 opcode = StringPrintf("%s%c%c", (l ? "ldm" : "stm"), (u ? 'i' : 'd'), (p ? 'b' : 'a')); 340 args << ArmRegister(instruction, 16) << (w ? "!" : "") << ", " << RegisterList(instruction); 341 } 342 break; 343 case 5: // Branch/branch with link. 344 { 345 bool bl = (instruction & (1 << 24)) != 0; 346 opcode = (bl ? "bl" : "b"); 347 int32_t imm26 = (instruction & 0xffffff) << 2; 348 int32_t imm32 = (imm26 << 6) >> 6; // Sign extend. 349 DumpBranchTarget(args, instr_ptr + 8, imm32); 350 } 351 break; 352 default: 353 opcode = "???"; 354 break; 355 } 356 opcode += kConditionCodeNames[cond]; 357 opcode += suffixes; 358 // TODO: a more complete ARM disassembler could generate wider opcodes. 359 os << FormatInstructionPointer(instr_ptr) 360 << StringPrintf(": %08x\t%-7s ", instruction, opcode.c_str()) 361 << args.str() << '\n'; 362 } 363 364 int32_t ThumbExpand(int32_t imm12) { 365 if ((imm12 & 0xC00) == 0) { 366 switch ((imm12 >> 8) & 3) { 367 case 0: 368 return imm12 & 0xFF; 369 case 1: 370 return ((imm12 & 0xFF) << 16) | (imm12 & 0xFF); 371 case 2: 372 return ((imm12 & 0xFF) << 24) | ((imm12 & 0xFF) << 8); 373 default: // 3 374 return ((imm12 & 0xFF) << 24) | ((imm12 & 0xFF) << 16) | ((imm12 & 0xFF) << 8) | 375 (imm12 & 0xFF); 376 } 377 } else { 378 uint32_t val = 0x80 | (imm12 & 0x7F); 379 int32_t rotate = (imm12 >> 7) & 0x1F; 380 return (val >> rotate) | (val << (32 - rotate)); 381 } 382 } 383 384 uint32_t VFPExpand32(uint32_t imm8) { 385 CHECK_EQ(imm8 & 0xffu, imm8); 386 uint32_t bit_a = (imm8 >> 7) & 1; 387 uint32_t bit_b = (imm8 >> 6) & 1; 388 uint32_t slice = imm8 & 0x3f; 389 return (bit_a << 31) | ((1 << 30) - (bit_b << 25)) | (slice << 19); 390 } 391 392 uint64_t VFPExpand64(uint32_t imm8) { 393 CHECK_EQ(imm8 & 0xffu, imm8); 394 uint64_t bit_a = (imm8 >> 7) & 1; 395 uint64_t bit_b = (imm8 >> 6) & 1; 396 uint64_t slice = imm8 & 0x3f; 397 return (bit_a << 31) | ((UINT64_C(1) << 62) - (bit_b << 54)) | (slice << 48); 398 } 399 400 uint64_t AdvSIMDExpand(uint32_t op, uint32_t cmode, uint32_t imm8) { 401 CHECK_EQ(op & 1, op); 402 CHECK_EQ(cmode & 0xf, cmode); 403 CHECK_EQ(imm8 & 0xff, imm8); 404 int32_t cmode321 = cmode >> 1; 405 if (imm8 == 0 && cmode321 != 0 && cmode321 != 4 && cmode321 != 7) { 406 return INT64_C(0x00000000deadbeef); // UNPREDICTABLE 407 } 408 uint64_t imm = imm8; 409 switch (cmode321) { 410 case 3: imm <<= 8; // Fall through. 411 case 2: imm <<= 8; // Fall through. 412 case 1: imm <<= 8; // Fall through. 413 case 0: return static_cast<int64_t>((imm << 32) | imm); 414 case 5: imm <<= 8; // Fall through. 415 case 4: return static_cast<int64_t>((imm << 48) | (imm << 32) | (imm << 16) | imm); 416 case 6: 417 imm = ((imm + 1u) << ((cmode & 1) != 0 ? 16 : 8)) - 1u; // Add 8 or 16 ones. 418 return static_cast<int64_t>((imm << 32) | imm); 419 default: 420 CHECK_EQ(cmode321, 7); 421 if ((cmode & 1) == 0 && op == 0) { 422 imm = (imm << 8) | imm; 423 return static_cast<int64_t>((imm << 48) | (imm << 32) | (imm << 16) | imm); 424 } else if ((cmode & 1) == 0 && op != 0) { 425 for (int i = 1; i != 8; ++i) { 426 imm |= ((imm >> i) & UINT64_C(1)) << (i * 8); 427 } 428 imm = imm & ~UINT64_C(0xfe); 429 return static_cast<int64_t>((imm << 8) - imm); 430 } else if ((cmode & 1) != 0 && op == 0) { 431 imm = static_cast<uint32_t>(VFPExpand32(imm8)); 432 return static_cast<int64_t>((imm << 32) | imm); 433 } else { 434 return INT64_C(0xdeadbeef00000000); // UNDEFINED 435 } 436 } 437 } 438 439 size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr) { 440 uint32_t instr = (ReadU16(instr_ptr) << 16) | ReadU16(instr_ptr + 2); 441 // |111|1 1|1000000|0000|1111110000000000| 442 // |5 3|2 1|0987654|3 0|5 0 5 0| 443 // |---|---|-------|----|----------------| 444 // |332|2 2|2222222|1111|1111110000000000| 445 // |1 9|8 7|6543210|9 6|5 0 5 0| 446 // |---|---|-------|----|----------------| 447 // |111|op1| op2 | | | 448 uint32_t op1 = (instr >> 27) & 3; 449 if (op1 == 0) { 450 return DumpThumb16(os, instr_ptr); 451 } 452 453 uint32_t op2 = (instr >> 20) & 0x7F; 454 std::ostringstream opcode; 455 std::ostringstream args; 456 switch (op1) { 457 case 0: 458 break; 459 case 1: 460 if ((op2 & 0x64) == 0) { // 00x x0xx 461 // |111|11|10|00|0|00|0000|1111110000000000| 462 // |5 3|21|09|87|6|54|3 0|5 0 5 0| 463 // |---|--|--|--|-|--|----|----------------| 464 // |332|22|22|22|2|22|1111|1111110000000000| 465 // |1 9|87|65|43|2|10|9 6|5 0 5 0| 466 // |---|--|--|--|-|--|----|----------------| 467 // |111|01|00|op|0|WL| Rn | | 468 // |111|01| op2 | | | 469 // STM - 111 01 00-01-0-W0 nnnn rrrrrrrrrrrrrrrr 470 // LDM - 111 01 00-01-0-W1 nnnn rrrrrrrrrrrrrrrr 471 // PUSH- 111 01 00-01-0-10 1101 0M0rrrrrrrrrrrrr 472 // POP - 111 01 00-01-0-11 1101 PM0rrrrrrrrrrrrr 473 uint32_t op = (instr >> 23) & 3; 474 uint32_t W = (instr >> 21) & 1; 475 uint32_t L = (instr >> 20) & 1; 476 ArmRegister Rn(instr, 16); 477 if (op == 1 || op == 2) { 478 if (op == 1) { 479 if (L == 0) { 480 opcode << "stm"; 481 args << Rn << (W == 0 ? "" : "!") << ", "; 482 } else { 483 if (Rn.r != 13) { 484 opcode << "ldm"; 485 args << Rn << (W == 0 ? "" : "!") << ", "; 486 } else { 487 opcode << "pop"; 488 } 489 } 490 } else { 491 if (L == 0) { 492 if (Rn.r != 13) { 493 opcode << "stmdb"; 494 args << Rn << (W == 0 ? "" : "!") << ", "; 495 } else { 496 opcode << "push"; 497 } 498 } else { 499 opcode << "ldmdb"; 500 args << Rn << (W == 0 ? "" : "!") << ", "; 501 } 502 } 503 args << RegisterList(instr); 504 } 505 } else if ((op2 & 0x64) == 4) { // 00x x1xx 506 uint32_t op3 = (instr >> 23) & 3; 507 uint32_t op4 = (instr >> 20) & 3; 508 // uint32_t op5 = (instr >> 4) & 0xF; 509 ArmRegister Rn(instr, 16); 510 ArmRegister Rt(instr, 12); 511 ArmRegister Rd(instr, 8); 512 uint32_t imm8 = instr & 0xFF; 513 if ((op3 & 2) == 2) { // 1x 514 int W = (instr >> 21) & 1; 515 int U = (instr >> 23) & 1; 516 int P = (instr >> 24) & 1; 517 518 if ((op4 & 1) == 1) { 519 opcode << "ldrd"; 520 } else { 521 opcode << "strd"; 522 } 523 args << Rt << "," << Rd << ", [" << Rn; 524 const char *sign = U ? "+" : "-"; 525 if (P == 0 && W == 1) { 526 args << "], #" << sign << (imm8 << 2); 527 } else { 528 args << ", #" << sign << (imm8 << 2) << "]"; 529 if (W == 1) { 530 args << "!"; 531 } 532 } 533 } else { // 0x 534 switch (op4) { 535 case 0: 536 if (op3 == 0) { // op3 is 00, op4 is 00 537 opcode << "strex"; 538 args << Rd << ", " << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]"; 539 if (Rd.r == 13 || Rd.r == 15 || Rt.r == 13 || Rt.r == 15 || Rn.r == 15 || 540 Rd.r == Rn.r || Rd.r == Rt.r) { 541 args << " (UNPREDICTABLE)"; 542 } 543 } else { // op3 is 01, op4 is 00 544 // this is one of strexb, strexh or strexd 545 int op5 = (instr >> 4) & 0xf; 546 switch (op5) { 547 case 4: 548 case 5: 549 opcode << ((op5 == 4) ? "strexb" : "strexh"); 550 Rd = ArmRegister(instr, 0); 551 args << Rd << ", " << Rt << ", [" << Rn << "]"; 552 if (Rd.r == 13 || Rd.r == 15 || Rt.r == 13 || Rt.r == 15 || Rn.r == 15 || 553 Rd.r == Rn.r || Rd.r == Rt.r || (instr & 0xf00) != 0xf00) { 554 args << " (UNPREDICTABLE)"; 555 } 556 break; 557 case 7: 558 opcode << "strexd"; 559 ArmRegister Rt2 = Rd; 560 Rd = ArmRegister(instr, 0); 561 args << Rd << ", " << Rt << ", " << Rt2 << ", [" << Rn << "]"; 562 if (Rd.r == 13 || Rd.r == 15 || Rt.r == 13 || Rt.r == 15 || 563 Rt2.r == 13 || Rt2.r == 15 || Rn.r == 15 || 564 Rd.r == Rn.r || Rd.r == Rt.r || Rd.r == Rt2.r) { 565 args << " (UNPREDICTABLE)"; 566 } 567 break; 568 } 569 } 570 break; 571 case 1: 572 if (op3 == 0) { // op3 is 00, op4 is 01 573 opcode << "ldrex"; 574 args << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]"; 575 if (Rt.r == 13 || Rt.r == 15 || Rn.r == 15 || (instr & 0xf00) != 0xf00) { 576 args << " (UNPREDICTABLE)"; 577 } 578 } else { // op3 is 01, op4 is 01 579 // this is one of strexb, strexh or strexd 580 int op5 = (instr >> 4) & 0xf; 581 switch (op5) { 582 case 0: 583 opcode << "tbb"; 584 break; 585 case 1: 586 opcode << "tbh"; 587 break; 588 case 4: 589 case 5: 590 opcode << ((op5 == 4) ? "ldrexb" : "ldrexh"); 591 args << Rt << ", [" << Rn << "]"; 592 if (Rt.r == 13 || Rt.r == 15 || Rn.r == 15 || (instr & 0xf0f) != 0xf0f) { 593 args << " (UNPREDICTABLE)"; 594 } 595 break; 596 case 7: 597 opcode << "ldrexd"; 598 args << Rt << ", " << Rd /* Rt2 */ << ", [" << Rn << "]"; 599 if (Rt.r == 13 || Rt.r == 15 || Rd.r == 13 /* Rt2 */ || Rd.r == 15 /* Rt2 */ || 600 Rn.r == 15 || (instr & 0x00f) != 0x00f) { 601 args << " (UNPREDICTABLE)"; 602 } 603 break; 604 } 605 } 606 break; 607 case 2: // op3 is 0x, op4 is 10 608 case 3: // op3 is 0x, op4 is 11 609 if (op4 == 2) { 610 opcode << "strd"; 611 } else { 612 opcode << "ldrd"; 613 } 614 int W = (instr >> 21) & 1; 615 int U = (instr >> 23) & 1; 616 int P = (instr >> 24) & 1; 617 618 args << Rt << "," << Rd << ", [" << Rn; 619 const char *sign = U ? "+" : "-"; 620 if (P == 0 && W == 1) { 621 args << "], #" << sign << imm8; 622 } else { 623 args << ", #" << sign << imm8 << "]"; 624 if (W == 1) { 625 args << "!"; 626 } 627 } 628 break; 629 } 630 } 631 632 } else if ((op2 & 0x60) == 0x20) { // 01x xxxx 633 // Data-processing (shifted register) 634 // |111|1110|0000|0|0000|1111|1100|00|00|0000| 635 // |5 3|2109|8765|4|3 0|5 |10 8|7 |5 |3 0| 636 // |---|----|----|-|----|----|----|--|--|----| 637 // |332|2222|2222|2|1111|1111|1100|00|00|0000| 638 // |1 9|8765|4321|0|9 6|5 |10 8|7 |5 |3 0| 639 // |---|----|----|-|----|----|----|--|--|----| 640 // |111|0101| op3|S| Rn |imm3| Rd |i2|ty| Rm | 641 uint32_t op3 = (instr >> 21) & 0xF; 642 uint32_t S = (instr >> 20) & 1; 643 uint32_t imm3 = ((instr >> 12) & 0x7); 644 uint32_t imm2 = ((instr >> 6) & 0x3); 645 uint32_t imm5 = ((imm3 << 2) | imm2); 646 uint32_t shift_type = ((instr >> 4) & 0x3); 647 ArmRegister Rd(instr, 8); 648 ArmRegister Rn(instr, 16); 649 ArmRegister Rm(instr, 0); 650 switch (op3) { 651 case 0x0: 652 if (Rd.r != 0xF) { 653 opcode << "and"; 654 } else { 655 if (S != 1U) { 656 opcode << "UNKNOWN TST-" << S; 657 break; 658 } 659 opcode << "tst"; 660 S = 0; // don't print 's' 661 } 662 break; 663 case 0x1: opcode << "bic"; break; 664 case 0x2: 665 if (Rn.r != 0xF) { 666 opcode << "orr"; 667 } else { 668 // TODO: use canonical form if there is a shift (lsl, ...). 669 opcode << "mov"; 670 } 671 break; 672 case 0x3: 673 if (Rn.r != 0xF) { 674 opcode << "orn"; 675 } else { 676 opcode << "mvn"; 677 } 678 break; 679 case 0x4: 680 if (Rd.r != 0xF) { 681 opcode << "eor"; 682 } else { 683 if (S != 1U) { 684 opcode << "UNKNOWN TEQ-" << S; 685 break; 686 } 687 opcode << "teq"; 688 S = 0; // don't print 's' 689 } 690 break; 691 case 0x6: opcode << "pkh"; break; 692 case 0x8: 693 if (Rd.r != 0xF) { 694 opcode << "add"; 695 } else { 696 if (S != 1U) { 697 opcode << "UNKNOWN CMN-" << S; 698 break; 699 } 700 opcode << "cmn"; 701 S = 0; // don't print 's' 702 } 703 break; 704 case 0xA: opcode << "adc"; break; 705 case 0xB: opcode << "sbc"; break; 706 case 0xD: 707 if (Rd.r != 0xF) { 708 opcode << "sub"; 709 } else { 710 if (S != 1U) { 711 opcode << "UNKNOWN CMP-" << S; 712 break; 713 } 714 opcode << "cmp"; 715 S = 0; // don't print 's' 716 } 717 break; 718 case 0xE: opcode << "rsb"; break; 719 default: opcode << "UNKNOWN DPSR-" << op3; break; 720 } 721 722 if (S == 1) { 723 opcode << "s"; 724 } 725 opcode << ".w"; 726 727 if (Rd.r != 0xF) { 728 args << Rd << ", "; 729 } 730 if (Rn.r != 0xF) { 731 args << Rn << ", "; 732 } 733 args << Rm; 734 735 // Shift operand. 736 bool noShift = (imm5 == 0 && shift_type != 0x3); 737 if (!noShift) { 738 args << ", "; 739 switch (shift_type) { 740 case 0x0: args << "lsl"; break; 741 case 0x1: args << "lsr"; break; 742 case 0x2: args << "asr"; break; 743 case 0x3: 744 if (imm5 == 0) { 745 args << "rrx"; 746 } else { 747 args << "ror"; 748 } 749 break; 750 } 751 if (shift_type != 0x3 /* rrx */) { 752 args << StringPrintf(" #%d", (0 != imm5 || 0 == shift_type) ? imm5 : 32); 753 } 754 } 755 756 } else if ((op2 & 0x40) == 0x40) { // 1xx xxxx 757 // Co-processor instructions 758 // |111|1|11|000000|0000|1111|1100|000|0 |0000| 759 // |5 3|2|10|987654|3 0|54 2|10 8|7 5|4 | 0| 760 // |---|-|--|------|----|----|----|---|---|----| 761 // |332|2|22|222222|1111|1111|1100|000|0 |0000| 762 // |1 9|8|76|543210|9 6|54 2|10 8|7 5|4 | 0| 763 // |---|-|--|------|----|----|----|---|---|----| 764 // |111| |11| op3 | Rn | |copr| |op4| | 765 uint32_t op3 = (instr >> 20) & 0x3F; 766 uint32_t coproc = (instr >> 8) & 0xF; 767 uint32_t op4 = (instr >> 4) & 0x1; 768 769 if (coproc == 0xA || coproc == 0xB) { // 101x 770 if (op3 < 0x20 && (op3 & ~5) != 0) { // 0xxxxx and not 000x0x 771 // Extension register load/store instructions 772 // |1111|110|00000|0000|1111|110|0|00000000| 773 // |5 2|1 9|87654|3 0|5 2|1 9|8|7 0| 774 // |----|---|-----|----|----|---|-|--------| 775 // |3322|222|22222|1111|1111|110|0|00000000| 776 // |1 8|7 5|4 0|9 6|5 2|1 9|8|7 0| 777 // |----|---|-----|----|----|---|-|--------| 778 // |1110|110|PUDWL| Rn | Vd |101|S| imm8 | 779 uint32_t P = (instr >> 24) & 1; 780 uint32_t U = (instr >> 23) & 1; 781 uint32_t W = (instr >> 21) & 1; 782 if (P == U && W == 1) { 783 opcode << "UNDEFINED"; 784 } else { 785 uint32_t L = (instr >> 20) & 1; 786 uint32_t S = (instr >> 8) & 1; 787 ArmRegister Rn(instr, 16); 788 if (P == 1 && W == 0) { // VLDR 789 FpRegister d(instr, 12, 22); 790 uint32_t imm8 = instr & 0xFF; 791 opcode << (L == 1 ? "vldr" : "vstr"); 792 args << d << ", [" << Rn << ", #" << ((U == 1) ? "" : "-") 793 << (imm8 << 2) << "]"; 794 if (Rn.r == 15 && U == 1) { 795 intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr); 796 lit_adr = RoundDown(lit_adr, 4) + 4 + (imm8 << 2); 797 typedef const int64_t unaligned_int64_t __attribute__ ((aligned (2))); 798 args << StringPrintf(" ; 0x%" PRIx64, *reinterpret_cast<unaligned_int64_t*>(lit_adr)); 799 } 800 } else if (Rn.r == 13 && W == 1 && U == L) { // VPUSH/VPOP 801 opcode << (L == 1 ? "vpop" : "vpush"); 802 args << FpRegisterRange(instr); 803 } else { // VLDM 804 opcode << (L == 1 ? "vldm" : "vstm"); 805 args << Rn << ((W == 1) ? "!" : "") << ", " 806 << FpRegisterRange(instr); 807 } 808 opcode << (S == 1 ? ".f64" : ".f32"); 809 } 810 } else if ((op3 >> 1) == 2) { // 00010x 811 if ((instr & 0xD0) == 0x10) { 812 // 64bit transfers between ARM core and extension registers. 813 uint32_t L = (instr >> 20) & 1; 814 uint32_t S = (instr >> 8) & 1; 815 ArmRegister Rt2(instr, 16); 816 ArmRegister Rt(instr, 12); 817 FpRegister m(instr, 0, 5); 818 opcode << "vmov" << (S ? ".f64" : ".f32"); 819 if (L == 1) { 820 args << Rt << ", " << Rt2 << ", "; 821 } 822 if (S) { 823 args << m; 824 } else { 825 args << m << ", " << FpRegister(m, 1); 826 } 827 if (L == 0) { 828 args << ", " << Rt << ", " << Rt2; 829 } 830 if (Rt.r == 15 || Rt.r == 13 || Rt2.r == 15 || Rt2.r == 13 || 831 (S == 0 && m.r == 31) || (L == 1 && Rt.r == Rt2.r)) { 832 args << " (UNPREDICTABLE)"; 833 } 834 } 835 } else if ((op3 >> 4) == 2 && op4 == 0) { // 10xxxx, op = 0 836 // fp data processing 837 // VMLA, VMLS, VMUL, VNMUL, VADD, VSUB, VDIV, VMOV, ... 838 // |1111|1100|0|0|00|0000|1111|110|0|0|0|0|0|0000| 839 // |5 2|1 8|7|6|54|3 0|5 2|1 9|8|7|6|5|4|3 0| 840 // |----|----|-|-|--|----|----|---|-|-|-|-|-|----| 841 // |3322|2222|2|2|22|1111|1111|110|0|0|0|0|0|0000| 842 // |1 8|7 4|3|2|10|9 6|5 2|1 9|8|7|6|5|4|3 0| 843 // |----|----|-|-|--|----|----|---|-|-|-|-|-|----| 844 // |1110|1110| op3 | Vn | Vd |101|S|N|Q|M|0| Vm | 845 // |1110|1110|0|D|00| Vn | Vd |101|S|N|0|M|0| Vm | VMLA 846 // |1110|1110|0|D|00| Vn | Vd |101|S|N|1|M|0| Vm | VMLS 847 // |1110|1110|0|D|10| Vn | Vd |101|S|N|0|M|0| Vm | VMUL 848 // |1110|1110|0|D|10| Vn | Vd |101|S|N|1|M|0| Vm | VNMUL 849 // |1110|1110|0|D|11| Vn | Vd |101|S|N|0|M|0| Vm | VADD 850 // |1110|1110|0|D|11| Vn | Vd |101|S|N|1|M|0| Vm | VSUB 851 // |1110|1110|1|D|00| Vn | Vd |101|S|N|0|M|0| Vm | VDIV 852 // |1110|1110|1|D|11| iH | Vd |101|S|0|0|0|0| iL | VMOV (imm) 853 // |1110|1110|1|D|11|op5 | Vd |101|S|.|1|M|0| Vm | ... (see below) 854 uint32_t S = (instr >> 8) & 1; 855 uint32_t Q = (instr >> 6) & 1; 856 FpRegister d(instr, 12, 22); 857 FpRegister n(instr, 16, 7); 858 FpRegister m(instr, 0, 5); 859 if ((op3 & 0xB) == 0) { // 100x00 860 opcode << (Q == 0 ? "vmla" : "vmls") << (S != 0 ? ".f64" : ".f32"); 861 args << d << ", " << n << ", " << m; 862 } else if ((op3 & 0xB) == 0x2) { // 100x10 863 opcode << (Q == 0 ? "vmul" : "vnmul") << (S != 0 ? ".f64" : ".f32"); 864 args << d << ", " << n << ", " << m; 865 } else if ((op3 & 0xB) == 0x3) { // 100x11 866 opcode << (Q == 0 ? "vadd" : "vsub") << (S != 0 ? ".f64" : ".f32"); 867 args << d << ", " << n << ", " << m; 868 } else if ((op3 & 0xB) == 0x8 && Q == 0) { // 101x00, Q == 0 869 opcode << "vdiv" << (S != 0 ? ".f64" : ".f32"); 870 args << d << ", " << n << ", " << m; 871 } else if ((op3 & 0xB) == 0xB && Q == 0) { // 101x11, Q == 0 872 uint32_t imm8 = ((instr & 0xf0000u) >> 12) | (instr & 0xfu); 873 opcode << "vmov" << (S != 0 ? ".f64" : ".f32"); 874 args << d << ", " << (S != 0 ? StringPrintf("0x%016" PRIx64, VFPExpand64(imm8)) 875 : StringPrintf("0x%08x", VFPExpand32(imm8))); 876 if ((instr & 0xa0) != 0) { 877 args << " (UNPREDICTABLE)"; 878 } 879 } else if ((op3 & 0xB) == 0xB && Q == 1) { // 101x11, Q == 1 880 // VNEG, VSQRT, VCMP, VCMPE, VCVT (floating-point conversion) 881 // |1111|1100|0|0|00|0000|1111|110|0|0 |0|0|0|0000| 882 // |5 2|1 8|7|6|54|3 0|5 2|1 9|8|7 |6|5|4|3 0| 883 // |----|----|-|-|--|----|----|---|-|- |-|-|-|----| 884 // |3322|2222|2|2|22|1111|1111|110|0|0 |0|0|0|0000| 885 // |1 8|7 4|3|2|10|9 6|5 2|1 9|8|7 |6|5|4|3 0| 886 // |----|----|-|-|--|----|----|---|-|- |-|-|-|----| 887 // |1110|1110|1|D|11|0000| Vd |101|S|0 |1|M|0| Vm | VMOV (reg) 888 // |1110|1110|1|D|11|0000| Vd |101|S|1 |1|M|0| Vm | VABS 889 // |1110|1110|1|D|11|0001| Vd |101|S|0 |1|M|0| Vm | VNEG 890 // |1110|1110|1|D|11|0001| Vd |101|S|1 |1|M|0| Vm | VSQRT 891 // |1110|1110|1|D|11|0100| Vd |101|S|op|1|M|0| Vm | VCMP 892 // |1110|1110|1|D|11|0101| Vd |101|S|op|1|0|0|0000| VCMPE 893 // |1110|1110|1|D|11|op5 | Vd |101|S|op|1|M|0| Vm | VCVT 894 uint32_t op5 = (instr >> 16) & 0xF; 895 uint32_t op = (instr >> 7) & 1; 896 // Register types in VCVT instructions rely on the combination of op5 and S. 897 FpRegister Dd(instr, 12, 22, 1); 898 FpRegister Sd(instr, 12, 22, 0); 899 FpRegister Dm(instr, 0, 5, 1); 900 FpRegister Sm(instr, 0, 5, 0); 901 if (op5 == 0) { 902 opcode << (op == 0 ? "vmov" : "vabs") << (S != 0 ? ".f64" : ".f32"); 903 args << d << ", " << m; 904 } else if (op5 == 1) { 905 opcode << (op != 0 ? "vsqrt" : "vneg") << (S != 0 ? ".f64" : ".f32"); 906 args << d << ", " << m; 907 } else if (op5 == 4) { 908 opcode << "vcmp" << (S != 0 ? ".f64" : ".f32"); 909 args << d << ", " << m; 910 if (op != 0) { 911 args << " (quiet nan)"; 912 } 913 } else if (op5 == 5) { 914 opcode << "vcmpe" << (S != 0 ? ".f64" : ".f32"); 915 args << d << ", #0.0"; 916 if (op != 0) { 917 args << " (quiet nan)"; 918 } 919 if ((instr & 0x2f) != 0) { 920 args << " (UNPREDICTABLE)"; 921 } 922 } else if (op5 == 0xD) { 923 if (S == 1) { 924 // vcvt{r}.s32.f64 925 opcode << "vcvt" << (op == 0 ? "r" : "") << ".s32.f64"; 926 args << Sd << ", " << Dm; 927 } else { 928 // vcvt{r}.s32.f32 929 opcode << "vcvt" << (op == 0 ? "r" : "") << ".s32.f32"; 930 args << Sd << ", " << Sm; 931 } 932 } else if (op5 == 0xC) { 933 if (S == 1) { 934 // vcvt{r}.u32.f64 935 opcode << "vcvt" << (op == 0 ? "r" : "") << ".u32.f64"; 936 args << Sd << ", " << Dm; 937 } else { 938 // vcvt{r}.u32.f32 939 opcode << "vcvt" << (op == 0 ? "r" : "") << ".u32.f32"; 940 args << Sd << ", " << Sm; 941 } 942 } else if (op5 == 0x8) { 943 if (S == 1) { 944 // vcvt.f64.<Tm> 945 opcode << "vcvt.f64." << (op == 0 ? "u" : "s") << "32"; 946 args << Dd << ", " << Sm; 947 } else { 948 // vcvt.f32.<Tm> 949 opcode << "vcvt.f32." << (op == 0 ? "u" : "s") << "32"; 950 args << Sd << ", " << Sm; 951 } 952 } else if (op5 == 0x7) { 953 if (op == 1) { 954 if (S == 1) { 955 // vcvt.f64.f32 956 opcode << "vcvt.f64.f32"; 957 args << Dd << ", " << Sm; 958 } else { 959 // vcvt.f32.f64 960 opcode << "vcvt.f32.f64"; 961 args << Sd << ", " << Dm; 962 } 963 } 964 } else if ((op5 & 0xa) == 0xa) { 965 opcode << "vcvt"; 966 args << "[undecoded: floating <-> fixed]"; 967 } 968 } 969 } else if ((op3 >> 4) == 2 && op4 == 1) { // 10xxxx, op = 1 970 if (coproc == 10 && (op3 & 0xE) == 0) { 971 // VMOV (between ARM core register and single-precision register) 972 // |1111|1100|000|0 |0000|1111|1100|0|00|0|0000| 973 // |5 |1 8|7 5|4 |3 0|5 2|1 8|7|65|4|3 0| 974 // |----|----|---|- |----|----|----|-|--|-|----| 975 // |3322|2222|222|2 |1111|1111|1100|0|00|0|0000| 976 // |1 8|7 4|3 1|0 |9 6|5 2|1 8|7|65|4|3 0| 977 // |----|----|---|- |----|----|----|-|--|-|----| 978 // |1110|1110|000|op| Vn | Rt |1010|N|00|1|0000| 979 uint32_t op = op3 & 1; 980 ArmRegister Rt(instr, 12); 981 FpRegister n(instr, 16, 7); 982 opcode << "vmov.f32"; 983 if (op) { 984 args << Rt << ", " << n; 985 } else { 986 args << n << ", " << Rt; 987 } 988 if (Rt.r == 13 || Rt.r == 15 || (instr & 0x6F) != 0) { 989 args << " (UNPREDICTABLE)"; 990 } 991 } else if (coproc == 10 && op3 == 0x2F) { 992 // VMRS 993 // |1111|11000000|0000|1111|1100|000|0|0000| 994 // |5 |1 4|3 0|5 2|1 8|7 5|4|3 0| 995 // |----|--------|----|----|----|---|-|----| 996 // |3322|22222222|1111|1111|1100|000|0|0000| 997 // |1 8|7 0|9 6|5 2|1 8|7 5|4|3 0| 998 // |----|--------|----|----|----|---|-|----| 999 // |1110|11101111|reg | Rt |1010|000|1|0000| - last 7 0s are (0) 1000 uint32_t spec_reg = (instr >> 16) & 0xF; 1001 ArmRegister Rt(instr, 12); 1002 opcode << "vmrs"; 1003 if (spec_reg == 1) { 1004 if (Rt.r == 15) { 1005 args << "APSR_nzcv, FPSCR"; 1006 } else if (Rt.r == 13) { 1007 args << Rt << ", FPSCR (UNPREDICTABLE)"; 1008 } else { 1009 args << Rt << ", FPSCR"; 1010 } 1011 } else { 1012 args << "(PRIVILEGED)"; 1013 } 1014 } else if (coproc == 11 && (op3 & 0x9) != 8) { 1015 // VMOV (ARM core register to scalar or vice versa; 8/16/32-bit) 1016 } 1017 } 1018 } 1019 } 1020 break; 1021 case 2: 1022 if ((instr & 0x8000) == 0 && (op2 & 0x20) == 0) { 1023 // Data-processing (modified immediate) 1024 // |111|11|10|0000|0|0000|1|111|1100|00000000| 1025 // |5 3|21|09|8765|4|3 0|5|4 2|10 8|7 5 0| 1026 // |---|--|--|----|-|----|-|---|----|--------| 1027 // |332|22|22|2222|2|1111|1|111|1100|00000000| 1028 // |1 9|87|65|4321|0|9 6|5|4 2|10 8|7 5 0| 1029 // |---|--|--|----|-|----|-|---|----|--------| 1030 // |111|10|i0| op3|S| Rn |0|iii| Rd |iiiiiiii| 1031 // 111 10 x0 xxxx x xxxx opxxx xxxx xxxxxxxx 1032 uint32_t i = (instr >> 26) & 1; 1033 uint32_t op3 = (instr >> 21) & 0xF; 1034 uint32_t S = (instr >> 20) & 1; 1035 ArmRegister Rn(instr, 16); 1036 uint32_t imm3 = (instr >> 12) & 7; 1037 ArmRegister Rd(instr, 8); 1038 uint32_t imm8 = instr & 0xFF; 1039 int32_t imm32 = (i << 11) | (imm3 << 8) | imm8; 1040 if (Rn.r == 0xF && (op3 == 0x2 || op3 == 0x3)) { 1041 if (op3 == 0x2) { 1042 opcode << "mov"; 1043 if (S == 1) { 1044 opcode << "s"; 1045 } 1046 opcode << ".w"; 1047 } else { 1048 opcode << "mvn"; 1049 if (S == 1) { 1050 opcode << "s"; 1051 } 1052 } 1053 args << Rd << ", #" << ThumbExpand(imm32); 1054 } else if (Rd.r == 0xF && S == 1 && 1055 (op3 == 0x0 || op3 == 0x4 || op3 == 0x8 || op3 == 0xD)) { 1056 if (op3 == 0x0) { 1057 opcode << "tst"; 1058 } else if (op3 == 0x4) { 1059 opcode << "teq"; 1060 } else if (op3 == 0x8) { 1061 opcode << "cmn.w"; 1062 } else { 1063 opcode << "cmp.w"; 1064 } 1065 args << Rn << ", #" << ThumbExpand(imm32); 1066 } else { 1067 switch (op3) { 1068 case 0x0: opcode << "and"; break; 1069 case 0x1: opcode << "bic"; break; 1070 case 0x2: opcode << "orr"; break; 1071 case 0x3: opcode << "orn"; break; 1072 case 0x4: opcode << "eor"; break; 1073 case 0x8: opcode << "add"; break; 1074 case 0xA: opcode << "adc"; break; 1075 case 0xB: opcode << "sbc"; break; 1076 case 0xD: opcode << "sub"; break; 1077 case 0xE: opcode << "rsb"; break; 1078 default: opcode << "UNKNOWN DPMI-" << op3; break; 1079 } 1080 if (S == 1) { 1081 opcode << "s"; 1082 } 1083 args << Rd << ", " << Rn << ", #" << ThumbExpand(imm32); 1084 } 1085 } else if ((instr & 0x8000) == 0 && (op2 & 0x20) != 0) { 1086 // Data-processing (plain binary immediate) 1087 // |111|11|10|00000|0000|1|111110000000000| 1088 // |5 3|21|09|87654|3 0|5|4 0 5 0| 1089 // |---|--|--|-----|----|-|---------------| 1090 // |332|22|22|22222|1111|1|111110000000000| 1091 // |1 9|87|65|43210|9 6|5|4 0 5 0| 1092 // |---|--|--|-----|----|-|---------------| 1093 // |111|10|x1| op3 | Rn |0|xxxxxxxxxxxxxxx| 1094 uint32_t op3 = (instr >> 20) & 0x1F; 1095 switch (op3) { 1096 case 0x00: case 0x0A: { 1097 // ADD/SUB.W Rd, Rn #imm12 - 111 10 i1 0101 0 nnnn 0 iii dddd iiiiiiii 1098 ArmRegister Rd(instr, 8); 1099 ArmRegister Rn(instr, 16); 1100 uint32_t i = (instr >> 26) & 1; 1101 uint32_t imm3 = (instr >> 12) & 0x7; 1102 uint32_t imm8 = instr & 0xFF; 1103 uint32_t imm12 = (i << 11) | (imm3 << 8) | imm8; 1104 if (Rn.r != 0xF) { 1105 opcode << (op3 == 0 ? "addw" : "subw"); 1106 args << Rd << ", " << Rn << ", #" << imm12; 1107 } else { 1108 opcode << "adr"; 1109 args << Rd << ", "; 1110 DumpBranchTarget(args, instr_ptr + 4, (op3 == 0) ? imm12 : -imm12); 1111 } 1112 break; 1113 } 1114 case 0x04: case 0x0C: { 1115 // MOVW/T Rd, #imm16 - 111 10 i0 0010 0 iiii 0 iii dddd iiiiiiii 1116 ArmRegister Rd(instr, 8); 1117 uint32_t i = (instr >> 26) & 1; 1118 uint32_t imm3 = (instr >> 12) & 0x7; 1119 uint32_t imm8 = instr & 0xFF; 1120 uint32_t Rn = (instr >> 16) & 0xF; 1121 uint32_t imm16 = (Rn << 12) | (i << 11) | (imm3 << 8) | imm8; 1122 opcode << (op3 == 0x04 ? "movw" : "movt"); 1123 args << Rd << ", #" << imm16; 1124 break; 1125 } 1126 case 0x16: { 1127 // BFI Rd, Rn, #lsb, #width - 111 10 0 11 011 0 nnnn 0 iii dddd ii 0 iiiii 1128 ArmRegister Rd(instr, 8); 1129 ArmRegister Rn(instr, 16); 1130 uint32_t msb = instr & 0x1F; 1131 uint32_t imm2 = (instr >> 6) & 0x3; 1132 uint32_t imm3 = (instr >> 12) & 0x7; 1133 uint32_t lsb = (imm3 << 2) | imm2; 1134 uint32_t width = msb - lsb + 1; 1135 if (Rn.r != 0xF) { 1136 opcode << "bfi"; 1137 args << Rd << ", " << Rn << ", #" << lsb << ", #" << width; 1138 } else { 1139 opcode << "bfc"; 1140 args << Rd << ", #" << lsb << ", #" << width; 1141 } 1142 break; 1143 } 1144 default: 1145 break; 1146 } 1147 } else { 1148 // Branches and miscellaneous control 1149 // |111|11|1000000|0000|1|111|1100|00000000| 1150 // |5 3|21|0987654|3 0|5|4 2|10 8|7 5 0| 1151 // |---|--|-------|----|-|---|----|--------| 1152 // |332|22|2222222|1111|1|111|1100|00000000| 1153 // |1 9|87|6543210|9 6|5|4 2|10 8|7 5 0| 1154 // |---|--|-------|----|-|---|----|--------| 1155 // |111|10| op2 | |1|op3|op4 | | 1156 1157 uint32_t op3 = (instr >> 12) & 7; 1158 // uint32_t op4 = (instr >> 8) & 0xF; 1159 switch (op3) { 1160 case 0: 1161 if ((op2 & 0x38) != 0x38) { 1162 // Conditional branch 1163 // |111|11|1|0000|000000|1|1|1 |1|1 |10000000000| 1164 // |5 3|21|0|9876|543 0|5|4|3 |2|1 |0 5 0| 1165 // |---|--|-|----|------|-|-|--|-|--|-----------| 1166 // |332|22|2|2222|221111|1|1|1 |1|1 |10000000000| 1167 // |1 9|87|6|5432|109 6|5|4|3 |2|1 |0 5 0| 1168 // |---|--|-|----|------|-|-|--|-|--|-----------| 1169 // |111|10|S|cond| imm6 |1|0|J1|0|J2| imm11 | 1170 uint32_t S = (instr >> 26) & 1; 1171 uint32_t J2 = (instr >> 11) & 1; 1172 uint32_t J1 = (instr >> 13) & 1; 1173 uint32_t imm6 = (instr >> 16) & 0x3F; 1174 uint32_t imm11 = instr & 0x7FF; 1175 uint32_t cond = (instr >> 22) & 0xF; 1176 int32_t imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1); 1177 imm32 = (imm32 << 11) >> 11; // sign extend 21bit immediate 1178 opcode << "b"; 1179 DumpCond(opcode, cond); 1180 opcode << ".w"; 1181 DumpBranchTarget(args, instr_ptr + 4, imm32); 1182 } else if (op2 == 0x3B) { 1183 // Miscellaneous control instructions 1184 uint32_t op5 = (instr >> 4) & 0xF; 1185 switch (op5) { 1186 case 4: opcode << "dsb"; DumpMemoryDomain(args, instr & 0xF); break; 1187 case 5: opcode << "dmb"; DumpMemoryDomain(args, instr & 0xF); break; 1188 case 6: opcode << "isb"; DumpMemoryDomain(args, instr & 0xF); break; 1189 } 1190 } 1191 break; 1192 case 2: 1193 if ((op2 & 0x38) == 0x38) { 1194 if (op2 == 0x7F) { 1195 opcode << "udf"; 1196 } 1197 break; 1198 } 1199 // Else deliberate fall-through to B. 1200 case 1: case 3: { 1201 // B 1202 // |111|11|1|0000|000000|11|1 |1|1 |10000000000| 1203 // |5 3|21|0|9876|543 0|54|3 |2|1 |0 5 0| 1204 // |---|--|-|----|------|--|--|-|--|-----------| 1205 // |332|22|2|2222|221111|11|1 |1|1 |10000000000| 1206 // |1 9|87|6|5 2|10 6|54|3 |2|1 |0 5 0| 1207 // |---|--|-|----|------|--|--|-|--|-----------| 1208 // |111|10|S|cond| imm6 |10|J1|0|J2| imm11 | 1209 // |111|10|S| imm10 |10|J1|1|J2| imm11 | 1210 uint32_t S = (instr >> 26) & 1; 1211 uint32_t cond = (instr >> 22) & 0xF; 1212 uint32_t J2 = (instr >> 11) & 1; 1213 uint32_t form = (instr >> 12) & 1; 1214 uint32_t J1 = (instr >> 13) & 1; 1215 uint32_t imm10 = (instr >> 16) & 0x3FF; 1216 uint32_t imm6 = (instr >> 16) & 0x3F; 1217 uint32_t imm11 = instr & 0x7FF; 1218 opcode << "b"; 1219 int32_t imm32; 1220 if (form == 0) { 1221 DumpCond(opcode, cond); 1222 imm32 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1); 1223 imm32 = (imm32 << 11) >> 11; // sign extend 21 bit immediate. 1224 } else { 1225 uint32_t I1 = ~(J1 ^ S); 1226 uint32_t I2 = ~(J2 ^ S); 1227 imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1); 1228 imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate. 1229 } 1230 opcode << ".w"; 1231 DumpBranchTarget(args, instr_ptr + 4, imm32); 1232 break; 1233 } 1234 case 4: case 6: case 5: case 7: { 1235 // BL, BLX (immediate) 1236 // |111|11|1|0000000000|11|1 |1|1 |10000000000| 1237 // |5 3|21|0|9876543 0|54|3 |2|1 |0 5 0| 1238 // |---|--|-|----------|--|--|-|--|-----------| 1239 // |332|22|2|2222221111|11|1 |1|1 |10000000000| 1240 // |1 9|87|6|5 0 6|54|3 |2|1 |0 5 0| 1241 // |---|--|-|----------|--|--|-|--|-----------| 1242 // |111|10|S| imm10 |11|J1|L|J2| imm11 | 1243 uint32_t S = (instr >> 26) & 1; 1244 uint32_t J2 = (instr >> 11) & 1; 1245 uint32_t L = (instr >> 12) & 1; 1246 uint32_t J1 = (instr >> 13) & 1; 1247 uint32_t imm10 = (instr >> 16) & 0x3FF; 1248 uint32_t imm11 = instr & 0x7FF; 1249 if (L == 0) { 1250 opcode << "bx"; 1251 } else { 1252 opcode << "blx"; 1253 } 1254 uint32_t I1 = ~(J1 ^ S); 1255 uint32_t I2 = ~(J2 ^ S); 1256 int32_t imm32 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1); 1257 imm32 = (imm32 << 8) >> 8; // sign extend 24 bit immediate. 1258 DumpBranchTarget(args, instr_ptr + 4, imm32); 1259 break; 1260 } 1261 } 1262 } 1263 break; 1264 case 3: 1265 switch (op2) { 1266 case 0x00: case 0x02: case 0x04: case 0x06: // 000xxx0 1267 case 0x08: case 0x09: case 0x0A: case 0x0C: case 0x0E: { 1268 // Store single data item 1269 // |111|11|100|000|0|0000|1111|110000|000000| 1270 // |5 3|21|098|765|4|3 0|5 2|10 6|5 0| 1271 // |---|--|---|---|-|----|----|------|------| 1272 // |332|22|222|222|2|1111|1111|110000|000000| 1273 // |1 9|87|654|321|0|9 6|5 2|10 6|5 0| 1274 // |---|--|---|---|-|----|----|------|------| 1275 // |111|11|000|op3|0| | | op4 | | 1276 uint32_t op3 = (instr >> 21) & 7; 1277 // uint32_t op4 = (instr >> 6) & 0x3F; 1278 switch (op3) { 1279 case 0x0: case 0x4: { 1280 // {ST,LD}RB Rt,[Rn,#+/-imm12] - 111 11 00 0 1 00 0 nnnn tttt 1 PUWii ii iiii 1281 // {ST,LD}RB Rt,[Rn,#+/-imm8] - 111 11 00 0 0 00 0 nnnn tttt 1 PUWii ii iiii 1282 // {ST,LD}RB Rt,[Rn,Rm,lsl #imm2] - 111 11 00 0 0 00 0 nnnn tttt 0 00000 ii mmmm 1283 ArmRegister Rn(instr, 16); 1284 ArmRegister Rt(instr, 12); 1285 opcode << (HasBitSet(instr, 20) ? "ldrb" : "strb"); 1286 if (HasBitSet(instr, 23)) { 1287 uint32_t imm12 = instr & 0xFFF; 1288 args << Rt << ", [" << Rn << ",#" << imm12 << "]"; 1289 } else if ((instr & 0x800) != 0) { 1290 uint32_t imm8 = instr & 0xFF; 1291 args << Rt << ", [" << Rn << ",#" << imm8 << "]"; 1292 } else { 1293 uint32_t imm2 = (instr >> 4) & 3; 1294 ArmRegister Rm(instr, 0); 1295 args << Rt << ", [" << Rn << ", " << Rm; 1296 if (imm2 != 0) { 1297 args << ", " << "lsl #" << imm2; 1298 } 1299 args << "]"; 1300 } 1301 break; 1302 } 1303 case 0x1: case 0x5: { 1304 // STRH Rt,[Rn,#+/-imm12] - 111 11 00 0 1 01 0 nnnn tttt 1 PUWii ii iiii 1305 // STRH Rt,[Rn,#+/-imm8] - 111 11 00 0 0 01 0 nnnn tttt 1 PUWii ii iiii 1306 // STRH Rt,[Rn,Rm,lsl #imm2] - 111 11 00 0 0 01 0 nnnn tttt 0 00000 ii mmmm 1307 ArmRegister Rn(instr, 16); 1308 ArmRegister Rt(instr, 12); 1309 opcode << "strh"; 1310 if (HasBitSet(instr, 23)) { 1311 uint32_t imm12 = instr & 0xFFF; 1312 args << Rt << ", [" << Rn << ",#" << imm12 << "]"; 1313 } else if ((instr & 0x800) != 0) { 1314 uint32_t imm8 = instr & 0xFF; 1315 args << Rt << ", [" << Rn << ",#" << imm8 << "]"; 1316 } else { 1317 uint32_t imm2 = (instr >> 4) & 3; 1318 ArmRegister Rm(instr, 0); 1319 args << Rt << ", [" << Rn << ", " << Rm; 1320 if (imm2 != 0) { 1321 args << ", " << "lsl #" << imm2; 1322 } 1323 args << "]"; 1324 } 1325 break; 1326 } 1327 case 0x2: case 0x6: { 1328 ArmRegister Rn(instr, 16); 1329 ArmRegister Rt(instr, 12); 1330 if (op3 == 2) { 1331 if ((instr & 0x800) != 0) { 1332 // STR Rt, [Rn, #imm8] - 111 11 000 010 0 nnnn tttt 1PUWiiiiiiii 1333 uint32_t P = (instr >> 10) & 1; 1334 uint32_t U = (instr >> 9) & 1; 1335 uint32_t W = (instr >> 8) & 1; 1336 uint32_t imm8 = instr & 0xFF; 1337 int32_t imm32 = (imm8 << 24) >> 24; // sign-extend imm8 1338 if (Rn.r == 13 && P == 1 && U == 0 && W == 1 && imm32 == 4) { 1339 opcode << "push"; 1340 args << "{" << Rt << "}"; 1341 } else if (Rn.r == 15 || (P == 0 && W == 0)) { 1342 opcode << "UNDEFINED"; 1343 } else { 1344 if (P == 1 && U == 1 && W == 0) { 1345 opcode << "strt"; 1346 } else { 1347 opcode << "str"; 1348 } 1349 args << Rt << ", [" << Rn; 1350 if (P == 0 && W == 1) { 1351 args << "], #" << imm32; 1352 } else { 1353 args << ", #" << imm32 << "]"; 1354 if (W == 1) { 1355 args << "!"; 1356 } 1357 } 1358 } 1359 } else { 1360 // STR Rt, [Rn, Rm, LSL #imm2] - 111 11 000 010 0 nnnn tttt 000000iimmmm 1361 ArmRegister Rn(instr, 16); 1362 ArmRegister Rt(instr, 12); 1363 ArmRegister Rm(instr, 0); 1364 uint32_t imm2 = (instr >> 4) & 3; 1365 opcode << "str.w"; 1366 args << Rt << ", [" << Rn << ", " << Rm; 1367 if (imm2 != 0) { 1368 args << ", lsl #" << imm2; 1369 } 1370 args << "]"; 1371 } 1372 } else if (op3 == 6) { 1373 // STR.W Rt, [Rn, #imm12] - 111 11 000 110 0 nnnn tttt iiiiiiiiiiii 1374 uint32_t imm12 = instr & 0xFFF; 1375 opcode << "str.w"; 1376 args << Rt << ", [" << Rn << ", #" << imm12 << "]"; 1377 } 1378 break; 1379 } 1380 } 1381 1382 break; 1383 } 1384 case 0x03: case 0x0B: case 0x11: case 0x13: case 0x19: case 0x1B: { // 00xx011 1385 // Load byte/halfword 1386 // |111|11|10|0 0|00|0|0000|1111|110000|000000| 1387 // |5 3|21|09|8 7|65|4|3 0|5 2|10 6|5 0| 1388 // |---|--|--|---|--|-|----|----|------|------| 1389 // |332|22|22|2 2|22|2|1111|1111|110000|000000| 1390 // |1 9|87|65|4 3|21|0|9 6|5 2|10 6|5 0| 1391 // |---|--|--|---|--|-|----|----|------|------| 1392 // |111|11|00|op3|01|1| Rn | Rt | op4 | | 1393 // |111|11| op2 | | | imm12 | 1394 uint32_t op3 = (instr >> 23) & 3; 1395 ArmRegister Rn(instr, 16); 1396 ArmRegister Rt(instr, 12); 1397 if (Rt.r != 15) { 1398 if (op3 == 1) { 1399 // LDRH.W Rt, [Rn, #imm12] - 111 11 00 01 011 nnnn tttt iiiiiiiiiiii 1400 uint32_t imm12 = instr & 0xFFF; 1401 opcode << "ldrh.w"; 1402 args << Rt << ", [" << Rn << ", #" << imm12 << "]"; 1403 if (Rn.r == 9) { 1404 args << " ; "; 1405 Thread::DumpThreadOffset<4>(args, imm12); 1406 } else if (Rn.r == 15) { 1407 intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr); 1408 lit_adr = RoundDown(lit_adr, 4) + 4 + imm12; 1409 args << StringPrintf(" ; 0x%08x", *reinterpret_cast<int32_t*>(lit_adr)); 1410 } 1411 } else if (op3 == 3) { 1412 // LDRSH.W Rt, [Rn, #imm12] - 111 11 00 11 011 nnnn tttt iiiiiiiiiiii 1413 // LDRSB.W Rt, [Rn, #imm12] - 111 11 00 11 001 nnnn tttt iiiiiiiiiiii 1414 uint32_t imm12 = instr & 0xFFF; 1415 opcode << (HasBitSet(instr, 20) ? "ldrsb.w" : "ldrsh.w"); 1416 args << Rt << ", [" << Rn << ", #" << imm12 << "]"; 1417 if (Rn.r == 9) { 1418 args << " ; "; 1419 Thread::DumpThreadOffset<4>(args, imm12); 1420 } else if (Rn.r == 15) { 1421 intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr); 1422 lit_adr = RoundDown(lit_adr, 4) + 4 + imm12; 1423 args << StringPrintf(" ; 0x%08x", *reinterpret_cast<int32_t*>(lit_adr)); 1424 } 1425 } 1426 } 1427 break; 1428 } 1429 case 0x29: { // 0101001 1430 // |111|11|1000000|0000|1111|1100|00|0 0|0000| 1431 // |5 3|21|0 4|3 0|5 2|1 8|76|5 4|3 0| 1432 // |---|--|-------|----|----|----|--|---|----| 1433 // |332|22|2222222|1111|1111|1100|00|0 0|0000| 1434 // |1 9|87|6 0|9 6|5 2|1 8|76|5 4|3 0| 1435 // |---|--|-------|----|----|----|--|---|----| 1436 // |111|11|0101001| Rm |1111| Rd |11|op3| Rm | 1437 // REV - 111 11 0101001 mmmm 1111 dddd 1000 mmmm 1438 // REV16 - 111 11 0101001 mmmm 1111 dddd 1001 mmmm 1439 // RBIT - 111 11 0101001 mmmm 1111 dddd 1010 mmmm 1440 // REVSH - 111 11 0101001 mmmm 1111 dddd 1011 mmmm 1441 if ((instr & 0xf0c0) == 0xf080) { 1442 uint32_t op3 = (instr >> 4) & 3; 1443 opcode << kThumbReverseOperations[op3]; 1444 ArmRegister Rm(instr, 0); 1445 ArmRegister Rd(instr, 8); 1446 args << Rd << ", " << Rm; 1447 ArmRegister Rm2(instr, 16); 1448 if (Rm.r != Rm2.r || Rm.r == 13 || Rm.r == 15 || Rd.r == 13 || Rd.r == 15) { 1449 args << " (UNPREDICTABLE)"; 1450 } 1451 } // else unknown instruction 1452 break; 1453 } 1454 case 0x05: case 0x0D: case 0x15: case 0x1D: { // 00xx101 1455 // Load word 1456 // |111|11|10|0 0|00|0|0000|1111|110000|000000| 1457 // |5 3|21|09|8 7|65|4|3 0|5 2|10 6|5 0| 1458 // |---|--|--|---|--|-|----|----|------|------| 1459 // |332|22|22|2 2|22|2|1111|1111|110000|000000| 1460 // |1 9|87|65|4 3|21|0|9 6|5 2|10 6|5 0| 1461 // |---|--|--|---|--|-|----|----|------|------| 1462 // |111|11|00|op3|10|1| Rn | Rt | op4 | | 1463 // |111|11| op2 | | | imm12 | 1464 uint32_t op3 = (instr >> 23) & 3; 1465 uint32_t op4 = (instr >> 6) & 0x3F; 1466 ArmRegister Rn(instr, 16); 1467 ArmRegister Rt(instr, 12); 1468 if (op3 == 1 || Rn.r == 15) { 1469 // LDR.W Rt, [Rn, #imm12] - 111 11 00 00 101 nnnn tttt iiiiiiiiiiii 1470 // LDR.W Rt, [PC, #imm12] - 111 11 00 0x 101 1111 tttt iiiiiiiiiiii 1471 uint32_t imm12 = instr & 0xFFF; 1472 opcode << "ldr.w"; 1473 args << Rt << ", [" << Rn << ", #" << imm12 << "]"; 1474 if (Rn.r == 9) { 1475 args << " ; "; 1476 Thread::DumpThreadOffset<4>(args, imm12); 1477 } else if (Rn.r == 15) { 1478 intptr_t lit_adr = reinterpret_cast<intptr_t>(instr_ptr); 1479 lit_adr = RoundDown(lit_adr, 4) + 4 + imm12; 1480 args << StringPrintf(" ; 0x%08x", *reinterpret_cast<int32_t*>(lit_adr)); 1481 } 1482 } else if (op4 == 0) { 1483 // LDR.W Rt, [Rn, Rm{, LSL #imm2}] - 111 11 00 00 101 nnnn tttt 000000iimmmm 1484 uint32_t imm2 = (instr >> 4) & 0xF; 1485 ArmRegister rm(instr, 0); 1486 opcode << "ldr.w"; 1487 args << Rt << ", [" << Rn << ", " << rm; 1488 if (imm2 != 0) { 1489 args << ", lsl #" << imm2; 1490 } 1491 args << "]"; 1492 } else { 1493 bool p = (instr & (1 << 10)) != 0; 1494 bool w = (instr & (1 << 8)) != 0; 1495 bool u = (instr & (1 << 9)) != 0; 1496 if (p && u && !w) { 1497 // LDRT Rt, [Rn, #imm8] - 111 11 00 00 101 nnnn tttt 1110iiiiiiii 1498 uint32_t imm8 = instr & 0xFF; 1499 opcode << "ldrt"; 1500 args << Rt << ", [" << Rn << ", #" << imm8 << "]"; 1501 } else if (Rn.r == 13 && !p && u && w && (instr & 0xff) == 4) { 1502 // POP 1503 opcode << "pop"; 1504 args << "{" << Rt << "}"; 1505 } else { 1506 bool wback = !p || w; 1507 uint32_t offset = (instr & 0xff); 1508 opcode << "ldr.w"; 1509 args << Rt << ","; 1510 if (p && !wback) { 1511 args << "[" << Rn << ", #" << offset << "]"; 1512 } else if (p && wback) { 1513 args << "[" << Rn << ", #" << offset << "]!"; 1514 } else if (!p && wback) { 1515 args << "[" << Rn << "], #" << offset; 1516 } else { 1517 LOG(FATAL) << p << " " << w; 1518 } 1519 } 1520 } 1521 break; 1522 } 1523 default: // more formats 1524 if ((op2 >> 4) == 2) { // 010xxxx 1525 // data processing (register) 1526 if ((instr & 0x0080f0f0) == 0x0000f000) { 1527 // LSL, LSR, ASR, ROR 1528 uint32_t shift_op = (instr >> 21) & 3; 1529 uint32_t S = (instr >> 20) & 1; 1530 ArmRegister Rd(instr, 8); 1531 ArmRegister Rn(instr, 16); 1532 ArmRegister Rm(instr, 0); 1533 opcode << kThumb2ShiftOperations[shift_op] << (S != 0 ? "s" : ""); 1534 args << Rd << ", " << Rn << ", " << Rm; 1535 } 1536 } else if ((op2 >> 3) == 6) { // 0110xxx 1537 // Multiply, multiply accumulate, and absolute difference 1538 op1 = (instr >> 20) & 0x7; 1539 op2 = (instr >> 4) & 0x2; 1540 ArmRegister Ra(instr, 12); 1541 ArmRegister Rn(instr, 16); 1542 ArmRegister Rm(instr, 0); 1543 ArmRegister Rd(instr, 8); 1544 switch (op1) { 1545 case 0: 1546 if (op2 == 0) { 1547 if (Ra.r == 0xf) { 1548 opcode << "mul"; 1549 args << Rd << ", " << Rn << ", " << Rm; 1550 } else { 1551 opcode << "mla"; 1552 args << Rd << ", " << Rn << ", " << Rm << ", " << Ra; 1553 } 1554 } else { 1555 opcode << "mls"; 1556 args << Rd << ", " << Rn << ", " << Rm << ", " << Ra; 1557 } 1558 break; 1559 case 1: 1560 case 2: 1561 case 3: 1562 case 4: 1563 case 5: 1564 case 6: 1565 break; // do these sometime 1566 } 1567 } else if ((op2 >> 3) == 7) { // 0111xxx 1568 // Long multiply, long multiply accumulate, and divide 1569 op1 = (instr >> 20) & 0x7; 1570 op2 = (instr >> 4) & 0xf; 1571 ArmRegister Rn(instr, 16); 1572 ArmRegister Rm(instr, 0); 1573 ArmRegister Rd(instr, 8); 1574 ArmRegister RdHi(instr, 8); 1575 ArmRegister RdLo(instr, 12); 1576 switch (op1) { 1577 case 0: 1578 opcode << "smull"; 1579 args << RdLo << ", " << RdHi << ", " << Rn << ", " << Rm; 1580 break; 1581 case 1: 1582 opcode << "sdiv"; 1583 args << Rd << ", " << Rn << ", " << Rm; 1584 break; 1585 case 2: 1586 opcode << "umull"; 1587 args << RdLo << ", " << RdHi << ", " << Rn << ", " << Rm; 1588 break; 1589 case 3: 1590 opcode << "udiv"; 1591 args << Rd << ", " << Rn << ", " << Rm; 1592 break; 1593 case 4: 1594 case 5: 1595 case 6: 1596 break; // TODO: when we generate these... 1597 } 1598 } 1599 } 1600 default: 1601 break; 1602 } 1603 1604 // Apply any IT-block conditions to the opcode if necessary. 1605 if (!it_conditions_.empty()) { 1606 opcode << it_conditions_.back(); 1607 it_conditions_.pop_back(); 1608 } 1609 if (opcode.str().size() == 0) { 1610 opcode << "UNKNOWN " << op2; 1611 } 1612 1613 os << FormatInstructionPointer(instr_ptr) 1614 << StringPrintf(": %08x\t%-7s ", instr, opcode.str().c_str()) 1615 << args.str() << '\n'; 1616 return 4; 1617 } // NOLINT(readability/fn_size) 1618 1619 size_t DisassemblerArm::DumpThumb16(std::ostream& os, const uint8_t* instr_ptr) { 1620 uint16_t instr = ReadU16(instr_ptr); 1621 bool is_32bit = ((instr & 0xF000) == 0xF000) || ((instr & 0xF800) == 0xE800); 1622 if (is_32bit) { 1623 return DumpThumb32(os, instr_ptr); 1624 } else { 1625 std::ostringstream opcode; 1626 std::ostringstream args; 1627 uint16_t opcode1 = instr >> 10; 1628 if (opcode1 < 0x10) { 1629 // shift (immediate), add, subtract, move, and compare 1630 uint16_t opcode2 = instr >> 9; 1631 switch (opcode2) { 1632 case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: 1633 case 0x8: case 0x9: case 0xA: case 0xB: { 1634 // Logical shift left - 00 000xx iii mmm ddd 1635 // Logical shift right - 00 001xx iii mmm ddd 1636 // Arithmetic shift right - 00 010xx iii mmm ddd 1637 uint16_t imm5 = (instr >> 6) & 0x1F; 1638 ThumbRegister rm(instr, 3); 1639 ThumbRegister Rd(instr, 0); 1640 if (opcode2 <= 3) { 1641 opcode << "lsls"; 1642 } else if (opcode2 <= 7) { 1643 opcode << "lsrs"; 1644 } else { 1645 opcode << "asrs"; 1646 } 1647 args << Rd << ", " << rm << ", #" << imm5; 1648 break; 1649 } 1650 case 0xC: case 0xD: case 0xE: case 0xF: { 1651 // Add register - 00 01100 mmm nnn ddd 1652 // Sub register - 00 01101 mmm nnn ddd 1653 // Add 3-bit immediate - 00 01110 iii nnn ddd 1654 // Sub 3-bit immediate - 00 01111 iii nnn ddd 1655 uint16_t imm3_or_Rm = (instr >> 6) & 7; 1656 ThumbRegister Rn(instr, 3); 1657 ThumbRegister Rd(instr, 0); 1658 if ((opcode2 & 2) != 0 && imm3_or_Rm == 0) { 1659 opcode << "mov"; 1660 } else { 1661 if ((opcode2 & 1) == 0) { 1662 opcode << "adds"; 1663 } else { 1664 opcode << "subs"; 1665 } 1666 } 1667 args << Rd << ", " << Rn; 1668 if ((opcode2 & 2) == 0) { 1669 ArmRegister Rm(imm3_or_Rm); 1670 args << ", " << Rm; 1671 } else if (imm3_or_Rm != 0) { 1672 args << ", #" << imm3_or_Rm; 1673 } 1674 break; 1675 } 1676 case 0x10: case 0x11: case 0x12: case 0x13: 1677 case 0x14: case 0x15: case 0x16: case 0x17: 1678 case 0x18: case 0x19: case 0x1A: case 0x1B: 1679 case 0x1C: case 0x1D: case 0x1E: case 0x1F: { 1680 // MOVS Rd, #imm8 - 00100 ddd iiiiiiii 1681 // CMP Rn, #imm8 - 00101 nnn iiiiiiii 1682 // ADDS Rn, #imm8 - 00110 nnn iiiiiiii 1683 // SUBS Rn, #imm8 - 00111 nnn iiiiiiii 1684 ThumbRegister Rn(instr, 8); 1685 uint16_t imm8 = instr & 0xFF; 1686 switch (opcode2 >> 2) { 1687 case 4: opcode << "movs"; break; 1688 case 5: opcode << "cmp"; break; 1689 case 6: opcode << "adds"; break; 1690 case 7: opcode << "subs"; break; 1691 } 1692 args << Rn << ", #" << imm8; 1693 break; 1694 } 1695 default: 1696 break; 1697 } 1698 } else if (opcode1 == 0x10) { 1699 // Data-processing 1700 uint16_t opcode2 = (instr >> 6) & 0xF; 1701 ThumbRegister rm(instr, 3); 1702 ThumbRegister rdn(instr, 0); 1703 opcode << kThumbDataProcessingOperations[opcode2]; 1704 args << rdn << ", " << rm; 1705 } else if (opcode1 == 0x11) { 1706 // Special data instructions and branch and exchange 1707 uint16_t opcode2 = (instr >> 6) & 0x0F; 1708 switch (opcode2) { 1709 case 0x0: case 0x1: case 0x2: case 0x3: { 1710 // Add low registers - 010001 0000 xxxxxx 1711 // Add high registers - 010001 0001/001x xxxxxx 1712 uint16_t DN = (instr >> 7) & 1; 1713 ArmRegister rm(instr, 3); 1714 uint16_t Rdn = instr & 7; 1715 ArmRegister DN_Rdn((DN << 3) | Rdn); 1716 opcode << "add"; 1717 args << DN_Rdn << ", " << rm; 1718 break; 1719 } 1720 case 0x8: case 0x9: case 0xA: case 0xB: { 1721 // Move low registers - 010001 1000 xxxxxx 1722 // Move high registers - 010001 1001/101x xxxxxx 1723 uint16_t DN = (instr >> 7) & 1; 1724 ArmRegister rm(instr, 3); 1725 uint16_t Rdn = instr & 7; 1726 ArmRegister DN_Rdn((DN << 3) | Rdn); 1727 opcode << "mov"; 1728 args << DN_Rdn << ", " << rm; 1729 break; 1730 } 1731 case 0x5: case 0x6: case 0x7: { 1732 // Compare high registers - 010001 0101/011x xxxxxx 1733 uint16_t N = (instr >> 7) & 1; 1734 ArmRegister rm(instr, 3); 1735 uint16_t Rn = instr & 7; 1736 ArmRegister N_Rn((N << 3) | Rn); 1737 opcode << "cmp"; 1738 args << N_Rn << ", " << rm; 1739 break; 1740 } 1741 case 0xC: case 0xD: case 0xE: case 0xF: { 1742 // Branch and exchange - 010001 110x xxxxxx 1743 // Branch with link and exchange - 010001 111x xxxxxx 1744 ArmRegister rm(instr, 3); 1745 opcode << ((opcode2 & 0x2) == 0 ? "bx" : "blx"); 1746 args << rm; 1747 break; 1748 } 1749 default: 1750 break; 1751 } 1752 } else if (opcode1 == 0x12 || opcode1 == 0x13) { // 01001x 1753 ThumbRegister Rt(instr, 8); 1754 uint16_t imm8 = instr & 0xFF; 1755 opcode << "ldr"; 1756 args << Rt << ", [pc, #" << (imm8 << 2) << "]"; 1757 } else if ((opcode1 >= 0x14 && opcode1 <= 0x17) || // 0101xx 1758 (opcode1 >= 0x18 && opcode1 <= 0x1f) || // 011xxx 1759 (opcode1 >= 0x20 && opcode1 <= 0x27)) { // 100xxx 1760 // Load/store single data item 1761 uint16_t opA = (instr >> 12) & 0xF; 1762 if (opA == 0x5) { 1763 uint16_t opB = (instr >> 9) & 0x7; 1764 ThumbRegister Rm(instr, 6); 1765 ThumbRegister Rn(instr, 3); 1766 ThumbRegister Rt(instr, 0); 1767 switch (opB) { 1768 case 0: opcode << "str"; break; 1769 case 1: opcode << "strh"; break; 1770 case 2: opcode << "strb"; break; 1771 case 3: opcode << "ldrsb"; break; 1772 case 4: opcode << "ldr"; break; 1773 case 5: opcode << "ldrh"; break; 1774 case 6: opcode << "ldrb"; break; 1775 case 7: opcode << "ldrsh"; break; 1776 } 1777 args << Rt << ", [" << Rn << ", " << Rm << "]"; 1778 } else if (opA == 9) { 1779 uint16_t opB = (instr >> 11) & 1; 1780 ThumbRegister Rt(instr, 8); 1781 uint16_t imm8 = instr & 0xFF; 1782 opcode << (opB == 0 ? "str" : "ldr"); 1783 args << Rt << ", [sp, #" << (imm8 << 2) << "]"; 1784 } else { 1785 uint16_t imm5 = (instr >> 6) & 0x1F; 1786 uint16_t opB = (instr >> 11) & 1; 1787 ThumbRegister Rn(instr, 3); 1788 ThumbRegister Rt(instr, 0); 1789 switch (opA) { 1790 case 6: 1791 imm5 <<= 2; 1792 opcode << (opB == 0 ? "str" : "ldr"); 1793 break; 1794 case 7: 1795 imm5 <<= 0; 1796 opcode << (opB == 0 ? "strb" : "ldrb"); 1797 break; 1798 case 8: 1799 imm5 <<= 1; 1800 opcode << (opB == 0 ? "strh" : "ldrh"); 1801 break; 1802 } 1803 args << Rt << ", [" << Rn << ", #" << imm5 << "]"; 1804 } 1805 } else if (opcode1 >= 0x34 && opcode1 <= 0x37) { // 1101xx 1806 int8_t imm8 = instr & 0xFF; 1807 uint32_t cond = (instr >> 8) & 0xF; 1808 opcode << "b"; 1809 DumpCond(opcode, cond); 1810 DumpBranchTarget(args, instr_ptr + 4, (imm8 << 1)); 1811 } else if ((instr & 0xF800) == 0xA800) { 1812 // Generate SP-relative address 1813 ThumbRegister rd(instr, 8); 1814 int imm8 = instr & 0xFF; 1815 opcode << "add"; 1816 args << rd << ", sp, #" << (imm8 << 2); 1817 } else if ((instr & 0xF000) == 0xB000) { 1818 // Miscellaneous 16-bit instructions 1819 uint16_t opcode2 = (instr >> 5) & 0x7F; 1820 switch (opcode2) { 1821 case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: { 1822 // Add immediate to SP - 1011 00000 ii iiiii 1823 // Subtract immediate from SP - 1011 00001 ii iiiii 1824 int imm7 = instr & 0x7F; 1825 opcode << ((opcode2 & 4) == 0 ? "add" : "sub"); 1826 args << "sp, sp, #" << (imm7 << 2); 1827 break; 1828 } 1829 case 0x08: case 0x09: case 0x0A: case 0x0B: // 0001xxx 1830 case 0x0C: case 0x0D: case 0x0E: case 0x0F: 1831 case 0x18: case 0x19: case 0x1A: case 0x1B: // 0011xxx 1832 case 0x1C: case 0x1D: case 0x1E: case 0x1F: 1833 case 0x48: case 0x49: case 0x4A: case 0x4B: // 1001xxx 1834 case 0x4C: case 0x4D: case 0x4E: case 0x4F: 1835 case 0x58: case 0x59: case 0x5A: case 0x5B: // 1011xxx 1836 case 0x5C: case 0x5D: case 0x5E: case 0x5F: { 1837 // CBNZ, CBZ 1838 uint16_t op = (instr >> 11) & 1; 1839 uint16_t i = (instr >> 9) & 1; 1840 uint16_t imm5 = (instr >> 3) & 0x1F; 1841 ThumbRegister Rn(instr, 0); 1842 opcode << (op != 0 ? "cbnz" : "cbz"); 1843 uint32_t imm32 = (i << 6) | (imm5 << 1); 1844 args << Rn << ", "; 1845 DumpBranchTarget(args, instr_ptr + 4, imm32); 1846 break; 1847 } 1848 case 0x50: case 0x51: // 101000x 1849 case 0x52: case 0x53: // 101001x 1850 case 0x56: case 0x57: { // 101011x 1851 uint16_t op = (instr >> 6) & 3; 1852 opcode << kThumbReverseOperations[op]; 1853 ThumbRegister Rm(instr, 3); 1854 ThumbRegister Rd(instr, 0); 1855 args << Rd << ", " << Rm; 1856 break; 1857 } 1858 case 0x78: case 0x79: case 0x7A: case 0x7B: // 1111xxx 1859 case 0x7C: case 0x7D: case 0x7E: case 0x7F: { 1860 // If-Then, and hints 1861 uint16_t opA = (instr >> 4) & 0xF; 1862 uint16_t opB = instr & 0xF; 1863 if (opB == 0) { 1864 switch (opA) { 1865 case 0: opcode << "nop"; break; 1866 case 1: opcode << "yield"; break; 1867 case 2: opcode << "wfe"; break; 1868 case 3: opcode << "sev"; break; 1869 default: break; 1870 } 1871 } else { 1872 uint32_t first_cond = opA; 1873 uint32_t mask = opB; 1874 opcode << "it"; 1875 1876 // Flesh out the base "it" opcode with the specific collection of 't's and 'e's, 1877 // and store up the actual condition codes we'll want to add to the next few opcodes. 1878 size_t count = 3 - CTZ(mask); 1879 it_conditions_.resize(count + 2); // Plus the implicit 't', plus the "" for the IT itself. 1880 for (size_t i = 0; i < count; ++i) { 1881 bool positive_cond = ((first_cond & 1) != 0); 1882 bool positive_mask = ((mask & (1 << (3 - i))) != 0); 1883 if (positive_mask == positive_cond) { 1884 opcode << 't'; 1885 it_conditions_[i] = kConditionCodeNames[first_cond]; 1886 } else { 1887 opcode << 'e'; 1888 it_conditions_[i] = kConditionCodeNames[first_cond ^ 1]; 1889 } 1890 } 1891 it_conditions_[count] = kConditionCodeNames[first_cond]; // The implicit 't'. 1892 1893 it_conditions_[count + 1] = ""; // No condition code for the IT itself... 1894 DumpCond(args, first_cond); // ...because it's considered an argument. 1895 } 1896 break; 1897 } 1898 default: 1899 break; 1900 } 1901 } else if (((instr & 0xF000) == 0x5000) || ((instr & 0xE000) == 0x6000) || 1902 ((instr & 0xE000) == 0x8000)) { 1903 // Load/store single data item 1904 uint16_t opA = instr >> 12; 1905 // uint16_t opB = (instr >> 9) & 7; 1906 switch (opA) { 1907 case 0x6: { 1908 // STR Rt, [Rn, #imm] - 01100 iiiii nnn ttt 1909 // LDR Rt, [Rn, #imm] - 01101 iiiii nnn ttt 1910 uint16_t imm5 = (instr >> 6) & 0x1F; 1911 ThumbRegister Rn(instr, 3); 1912 ThumbRegister Rt(instr, 0); 1913 opcode << ((instr & 0x800) == 0 ? "str" : "ldr"); 1914 args << Rt << ", [" << Rn << ", #" << (imm5 << 2) << "]"; 1915 break; 1916 } 1917 case 0x9: { 1918 // STR Rt, [SP, #imm] - 01100 ttt iiiiiiii 1919 // LDR Rt, [SP, #imm] - 01101 ttt iiiiiiii 1920 uint16_t imm8 = instr & 0xFF; 1921 ThumbRegister Rt(instr, 8); 1922 opcode << ((instr & 0x800) == 0 ? "str" : "ldr"); 1923 args << Rt << ", [sp, #" << (imm8 << 2) << "]"; 1924 break; 1925 } 1926 default: 1927 break; 1928 } 1929 } else if (opcode1 == 0x38 || opcode1 == 0x39) { 1930 uint16_t imm11 = instr & 0x7FFF; 1931 int32_t imm32 = imm11 << 1; 1932 imm32 = (imm32 << 20) >> 20; // sign extend 12 bit immediate 1933 opcode << "b"; 1934 DumpBranchTarget(args, instr_ptr + 4, imm32); 1935 } 1936 1937 // Apply any IT-block conditions to the opcode if necessary. 1938 if (!it_conditions_.empty()) { 1939 opcode << it_conditions_.back(); 1940 it_conditions_.pop_back(); 1941 } 1942 1943 os << FormatInstructionPointer(instr_ptr) 1944 << StringPrintf(": %04x \t%-7s ", instr, opcode.str().c_str()) 1945 << args.str() << '\n'; 1946 } 1947 return 2; 1948 } 1949 1950 } // namespace arm 1951 } // namespace art 1952