A64DOpcode.cpp
1 /* 2 * Copyright (C) 2012, 2016 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 28 #if ENABLE(ARM64_DISASSEMBLER) 29 30 #include "A64DOpcode.h" 31 32 #include <stdarg.h> 33 #include <stdint.h> 34 #include <stdio.h> 35 36 namespace JSC { namespace ARM64Disassembler { 37 38 A64DOpcode::OpcodeGroup* A64DOpcode::opcodeTable[32]; 39 40 const char* const A64DOpcode::s_conditionNames[16] = { 41 "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc", 42 "hi", "ls", "ge", "lt", "gt", "le", "al", "ne" 43 }; 44 45 const char* const A64DOpcode::s_optionName[8] = { 46 "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx" 47 }; 48 49 const char* const A64DOpcode::s_shiftNames[4] = { 50 "lsl", "lsr", "asl", "ror" 51 }; 52 53 const char A64DOpcode::s_FPRegisterPrefix[5] = { 54 'b', 'h', 's', 'd', 'q' 55 }; 56 57 struct OpcodeGroupInitializer { 58 unsigned m_opcodeGroupNumber; 59 uint32_t m_mask; 60 uint32_t m_pattern; 61 const char* (*m_format)(A64DOpcode*); 62 }; 63 64 #define OPCODE_GROUP_ENTRY(groupIndex, groupClass) \ 65 { groupIndex, groupClass::mask, groupClass::pattern, groupClass::format } 66 67 static const OpcodeGroupInitializer opcodeGroupList[] = { 68 OPCODE_GROUP_ENTRY(0x08, A64DOpcodeCAS), 69 OPCODE_GROUP_ENTRY(0x08, A64DOpcodeLoadStoreRegisterPair), 70 OPCODE_GROUP_ENTRY(0x08, A64DOpcodeLoadStoreExclusive), 71 OPCODE_GROUP_ENTRY(0x09, A64DOpcodeLoadStoreRegisterPair), 72 OPCODE_GROUP_ENTRY(0x0a, A64DOpcodeLogicalShiftedRegister), 73 OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractExtendedRegister), 74 OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractShiftedRegister), 75 OPCODE_GROUP_ENTRY(0x11, A64DOpcodeAddSubtractImmediate), 76 OPCODE_GROUP_ENTRY(0x12, A64DOpcodeMoveWide), 77 OPCODE_GROUP_ENTRY(0x12, A64DOpcodeLogicalImmediate), 78 OPCODE_GROUP_ENTRY(0x13, A64DOpcodeBitfield), 79 OPCODE_GROUP_ENTRY(0x13, A64DOpcodeExtract), 80 OPCODE_GROUP_ENTRY(0x14, A64DOpcodeUnconditionalBranchImmediate), 81 OPCODE_GROUP_ENTRY(0x14, A64DOpcodeConditionalBranchImmediate), 82 OPCODE_GROUP_ENTRY(0x14, A64DOpcodeCompareAndBranchImmediate), 83 OPCODE_GROUP_ENTRY(0x14, A64OpcodeExceptionGeneration), 84 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeUnconditionalBranchImmediate), 85 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeConditionalBranchImmediate), 86 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeCompareAndBranchImmediate), 87 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeHint), 88 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeSystemSync), 89 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeMSRImmediate), 90 OPCODE_GROUP_ENTRY(0x15, A64DOpcodeMSROrMRSRegister), 91 OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchImmediate), 92 OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchRegister), 93 OPCODE_GROUP_ENTRY(0x16, A64DOpcodeTestAndBranchImmediate), 94 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeUnconditionalBranchImmediate), 95 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeUnconditionalBranchRegister), 96 OPCODE_GROUP_ENTRY(0x17, A64DOpcodeTestAndBranchImmediate), 97 OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreImmediate), 98 OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreRegisterOffset), 99 OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreAuthenticated), 100 OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadAtomic), 101 OPCODE_GROUP_ENTRY(0x18, A64DOpcodeSwapAtomic), 102 OPCODE_GROUP_ENTRY(0x19, A64DOpcodeLoadStoreUnsignedImmediate), 103 OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeConditionalSelect), 104 OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeDataProcessing1Source), 105 OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeDataProcessing2Source), 106 OPCODE_GROUP_ENTRY(0x1b, A64DOpcodeDataProcessing3Source), 107 OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreImmediate), 108 OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreRegisterOffset), 109 OPCODE_GROUP_ENTRY(0x1d, A64DOpcodeLoadStoreUnsignedImmediate), 110 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointCompare), 111 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointConditionalSelect), 112 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing2Source), 113 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing1Source), 114 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingFixedPointConversions), 115 OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointIntegerConversions), 116 }; 117 118 bool A64DOpcode::s_initialized = false; 119 120 void A64DOpcode::init() 121 { 122 if (s_initialized) 123 return; 124 125 OpcodeGroup* lastGroups[32]; 126 127 for (unsigned i = 0; i < 32; i++) { 128 opcodeTable[i] = 0; 129 lastGroups[i] = 0; 130 } 131 132 for (unsigned i = 0; i < sizeof(opcodeGroupList) / sizeof(struct OpcodeGroupInitializer); i++) { 133 OpcodeGroup* newOpcodeGroup = new OpcodeGroup(opcodeGroupList[i].m_mask, opcodeGroupList[i].m_pattern, opcodeGroupList[i].m_format); 134 uint32_t opcodeGroupNumber = opcodeGroupList[i].m_opcodeGroupNumber; 135 136 if (!opcodeTable[opcodeGroupNumber]) 137 opcodeTable[opcodeGroupNumber] = newOpcodeGroup; 138 else 139 lastGroups[opcodeGroupNumber]->setNext(newOpcodeGroup); 140 lastGroups[opcodeGroupNumber] = newOpcodeGroup; 141 } 142 143 s_initialized = true; 144 } 145 146 void A64DOpcode::setPCAndOpcode(uint32_t* newPC, uint32_t newOpcode) 147 { 148 m_currentPC = newPC; 149 m_opcode = newOpcode; 150 m_bufferOffset = 0; 151 m_formatBuffer[0] = '\0'; 152 } 153 154 const char* A64DOpcode::disassemble(uint32_t* currentPC) 155 { 156 setPCAndOpcode(currentPC, *currentPC); 157 158 OpcodeGroup* opGroup = opcodeTable[opcodeGroupNumber(m_opcode)]; 159 160 while (opGroup) { 161 if (opGroup->matches(m_opcode)) 162 return opGroup->format(this); 163 opGroup = opGroup->next(); 164 } 165 166 return A64DOpcode::format(); 167 } 168 169 void A64DOpcode::bufferPrintf(const char* format, ...) 170 { 171 if (m_bufferOffset >= bufferSize) 172 return; 173 174 va_list argList; 175 va_start(argList, format); 176 177 m_bufferOffset += vsnprintf(m_formatBuffer + m_bufferOffset, bufferSize - m_bufferOffset, format, argList); 178 179 va_end(argList); 180 } 181 182 const char* A64DOpcode::format() 183 { 184 bufferPrintf(" .long %08x", m_opcode); 185 return m_formatBuffer; 186 } 187 188 void A64DOpcode::appendRegisterName(unsigned registerNumber, bool is64Bit) 189 { 190 if (registerNumber == 29) { 191 bufferPrintf(is64Bit ? "fp" : "wfp"); 192 return; 193 } 194 195 if (registerNumber == 30) { 196 bufferPrintf(is64Bit ? "lr" : "wlr"); 197 return; 198 } 199 200 bufferPrintf("%c%u", is64Bit ? 'x' : 'w', registerNumber); 201 } 202 203 void A64DOpcode::appendFPRegisterName(unsigned registerNumber, unsigned registerSize) 204 { 205 bufferPrintf("%c%u", FPRegisterPrefix(registerSize), registerNumber); 206 } 207 208 const char* const A64DOpcodeAddSubtract::s_opNames[4] = { "add", "adds", "sub", "subs" }; 209 210 const char* A64DOpcodeAddSubtractImmediate::format() 211 { 212 if (isCMP()) 213 appendInstructionName(cmpName()); 214 else { 215 if (isMovSP()) 216 appendInstructionName("mov"); 217 else 218 appendInstructionName(opName()); 219 appendSPOrRegisterName(rd(), is64Bit()); 220 appendSeparator(); 221 } 222 appendSPOrRegisterName(rn(), is64Bit()); 223 224 if (!isMovSP()) { 225 appendSeparator(); 226 appendUnsignedImmediate(immed12()); 227 if (shift()) { 228 appendSeparator(); 229 appendString(shift() == 1 ? "lsl" : "reserved"); 230 } 231 } 232 return m_formatBuffer; 233 } 234 235 const char* A64DOpcodeAddSubtractExtendedRegister::format() 236 { 237 if (immediate3() > 4) 238 return A64DOpcode::format(); 239 240 if (isCMP()) 241 appendInstructionName(cmpName()); 242 else { 243 appendInstructionName(opName()); 244 appendSPOrRegisterName(rd(), is64Bit()); 245 appendSeparator(); 246 } 247 appendSPOrRegisterName(rn(), is64Bit()); 248 appendSeparator(); 249 appendZROrRegisterName(rm(), is64Bit() && ((option() & 0x3) == 0x3)); 250 appendSeparator(); 251 if (option() == 0x2 && ((rd() == 31) || (rn() == 31))) 252 appendString("lsl"); 253 else 254 appendString(optionName()); 255 if (immediate3()) { 256 appendCharacter(' '); 257 appendUnsignedImmediate(immediate3()); 258 } 259 260 return m_formatBuffer; 261 } 262 263 const char* A64DOpcodeAddSubtractShiftedRegister::format() 264 { 265 if (!is64Bit() && immediate6() & 0x20) 266 return A64DOpcode::format(); 267 268 if (shift() == 0x3) 269 return A64DOpcode::format(); 270 271 if (isCMP()) 272 appendInstructionName(cmpName()); 273 else { 274 if (isNeg()) 275 appendInstructionName(cmpName()); 276 else 277 appendInstructionName(opName()); 278 appendSPOrRegisterName(rd(), is64Bit()); 279 appendSeparator(); 280 } 281 if (!isNeg()) { 282 appendRegisterName(rn(), is64Bit()); 283 appendSeparator(); 284 } 285 appendZROrRegisterName(rm(), is64Bit()); 286 if (immediate6()) { 287 appendSeparator(); 288 appendShiftType(shift()); 289 appendUnsignedImmediate(immediate6()); 290 } 291 292 return m_formatBuffer; 293 } 294 295 const char* const A64DOpcodeBitfield::s_opNames[3] = { "sbfm", "bfm", "ubfm" }; 296 const char* const A64DOpcodeBitfield::s_extendPseudoOpNames[3][3] = { 297 { "sxtb", "sxth", "sxtw" }, { 0, 0, 0} , { "uxtb", "uxth", "uxtw" } }; 298 const char* const A64DOpcodeBitfield::s_insertOpNames[3] = { "sbfiz", "bfi", "ubfiz" }; 299 const char* const A64DOpcodeBitfield::s_extractOpNames[3] = { "sbfx", "bfxil", "ubfx" }; 300 301 const char* A64DOpcodeBitfield::format() 302 { 303 if (opc() == 0x3) 304 return A64DOpcode::format(); 305 306 if (is64Bit() != nBit()) 307 return A64DOpcode::format(); 308 309 if (!is64Bit() && ((immediateR() & 0x20) || (immediateS() & 0x20))) 310 return A64DOpcode::format(); 311 312 if (!(opc() & 0x1) && !immediateR()) { 313 // [un]signed {btye,half-word,word} extend 314 bool isSTXType = false; 315 if (immediateS() == 7) { 316 appendInstructionName(extendPseudoOpNames(0)); 317 isSTXType = true; 318 } else if (immediateS() == 15) { 319 appendInstructionName(extendPseudoOpNames(1)); 320 isSTXType = true; 321 } else if (immediateS() == 31 && is64Bit() && !opc()) { 322 appendInstructionName(extendPseudoOpNames(2)); 323 isSTXType = true; 324 } 325 326 if (isSTXType) { 327 appendRegisterName(rd(), is64Bit()); 328 appendSeparator(); 329 appendRegisterName(rn(), false); 330 331 return m_formatBuffer; 332 } 333 } 334 335 if (!(opc() & 0x1) && ((immediateS() & 0x1f) == 0x1f) && (is64Bit() == (immediateS() >> 5))) { 336 // asr/lsr 337 appendInstructionName(!opc() ? "asr" : "lsr"); 338 339 appendRegisterName(rd(), is64Bit()); 340 appendSeparator(); 341 appendRegisterName(rn(), is64Bit()); 342 appendSeparator(); 343 appendUnsignedImmediate(immediateR()); 344 345 return m_formatBuffer; 346 } 347 348 if (opc() == 0x2 && (immediateS() + 1) == immediateR()) { 349 // lsl 350 appendInstructionName("lsl"); 351 appendRegisterName(rd(), is64Bit()); 352 appendSeparator(); 353 appendRegisterName(rn(), is64Bit()); 354 appendSeparator(); 355 appendUnsignedImmediate((is64Bit() ? 64u : 32u) - immediateR()); 356 357 return m_formatBuffer; 358 } 359 360 if (immediateS() < immediateR()) { 361 if (opc() != 1 || rn() != 0x1f) { 362 // bit field insert 363 appendInstructionName(insertOpNames()); 364 365 appendRegisterName(rd(), is64Bit()); 366 appendSeparator(); 367 appendRegisterName(rn(), is64Bit()); 368 appendSeparator(); 369 appendUnsignedImmediate((is64Bit() ? 64u : 32u) - immediateR()); 370 appendSeparator(); 371 appendUnsignedImmediate(immediateS() + 1); 372 373 return m_formatBuffer; 374 } 375 376 appendInstructionName(opName()); 377 appendRegisterName(rd(), is64Bit()); 378 appendSeparator(); 379 appendRegisterName(rn(), is64Bit()); 380 appendSeparator(); 381 appendUnsignedImmediate(immediateR()); 382 appendSeparator(); 383 appendUnsignedImmediate(immediateS()); 384 385 return m_formatBuffer; 386 } 387 388 // bit field extract 389 appendInstructionName(extractOpNames()); 390 391 appendRegisterName(rd(), is64Bit()); 392 appendSeparator(); 393 appendRegisterName(rn(), is64Bit()); 394 appendSeparator(); 395 appendUnsignedImmediate(immediateR()); 396 appendSeparator(); 397 appendUnsignedImmediate(immediateS() - immediateR() + 1); 398 399 return m_formatBuffer; 400 } 401 402 const char* A64DOpcodeCompareAndBranchImmediate::format() 403 { 404 appendInstructionName(opBit() ? "cbnz" : "cbz"); 405 appendRegisterName(rt(), is64Bit()); 406 appendSeparator(); 407 appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate19())); 408 return m_formatBuffer; 409 } 410 411 const char* A64DOpcodeConditionalBranchImmediate::format() 412 { 413 bufferPrintf(" b.%-5.5s", conditionName(condition())); 414 appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate19())); 415 return m_formatBuffer; 416 } 417 418 const char* const A64DOpcodeConditionalSelect::s_opNames[4] = { 419 "csel", "csinc", "csinv", "csneg" 420 }; 421 422 const char* A64DOpcodeConditionalSelect::format() 423 { 424 if (sBit()) 425 return A64DOpcode::format(); 426 427 if (op2() & 0x2) 428 return A64DOpcode::format(); 429 430 if (rn() == rm() && (opNum() == 1 || opNum() == 2)) { 431 if (rn() == 31) { 432 appendInstructionName((opNum() == 1) ? "cset" : "csetm"); 433 appendRegisterName(rd(), is64Bit()); 434 } else { 435 appendInstructionName((opNum() == 1) ? "cinc" : "cinv"); 436 appendRegisterName(rd(), is64Bit()); 437 appendSeparator(); 438 appendZROrRegisterName(rn(), is64Bit()); 439 } 440 appendSeparator(); 441 appendString(conditionName(condition() ^ 0x1)); 442 443 return m_formatBuffer; 444 } 445 446 appendInstructionName(opName()); 447 appendRegisterName(rd(), is64Bit()); 448 appendSeparator(); 449 appendZROrRegisterName(rn(), is64Bit()); 450 appendSeparator(); 451 appendZROrRegisterName(rm(), is64Bit()); 452 appendSeparator(); 453 appendString(conditionName(condition())); 454 455 return m_formatBuffer; 456 457 } 458 459 const char* const A64DOpcodeDataProcessing1Source::s_opNames[8] = { 460 "rbit", "rev16", "rev32", "rev", "clz", "cls", 0, 0 461 }; 462 463 const char* const A64DOpcodeDataProcessing1Source::s_pacAutOpNames[18] = { 464 "pacia", "pacib", "pacda", "pacdb", "autia", "autib", "autda", "autdb", 465 "paciza", "pacizb", "pacdza", "pacdzb", "autiza", "autizb", "autdza", "autdzb", 466 "xpaci", "xpacd" 467 }; 468 469 const char* A64DOpcodeDataProcessing1Source::format() 470 { 471 if (sBit()) 472 return A64DOpcode::format(); 473 474 if (opCode2() == 1 && is64Bit() && opCode() <= 0x1001) { 475 if (opCode() <= 0x00111 || rt() == 0x11111) { 476 appendInstructionName(s_pacAutOpNames[opCode()]); 477 appendZROrRegisterName(rd(), is64Bit()); 478 if (opCode() <= 0x00111) { 479 appendSeparator(); 480 appendZROrRegisterName(rn(), is64Bit()); 481 } 482 return m_formatBuffer; 483 } 484 return A64DOpcode::format(); 485 } 486 487 if (opCode2()) 488 return A64DOpcode::format(); 489 490 if (opCode() & 0x38) 491 return A64DOpcode::format(); 492 493 if ((opCode() & 0x3e) == 0x6) 494 return A64DOpcode::format(); 495 496 if (is64Bit() && opCode() == 0x3) 497 return A64DOpcode::format(); 498 499 if (!is64Bit() && opCode() == 0x2) 500 appendInstructionName("rev"); 501 else 502 appendInstructionName(opName()); 503 appendZROrRegisterName(rd(), is64Bit()); 504 appendSeparator(); 505 appendZROrRegisterName(rn(), is64Bit()); 506 507 return m_formatBuffer; 508 } 509 510 const char* const A64DOpcodeDataProcessing2Source::s_opNames[16] = { 511 // We use the pseudo-op names for the shift/rotate instructions 512 0, 0, "udiv", "sdiv", 0, 0, 0, 0, 513 "lsl", "lsr", "asr", "ror", 0, "pacga", 0, 0 514 }; 515 516 const char* A64DOpcodeDataProcessing2Source::format() 517 { 518 if (sBit()) 519 return A64DOpcode::format(); 520 521 if (!(opCode() & 0x3e)) 522 return A64DOpcode::format(); 523 524 if (opCode() & 0x30) 525 return A64DOpcode::format(); 526 527 if ((opCode() & 0x3c) == 0x4) 528 return A64DOpcode::format(); 529 530 const char* opcodeName = opName(); 531 if (!opcodeName) 532 return A64DOpcode::format(); 533 534 appendInstructionName(opcodeName); 535 appendZROrRegisterName(rd(), is64Bit()); 536 appendSeparator(); 537 appendZROrRegisterName(rn(), is64Bit()); 538 appendSeparator(); 539 appendZROrRegisterName(rm(), is64Bit()); 540 541 return m_formatBuffer; 542 } 543 544 const char* const A64DOpcodeDataProcessing3Source::s_opNames[16] = { 545 "madd", "msub", "smaddl", "smsubl", "smulh", 0, 0, 0, 546 0, 0, "umaddl", "umsubl", "umulh", 0, 0, 0 547 }; 548 549 const char* const A64DOpcodeDataProcessing3Source::s_pseudoOpNames[16] = { 550 "mul", "mneg", "smull", "smnegl", "smulh", 0, 0, 0, 551 0, 0, "umull", "umnegl", "umulh", 0, 0, 0 552 }; 553 554 const char* A64DOpcodeDataProcessing3Source::format() 555 { 556 if (op54()) 557 return A64DOpcode::format(); 558 559 if (opNum() > 12) 560 return A64DOpcode::format(); 561 562 if (!is64Bit() && opNum() > 1) 563 return A64DOpcode::format(); 564 565 if (!opName()) 566 return A64DOpcode::format(); 567 568 if ((opNum() & 0x4) && (ra() != 31)) 569 return A64DOpcode::format(); 570 571 appendInstructionName(opName()); 572 appendZROrRegisterName(rd(), is64Bit()); 573 appendSeparator(); 574 bool srcOneAndTwoAre64Bit = is64Bit() & !(opNum() & 0x2); 575 appendZROrRegisterName(rn(), srcOneAndTwoAre64Bit); 576 appendSeparator(); 577 appendZROrRegisterName(rm(), srcOneAndTwoAre64Bit); 578 579 if (ra() != 31) { 580 appendSeparator(); 581 appendRegisterName(ra(), is64Bit()); 582 } 583 584 return m_formatBuffer; 585 } 586 587 const char* A64OpcodeExceptionGeneration::format() 588 { 589 const char* opname = 0; 590 if (!op2()) { 591 switch (opc()) { 592 case 0x0: // SVC, HVC & SMC 593 switch (ll()) { 594 case 0x1: 595 opname = "svc"; 596 break; 597 case 0x2: 598 opname = "hvc"; 599 break; 600 case 0x3: 601 opname = "smc"; 602 break; 603 } 604 break; 605 case 0x1: // BRK 606 if (!ll()) 607 opname = "brk"; 608 break; 609 case 0x2: // HLT 610 if (!ll()) 611 opname = "hlt"; 612 break; 613 case 0x5: // DPCS1-3 614 switch (ll()) { 615 case 0x1: 616 opname = "dpcs1"; 617 break; 618 case 0x2: 619 opname = "dpcs2"; 620 break; 621 case 0x3: 622 opname = "dpcs3"; 623 break; 624 } 625 break; 626 } 627 } 628 629 if (!opname) 630 return A64DOpcode::format(); 631 632 appendInstructionName(opname); 633 appendUnsignedImmediate(immediate16()); 634 return m_formatBuffer; 635 } 636 637 const char* A64DOpcodeExtract::format() 638 { 639 if (op21() || o0Bit()) 640 return A64DOpcode::format(); 641 642 if (is64Bit() != nBit()) 643 return A64DOpcode::format(); 644 645 if (!is64Bit() && (immediateS() & 0x20)) 646 return A64DOpcode::format(); 647 648 bool isROR = rn() == rm(); 649 const char* opName = (isROR) ? "ror" : "extr"; 650 651 appendInstructionName(opName); 652 appendZROrRegisterName(rd(), is64Bit()); 653 appendSeparator(); 654 appendZROrRegisterName(rn(), is64Bit()); 655 if (!isROR) { 656 appendSeparator(); 657 appendZROrRegisterName(rm(), is64Bit()); 658 } 659 appendSeparator(); 660 appendUnsignedImmediate(immediateS()); 661 662 return m_formatBuffer; 663 } 664 665 const char* A64DOpcodeFloatingPointCompare::format() 666 { 667 if (mBit()) 668 return A64DOpcode::format(); 669 670 if (sBit()) 671 return A64DOpcode::format(); 672 673 if (type() & 0x2) 674 return A64DOpcode::format(); 675 676 if (op()) 677 return A64DOpcode::format(); 678 679 if (opCode2() & 0x7) 680 return A64DOpcode::format(); 681 682 appendInstructionName(opName()); 683 unsigned registerSize = type() + 2; 684 appendFPRegisterName(rn(), registerSize); 685 appendSeparator(); 686 if (opCode2() & 0x8) 687 bufferPrintf("#0.0"); 688 else 689 appendFPRegisterName(rm(), registerSize); 690 691 return m_formatBuffer; 692 } 693 694 const char* A64DOpcodeFloatingPointConditionalSelect::format() 695 { 696 if (mBit()) 697 return A64DOpcode::format(); 698 699 if (sBit()) 700 return A64DOpcode::format(); 701 702 if (type() & 0x2) 703 return A64DOpcode::format(); 704 705 appendInstructionName(opName()); 706 unsigned registerSize = type() + 2; 707 appendFPRegisterName(rd(), registerSize); 708 appendSeparator(); 709 appendFPRegisterName(rn(), registerSize); 710 appendSeparator(); 711 appendFPRegisterName(rm(), registerSize); 712 appendSeparator(); 713 appendString(conditionName(condition())); 714 715 return m_formatBuffer; 716 } 717 718 const char* const A64DOpcodeFloatingPointDataProcessing1Source::s_opNames[16] = { 719 "fmov", "fabs", "fneg", "fsqrt", "fcvt", "fcvt", 0, "fcvt", 720 "frintn", "frintp", "frintm", "frintz", "frinta", 0, "frintx", "frinti" 721 }; 722 723 const char* A64DOpcodeFloatingPointDataProcessing1Source::format() 724 { 725 if (mBit()) 726 return A64DOpcode::format(); 727 728 if (sBit()) 729 return A64DOpcode::format(); 730 731 if (opNum() > 16) 732 return A64DOpcode::format(); 733 734 switch (type()) { 735 case 0: 736 if ((opNum() == 0x4) || (opNum() == 0x6) || (opNum() == 0xd)) 737 return A64DOpcode::format(); 738 break; 739 case 1: 740 if ((opNum() == 0x5) || (opNum() == 0x6) || (opNum() == 0xd)) 741 return A64DOpcode::format(); 742 break; 743 case 2: 744 return A64DOpcode::format(); 745 case 3: 746 if ((opNum() < 0x4) || (opNum() > 0x5)) 747 return A64DOpcode::format(); 748 break; 749 } 750 751 appendInstructionName(opName()); 752 if ((opNum() >= 0x4) && (opNum() <= 0x7)) { 753 unsigned srcRegisterSize = type() ^ 0x2; // 0:s, 1:d & 3:h 754 unsigned destRegisterSize = (opNum() & 0x3) ^ 0x2; 755 appendFPRegisterName(rd(), destRegisterSize); 756 appendSeparator(); 757 appendFPRegisterName(rn(), srcRegisterSize); 758 } else { 759 unsigned registerSize = type() + 2; 760 appendFPRegisterName(rd(), registerSize); 761 appendSeparator(); 762 appendFPRegisterName(rn(), registerSize); 763 } 764 765 return m_formatBuffer; 766 } 767 768 const char* const A64DOpcodeFloatingPointDataProcessing2Source::s_opNames[16] = { 769 "fmul", "fdiv", "fadd", "fsub", "fmax", "fmin", "fmaxnm", "fminnm", "fnmul" 770 }; 771 772 const char* A64DOpcodeFloatingPointDataProcessing2Source::format() 773 { 774 if (mBit()) 775 return A64DOpcode::format(); 776 777 if (sBit()) 778 return A64DOpcode::format(); 779 780 if (type() & 0x2) 781 return A64DOpcode::format(); 782 783 if (opNum() > 8) 784 return A64DOpcode::format(); 785 786 appendInstructionName(opName()); 787 unsigned registerSize = type() + 2; 788 appendFPRegisterName(rd(), registerSize); 789 appendSeparator(); 790 appendFPRegisterName(rn(), registerSize); 791 appendSeparator(); 792 appendFPRegisterName(rm(), registerSize); 793 794 return m_formatBuffer; 795 } 796 797 const char* const A64DOpcodeFloatingFixedPointConversions::s_opNames[4] = { 798 "fcvtzs", "fcvtzu", "scvtf", "ucvtf" 799 }; 800 801 const char* A64DOpcodeFloatingFixedPointConversions::format() 802 { 803 if (sBit()) 804 return A64DOpcode::format(); 805 806 if (type() & 0x2) 807 return A64DOpcode::format(); 808 809 if (opcode() & 0x4) 810 return A64DOpcode::format(); 811 812 if (!(rmode() & 0x1) && !(opcode() & 0x6)) 813 return A64DOpcode::format(); 814 815 if ((rmode() & 0x1) && (opcode() & 0x6) == 0x2) 816 return A64DOpcode::format(); 817 818 if (!(rmode() & 0x2) && !(opcode() & 0x6)) 819 return A64DOpcode::format(); 820 821 if ((rmode() & 0x2) && (opcode() & 0x6) == 0x2) 822 return A64DOpcode::format(); 823 824 if (!is64Bit() && scale() >= 32) 825 return A64DOpcode::format(); 826 827 appendInstructionName(opName()); 828 unsigned FPRegisterSize = type() + 2; 829 bool destIsFP = !rmode(); 830 831 if (destIsFP) { 832 appendFPRegisterName(rd(), FPRegisterSize); 833 appendSeparator(); 834 appendRegisterName(rn(), is64Bit()); 835 } else { 836 appendRegisterName(rd(), is64Bit()); 837 appendSeparator(); 838 appendFPRegisterName(rn(), FPRegisterSize); 839 } 840 appendSeparator(); 841 appendUnsignedImmediate(64 - scale()); 842 843 return m_formatBuffer; 844 } 845 846 const char* const A64DOpcodeFloatingPointIntegerConversions::s_opNames[32] = { 847 "fcvtns", "fcvtnu", "scvtf", "ucvtf", "fcvtas", "fcvtau", "fmov", "fmov", 848 "fcvtps", "fcvtpu", 0, 0, 0, 0, "fmov", "fmov", 849 "fcvtms", "fcvtmu", 0, 0, 0, 0, 0, 0, 850 "fcvtzs", "fcvtzu", 0, 0, 0, 0, "fjcvtzs", 0 851 }; 852 853 const char* A64DOpcodeFloatingPointIntegerConversions::format() 854 { 855 if (sBit()) 856 return A64DOpcode::format(); 857 858 if (type() == 0x3) 859 return A64DOpcode::format(); 860 861 if (((rmode() & 0x1) || (rmode() & 0x2)) && (((opcode() & 0x6) == 0x2) || ((opcode() & 0x6) == 0x4))) 862 return A64DOpcode::format(); 863 864 if ((type() == 0x2) && (!(opcode() & 0x4) || ((opcode() & 0x6) == 0x4))) 865 return A64DOpcode::format(); 866 867 if (!type() && (rmode() & 0x1) && ((opcode() & 0x6) == 0x6)) 868 return A64DOpcode::format(); 869 870 if (is64Bit() && type() == 0x2 && ((opNum() & 0xe) == 0x6)) 871 return A64DOpcode::format(); 872 873 if (!opName()) 874 return A64DOpcode::format(); 875 876 if ((opNum() & 0x1e) == 0xe) { 877 // Handle fmov to/from upper half of quad separately 878 if (!is64Bit() || (type() != 0x2)) 879 return A64DOpcode::format(); 880 881 appendInstructionName(opName()); 882 if (opcode() & 0x1) { 883 // fmov Vd.D[1], Xn 884 bufferPrintf("V%u.D[1]", rd()); 885 appendSeparator(); 886 appendZROrRegisterName(rn()); 887 } else { 888 // fmov Xd, Vn.D[1] 889 appendZROrRegisterName(rd()); 890 appendSeparator(); 891 bufferPrintf("V%u.D[1]", rn()); 892 } 893 894 return m_formatBuffer; 895 } 896 897 appendInstructionName(opName()); 898 unsigned FPRegisterSize = type() + 2; 899 bool destIsFP = ((opNum() == 2) || (opNum() == 3) || (opNum() == 7)); 900 901 if (destIsFP) { 902 appendFPRegisterName(rd(), FPRegisterSize); 903 appendSeparator(); 904 appendZROrRegisterName(rn(), is64Bit()); 905 } else { 906 appendZROrRegisterName(rd(), is64Bit()); 907 appendSeparator(); 908 appendFPRegisterName(rn(), FPRegisterSize); 909 } 910 911 return m_formatBuffer; 912 } 913 914 const char* A64DOpcodeMSRImmediate::format() 915 { 916 const char* pstateField = nullptr; 917 918 if (!op1() && (op2() == 0x5)) 919 pstateField = "spsel"; 920 921 if ((op1() == 0x3) && (op2() == 0x6)) 922 pstateField = "daifset"; 923 924 if ((op1() == 0x3) && (op2() == 0x7)) 925 pstateField = "daifclr"; 926 927 if (!!op1() && !(op2() & 0x4)) 928 return A64DOpcode::format(); 929 930 if (!pstateField) 931 return A64DOpcode::format(); 932 933 appendInstructionName("msr"); 934 appendString(pstateField); 935 appendSeparator(); 936 appendUnsignedImmediate(crM()); 937 938 return m_formatBuffer; 939 } 940 941 const char* A64DOpcodeMSROrMRSRegister::format() 942 { 943 appendInstructionName(opName()); 944 945 if (lBit()) { 946 appendZROrRegisterName(rt()); 947 appendSeparator(); 948 } 949 950 bufferPrintf("S%u_%u_C%u_C%u_%u", op0(), op1(), crN(), crM(), op2()); 951 952 if (!lBit()) { 953 appendSeparator(); 954 appendZROrRegisterName(rt()); 955 } 956 957 const char* systemRegisterName = nullptr; 958 959 switch (systemRegister()) { 960 case 0b1101100000000001: 961 systemRegisterName = "ctr_el0"; 962 break; 963 case 0b1101101000010000: 964 systemRegisterName = "nzcv"; 965 break; 966 case 0b1101101000010001: 967 systemRegisterName = "daif"; 968 break; 969 case 0b1101101000100000: 970 systemRegisterName = "fpcr"; 971 break; 972 case 0b1101101000100001: 973 systemRegisterName = "fpsr"; 974 break; 975 case 0b1101111010000010: 976 systemRegisterName = "tpidr_el0"; 977 break; 978 case 0b1101111010000011: 979 systemRegisterName = "tpidrr0_el0"; 980 break; 981 } 982 983 if (systemRegisterName) { 984 appendString(" ; "); 985 appendString(systemRegisterName); 986 } 987 return m_formatBuffer; 988 } 989 990 const char* const A64DOpcodeHint::s_opNames[32] = { 991 "nop", "yield", "wfe", "wfi", "sev", "sevl", 0, "xpaclri", 992 "pacia1716", 0, "pacib1716", 0, "autia1716", 0, "autib1716", 0, 993 0, 0, 0, 0, 0, 0, 0, 0, 994 "paciaz", "paciasp", "pacibz", "pacibsp", "autiaz", "autiasp", "autibz", "autibsp" 995 }; 996 997 const char* A64DOpcodeHint::format() 998 { 999 appendInstructionName(opName()); 1000 1001 if (immediate7() >= 32 || !s_opNames[immediate7()]) 1002 appendUnsignedImmediate(immediate7()); 1003 1004 return m_formatBuffer; 1005 } 1006 1007 const char* A64DOpcodeHint::opName() 1008 { 1009 const char* opName = (immediate7() < 32 ? s_opNames[immediate7()] : 0); 1010 if (!opName) 1011 return "hint"; 1012 1013 return opName; 1014 } 1015 1016 const char* const A64DOpcodeSystemSync::s_opNames[8] = { 1017 0, 0, "clrex", 0, "dsb", "dmb", "isb", 0 1018 }; 1019 1020 const char* const A64DOpcodeSystemSync::s_optionNames[16] = { 1021 0, "oshld", "oshst", "osh", 0, "nshld", "nshst", "nsh", 1022 0, "ishld", "ishst", "ish", 0, "ld", "st", "sy" 1023 }; 1024 1025 const char* A64DOpcodeSystemSync::format() 1026 { 1027 const char* thisOpName = opName(); 1028 1029 if (!thisOpName) 1030 return A64DOpcode::format(); 1031 1032 appendInstructionName(thisOpName); 1033 1034 if (op2() & 0x2) { 1035 if (crM() != 0xf) { 1036 appendCharacter('#'); 1037 appendUnsignedImmediate(crM()); 1038 } 1039 } else { 1040 const char* thisOption = option(); 1041 if (thisOption) 1042 appendString(thisOption); 1043 else 1044 appendUnsignedImmediate(crM()); 1045 } 1046 1047 return m_formatBuffer; 1048 } 1049 1050 const char* const A64DOpcodeLoadStoreExclusive::s_opNames[64] = { 1051 "stxrb", "stlxrb", 0, 0, "ldxrb", "ldaxrb", 0, 0, 1052 0, "stlrb", 0, 0, 0, "ldarb", 0, 0, 1053 "stxrh", "stlxrh", 0, 0, "ldxrh", "ldaxrh", 0, 0, 1054 0, "stlrh", 0, 0, 0, "ldarh", 0, 0, 1055 "stxr", "stlxr", "stxp", "stlxp", "ldxr", "ldaxr", "ldxp", "ldaxp", 1056 0, "stlr", 0, 0, 0, "ldar", 0, 0, 1057 "stxr", "stlxr", "stxp", "stlxp", "ldxr", "ldaxr", "ldxp", "ldaxp", 1058 0, "stlr", 0, 0, 0, "ldar", 0, 0 1059 }; 1060 1061 const char* A64DOpcodeLoadStoreExclusive::format() 1062 { 1063 if (o2() && !o1() && !o0()) 1064 return A64DOpcode::format(); 1065 1066 if (o2() && o1()) 1067 return A64DOpcode::format(); 1068 1069 if ((size() < 2) && o1()) 1070 return A64DOpcode::format(); 1071 1072 if (loadBit() && (rs() != 0x1f)) 1073 return A64DOpcode::format(); 1074 1075 if (!isPairOp() && (rt2() != 0x1f)) 1076 return A64DOpcode::format(); 1077 1078 const char* thisOpName = opName(); 1079 1080 if (!thisOpName) 1081 return A64DOpcode::format(); 1082 1083 appendInstructionName(thisOpName); 1084 1085 if (!loadBit()) { 1086 appendZROrRegisterName(rs(), size() == 0x3); 1087 appendSeparator(); 1088 } 1089 1090 appendZROrRegisterName(rt(), size() == 0x3); 1091 appendSeparator(); 1092 if (isPairOp()) { 1093 appendZROrRegisterName(rt2(), size() == 0x3); 1094 appendSeparator(); 1095 } 1096 appendCharacter('['); 1097 appendSPOrRegisterName(rn()); 1098 appendCharacter(']'); 1099 1100 return m_formatBuffer; 1101 } 1102 1103 // A zero in an entry of the table means the instruction is Unallocated 1104 const char* const A64DOpcodeLoadStore::s_opNames[32] = { 1105 "strb", "ldrb", "ldrsb", "ldrsb", "str", "ldr", "str", "ldr", 1106 "strh", "ldrh", "ldrsh", "ldrsh", "str", "ldr", 0, 0, 1107 "str", "ldr", "ldrsw", 0, "str", "ldr", 0, 0, 1108 "str", "ldr", 0, 0, "str", "ldr", 0, 0 1109 }; 1110 1111 // A zero in an entry of the table means the instruction is Unallocated 1112 const char* const A64DOpcodeLoadStoreImmediate::s_unprivilegedOpNames[32] = { 1113 "sttrb", "ldtrb", "ldtrsb", "ldtrsb", 0, 0, 0, 0, 1114 "sttrh", "ldtrh", "ldtrsh", "ldtrsh", 0, 0, 0, 0, 1115 "sttr", "ldtr", "ldtrsw", 0, 0, 0, 0, 0, 1116 "sttr", "ldtr", 0, 0, 0, 0, 0, 0 1117 }; 1118 1119 // A zero in an entry of the table means the instruction is Unallocated 1120 const char* const A64DOpcodeLoadStoreImmediate::s_unscaledOpNames[32] = { 1121 "sturb", "ldurb", "ldursb", "ldursb", "stur", "ldur", "stur", "ldur", 1122 "sturh", "ldurh", "ldursh", "ldursh", "stur", "ldur", 0, 0, 1123 "stur", "ldur", "ldursw", 0, "stur", "ldur", 0, 0, 1124 "stur", "ldur", "prfum", 0, "stur", "ldur", 0, 0 1125 }; 1126 1127 const char* A64DOpcodeLoadStoreImmediate::format() 1128 { 1129 const char* thisOpName; 1130 1131 if (type() & 0x1) 1132 thisOpName = opName(); 1133 else if (!type()) 1134 thisOpName = unscaledOpName(); 1135 else 1136 thisOpName = unprivilegedOpName(); 1137 1138 if (!thisOpName) 1139 return A64DOpcode::format(); 1140 1141 appendInstructionName(thisOpName); 1142 if (vBit()) 1143 appendFPRegisterName(rt(), size()); 1144 else if (!opc()) 1145 appendZROrRegisterName(rt(), is64BitRT()); 1146 else 1147 appendRegisterName(rt(), is64BitRT()); 1148 appendSeparator(); 1149 appendCharacter('['); 1150 appendSPOrRegisterName(rn()); 1151 1152 switch (type()) { 1153 case 0: // Unscaled Immediate 1154 if (immediate9()) { 1155 appendSeparator(); 1156 appendSignedImmediate(immediate9()); 1157 } 1158 appendCharacter(']'); 1159 break; 1160 case 1: // Immediate Post-Indexed 1161 appendCharacter(']'); 1162 if (immediate9()) { 1163 appendSeparator(); 1164 appendSignedImmediate(immediate9()); 1165 } 1166 break; 1167 case 2: // Unprivileged 1168 if (immediate9()) { 1169 appendSeparator(); 1170 appendSignedImmediate(immediate9()); 1171 } 1172 appendCharacter(']'); 1173 break; 1174 case 3: // Immediate Pre-Indexed 1175 if (immediate9()) { 1176 appendSeparator(); 1177 appendSignedImmediate(immediate9()); 1178 } 1179 appendCharacter(']'); 1180 appendCharacter('!'); 1181 break; 1182 } 1183 1184 return m_formatBuffer; 1185 } 1186 1187 const char* A64DOpcodeLoadStoreRegisterOffset::format() 1188 { 1189 const char* thisOpName = opName(); 1190 1191 if (!thisOpName) 1192 return A64DOpcode::format(); 1193 1194 if (!(option() & 0x2)) 1195 return A64DOpcode::format(); 1196 1197 appendInstructionName(thisOpName); 1198 unsigned scale; 1199 if (vBit()) { 1200 appendFPRegisterName(rt(), size()); 1201 scale = ((opc() & 2)<<1) | size(); 1202 } else { 1203 if (!opc()) 1204 appendZROrRegisterName(rt(), is64BitRT()); 1205 else 1206 appendRegisterName(rt(), is64BitRT()); 1207 scale = size(); 1208 } 1209 appendSeparator(); 1210 appendCharacter('['); 1211 appendSPOrRegisterName(rn()); 1212 if (rm() != 31) { 1213 appendSeparator(); 1214 appendRegisterName(rm(), (option() & 0x3) == 0x3); 1215 1216 unsigned shift = sBit() ? scale : 0; 1217 1218 if (option() == 0x3) { 1219 if (shift) { 1220 appendSeparator(); 1221 appendString("lsl "); 1222 appendUnsignedImmediate(shift); 1223 } 1224 } else { 1225 appendSeparator(); 1226 appendString(optionName()); 1227 if (shift) 1228 appendUnsignedImmediate(shift); 1229 } 1230 } 1231 1232 appendCharacter(']'); 1233 1234 return m_formatBuffer; 1235 } 1236 1237 const char* const A64DOpcodeLoadStoreAuthenticated::s_opNames[2] = { 1238 "ldraa", "ldrab" 1239 }; 1240 1241 const char* A64DOpcodeLoadStoreAuthenticated::format() 1242 { 1243 appendInstructionName(opName()); 1244 appendRegisterName(rt()); 1245 appendSeparator(); 1246 appendCharacter('['); 1247 appendSPOrRegisterName(rn()); 1248 1249 if (wBit() || immediate10()) { 1250 appendSeparator(); 1251 appendSignedImmediate(immediate10() << size()); 1252 } 1253 appendCharacter(']'); 1254 1255 if (wBit()) 1256 appendCharacter('!'); 1257 1258 return m_formatBuffer; 1259 } 1260 1261 const char* const A64DOpcodeLoadAtomic::s_opNames[64] = { 1262 "ldaddb", "ldaddlb", "ldaddab", "ldaddalb", 1263 "ldaddh", "ldaddlh", "ldaddah", "ldaddalh", 1264 "ldadd", "ldaddl", "ldadda", "ldaddal", 1265 "ldadd", "ldaddl", "ldadda", "ldaddal", 1266 1267 "ldclrb", "ldclrlb", "ldclrab", "ldclralb", 1268 "ldclrh", "ldclrlh", "ldclrah", "ldclralh", 1269 "ldclr", "ldclrl", "ldclra", "ldclral", 1270 "ldclr", "ldclrl", "ldclra", "ldclral", 1271 1272 "ldeorb", "ldeorlb", "ldeorab", "ldeoralb", 1273 "ldeorh", "ldeorlh", "ldeorah", "ldeoralh", 1274 "ldeor", "ldeorl", "ldeora", "ldeoral", 1275 "ldeor", "ldeorl", "ldeora", "ldeoral", 1276 1277 "ldsetb", "ldsetlb", "ldsetab", "ldsetalb", 1278 "ldseth", "ldsetlh", "ldsetah", "ldsetalh", 1279 "ldset", "ldsetl", "ldseta", "ldsetal", 1280 "ldset", "ldsetl", "ldseta", "ldsetal", 1281 }; 1282 1283 const char* A64DOpcodeLoadAtomic::format() 1284 { 1285 const auto* name = opName(); 1286 if (!name) 1287 return A64DOpcode::format(); 1288 appendInstructionName(name); 1289 appendSPOrRegisterName(rs(), is64Bit()); 1290 appendSeparator(); 1291 appendSPOrRegisterName(rt(), is64Bit()); 1292 appendSeparator(); 1293 appendCharacter('['); 1294 appendSPOrRegisterName(rn(), is64Bit()); 1295 appendCharacter(']'); 1296 return m_formatBuffer; 1297 } 1298 1299 const char* const A64DOpcodeSwapAtomic::s_opNames[16] = { 1300 "swpb", "swplb", "swpab", "swpalb", 1301 "swph", "swplh", "swpah", "swpalh", 1302 "swp", "swpl", "swpa", "swpal", 1303 "swp", "swpl", "swpa", "swpal", 1304 }; 1305 1306 const char* A64DOpcodeSwapAtomic::format() 1307 { 1308 const auto* name = opName(); 1309 appendInstructionName(name); 1310 appendSPOrRegisterName(rs(), is64Bit()); 1311 appendSeparator(); 1312 appendSPOrRegisterName(rt(), is64Bit()); 1313 appendSeparator(); 1314 appendCharacter('['); 1315 appendSPOrRegisterName(rn(), is64Bit()); 1316 appendCharacter(']'); 1317 return m_formatBuffer; 1318 } 1319 1320 const char* const A64DOpcodeCAS::s_opNames[16] = { 1321 "casb", "caslb", "casab", "casalb", 1322 "cash", "caslh", "casah", "casalh", 1323 "cas", "casl", "casa", "casal", 1324 "cas", "casl", "casa", "casal", 1325 }; 1326 1327 const char* A64DOpcodeCAS::format() 1328 { 1329 const auto* name = opName(); 1330 appendInstructionName(name); 1331 appendSPOrRegisterName(rs(), is64Bit()); 1332 appendSeparator(); 1333 appendSPOrRegisterName(rt(), is64Bit()); 1334 appendSeparator(); 1335 appendCharacter('['); 1336 appendSPOrRegisterName(rn(), is64Bit()); 1337 appendCharacter(']'); 1338 return m_formatBuffer; 1339 } 1340 1341 const char* A64DOpcodeLoadStoreRegisterPair::opName() 1342 { 1343 if (!vBit() && lBit() && size() == 0x1) 1344 return "ldpsw"; 1345 if (lBit()) 1346 return "ldp"; 1347 return "stp"; 1348 } 1349 1350 const char* A64DOpcodeLoadStoreRegisterPair::format() 1351 { 1352 const char* thisOpName = opName(); 1353 1354 if (size() == 0x3) 1355 return A64DOpcode::format(); 1356 1357 if ((offsetMode() < 0x1) || (offsetMode() > 0x3)) 1358 return A64DOpcode::format(); 1359 1360 if ((offsetMode() == 0x1) && !vBit() && !lBit()) 1361 return A64DOpcode::format(); 1362 1363 appendInstructionName(thisOpName); 1364 unsigned offsetShift; 1365 if (vBit()) { 1366 appendFPRegisterName(rt(), size()); 1367 appendSeparator(); 1368 appendFPRegisterName(rt2(), size()); 1369 offsetShift = size() + 2; 1370 } else { 1371 if (!lBit()) 1372 appendZROrRegisterName(rt(), is64Bit()); 1373 else 1374 appendRegisterName(rt(), is64Bit()); 1375 appendSeparator(); 1376 if (!lBit()) 1377 appendZROrRegisterName(rt2(), is64Bit()); 1378 else 1379 appendRegisterName(rt2(), is64Bit()); 1380 offsetShift = (size() >> 1) + 2; 1381 } 1382 1383 appendSeparator(); 1384 appendCharacter('['); 1385 appendSPOrRegisterName(rn()); 1386 1387 int offset = immediate7() << offsetShift; 1388 1389 if (offsetMode() == 1) { 1390 appendCharacter(']'); 1391 appendSeparator(); 1392 appendSignedImmediate(offset); 1393 } else { 1394 appendSeparator(); 1395 appendSignedImmediate(offset); 1396 appendCharacter(']'); 1397 if (offsetMode() == 0x3) 1398 appendCharacter('!'); 1399 } 1400 1401 return m_formatBuffer; 1402 } 1403 1404 const char* A64DOpcodeLoadStoreUnsignedImmediate::format() 1405 { 1406 const char* thisOpName = opName(); 1407 1408 if (!thisOpName) 1409 return A64DOpcode::format(); 1410 1411 appendInstructionName(thisOpName); 1412 unsigned scale; 1413 if (vBit()) { 1414 appendFPRegisterName(rt(), size()); 1415 scale = ((opc() & 2)<<1) | size(); 1416 } else { 1417 if (!opc()) 1418 appendZROrRegisterName(rt(), is64BitRT()); 1419 else 1420 appendRegisterName(rt(), is64BitRT()); 1421 scale = size(); 1422 } 1423 appendSeparator(); 1424 appendCharacter('['); 1425 appendSPOrRegisterName(rn()); 1426 1427 if (immediate12()) { 1428 appendSeparator(); 1429 appendUnsignedImmediate(immediate12() << scale); 1430 } 1431 1432 appendCharacter(']'); 1433 1434 return m_formatBuffer; 1435 } 1436 1437 // A zero in an entry of the table means the instruction is Unallocated 1438 const char* const A64DOpcodeLogical::s_opNames[8] = { 1439 "and", "bic", "orr", "orn", "eor", "eon", "ands", "bics" 1440 }; 1441 1442 const char* A64DOpcodeLogicalShiftedRegister::format() 1443 { 1444 if (!is64Bit() && immediate6() & 0x20) 1445 return A64DOpcode::format(); 1446 1447 if (isTst()) 1448 appendInstructionName("tst"); 1449 else { 1450 if (isMov()) 1451 appendInstructionName(nBit() ? "mvn" : "mov"); 1452 else 1453 appendInstructionName(opName(opNumber())); 1454 appendZROrRegisterName(rd(), is64Bit()); 1455 appendSeparator(); 1456 } 1457 1458 if (!isMov()) { 1459 appendZROrRegisterName(rn(), is64Bit()); 1460 appendSeparator(); 1461 } 1462 1463 appendZROrRegisterName(rm(), is64Bit()); 1464 if (immediate6()) { 1465 appendSeparator(); 1466 appendShiftType(shift()); 1467 appendUnsignedImmediate(immediate6()); 1468 } 1469 1470 return m_formatBuffer; 1471 } 1472 1473 static unsigned highestBitSet(unsigned value) 1474 { 1475 unsigned result = 0; 1476 1477 while (value >>= 1) 1478 result++; 1479 1480 return result; 1481 } 1482 1483 static uint64_t rotateRight(uint64_t value, unsigned width, unsigned shift) 1484 { 1485 uint64_t result = value; 1486 1487 if (shift) 1488 result = (value >> (shift % width)) | (value << (width - shift)); 1489 1490 return result; 1491 } 1492 1493 static uint64_t replicate(uint64_t value, unsigned width) 1494 { 1495 uint64_t result = 0; 1496 1497 for (unsigned totalBits = 0; totalBits < 64; totalBits += width) 1498 result = (result << width) | value; 1499 1500 return result; 1501 } 1502 1503 const char* A64DOpcodeLogicalImmediate::format() 1504 { 1505 if (!is64Bit() && nBit()) 1506 return A64DOpcode::format(); 1507 1508 unsigned len = highestBitSet(nBit() << 6 | (immediateS() ^ 0x3f)); 1509 unsigned levels = (1 << len) - 1; // len number of 1 bits starting at LSB 1510 1511 if ((immediateS() & levels) == levels) 1512 return A64DOpcode::format(); 1513 1514 unsigned r = immediateR() & levels; 1515 unsigned s = immediateS() & levels; 1516 unsigned eSize = 1 << len; 1517 uint64_t pattern = rotateRight((1ull << (s + 1)) - 1, eSize, r); 1518 1519 uint64_t immediate = replicate(pattern, eSize); 1520 1521 if (!is64Bit()) 1522 immediate &= 0xffffffffull; 1523 1524 if (isTst()) 1525 appendInstructionName("tst"); 1526 else { 1527 if (isMov()) 1528 appendInstructionName("mov"); 1529 else 1530 appendInstructionName(opName(opNumber())); 1531 appendRegisterName(rd(), is64Bit()); 1532 appendSeparator(); 1533 } 1534 if (!isMov()) { 1535 appendRegisterName(rn(), is64Bit()); 1536 appendSeparator(); 1537 } 1538 appendUnsignedImmediate64(immediate); 1539 1540 return m_formatBuffer; 1541 } 1542 1543 const char* const A64DOpcodeMoveWide::s_opNames[4] = { "movn", 0, "movz", "movk" }; 1544 1545 const char* A64DOpcodeMoveWide::format() 1546 { 1547 if (opc() == 1) 1548 return A64DOpcode::format(); 1549 if (!is64Bit() && hw() >= 2) 1550 return A64DOpcode::format(); 1551 1552 if (!opc() && (!immediate16() || !hw()) && (is64Bit() || immediate16() != 0xffff)) { 1553 // MOV pseudo op for MOVN 1554 appendInstructionName("mov"); 1555 appendRegisterName(rd(), is64Bit()); 1556 appendSeparator(); 1557 1558 if (is64Bit()) { 1559 int64_t amount = immediate16() << (hw() * 16); 1560 amount = ~amount; 1561 appendSignedImmediate64(amount); 1562 } else { 1563 int32_t amount = immediate16() << (hw() * 16); 1564 amount = ~amount; 1565 appendSignedImmediate(amount); 1566 } 1567 } else { 1568 appendInstructionName(opName()); 1569 appendRegisterName(rd(), is64Bit()); 1570 appendSeparator(); 1571 appendUnsignedHexImmediate(immediate16()); 1572 if (hw()) { 1573 appendSeparator(); 1574 appendShiftAmount(hw()); 1575 } 1576 } 1577 1578 return m_formatBuffer; 1579 } 1580 1581 const char* A64DOpcodeTestAndBranchImmediate::format() 1582 { 1583 appendInstructionName(opBit() ? "tbnz" : "tbz"); 1584 appendRegisterName(rt()); 1585 appendSeparator(); 1586 appendUnsignedImmediate(bitNumber()); 1587 appendSeparator(); 1588 appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate14())); 1589 return m_formatBuffer; 1590 } 1591 1592 const char* A64DOpcodeUnconditionalBranchImmediate::format() 1593 { 1594 appendInstructionName(op() ? "bl" : "b"); 1595 appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate26())); 1596 return m_formatBuffer; 1597 } 1598 1599 const char* const A64DOpcodeUnconditionalBranchRegister::s_opNames[8] = { "br", "blr", "ret", "", "eret", "drps", "", "" }; 1600 const char* const A64DOpcodeUnconditionalBranchRegister::s_AuthOpNames[20] = { 1601 "braaz", "brabz", "blraaz", "blrabz", "retaa", "retab", 0, 0, 1602 "eretaa", "eretab", 0, 0, 0, 0, 0, 0, 1603 "braa", "brab", "blraa", "blrab" 1604 }; 1605 1606 const char* A64DOpcodeUnconditionalBranchRegister::authOpName() 1607 { 1608 unsigned opCode = authOpCode(); 1609 if (opCode >= 20) 1610 return 0; 1611 return s_AuthOpNames[opCode]; 1612 } 1613 1614 const char* A64DOpcodeUnconditionalBranchRegister::format() 1615 { 1616 unsigned opcValue = opc(); 1617 if (op2() == 0x1f && (op3() & 0x3e) == 0x2) { 1618 const char* opName = authOpName(); 1619 if (!opName) 1620 return A64DOpcode::format(); 1621 if (rn() != 0x1f && (opcValue == 0x2 || opcValue == 0x4)) 1622 return A64DOpcode::format(); 1623 1624 appendInstructionName(opName); 1625 if ((opcValue & 0x7) <= 0x1) 1626 appendRegisterName(rn()); 1627 if (opcValue & 0x8) { 1628 appendSeparator(); 1629 appendRegisterName(rm()); 1630 } 1631 1632 return m_formatBuffer; 1633 } 1634 if (opcValue == 3 || opcValue > 5) 1635 return A64DOpcode::format(); 1636 if (((opcValue & 0xe) == 0x4) && rn() != 0x1f) 1637 return A64DOpcode::format(); 1638 appendInstructionName(opName()); 1639 if (opcValue <= 2) 1640 appendRegisterName(rn()); 1641 return m_formatBuffer; 1642 } 1643 1644 } } // namespace JSC::ARM64Disassembler 1645 1646 #endif // ENABLE(ARM64_DISASSEMBLER)