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