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