1/* 2 * Copyright (C) 2012 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "A64DOpcode.h" 28 29#include <stdarg.h> 30#include <stdint.h> 31#include <stdio.h> 32 33namespace JSC { namespace ARM64Disassembler { 34 35A64DOpcode::OpcodeGroup* A64DOpcode::opcodeTable[32]; 36 37const char* const A64DOpcode::s_conditionNames[16] = { 38 "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc", 39 "hi", "ls", "ge", "lt", "gt", "le", "al", "ne" 40}; 41 42const char* const A64DOpcode::s_optionName[8] = { 43 "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx" 44}; 45 46const char* const A64DOpcode::s_shiftNames[4] = { 47 "lsl", "lsr", "asl", "ror" 48}; 49 50const char A64DOpcode::s_FPRegisterPrefix[5] = { 51 'b', 'h', 's', 'd', 'q' 52}; 53 54struct OpcodeGroupInitializer { 55 unsigned m_opcodeGroupNumber; 56 uint32_t m_mask; 57 uint32_t m_pattern; 58 const char* (*m_format)(A64DOpcode*); 59}; 60 61#define OPCODE_GROUP_ENTRY(groupIndex, groupClass) \ 62{ groupIndex, groupClass::mask, groupClass::pattern, groupClass::format } 63 64static OpcodeGroupInitializer opcodeGroupList[] = { 65 OPCODE_GROUP_ENTRY(0x08, A64DOpcodeLoadStoreRegisterPair), 66 OPCODE_GROUP_ENTRY(0x09, A64DOpcodeLoadStoreRegisterPair), 67 OPCODE_GROUP_ENTRY(0x0a, A64DOpcodeLogicalShiftedRegister), 68 OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractExtendedRegister), 69 OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractShiftedRegister), 70 OPCODE_GROUP_ENTRY(0x11, A64DOpcodeAddSubtractImmediate), 71 OPCODE_GROUP_ENTRY(0x12, A64DOpcodeMoveWide), 72 OPCODE_GROUP_ENTRY(0x12, A64DOpcodeLogicalImmediate), 73 OPCODE_GROUP_ENTRY(0x13, A64DOpcodeBitfield), 74 OPCODE_GROUP_ENTRY(0x13, A64DOpcodeExtract), 75 OPCODE_GROUP_ENTRY(0x14, A64DOpcodeUnconditionalBranchImmediate), 76 OPCODE_GROUP_ENTRY(0x14, A64DOpcodeConditionalBranchImmediate), 77 OPCODE_GROUP_ENTRY(0x14, A64DOpcodeCompareAndBranchImmediate), 78 OPCODE_GROUP_ENTRY(0x14, A64OpcodeExceptionGeneration), 79 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeUnconditionalBranchImmediate), 80 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeConditionalBranchImmediate), 81 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeCompareAndBranchImmediate), 82 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeHint), 83 OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchImmediate), 84 OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchRegister), 85 OPCODE_GROUP_ENTRY(0x16, A64DOpcodeTestAndBranchImmediate), 86 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeUnconditionalBranchImmediate), 87 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeUnconditionalBranchRegister), 88 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeTestAndBranchImmediate), 89 OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreImmediate), 90 OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreRegisterOffset), 91 OPCODE_GROUP_ENTRY(0x19, A64DOpcodeLoadStoreUnsignedImmediate), 92 OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeConditionalSelect), 93 OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeDataProcessing2Source), 94 OPCODE_GROUP_ENTRY(0x1b, A64DOpcodeDataProcessing3Source), 95 OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreImmediate), 96 OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreRegisterOffset), 97 OPCODE_GROUP_ENTRY(0x1d, A64DOpcodeLoadStoreUnsignedImmediate), 98 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointCompare), 99 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing2Source), 100 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing1Source), 101 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingFixedPointConversions), 102 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointIntegerConversions), 103}; 104 105bool A64DOpcode::s_initialized = false; 106 107void A64DOpcode::init() 108{ 109 if (s_initialized) 110 return; 111 112 OpcodeGroup* lastGroups[32]; 113 114 for (unsigned i = 0; i < 32; i++) { 115 opcodeTable[i] = 0; 116 lastGroups[i] = 0; 117 } 118 119 for (unsigned i = 0; i < sizeof(opcodeGroupList) / sizeof(struct OpcodeGroupInitializer); i++) { 120 OpcodeGroup* newOpcodeGroup = new OpcodeGroup(opcodeGroupList[i].m_mask, opcodeGroupList[i].m_pattern, opcodeGroupList[i].m_format); 121 uint32_t opcodeGroupNumber = opcodeGroupList[i].m_opcodeGroupNumber; 122 123 if (!opcodeTable[opcodeGroupNumber]) 124 opcodeTable[opcodeGroupNumber] = newOpcodeGroup; 125 else 126 lastGroups[opcodeGroupNumber]->setNext(newOpcodeGroup); 127 lastGroups[opcodeGroupNumber] = newOpcodeGroup; 128 } 129 130 s_initialized = true; 131} 132 133void A64DOpcode::setPCAndOpcode(uint32_t* newPC, uint32_t newOpcode) 134{ 135 m_currentPC = newPC; 136 m_opcode = newOpcode; 137 m_bufferOffset = 0; 138 m_formatBuffer[0] = '\0'; 139} 140 141const char* A64DOpcode::disassemble(uint32_t* currentPC) 142{ 143 setPCAndOpcode(currentPC, *currentPC); 144 145 OpcodeGroup* opGroup = opcodeTable[opcodeGroupNumber(m_opcode)]; 146 147 while (opGroup) { 148 if (opGroup->matches(m_opcode)) 149 return opGroup->format(this); 150 opGroup = opGroup->next(); 151 } 152 153 return A64DOpcode::format(); 154} 155 156void A64DOpcode::bufferPrintf(const char* format, ...) 157{ 158 if (m_bufferOffset >= bufferSize) 159 return; 160 161 va_list argList; 162 va_start(argList, format); 163 164 m_bufferOffset += vsnprintf(m_formatBuffer + m_bufferOffset, bufferSize - m_bufferOffset, format, argList); 165 166 va_end(argList); 167} 168 169const char* A64DOpcode::format() 170{ 171 bufferPrintf(" .long %08x", m_opcode); 172 return m_formatBuffer; 173} 174 175void A64DOpcode::appendRegisterName(unsigned registerNumber, bool is64Bit) 176{ 177 if (registerNumber == 29) { 178 bufferPrintf(is64Bit ? "fp" : "wfp"); 179 return; 180 } 181 182 if (registerNumber == 30) { 183 bufferPrintf(is64Bit ? "lr" : "wlr"); 184 return; 185 } 186 187 bufferPrintf("%c%u", is64Bit ? 'x' : 'w', registerNumber); 188} 189 190void A64DOpcode::appendFPRegisterName(unsigned registerNumber, unsigned registerSize) 191{ 192 bufferPrintf("%c%u", FPRegisterPrefix(registerSize), registerNumber); 193} 194 195const char* const A64DOpcodeAddSubtract::s_opNames[4] = { "add", "adds", "sub", "subs" }; 196 197const char* A64DOpcodeAddSubtractImmediate::format() 198{ 199 if (isCMP()) 200 appendInstructionName(cmpName()); 201 else { 202 if (isMovSP()) 203 appendInstructionName("mov"); 204 else 205 appendInstructionName(opName()); 206 appendSPOrRegisterName(rd(), is64Bit()); 207 appendSeparator(); 208 } 209 appendSPOrRegisterName(rn(), is64Bit()); 210 211 if (!isMovSP()) { 212 appendSeparator(); 213 appendUnsignedImmediate(immed12()); 214 if (shift()) { 215 appendSeparator(); 216 appendString(shift() == 1 ? "lsl" : "reserved"); 217 } 218 } 219 return m_formatBuffer; 220} 221 222const char* A64DOpcodeAddSubtractExtendedRegister::format() 223{ 224 if (immediate3() > 4) 225 return A64DOpcode::format(); 226 227 if (isCMP()) 228 appendInstructionName(cmpName()); 229 else { 230 appendInstructionName(opName()); 231 appendSPOrRegisterName(rd(), is64Bit()); 232 appendSeparator(); 233 } 234 appendSPOrRegisterName(rn(), is64Bit()); 235 appendSeparator(); 236 appendZROrRegisterName(rm(), is64Bit() && ((option() & 0x3) == 0x3)); 237 appendSeparator(); 238 if (option() == 0x2 && ((rd() == 31) || (rn() == 31))) 239 appendString("lsl"); 240 else 241 appendString(optionName()); 242 if (immediate3()) { 243 appendCharacter(' '); 244 appendUnsignedImmediate(immediate3()); 245 } 246 247 return m_formatBuffer; 248} 249 250const char* A64DOpcodeAddSubtractShiftedRegister::format() 251{ 252 if (!is64Bit() && immediate6() & 0x20) 253 return A64DOpcode::format(); 254 255 if (shift() == 0x3) 256 return A64DOpcode::format(); 257 258 if (isCMP()) 259 appendInstructionName(cmpName()); 260 else { 261 if (isNeg()) 262 appendInstructionName(cmpName()); 263 else 264 appendInstructionName(opName()); 265 appendSPOrRegisterName(rd(), is64Bit()); 266 appendSeparator(); 267 } 268 if (!isNeg()) { 269 appendRegisterName(rn(), is64Bit()); 270 appendSeparator(); 271 } 272 appendZROrRegisterName(rm(), is64Bit()); 273 if (immediate6()) { 274 appendSeparator(); 275 appendShiftType(shift()); 276 appendUnsignedImmediate(immediate6()); 277 } 278 279 return m_formatBuffer; 280} 281 282const char* const A64DOpcodeBitfield::s_opNames[3] = { "sbfm", "bfm", "ubfm" }; 283const char* const A64DOpcodeBitfield::s_extendPseudoOpNames[3][3] = { 284 { "sxtb", "sxth", "sxtw" }, { 0, 0, 0} , { "uxtb", "uxth", "uxtw" } }; 285const char* const A64DOpcodeBitfield::s_insertOpNames[3] = { "sbfiz", "bfi", "ubfiz" }; 286const char* const A64DOpcodeBitfield::s_extractOpNames[3] = { "sbfx", "bf", "ubfx" }; 287 288const char* A64DOpcodeBitfield::format() 289{ 290 if (opc() == 0x3) 291 return A64DOpcode::format(); 292 293 if (is64Bit() != nBit()) 294 return A64DOpcode::format(); 295 296 if (!is64Bit() && ((immediateR() & 0x20) || (immediateS() & 0x20))) 297 return A64DOpcode::format(); 298 299 if (!(opc() & 0x1) && !immediateR()) { 300 // [un]signed {btye,half-word,word} extend 301 bool isSTXType = false; 302 if (immediateS() == 7) { 303 appendInstructionName(extendPseudoOpNames(0)); 304 isSTXType = true; 305 } else if (immediateS() == 15) { 306 appendInstructionName(extendPseudoOpNames(1)); 307 isSTXType = true; 308 } else if (immediateS() == 31 && is64Bit()) { 309 appendInstructionName(extendPseudoOpNames(2)); 310 isSTXType = true; 311 } 312 313 if (isSTXType) { 314 appendRegisterName(rd(), is64Bit()); 315 appendSeparator(); 316 appendRegisterName(rn(), false); 317 318 return m_formatBuffer; 319 } 320 } 321 322 if (opc() == 0x2 && immediateS() == (immediateR() + 1)) { 323 // lsl 324 appendInstructionName("lsl"); 325 appendRegisterName(rd(), is64Bit()); 326 appendSeparator(); 327 appendRegisterName(rn(), is64Bit()); 328 appendSeparator(); 329 appendUnsignedImmediate((is64Bit() ? 63u : 31u) - immediateR()); 330 331 return m_formatBuffer; 332 } else if (!(opc() & 0x1) && ((immediateS() & 0x1f) == 0x1f) && (is64Bit() == (immediateS() >> 5))) { 333 // asr/lsr 334 appendInstructionName(!opc() ? "ars" : "lsr"); 335 336 appendRegisterName(rd(), is64Bit()); 337 appendSeparator(); 338 appendRegisterName(rn(), is64Bit()); 339 appendSeparator(); 340 appendUnsignedImmediate(immediateR()); 341 342 return m_formatBuffer; 343 } else if (immediateS() < immediateR()) { 344 // bit field insert 345 appendInstructionName(insertOpNames()); 346 347 appendRegisterName(rd(), is64Bit()); 348 appendSeparator(); 349 appendRegisterName(rn(), is64Bit()); 350 appendSeparator(); 351 appendUnsignedImmediate((is64Bit() ? 64u : 32u) - immediateR()); 352 appendSeparator(); 353 appendUnsignedImmediate(immediateS() + 1); 354 355 return m_formatBuffer; 356 } else { 357 // bit field extract 358 appendInstructionName(extractOpNames()); 359 360 appendRegisterName(rd(), is64Bit()); 361 appendSeparator(); 362 appendRegisterName(rn(), is64Bit()); 363 appendSeparator(); 364 appendUnsignedImmediate(immediateR()); 365 appendSeparator(); 366 appendUnsignedImmediate(immediateS() - immediateR() + 1); 367 368 return m_formatBuffer; 369 } 370 371 appendInstructionName(opName()); 372 appendRegisterName(rd(), is64Bit()); 373 appendSeparator(); 374 appendRegisterName(rn(), is64Bit()); 375 appendSeparator(); 376 appendUnsignedImmediate(immediateR()); 377 appendSeparator(); 378 appendUnsignedImmediate(immediateS()); 379 380 return m_formatBuffer; 381} 382 383const char* A64DOpcodeCompareAndBranchImmediate::format() 384{ 385 appendInstructionName(opBit() ? "cbnz" : "cbz"); 386 appendRegisterName(rt(), is64Bit()); 387 appendSeparator(); 388 appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate19())); 389 return m_formatBuffer; 390} 391 392const char* A64DOpcodeConditionalBranchImmediate::format() 393{ 394 bufferPrintf(" b.%-5.5s", conditionName(condition())); 395 appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate19())); 396 return m_formatBuffer; 397} 398 399const char* const A64DOpcodeConditionalSelect::s_opNames[4] = { 400 "csel", "csinc", "csinv", "csneg" 401}; 402 403const char* A64DOpcodeConditionalSelect::format() 404{ 405 if (sBit()) 406 return A64DOpcode::format(); 407 408 if (op2() & 0x2) 409 return A64DOpcode::format(); 410 411 if (rn() == rm() && (opNum() == 1 || opNum() == 2)) { 412 if (rn() == 31) { 413 appendInstructionName((opNum() == 1) ? "cset" : "csetm"); 414 appendRegisterName(rd(), is64Bit()); 415 } else { 416 appendInstructionName((opNum() == 1) ? "cinc" : "cinv"); 417 appendRegisterName(rd(), is64Bit()); 418 appendSeparator(); 419 appendZROrRegisterName(rn(), is64Bit()); 420 } 421 appendSeparator(); 422 appendString(conditionName(condition() ^ 0x1)); 423 424 return m_formatBuffer; 425 } 426 427 appendInstructionName(opName()); 428 appendRegisterName(rd(), is64Bit()); 429 appendSeparator(); 430 appendZROrRegisterName(rn(), is64Bit()); 431 appendSeparator(); 432 appendZROrRegisterName(rm(), is64Bit()); 433 appendSeparator(); 434 appendString(conditionName(condition())); 435 436 return m_formatBuffer; 437 438} 439 440const char* const A64DOpcodeDataProcessing2Source::s_opNames[8] = { 441 0, 0, "udiv", "sdiv", "lsl", "lsr", "asr", "ror" // We use the pseudo-op names for the shift/rotate instructions 442}; 443 444const char* A64DOpcodeDataProcessing2Source::format() 445{ 446 if (sBit()) 447 return A64DOpcode::format(); 448 449 if (!(opCode() & 0x3e)) 450 return A64DOpcode::format(); 451 452 if (opCode() & 0x30) 453 return A64DOpcode::format(); 454 455 if ((opCode() & 0x34) == 0x4) 456 return A64DOpcode::format(); 457 458 appendInstructionName(opName()); 459 appendRegisterName(rd(), is64Bit()); 460 appendSeparator(); 461 appendRegisterName(rn(), is64Bit()); 462 appendSeparator(); 463 appendRegisterName(rm(), is64Bit()); 464 465 return m_formatBuffer; 466} 467 468const char* const A64DOpcodeDataProcessing3Source::s_opNames[16] = { 469 "madd", "msub", "smaddl", "smsubl", "smulh", 0, 0, 0, 470 0, 0, "umaddl", "umsubl", "umulh", 0, 0, 0 471}; 472 473const char* const A64DOpcodeDataProcessing3Source::s_pseudoOpNames[16] = { 474 "mul", "mneg", "smull", "smnegl", "smulh", 0, 0, 0, 475 0, 0, "umull", "umnegl", "umulh", 0, 0, 0 476}; 477 478const char* A64DOpcodeDataProcessing3Source::format() 479{ 480 if (op54()) 481 return A64DOpcode::format(); 482 483 if (opNum() > 12) 484 return A64DOpcode::format(); 485 486 if (!is64Bit() && opNum() > 1) 487 return A64DOpcode::format(); 488 489 if (!opName()) 490 return A64DOpcode::format(); 491 492 appendInstructionName(opName()); 493 appendRegisterName(rd(), is64Bit()); 494 appendSeparator(); 495 bool srcOneAndTwoAre64Bit = is64Bit() & !(opNum() & 0x2); 496 appendRegisterName(rn(), srcOneAndTwoAre64Bit); 497 appendSeparator(); 498 appendRegisterName(rm(), srcOneAndTwoAre64Bit); 499 500 if ((ra() != 31) || !(opNum() & 0x4)) { 501 appendSeparator(); 502 appendRegisterName(ra(), is64Bit()); 503 } 504 505 return m_formatBuffer; 506} 507 508const char* A64OpcodeExceptionGeneration::format() 509{ 510 const char* opname = 0; 511 if (!op2()) { 512 switch (opc()) { 513 case 0x0: // SVC, HVC & SMC 514 switch (ll()) { 515 case 0x1: 516 opname = "svc"; 517 break; 518 case 0x2: 519 opname = "hvc"; 520 break; 521 case 0x3: 522 opname = "smc"; 523 break; 524 } 525 break; 526 case 0x1: // BRK 527 if (!ll()) 528 opname = "brk"; 529 break; 530 case 0x2: // HLT 531 if (!ll()) 532 opname = "hlt"; 533 break; 534 case 0x5: // DPCS1-3 535 switch (ll()) { 536 case 0x1: 537 opname = "dpcs1"; 538 break; 539 case 0x2: 540 opname = "dpcs2"; 541 break; 542 case 0x3: 543 opname = "dpcs3"; 544 break; 545 } 546 break; 547 } 548 } 549 550 if (!opname) 551 return A64DOpcode::format(); 552 553 appendInstructionName(opname); 554 appendUnsignedImmediate(immediate16()); 555 return m_formatBuffer; 556} 557 558const char* A64DOpcodeExtract::format() 559{ 560 if (!op21() || !o0Bit()) 561 return A64DOpcode::format(); 562 563 if (is64Bit() != nBit()) 564 return A64DOpcode::format(); 565 566 if (is64Bit() && (immediateS() & 0x20)) 567 return A64DOpcode::format(); 568 569 const char* opName = (rn() == rm()) ? "ror" : "extr"; 570 571 appendInstructionName(opName); 572 appendRegisterName(rd(), is64Bit()); 573 appendSeparator(); 574 appendRegisterName(rn(), is64Bit()); 575 appendSeparator(); 576 appendRegisterName(rm(), is64Bit()); 577 appendSeparator(); 578 appendUnsignedImmediate(immediateS()); 579 580 return m_formatBuffer; 581} 582 583const char* A64DOpcodeFloatingPointCompare::format() 584{ 585 if (mBit()) 586 return A64DOpcode::format(); 587 588 if (sBit()) 589 return A64DOpcode::format(); 590 591 if (type() & 0x2) 592 return A64DOpcode::format(); 593 594 if (op()) 595 return A64DOpcode::format(); 596 597 if (opCode2() & 0x7) 598 return A64DOpcode::format(); 599 600 appendInstructionName(opName()); 601 unsigned registerSize = type() + 2; 602 appendFPRegisterName(rn(), registerSize); 603 appendSeparator(); 604 if (opCode2() & 0x8) 605 bufferPrintf("#0.0"); 606 else 607 appendFPRegisterName(rm(), registerSize); 608 609 return m_formatBuffer; 610} 611 612const char* const A64DOpcodeFloatingPointDataProcessing1Source::s_opNames[16] = { 613 "fmov", "fabs", "fneg", "fsqrt", "fcvt", "fcvt", 0, "fcvt", 614 "frintn", "frintp", "frintm", "frintz", "frinta", 0, "frintx", "frinti" 615}; 616 617const char* A64DOpcodeFloatingPointDataProcessing1Source::format() 618{ 619 if (mBit()) 620 return A64DOpcode::format(); 621 622 if (sBit()) 623 return A64DOpcode::format(); 624 625 if (opNum() > 16) 626 return A64DOpcode::format(); 627 628 switch (type()) { 629 case 0: 630 if ((opNum() == 0x4) || (opNum() == 0x6) || (opNum() == 0xd)) 631 return A64DOpcode::format(); 632 break; 633 case 1: 634 if ((opNum() == 0x5) || (opNum() == 0x6) || (opNum() == 0xd)) 635 return A64DOpcode::format(); 636 break; 637 case 2: 638 return A64DOpcode::format(); 639 case 3: 640 if ((opNum() < 0x4) || (opNum() > 0x5)) 641 return A64DOpcode::format(); 642 break; 643 } 644 645 appendInstructionName(opName()); 646 if ((opNum() >= 0x4) && (opNum() <= 0x7)) { 647 unsigned srcRegisterSize = type() ^ 0x2; // 0:s, 1:d & 3:h 648 unsigned destRegisterSize = (opNum() & 0x3) ^ 0x2; 649 appendFPRegisterName(rd(), destRegisterSize); 650 appendSeparator(); 651 appendFPRegisterName(rn(), srcRegisterSize); 652 } else { 653 unsigned registerSize = type() + 2; 654 appendFPRegisterName(rd(), registerSize); 655 appendSeparator(); 656 appendFPRegisterName(rn(), registerSize); 657 } 658 659 return m_formatBuffer; 660} 661 662const char* const A64DOpcodeFloatingPointDataProcessing2Source::s_opNames[16] = { 663 "fmul", "fdiv", "fadd", "fsub", "fmax", "fmin", "fmaxnm", "fminnm", "fnmul" 664}; 665 666const char* A64DOpcodeFloatingPointDataProcessing2Source::format() 667{ 668 if (mBit()) 669 return A64DOpcode::format(); 670 671 if (sBit()) 672 return A64DOpcode::format(); 673 674 if (type() & 0x2) 675 return A64DOpcode::format(); 676 677 if (opNum() > 8) 678 return A64DOpcode::format(); 679 680 appendInstructionName(opName()); 681 unsigned registerSize = type() + 2; 682 appendFPRegisterName(rd(), registerSize); 683 appendSeparator(); 684 appendFPRegisterName(rn(), registerSize); 685 appendSeparator(); 686 appendFPRegisterName(rm(), registerSize); 687 688 return m_formatBuffer; 689} 690 691const char* const A64DOpcodeFloatingFixedPointConversions::s_opNames[4] = { 692 "fcvtzs", "fcvtzu", "scvtf", "ucvtf" 693}; 694 695const char* A64DOpcodeFloatingFixedPointConversions::format() 696{ 697 if (sBit()) 698 return A64DOpcode::format(); 699 700 if (type() & 0x2) 701 return A64DOpcode::format(); 702 703 if (opcode() & 0x4) 704 return A64DOpcode::format(); 705 706 if (!(rmode() & 0x1) && !(opcode() & 0x6)) 707 return A64DOpcode::format(); 708 709 if ((rmode() & 0x1) && (opcode() & 0x6) == 0x2) 710 return A64DOpcode::format(); 711 712 if (!(rmode() & 0x2) && !(opcode() & 0x6)) 713 return A64DOpcode::format(); 714 715 if ((rmode() & 0x2) && (opcode() & 0x6) == 0x2) 716 return A64DOpcode::format(); 717 718 if (!is64Bit() && scale() >= 32) 719 return A64DOpcode::format(); 720 721 appendInstructionName(opName()); 722 unsigned FPRegisterSize = type() + 2; 723 bool destIsFP = !rmode(); 724 725 if (destIsFP) { 726 appendFPRegisterName(rd(), FPRegisterSize); 727 appendSeparator(); 728 appendRegisterName(rn(), is64Bit()); 729 } else { 730 appendRegisterName(rd(), is64Bit()); 731 appendSeparator(); 732 appendFPRegisterName(rn(), FPRegisterSize); 733 } 734 appendSeparator(); 735 appendUnsignedImmediate(64 - scale()); 736 737 return m_formatBuffer; 738} 739 740const char* const A64DOpcodeFloatingPointIntegerConversions::s_opNames[32] = { 741 "fcvtns", "fcvtnu", "scvtf", "ucvtf", "fcvtas", "fcvtau", "fmov", "fmov", 742 "fcvtps", "fcvtpu", 0, 0, 0, 0, "fmov", "fmov", 743 "fcvtms", "fcvtmu", 0, 0, 0, 0, 0, 0, 744 "fcvtzs", "fcvtzu", 0, 0, 0, 0, 0, 0 745}; 746 747const char* A64DOpcodeFloatingPointIntegerConversions::format() 748{ 749 if (sBit()) 750 return A64DOpcode::format(); 751 752 if (type() == 0x3) 753 return A64DOpcode::format(); 754 755 if (((rmode() & 0x1) || (rmode() & 0x2)) && (((opcode() & 0x6) == 0x2) || ((opcode() & 0x6) == 0x4))) 756 return A64DOpcode::format(); 757 758 if ((type() == 0x2) && (!(opcode() & 0x4) || ((opcode() & 0x6) == 0x4))) 759 return A64DOpcode::format(); 760 761 if (!type() && (rmode() & 0x1) && ((opcode() & 0x6) == 0x6)) 762 return A64DOpcode::format(); 763 764 if (is64Bit() && type() == 0x2 && ((opNum() & 0xe) == 0x6)) 765 return A64DOpcode::format(); 766 767 if (!opName()) 768 return A64DOpcode::format(); 769 770 if ((opNum() & 0x1e) == 0xe) { 771 // Handle fmov to/from upper half of quad separately 772 if (!is64Bit() || (type() != 0x2)) 773 return A64DOpcode::format(); 774 775 appendInstructionName(opName()); 776 if (opcode() & 0x1) { 777 // fmov Vd.D[1], Xn 778 bufferPrintf("V%u.D[1]", rd()); 779 appendSeparator(); 780 appendRegisterName(rn()); 781 } else { 782 // fmov Xd, Vn.D[1] 783 appendRegisterName(rd()); 784 appendSeparator(); 785 bufferPrintf("V%u.D[1]", rn()); 786 } 787 788 return m_formatBuffer; 789 } 790 791 appendInstructionName(opName()); 792 unsigned FPRegisterSize = type() + 2; 793 bool destIsFP = ((opNum() == 2) || (opNum() == 3) || (opNum() == 7)); 794 795 if (destIsFP) { 796 appendFPRegisterName(rd(), FPRegisterSize); 797 appendSeparator(); 798 appendRegisterName(rn(), is64Bit()); 799 } else { 800 appendRegisterName(rd(), is64Bit()); 801 appendSeparator(); 802 appendFPRegisterName(rn(), FPRegisterSize); 803 } 804 805 return m_formatBuffer; 806} 807 808const char* const A64DOpcodeHint::s_opNames[6] = { 809 "nop", "yield", "wfe", "wfi", "sev", "sevl" 810}; 811 812const char* A64DOpcodeHint::format() 813{ 814 appendInstructionName(opName()); 815 816 if (immediate7() > 5) 817 appendUnsignedImmediate(immediate7()); 818 819 return m_formatBuffer; 820} 821 822// A zero in an entry of the table means the instruction is Unallocated 823const char* const A64DOpcodeLoadStore::s_opNames[32] = { 824 "strb", "ldrb", "ldrsb", "ldrsb", "str", "ldr", "str", "ldr", 825 "strh", "ldrh", "ldrsh", "ldrsh", "str", "ldr", 0, 0, 826 "str", "ldr", "ldrsw", 0, "str", "ldr", 0, 0, 827 "str", "ldr", 0, 0, "str", "ldr", 0, 0 828}; 829 830// A zero in an entry of the table means the instruction is Unallocated 831const char* const A64DOpcodeLoadStoreImmediate::s_unprivilegedOpNames[32] = { 832 "sttrb", "ldtrb", "ldtrsb", "ldtrsb", 0, 0, 0, 0, 833 "sttrh", "ldtrh", "ldtrsh", "ldtrsh", 0, 0, 0, 0, 834 "sttr", "ldtr", "ldtrsw", 0, 0, 0, 0, 0, 835 "sttr", "ldtr", 0, 0, 0, 0, 0, 0 836}; 837 838// A zero in an entry of the table means the instruction is Unallocated 839const char* const A64DOpcodeLoadStoreImmediate::s_unscaledOpNames[32] = { 840 "sturb", "ldurb", "ldursb", "ldursb", "stur", "ldur", "stur", "ldur", 841 "sturh", "ldurh", "ldursh", "ldursh", "stur", "ldur", 0, 0, 842 "stur", "ldur", "ldursw", 0, "stur", "ldur", 0, 0, 843 "stur", "ldur", "prfum", 0, "stur", "ldur", 0, 0 844}; 845 846const char* A64DOpcodeLoadStoreImmediate::format() 847{ 848 const char* thisOpName; 849 850 if (type() & 0x1) 851 thisOpName = opName(); 852 else if (!type()) 853 thisOpName = unscaledOpName(); 854 else 855 thisOpName = unprivilegedOpName(); 856 857 if (!thisOpName) 858 return A64DOpcode::format(); 859 860 appendInstructionName(thisOpName); 861 if (vBit()) 862 appendFPRegisterName(rt(), size()); 863 else 864 appendRegisterName(rt(), is64BitRT()); 865 appendSeparator(); 866 appendCharacter('['); 867 appendSPOrRegisterName(rn()); 868 869 switch (type()) { 870 case 0: // Unscaled Immediate 871 if (immediate9()) { 872 appendSeparator(); 873 appendSignedImmediate(immediate9()); 874 } 875 appendCharacter(']'); 876 break; 877 case 1: // Immediate Post-Indexed 878 appendCharacter(']'); 879 if (immediate9()) { 880 appendSeparator(); 881 appendSignedImmediate(immediate9()); 882 } 883 break; 884 case 2: // Unprivileged 885 if (immediate9()) { 886 appendSeparator(); 887 appendSignedImmediate(immediate9()); 888 } 889 appendCharacter(']'); 890 break; 891 case 3: // Immediate Pre-Indexed 892 if (immediate9()) { 893 appendSeparator(); 894 appendSignedImmediate(immediate9()); 895 } 896 appendCharacter(']'); 897 appendCharacter('!'); 898 break; 899 } 900 901 return m_formatBuffer; 902} 903 904const char* A64DOpcodeLoadStoreRegisterOffset::format() 905{ 906 const char* thisOpName = opName(); 907 908 if (!thisOpName) 909 return A64DOpcode::format(); 910 911 if (!(option() & 0x2)) 912 return A64DOpcode::format(); 913 914 appendInstructionName(thisOpName); 915 unsigned scale; 916 if (vBit()) { 917 appendFPRegisterName(rt(), size()); 918 scale = ((opc() & 2)<<1) | size(); 919 } else { 920 appendRegisterName(rt(), is64BitRT()); 921 scale = size(); 922 } 923 appendSeparator(); 924 appendCharacter('['); 925 appendSPOrRegisterName(rn()); 926 appendSeparator(); 927 appendZROrRegisterName(rm(), (option() & 0x3) == 0x3); 928 929 unsigned shift = sBit() ? scale : 0; 930 931 if (option() == 0x3) { 932 if (shift) { 933 appendSeparator(); 934 appendString("lsl "); 935 appendUnsignedImmediate(shift); 936 } 937 } else { 938 appendSeparator(); 939 appendString(optionName()); 940 if (shift) 941 appendUnsignedImmediate(shift); 942 } 943 944 appendCharacter(']'); 945 946 return m_formatBuffer; 947} 948 949const char* A64DOpcodeLoadStoreRegisterPair::opName() 950{ 951 if (!vBit() && lBit() && size() == 0x1) 952 return "ldpsw"; 953 if (lBit()) 954 return "ldp"; 955 return "stp"; 956} 957 958const char* A64DOpcodeLoadStoreRegisterPair::format() 959{ 960 const char* thisOpName = opName(); 961 962 if (size() == 0x3) 963 return A64DOpcode::format(); 964 965 if ((offsetMode() < 0x1) || (offsetMode() > 0x3)) 966 return A64DOpcode::format(); 967 968 if ((offsetMode() == 0x1) && !vBit() && !lBit()) 969 return A64DOpcode::format(); 970 971 appendInstructionName(thisOpName); 972 unsigned offsetShift; 973 if (vBit()) { 974 appendFPRegisterName(rt(), size()); 975 appendSeparator(); 976 appendFPRegisterName(rt2(), size()); 977 offsetShift = size() + 2; 978 } else { 979 appendRegisterName(rt(), is64Bit()); 980 appendSeparator(); 981 appendRegisterName(rt2(), is64Bit()); 982 offsetShift = (size() >> 1) + 2; 983 } 984 985 appendSeparator(); 986 appendCharacter('['); 987 appendSPOrRegisterName(rn()); 988 989 int offset = immediate7() << offsetShift; 990 991 if (offsetMode() == 1) { 992 appendCharacter(']'); 993 appendSeparator(); 994 appendSignedImmediate(offset); 995 } else { 996 appendSeparator(); 997 appendSignedImmediate(offset); 998 appendCharacter(']'); 999 if (offsetMode() == 0x3) 1000 appendCharacter('!'); 1001 } 1002 1003 return m_formatBuffer; 1004} 1005 1006const char* A64DOpcodeLoadStoreUnsignedImmediate::format() 1007{ 1008 const char* thisOpName = opName(); 1009 1010 if (!thisOpName) 1011 return A64DOpcode::format(); 1012 1013 appendInstructionName(thisOpName); 1014 unsigned scale; 1015 if (vBit()) { 1016 appendFPRegisterName(rt(), size()); 1017 scale = ((opc() & 2)<<1) | size(); 1018 } else { 1019 appendRegisterName(rt(), is64BitRT()); 1020 scale = size(); 1021 } 1022 appendSeparator(); 1023 appendCharacter('['); 1024 appendSPOrRegisterName(rn()); 1025 1026 if (immediate12()) { 1027 appendSeparator(); 1028 appendUnsignedImmediate(immediate12() << scale); 1029 } 1030 1031 appendCharacter(']'); 1032 1033 return m_formatBuffer; 1034} 1035 1036// A zero in an entry of the table means the instruction is Unallocated 1037const char* const A64DOpcodeLogical::s_opNames[8] = { 1038 "and", "bic", "orr", "orn", "eor", "eon", "ands", "bics" 1039}; 1040 1041const char* A64DOpcodeLogicalShiftedRegister::format() 1042{ 1043 if (!is64Bit() && immediate6() & 0x20) 1044 return A64DOpcode::format(); 1045 1046 if (isTst()) 1047 appendInstructionName("tst"); 1048 else { 1049 if (isMov()) 1050 appendInstructionName("mov"); 1051 else 1052 appendInstructionName(opName(opNumber())); 1053 appendSPOrRegisterName(rd(), is64Bit()); 1054 appendSeparator(); 1055 } 1056 1057 if (!isMov()) { 1058 appendRegisterName(rn(), is64Bit()); 1059 appendSeparator(); 1060 } 1061 1062 appendZROrRegisterName(rm(), is64Bit()); 1063 if (immediate6()) { 1064 appendSeparator(); 1065 appendShiftType(shift()); 1066 appendUnsignedImmediate(immediate6()); 1067 } 1068 1069 return m_formatBuffer; 1070} 1071 1072static unsigned highestBitSet(unsigned value) 1073{ 1074 unsigned result = 0; 1075 1076 while (value >>= 1) 1077 result++; 1078 1079 return result; 1080} 1081 1082static uint64_t rotateRight(uint64_t value, unsigned width, unsigned shift) 1083{ 1084 uint64_t result = value; 1085 1086 if (shift) 1087 result = (value >> (shift % width)) | (value << (width - shift)); 1088 1089 return result; 1090} 1091 1092static uint64_t replicate(uint64_t value, unsigned width) 1093{ 1094 uint64_t result = 0; 1095 1096 for (unsigned totalBits = 0; totalBits < 64; totalBits += width) 1097 result = (result << width) | value; 1098 1099 return result; 1100} 1101 1102const char* A64DOpcodeLogicalImmediate::format() 1103{ 1104 if (!is64Bit() && nBit()) 1105 return A64DOpcode::format(); 1106 1107 unsigned len = highestBitSet(nBit() << 6 | (immediateS() ^ 0x3f)); 1108 unsigned levels = (1 << len) - 1; // len number of 1 bits starting at LSB 1109 1110 if ((immediateS() & levels) == levels) 1111 return A64DOpcode::format(); 1112 1113 unsigned r = immediateR() & levels; 1114 unsigned s = immediateS() & levels; 1115 unsigned eSize = 1 << len; 1116 uint64_t pattern = rotateRight((1ull << (s + 1)) - 1, eSize, r); 1117 1118 uint64_t immediate = replicate(pattern, eSize); 1119 1120 if (!is64Bit()) 1121 immediate &= 0xffffffffull; 1122 1123 if (isTst()) 1124 appendInstructionName("tst"); 1125 else { 1126 if (isMov()) 1127 appendInstructionName("mov"); 1128 else 1129 appendInstructionName(opName(opNumber())); 1130 appendRegisterName(rd(), is64Bit()); 1131 appendSeparator(); 1132 } 1133 if (!isMov()) { 1134 appendRegisterName(rn(), is64Bit()); 1135 appendSeparator(); 1136 } 1137 appendUnsignedImmediate64(immediate); 1138 1139 return m_formatBuffer; 1140} 1141 1142const char* const A64DOpcodeMoveWide::s_opNames[4] = { "movn", "", "movz", "movk" }; 1143 1144const char* A64DOpcodeMoveWide::format() 1145{ 1146 if (opc() == 1) 1147 return A64DOpcode::format(); 1148 if (!size() && hw() >= 2) 1149 return A64DOpcode::format(); 1150 1151 appendInstructionName(opName()); 1152 appendRegisterName(rd(), is64Bit()); 1153 appendSeparator(); 1154 appendUnsignedImmediate(immediate16()); 1155 if (hw()) { 1156 appendSeparator(); 1157 appendShiftAmount(hw()); 1158 } 1159 1160 return m_formatBuffer; 1161} 1162 1163const char* A64DOpcodeTestAndBranchImmediate::format() 1164{ 1165 appendInstructionName(opBit() ? "tbnz" : "tbz"); 1166 appendRegisterName(rt()); 1167 appendSeparator(); 1168 appendUnsignedImmediate(bitNumber()); 1169 appendSeparator(); 1170 appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate14())); 1171 return m_formatBuffer; 1172} 1173 1174const char* A64DOpcodeUnconditionalBranchImmediate::format() 1175{ 1176 appendInstructionName(op() ? "bl" : "b"); 1177 appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate26())); 1178 return m_formatBuffer; 1179} 1180 1181const char* const A64DOpcodeUnconditionalBranchRegister::s_opNames[8] = { "br", "blr", "ret", "", "eret", "drps", "", "" }; 1182 1183const char* A64DOpcodeUnconditionalBranchRegister::format() 1184{ 1185 unsigned opcValue = opc(); 1186 if (opcValue == 3 || opcValue > 5) 1187 return A64DOpcode::format(); 1188 if (((opcValue & 0xe) == 0x4) && rn() != 0x1f) 1189 return A64DOpcode::format(); 1190 appendInstructionName(opName()); 1191 if (opcValue <= 2) 1192 appendRegisterName(rn()); 1193 return m_formatBuffer; 1194} 1195 1196} } // namespace JSC::ARM64Disassembler 1197