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