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#ifndef A64DOpcode_h 27#define A64DOpcode_h 28 29#include <wtf/Assertions.h> 30#include <stdint.h> 31 32namespace JSC { namespace ARM64Disassembler { 33 34class A64DOpcode { 35private: 36 class OpcodeGroup { 37 public: 38 OpcodeGroup(uint32_t opcodeMask, uint32_t opcodePattern, const char* (*format)(A64DOpcode*)) 39 : m_opcodeMask(opcodeMask) 40 , m_opcodePattern(opcodePattern) 41 , m_format(format) 42 , m_next(0) 43 { 44 } 45 46 void setNext(OpcodeGroup* next) 47 { 48 m_next = next; 49 } 50 51 OpcodeGroup* next() 52 { 53 return m_next; 54 } 55 56 bool matches(uint32_t opcode) 57 { 58 return (opcode & m_opcodeMask) == m_opcodePattern; 59 } 60 61 const char* format(A64DOpcode* thisObj) 62 { 63 return m_format(thisObj); 64 } 65 66 private: 67 uint32_t m_opcodeMask; 68 uint32_t m_opcodePattern; 69 const char* (*m_format)(A64DOpcode*); 70 OpcodeGroup* m_next; 71 }; 72 73public: 74 static void init(); 75 76 A64DOpcode() 77 : m_opcode(0) 78 , m_bufferOffset(0) 79 { 80 init(); 81 m_formatBuffer[0] = '\0'; 82 } 83 84 const char* disassemble(uint32_t* currentPC); 85 86protected: 87 void setPCAndOpcode(uint32_t*, uint32_t); 88 const char* format(); 89 90 static const char* const s_conditionNames[16]; 91 static const char* const s_shiftNames[4]; 92 static const char* const s_optionName[8]; 93 static const char s_FPRegisterPrefix[5]; 94 95 static const char* conditionName(unsigned condition) { return s_conditionNames[condition & 0xf]; } 96 static const char* shiftName(unsigned shiftValue) { return s_shiftNames[shiftValue & 0x3]; } 97 const char* optionName() { return s_optionName[option()]; } 98 static char FPRegisterPrefix(unsigned FPRegisterSize) 99 { 100 if (FPRegisterSize > 4) 101 FPRegisterSize = 4; 102 return s_FPRegisterPrefix[FPRegisterSize]; 103 } 104 105 unsigned opcodeGroupNumber(uint32_t opcode) { return (opcode >> 24) & 0x1f; } 106 107 bool is64Bit() { return m_opcode & 0x80000000; } 108 unsigned size() { return m_opcode >> 30; } 109 unsigned option() { return (m_opcode >> 13) & 0x7; } 110 unsigned rd() { return m_opcode & 0x1f; } 111 unsigned rt() { return m_opcode & 0x1f; } 112 unsigned rn() { return (m_opcode >> 5) & 0x1f; } 113 unsigned rm() { return (m_opcode >> 16) & 0x1f; } 114 115 void bufferPrintf(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3); 116 117 void appendInstructionName(const char* instructionName) 118 { 119 bufferPrintf(" %-7.7s", instructionName); 120 } 121 122 void appendRegisterName(unsigned registerNumber, bool is64Bit = true); 123 void appendSPOrRegisterName(unsigned registerNumber, bool is64Bit = true) 124 { 125 if (registerNumber == 31) { 126 bufferPrintf(is64Bit ? "sp" : "wsp"); 127 return; 128 } 129 appendRegisterName(registerNumber, is64Bit); 130 } 131 132 void appendZROrRegisterName(unsigned registerNumber, bool is64Bit = true) 133 { 134 if (registerNumber == 31) { 135 bufferPrintf(is64Bit ? "xzr" : "wzr"); 136 return; 137 } 138 appendRegisterName(registerNumber, is64Bit); 139 } 140 141 void appendFPRegisterName(unsigned registerNumber, unsigned registerSize); 142 143 void appendSeparator() 144 { 145 bufferPrintf(", "); 146 } 147 148 void appendCharacter(const char c) 149 { 150 bufferPrintf("%c", c); 151 } 152 153 void appendString(const char* string) 154 { 155 bufferPrintf("%s", string); 156 } 157 158 void appendShiftType(unsigned shiftValue) 159 { 160 bufferPrintf("%s ", shiftName(shiftValue)); 161 } 162 163 void appendSignedImmediate(int immediate) 164 { 165 bufferPrintf("#%d", immediate); 166 } 167 168 void appendUnsignedImmediate(unsigned immediate) 169 { 170 bufferPrintf("#%u", immediate); 171 } 172 173 void appendUnsignedImmediate64(uint64_t immediate) 174 { 175 bufferPrintf("#0x%llx", immediate); 176 } 177 178 void appendPCRelativeOffset(uint32_t* pc, int32_t immediate) 179 { 180 bufferPrintf("0x%llx", reinterpret_cast<uint64_t>(pc + immediate)); 181 } 182 183 void appendShiftAmount(unsigned amount) 184 { 185 bufferPrintf("lsl #%u", 16 * amount); 186 } 187 188 static const int bufferSize = 81; 189 190 char m_formatBuffer[bufferSize]; 191 uint32_t* m_currentPC; 192 uint32_t m_opcode; 193 int m_bufferOffset; 194 195private: 196 static OpcodeGroup* opcodeTable[32]; 197 198 static bool s_initialized; 199}; 200 201#define DEFINE_STATIC_FORMAT(klass, thisObj) \ 202 static const char* format(A64DOpcode* thisObj) { return reinterpret_cast< klass *>(thisObj)->format(); } 203 204class A64DOpcodeAddSubtract : public A64DOpcode { 205private: 206 static const char* const s_opNames[4]; 207 208public: 209 const char* opName() { return s_opNames[opAndS()]; } 210 const char* cmpName() { return op() ? "cmp" : "cmn"; } 211 212 bool isCMP() { return (sBit() && rd() == 31); } 213 unsigned op() { return (m_opcode >> 30) & 0x1; } 214 unsigned sBit() { return (m_opcode >> 29) & 0x1; } 215 unsigned opAndS() { return (m_opcode >> 29) & 0x3; } 216}; 217 218class A64DOpcodeAddSubtractImmediate : public A64DOpcodeAddSubtract { 219public: 220 static const uint32_t mask = 0x1f000000; 221 static const uint32_t pattern = 0x11000000; 222 223 DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractImmediate, thisObj); 224 225 const char* format(); 226 227 bool isMovSP() { return (!opAndS() && !immed12() && ((rd() == 31) || rn() == 31)); } 228 unsigned shift() { return (m_opcode >> 22) & 0x3; } 229 unsigned immed12() { return (m_opcode >> 10) & 0xfff; } 230}; 231 232class A64DOpcodeAddSubtractExtendedRegister : public A64DOpcodeAddSubtract { 233public: 234 static const uint32_t mask = 0x1fe00000; 235 static const uint32_t pattern = 0x0b200000; 236 237 DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractExtendedRegister, thisObj); 238 239 const char* format(); 240 241 unsigned immediate3() { return (m_opcode >> 10) & 0x7; } 242}; 243 244class A64DOpcodeAddSubtractShiftedRegister : public A64DOpcodeAddSubtract { 245public: 246 static const uint32_t mask = 0x1f200000; 247 static const uint32_t pattern = 0x0b000000; 248 249 DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractShiftedRegister, thisObj); 250 251 const char* format(); 252 253 bool isNeg() { return (op() && rn() == 31); } 254 const char* negName() { return sBit() ? "negs" : "neg"; } 255 unsigned shift() { return (m_opcode >> 22) & 0x3; } 256 int immediate6() { return (static_cast<int>((m_opcode >> 10) & 0x3f) << 26) >> 26; } 257}; 258 259class A64DOpcodeBitfield : public A64DOpcode { 260private: 261 static const char* const s_opNames[3]; 262 static const char* const s_extendPseudoOpNames[3][3]; 263 static const char* const s_insertOpNames[3]; 264 static const char* const s_extractOpNames[3]; 265 266public: 267 static const uint32_t mask = 0x1f800000; 268 static const uint32_t pattern = 0x13000000; 269 270 DEFINE_STATIC_FORMAT(A64DOpcodeBitfield, thisObj); 271 272 const char* format(); 273 274 const char* opName() { return s_opNames[opc()]; } 275 const char* extendPseudoOpNames(unsigned opSize) { return s_extendPseudoOpNames[opc()][opSize]; } 276 const char* insertOpNames() { return s_insertOpNames[opc()]; } 277 const char* extractOpNames() { return s_extractOpNames[opc()]; } 278 279 unsigned opc() { return (m_opcode >> 29) & 0x3; } 280 unsigned nBit() { return (m_opcode >> 22) & 0x1; } 281 unsigned immediateR() { return (m_opcode >> 16) & 0x3f; } 282 unsigned immediateS() { return (m_opcode >> 10) & 0x3f; } 283}; 284 285class A64DOpcodeCompareAndBranchImmediate : public A64DOpcode { 286public: 287 static const uint32_t mask = 0x7e000000; 288 static const uint32_t pattern = 0x34000000; 289 290 DEFINE_STATIC_FORMAT(A64DOpcodeCompareAndBranchImmediate, thisObj); 291 292 const char* format(); 293 294 unsigned opBit() { return (m_opcode >> 24) & 0x1; } 295 int immediate19() { return (static_cast<int>((m_opcode >> 5) & 0x7ffff) << 13) >> 13; } 296}; 297 298class A64DOpcodeConditionalBranchImmediate : public A64DOpcode { 299public: 300 static const uint32_t mask = 0xff000010; 301 static const uint32_t pattern = 0x54000000; 302 303 DEFINE_STATIC_FORMAT(A64DOpcodeConditionalBranchImmediate, thisObj); 304 305 const char* format(); 306 307 unsigned condition() { return m_opcode & 0xf; } 308 int immediate19() { return (static_cast<int>((m_opcode >> 5) & 0x7ffff) << 13) >> 13; } 309}; 310 311class A64DOpcodeConditionalSelect : public A64DOpcode { 312private: 313 static const char* const s_opNames[4]; 314 315public: 316 static const uint32_t mask = 0x1fe00010; 317 static const uint32_t pattern = 0x1a800000; 318 319 DEFINE_STATIC_FORMAT(A64DOpcodeConditionalSelect, thisObj); 320 321 const char* format(); 322 323 const char* opName() { return s_opNames[opNum()]; } 324 unsigned opNum() { return (op() << 1 | (op2() & 0x1)); } 325 unsigned op() { return (m_opcode >> 30) & 0x1; } 326 unsigned sBit() { return (m_opcode >> 29) & 0x1; } 327 unsigned condition() { return (m_opcode >> 12) & 0xf; } 328 unsigned op2() { return (m_opcode >> 10) & 0x3; } 329}; 330 331class A64DOpcodeDataProcessing2Source : public A64DOpcode { 332private: 333 static const char* const s_opNames[8]; 334 335public: 336 static const uint32_t mask = 0x5fe00000; 337 static const uint32_t pattern = 0x1ac00000; 338 339 DEFINE_STATIC_FORMAT(A64DOpcodeDataProcessing2Source, thisObj); 340 341 const char* format(); 342 343 const char* opName() { return s_opNames[opNameIndex()]; } 344 unsigned sBit() { return (m_opcode >> 29) & 0x1; } 345 unsigned opCode() { return (m_opcode >> 10) & 0x3f; } 346 unsigned opNameIndex() { return ((m_opcode >> 11) & 0x4) | ((m_opcode >> 10) & 0x3); } 347}; 348 349class A64DOpcodeDataProcessing3Source : public A64DOpcode { 350private: 351 static const char* const s_opNames[16]; 352 static const char* const s_pseudoOpNames[16]; 353 354public: 355 static const uint32_t mask = 0x1f000000; 356 static const uint32_t pattern = 0x1b000000; 357 358 DEFINE_STATIC_FORMAT(A64DOpcodeDataProcessing3Source, thisObj); 359 360 const char* format(); 361 362 const char* opName() { return ra() == 31 ? s_opNames[opNum() & 0xf] : s_pseudoOpNames[opNum() & 0xf]; } 363 unsigned ra() { return (m_opcode >> 10) & 0x1f; } 364 unsigned op54() { return (m_opcode >> 29) & 0x3; } 365 unsigned op31() { return (m_opcode >> 21) & 0x7; } 366 unsigned op0() { return (m_opcode >> 15) & 0x1; } 367 unsigned opNum() { return ((m_opcode >> 25) & 0x30) | ((m_opcode >> 20) & 0xe) | ((m_opcode >> 15) & 0x1); } 368}; 369 370class A64OpcodeExceptionGeneration : public A64DOpcode { 371public: 372 static const uint32_t mask = 0xff000010; 373 static const uint32_t pattern = 0xd4000000; 374 375 DEFINE_STATIC_FORMAT(A64OpcodeExceptionGeneration, thisObj); 376 377 const char* format(); 378 379 unsigned opc() { return (m_opcode>>21) & 0x7; } 380 unsigned op2() { return (m_opcode>>2) & 0x7; } 381 unsigned ll() { return m_opcode & 0x3; } 382 int immediate16() { return (static_cast<int>((m_opcode >> 5) & 0xffff) << 16) >> 16; } 383}; 384 385class A64DOpcodeExtract : public A64DOpcode { 386public: 387 static const uint32_t mask = 0x1f800000; 388 static const uint32_t pattern = 0x13800000; 389 390 DEFINE_STATIC_FORMAT(A64DOpcodeExtract, thisObj); 391 392 const char* format(); 393 394 unsigned op21() { return (m_opcode >> 29) & 0x3; } 395 unsigned nBit() { return (m_opcode >> 22) & 0x1; } 396 unsigned o0Bit() { return (m_opcode >> 21) & 0x1; } 397 unsigned immediateS() { return (m_opcode >> 10) & 0x3f; } 398}; 399 400class A64DOpcodeFloatingPointOps : public A64DOpcode { 401public: 402 unsigned mBit() { return (m_opcode >> 31) & 0x1; } 403 unsigned sBit() { return (m_opcode >> 29) & 0x1; } 404 unsigned type() { return (m_opcode >> 22) & 0x3; } 405}; 406 407class A64DOpcodeFloatingPointCompare : public A64DOpcodeFloatingPointOps { 408private: 409 static const char* const s_opNames[16]; 410 411public: 412 static const uint32_t mask = 0x5f203c00; 413 static const uint32_t pattern = 0x1e202000; 414 415 DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointCompare, thisObj); 416 417 const char* format(); 418 419 const char* opName() { return (opNum() & 0x2) ? "fcmpe" : "fcmp"; } 420 421 unsigned op() { return (m_opcode >> 14) & 0x3; } 422 unsigned opCode2() { return m_opcode & 0x1f; } 423 unsigned opNum() { return (m_opcode >> 3) & 0x3; } 424}; 425 426class A64DOpcodeFloatingPointDataProcessing1Source : public A64DOpcodeFloatingPointOps { 427private: 428 static const char* const s_opNames[16]; 429 430public: 431 static const uint32_t mask = 0x5f207c00; 432 static const uint32_t pattern = 0x1e204000; 433 434 DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointDataProcessing1Source, thisObj); 435 436 const char* format(); 437 438 const char* opName() { return s_opNames[opNum()]; } 439 440 unsigned opNum() { return (m_opcode >> 15) & 0x3f; } 441}; 442 443class A64DOpcodeFloatingPointDataProcessing2Source : public A64DOpcodeFloatingPointOps { 444private: 445 static const char* const s_opNames[16]; 446 447public: 448 static const uint32_t mask = 0x5f200800; 449 static const uint32_t pattern = 0x1e200800; 450 451 DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointDataProcessing2Source, thisObj); 452 453 const char* format(); 454 455 const char* opName() { return s_opNames[opNum()]; } 456 457 unsigned opNum() { return (m_opcode >> 12) & 0xf; } 458}; 459 460class A64DOpcodeFloatingFixedPointConversions : public A64DOpcodeFloatingPointOps { 461private: 462 static const char* const s_opNames[4]; 463 464public: 465 static const uint32_t mask = 0x5f200000; 466 static const uint32_t pattern = 0x1e000000; 467 468 DEFINE_STATIC_FORMAT(A64DOpcodeFloatingFixedPointConversions, thisObj); 469 470 const char* format(); 471 472 const char* opName() { return s_opNames[opNum()]; } 473 unsigned rmode() { return (m_opcode >> 19) & 0x3; } 474 unsigned opcode() { return (m_opcode >> 16) & 0x7; } 475 unsigned scale() { return (m_opcode >> 10) & 0x3f; } 476 unsigned opNum() { return (m_opcode >> 16) & 0x3; } 477}; 478 479class A64DOpcodeFloatingPointIntegerConversions : public A64DOpcodeFloatingPointOps { 480private: 481 static const char* const s_opNames[32]; 482 483public: 484 static const uint32_t mask = 0x5f20fc00; 485 static const uint32_t pattern = 0x1e200000; 486 487 DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointIntegerConversions, thisObj); 488 489 const char* format(); 490 491 const char* opName() { return s_opNames[opNum()]; } 492 unsigned rmode() { return (m_opcode >> 19) & 0x3; } 493 unsigned opcode() { return (m_opcode >> 16) & 0x7; } 494 unsigned opNum() { return (m_opcode >> 16) & 0x1f; } 495}; 496 497class A64DOpcodeHint : public A64DOpcode { 498private: 499 static const char* const s_opNames[6]; 500 501public: 502 static const uint32_t mask = 0xfffff01f; 503 static const uint32_t pattern = 0xd503201f; 504 505 DEFINE_STATIC_FORMAT(A64DOpcodeHint, thisObj); 506 507 const char* format(); 508 509 const char* opName() { return immediate7() <= 5 ? s_opNames[immediate7()] : "hint"; } 510 unsigned immediate7() { return (m_opcode >> 5) & 0x7f; } 511}; 512 513class A64DOpcodeLoadStore : public A64DOpcode { 514private: 515 static const char* const s_opNames[32]; 516 517protected: 518 const char* opName() 519 { 520 return s_opNames[opNumber()]; 521 } 522 523 unsigned size() { return (m_opcode >> 30) & 0x3; } 524 unsigned vBit() { return (m_opcode >> 26) & 0x1; } 525 unsigned opc() { return (m_opcode >> 22) & 0x3; } 526 unsigned opNumber() { return (size() <<3 ) | (vBit() << 2) | opc(); } 527 bool is64BitRT() { return ((opNumber() & 0x17) == 0x02) || ((opNumber() & 0x1e) == 0x18); } 528}; 529 530class A64DOpcodeLoadStoreImmediate : public A64DOpcodeLoadStore { 531private: 532 static const char* const s_unprivilegedOpNames[32]; 533 static const char* const s_unscaledOpNames[32]; 534 535public: 536 static const uint32_t mask = 0x3b200000; 537 static const uint32_t pattern = 0x38000000; 538 539 DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreImmediate, thisObj); 540 541 const char* format(); 542 543 const char* unprivilegedOpName() 544 { 545 return s_unprivilegedOpNames[opNumber()]; 546 } 547 const char* unscaledOpName() 548 { 549 return s_unscaledOpNames[opNumber()]; 550 } 551 unsigned type() { return (m_opcode >> 10) & 0x3; } 552 int immediate9() { return (static_cast<int>((m_opcode >> 12) & 0x1ff) << 23) >> 23; } 553}; 554 555class A64DOpcodeLoadStoreRegisterOffset : public A64DOpcodeLoadStore { 556public: 557 static const uint32_t mask = 0x3b200c00; 558 static const uint32_t pattern = 0x38200800; 559 560 DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreRegisterOffset, thisObj); 561 562 const char* format(); 563 564 unsigned option() { return (m_opcode >> 13) & 0x7; } 565 int sBit() { return (m_opcode >> 12) & 0x1; } 566}; 567 568class A64DOpcodeLoadStoreRegisterPair : public A64DOpcodeLoadStore { 569public: 570 static const uint32_t mask = 0x3a000000; 571 static const uint32_t pattern = 0x28000000; 572 573 DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreRegisterPair, thisObj); 574 575 const char* format(); 576 const char* opName(); 577 578 unsigned rt2() { return (m_opcode >> 10) & 0x1f; } 579 int immediate7() { return (static_cast<int>((m_opcode >> 15) & 0x7f) << 25) >> 25; } 580 unsigned offsetMode() { return (m_opcode >> 23) & 0x7; } 581 int lBit() { return (m_opcode >> 22) & 0x1; } 582}; 583 584class A64DOpcodeLoadStoreUnsignedImmediate : public A64DOpcodeLoadStore { 585public: 586 static const uint32_t mask = 0x3b000000; 587 static const uint32_t pattern = 0x39000000; 588 589 DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreUnsignedImmediate, thisObj); 590 591 const char* format(); 592 593 unsigned immediate12() { return (m_opcode >> 10) & 0xfff; } 594}; 595 596class A64DOpcodeLogical : public A64DOpcode { 597private: 598 static const char* const s_opNames[8]; 599 600public: 601 const char* opName(unsigned opNumber) 602 { 603 return s_opNames[opNumber & 0x7]; 604 } 605 606 unsigned opc() { return (m_opcode >> 29) & 0x3; } 607 unsigned nBit() { return (m_opcode >> 21) & 0x1; } 608}; 609 610class A64DOpcodeLogicalImmediate : public A64DOpcodeLogical { 611public: 612 static const uint32_t mask = 0x1f800000; 613 static const uint32_t pattern = 0x12000000; 614 615 DEFINE_STATIC_FORMAT(A64DOpcodeLogicalImmediate, thisObj); 616 617 const char* format(); 618 619 bool isTst() { return ((opNumber() == 6) && (rd() == 31)); } 620 bool isMov() { return ((opNumber() == 2) && (rn() == 31)); } 621 unsigned opNumber() { return opc() << 1; } 622 unsigned nBit() { return (m_opcode >> 22) & 0x1; } 623 unsigned immediateR() { return (m_opcode >> 16) & 0x3f; } 624 unsigned immediateS() { return (m_opcode >> 10) & 0x3f; } 625}; 626 627class A64DOpcodeLogicalShiftedRegister : public A64DOpcodeLogical { 628public: 629 static const uint32_t mask = 0x1f000000; 630 static const uint32_t pattern = 0x0a000000; 631 632 DEFINE_STATIC_FORMAT(A64DOpcodeLogicalShiftedRegister, thisObj); 633 634 const char* format(); 635 636 bool isTst() { return ((opNumber() == 6) && (rd() == 31)); } 637 bool isMov() { return ((opNumber() == 2) && (rn() == 31)); } 638 unsigned opNumber() { return (opc() << 1) | nBit(); } 639 unsigned shift() { return (m_opcode >> 22) & 0x3; } 640 int immediate6() { return (static_cast<int>((m_opcode >> 10) & 0x3f) << 26) >> 26; } 641}; 642 643class A64DOpcodeMoveWide : public A64DOpcode { 644private: 645 static const char* const s_opNames[4]; 646 647public: 648 static const uint32_t mask = 0x1f800000; 649 static const uint32_t pattern = 0x12800000; 650 651 DEFINE_STATIC_FORMAT(A64DOpcodeMoveWide, thisObj); 652 653 const char* format(); 654 655 const char* opName() { return s_opNames[opc()]; } 656 unsigned opc() { return (m_opcode >> 29) & 0x3; } 657 unsigned hw() { return (m_opcode >> 21) & 0x3; } 658 unsigned immediate16() { return (m_opcode >> 5) & 0xffff; } 659}; 660 661class A64DOpcodeTestAndBranchImmediate : public A64DOpcode { 662public: 663 static const uint32_t mask = 0x7e000000; 664 static const uint32_t pattern = 0x36000000; 665 666 DEFINE_STATIC_FORMAT(A64DOpcodeTestAndBranchImmediate, thisObj); 667 668 const char* format(); 669 670 unsigned bitNumber() { return ((m_opcode >> 26) & 0x20) | ((m_opcode >> 19) & 0x1f); } 671 unsigned opBit() { return (m_opcode >> 24) & 0x1; } 672 int immediate14() { return (static_cast<int>((m_opcode >> 5) & 0x3fff) << 18) >> 18; } 673}; 674 675class A64DOpcodeUnconditionalBranchImmediate : public A64DOpcode { 676public: 677 static const uint32_t mask = 0x7c000000; 678 static const uint32_t pattern = 0x14000000; 679 680 DEFINE_STATIC_FORMAT(A64DOpcodeUnconditionalBranchImmediate, thisObj); 681 682 const char* format(); 683 684 unsigned op() { return (m_opcode >> 31) & 0x1; } 685 int immediate26() { return (static_cast<int>(m_opcode & 0x3ffffff) << 6) >> 6; } 686}; 687 688class A64DOpcodeUnconditionalBranchRegister : public A64DOpcode { 689private: 690 static const char* const s_opNames[8]; 691 692public: 693 static const uint32_t mask = 0xfe1ffc1f; 694 static const uint32_t pattern = 0xd61f0000; 695 696 DEFINE_STATIC_FORMAT(A64DOpcodeUnconditionalBranchRegister, thisObj); 697 698 const char* format(); 699 700 const char* opName() { return s_opNames[opc()]; } 701 unsigned opc() { return (m_opcode >> 21) & 0xf; } 702}; 703 704} } // namespace JSC::ARM64Disassembler 705 706using JSC::ARM64Disassembler::A64DOpcode; 707 708#endif // A64DOpcode_h 709