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