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