summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/disassembler
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-05-30 12:48:17 +0200
committerOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-05-30 12:48:17 +0200
commit881da28418d380042aa95a97f0cbd42560a64f7c (patch)
treea794dff3274695e99c651902dde93d934ea7a5af /Source/JavaScriptCore/disassembler
parent7e104c57a70fdf551bb3d22a5d637cdcbc69dbea (diff)
parent0fcedcd17cc00d3dd44c718b3cb36c1033319671 (diff)
downloadqtwebkit-881da28418d380042aa95a97f0cbd42560a64f7c.tar.gz
Merge 'wip/next' into dev
Change-Id: Iff9ee5e23bb326c4371ec8ed81d56f2f05d680e9
Diffstat (limited to 'Source/JavaScriptCore/disassembler')
-rw-r--r--Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp1201
-rw-r--r--Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.h708
-rw-r--r--Source/JavaScriptCore/disassembler/ARM64Disassembler.cpp57
-rw-r--r--Source/JavaScriptCore/disassembler/ARMv7/ARMv7DOpcode.cpp176
-rw-r--r--Source/JavaScriptCore/disassembler/ARMv7/ARMv7DOpcode.h103
-rw-r--r--Source/JavaScriptCore/disassembler/Disassembler.cpp110
-rw-r--r--Source/JavaScriptCore/disassembler/Disassembler.h14
-rw-r--r--Source/JavaScriptCore/disassembler/UDis86Disassembler.cpp6
-rw-r--r--Source/JavaScriptCore/disassembler/UDis86Disassembler.h46
-rw-r--r--Source/JavaScriptCore/disassembler/X86Disassembler.cpp46
-rw-r--r--Source/JavaScriptCore/disassembler/udis86/itab.py2
-rw-r--r--Source/JavaScriptCore/disassembler/udis86/udis86_decode.c3
-rw-r--r--Source/JavaScriptCore/disassembler/udis86/udis86_syn-att.c55
-rw-r--r--Source/JavaScriptCore/disassembler/udis86/udis86_syn-intel.c10
-rw-r--r--Source/JavaScriptCore/disassembler/udis86/udis86_types.h6
15 files changed, 2500 insertions, 43 deletions
diff --git a/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp b/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp
new file mode 100644
index 000000000..28f703801
--- /dev/null
+++ b/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp
@@ -0,0 +1,1201 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if USE(ARM64_DISASSEMBLER)
+
+#include "A64DOpcode.h"
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+
+namespace JSC { namespace ARM64Disassembler {
+
+A64DOpcode::OpcodeGroup* A64DOpcode::opcodeTable[32];
+
+const char* const A64DOpcode::s_conditionNames[16] = {
+ "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
+ "hi", "ls", "ge", "lt", "gt", "le", "al", "ne"
+};
+
+const char* const A64DOpcode::s_optionName[8] = {
+ "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx"
+};
+
+const char* const A64DOpcode::s_shiftNames[4] = {
+ "lsl", "lsr", "asl", "ror"
+};
+
+const char A64DOpcode::s_FPRegisterPrefix[5] = {
+ 'b', 'h', 's', 'd', 'q'
+};
+
+struct OpcodeGroupInitializer {
+ unsigned m_opcodeGroupNumber;
+ uint32_t m_mask;
+ uint32_t m_pattern;
+ const char* (*m_format)(A64DOpcode*);
+};
+
+#define OPCODE_GROUP_ENTRY(groupIndex, groupClass) \
+{ groupIndex, groupClass::mask, groupClass::pattern, groupClass::format }
+
+static OpcodeGroupInitializer opcodeGroupList[] = {
+ OPCODE_GROUP_ENTRY(0x08, A64DOpcodeLoadStoreRegisterPair),
+ OPCODE_GROUP_ENTRY(0x09, A64DOpcodeLoadStoreRegisterPair),
+ OPCODE_GROUP_ENTRY(0x0a, A64DOpcodeLogicalShiftedRegister),
+ OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractExtendedRegister),
+ OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractShiftedRegister),
+ OPCODE_GROUP_ENTRY(0x11, A64DOpcodeAddSubtractImmediate),
+ OPCODE_GROUP_ENTRY(0x12, A64DOpcodeMoveWide),
+ OPCODE_GROUP_ENTRY(0x12, A64DOpcodeLogicalImmediate),
+ OPCODE_GROUP_ENTRY(0x13, A64DOpcodeBitfield),
+ OPCODE_GROUP_ENTRY(0x13, A64DOpcodeExtract),
+ OPCODE_GROUP_ENTRY(0x14, A64DOpcodeUnconditionalBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x14, A64DOpcodeConditionalBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x14, A64DOpcodeCompareAndBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x14, A64OpcodeExceptionGeneration),
+ OPCODE_GROUP_ENTRY(0x15, A64DOpcodeUnconditionalBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x15, A64DOpcodeConditionalBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x15, A64DOpcodeCompareAndBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x15, A64DOpcodeHint),
+ OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x16, A64DOpcodeUnconditionalBranchRegister),
+ OPCODE_GROUP_ENTRY(0x16, A64DOpcodeTestAndBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x17, A64DOpcodeUnconditionalBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x17, A64DOpcodeUnconditionalBranchRegister),
+ OPCODE_GROUP_ENTRY(0x17, A64DOpcodeTestAndBranchImmediate),
+ OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreImmediate),
+ OPCODE_GROUP_ENTRY(0x18, A64DOpcodeLoadStoreRegisterOffset),
+ OPCODE_GROUP_ENTRY(0x19, A64DOpcodeLoadStoreUnsignedImmediate),
+ OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeConditionalSelect),
+ OPCODE_GROUP_ENTRY(0x1a, A64DOpcodeDataProcessing2Source),
+ OPCODE_GROUP_ENTRY(0x1b, A64DOpcodeDataProcessing3Source),
+ OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreImmediate),
+ OPCODE_GROUP_ENTRY(0x1c, A64DOpcodeLoadStoreRegisterOffset),
+ OPCODE_GROUP_ENTRY(0x1d, A64DOpcodeLoadStoreUnsignedImmediate),
+ OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointCompare),
+ OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing2Source),
+ OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointDataProcessing1Source),
+ OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingFixedPointConversions),
+ OPCODE_GROUP_ENTRY(0x1e, A64DOpcodeFloatingPointIntegerConversions),
+};
+
+bool A64DOpcode::s_initialized = false;
+
+void A64DOpcode::init()
+{
+ if (s_initialized)
+ return;
+
+ OpcodeGroup* lastGroups[32];
+
+ for (unsigned i = 0; i < 32; i++) {
+ opcodeTable[i] = 0;
+ lastGroups[i] = 0;
+ }
+
+ for (unsigned i = 0; i < sizeof(opcodeGroupList) / sizeof(struct OpcodeGroupInitializer); i++) {
+ OpcodeGroup* newOpcodeGroup = new OpcodeGroup(opcodeGroupList[i].m_mask, opcodeGroupList[i].m_pattern, opcodeGroupList[i].m_format);
+ uint32_t opcodeGroupNumber = opcodeGroupList[i].m_opcodeGroupNumber;
+
+ if (!opcodeTable[opcodeGroupNumber])
+ opcodeTable[opcodeGroupNumber] = newOpcodeGroup;
+ else
+ lastGroups[opcodeGroupNumber]->setNext(newOpcodeGroup);
+ lastGroups[opcodeGroupNumber] = newOpcodeGroup;
+ }
+
+ s_initialized = true;
+}
+
+void A64DOpcode::setPCAndOpcode(uint32_t* newPC, uint32_t newOpcode)
+{
+ m_currentPC = newPC;
+ m_opcode = newOpcode;
+ m_bufferOffset = 0;
+ m_formatBuffer[0] = '\0';
+}
+
+const char* A64DOpcode::disassemble(uint32_t* currentPC)
+{
+ setPCAndOpcode(currentPC, *currentPC);
+
+ OpcodeGroup* opGroup = opcodeTable[opcodeGroupNumber(m_opcode)];
+
+ while (opGroup) {
+ if (opGroup->matches(m_opcode))
+ return opGroup->format(this);
+ opGroup = opGroup->next();
+ }
+
+ return A64DOpcode::format();
+}
+
+void A64DOpcode::bufferPrintf(const char* format, ...)
+{
+ if (m_bufferOffset >= bufferSize)
+ return;
+
+ va_list argList;
+ va_start(argList, format);
+
+ m_bufferOffset += vsnprintf(m_formatBuffer + m_bufferOffset, bufferSize - m_bufferOffset, format, argList);
+
+ va_end(argList);
+}
+
+const char* A64DOpcode::format()
+{
+ bufferPrintf(" .long %08x", m_opcode);
+ return m_formatBuffer;
+}
+
+void A64DOpcode::appendRegisterName(unsigned registerNumber, bool is64Bit)
+{
+ if (registerNumber == 29) {
+ bufferPrintf(is64Bit ? "fp" : "wfp");
+ return;
+ }
+
+ if (registerNumber == 30) {
+ bufferPrintf(is64Bit ? "lr" : "wlr");
+ return;
+ }
+
+ bufferPrintf("%c%u", is64Bit ? 'x' : 'w', registerNumber);
+}
+
+void A64DOpcode::appendFPRegisterName(unsigned registerNumber, unsigned registerSize)
+{
+ bufferPrintf("%c%u", FPRegisterPrefix(registerSize), registerNumber);
+}
+
+const char* const A64DOpcodeAddSubtract::s_opNames[4] = { "add", "adds", "sub", "subs" };
+
+const char* A64DOpcodeAddSubtractImmediate::format()
+{
+ if (isCMP())
+ appendInstructionName(cmpName());
+ else {
+ if (isMovSP())
+ appendInstructionName("mov");
+ else
+ appendInstructionName(opName());
+ appendSPOrRegisterName(rd(), is64Bit());
+ appendSeparator();
+ }
+ appendSPOrRegisterName(rn(), is64Bit());
+
+ if (!isMovSP()) {
+ appendSeparator();
+ appendUnsignedImmediate(immed12());
+ if (shift()) {
+ appendSeparator();
+ appendString(shift() == 1 ? "lsl" : "reserved");
+ }
+ }
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeAddSubtractExtendedRegister::format()
+{
+ if (immediate3() > 4)
+ return A64DOpcode::format();
+
+ if (isCMP())
+ appendInstructionName(cmpName());
+ else {
+ appendInstructionName(opName());
+ appendSPOrRegisterName(rd(), is64Bit());
+ appendSeparator();
+ }
+ appendSPOrRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendZROrRegisterName(rm(), is64Bit() && ((option() & 0x3) == 0x3));
+ appendSeparator();
+ if (option() == 0x2 && ((rd() == 31) || (rn() == 31)))
+ appendString("lsl");
+ else
+ appendString(optionName());
+ if (immediate3()) {
+ appendCharacter(' ');
+ appendUnsignedImmediate(immediate3());
+ }
+
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeAddSubtractShiftedRegister::format()
+{
+ if (!is64Bit() && immediate6() & 0x20)
+ return A64DOpcode::format();
+
+ if (shift() == 0x3)
+ return A64DOpcode::format();
+
+ if (isCMP())
+ appendInstructionName(cmpName());
+ else {
+ if (isNeg())
+ appendInstructionName(cmpName());
+ else
+ appendInstructionName(opName());
+ appendSPOrRegisterName(rd(), is64Bit());
+ appendSeparator();
+ }
+ if (!isNeg()) {
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ }
+ appendZROrRegisterName(rm(), is64Bit());
+ if (immediate6()) {
+ appendSeparator();
+ appendShiftType(shift());
+ appendUnsignedImmediate(immediate6());
+ }
+
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeBitfield::s_opNames[3] = { "sbfm", "bfm", "ubfm" };
+const char* const A64DOpcodeBitfield::s_extendPseudoOpNames[3][3] = {
+ { "sxtb", "sxth", "sxtw" }, { 0, 0, 0} , { "uxtb", "uxth", "uxtw" } };
+const char* const A64DOpcodeBitfield::s_insertOpNames[3] = { "sbfiz", "bfi", "ubfiz" };
+const char* const A64DOpcodeBitfield::s_extractOpNames[3] = { "sbfx", "bf", "ubfx" };
+
+const char* A64DOpcodeBitfield::format()
+{
+ if (opc() == 0x3)
+ return A64DOpcode::format();
+
+ if (is64Bit() != nBit())
+ return A64DOpcode::format();
+
+ if (!is64Bit() && ((immediateR() & 0x20) || (immediateS() & 0x20)))
+ return A64DOpcode::format();
+
+ if (!(opc() & 0x1) && !immediateR()) {
+ // [un]signed {btye,half-word,word} extend
+ bool isSTXType = false;
+ if (immediateS() == 7) {
+ appendInstructionName(extendPseudoOpNames(0));
+ isSTXType = true;
+ } else if (immediateS() == 15) {
+ appendInstructionName(extendPseudoOpNames(1));
+ isSTXType = true;
+ } else if (immediateS() == 31 && is64Bit()) {
+ appendInstructionName(extendPseudoOpNames(2));
+ isSTXType = true;
+ }
+
+ if (isSTXType) {
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rn(), false);
+
+ return m_formatBuffer;
+ }
+ }
+
+ if (opc() == 0x2 && immediateS() == (immediateR() + 1)) {
+ // lsl
+ appendInstructionName("lsl");
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendUnsignedImmediate((is64Bit() ? 63u : 31u) - immediateR());
+
+ return m_formatBuffer;
+ } else if (!(opc() & 0x1) && ((immediateS() & 0x1f) == 0x1f) && (is64Bit() == (immediateS() >> 5))) {
+ // asr/lsr
+ appendInstructionName(!opc() ? "ars" : "lsr");
+
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendUnsignedImmediate(immediateR());
+
+ return m_formatBuffer;
+ } else if (immediateS() < immediateR()) {
+ // bit field insert
+ appendInstructionName(insertOpNames());
+
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendUnsignedImmediate((is64Bit() ? 64u : 32u) - immediateR());
+ appendSeparator();
+ appendUnsignedImmediate(immediateS() + 1);
+
+ return m_formatBuffer;
+ } else {
+ // bit field extract
+ appendInstructionName(extractOpNames());
+
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendUnsignedImmediate(immediateR());
+ appendSeparator();
+ appendUnsignedImmediate(immediateS() - immediateR() + 1);
+
+ return m_formatBuffer;
+ }
+
+ appendInstructionName(opName());
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendUnsignedImmediate(immediateR());
+ appendSeparator();
+ appendUnsignedImmediate(immediateS());
+
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeCompareAndBranchImmediate::format()
+{
+ appendInstructionName(opBit() ? "cbnz" : "cbz");
+ appendRegisterName(rt(), is64Bit());
+ appendSeparator();
+ appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate19()));
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeConditionalBranchImmediate::format()
+{
+ bufferPrintf(" b.%-5.5s", conditionName(condition()));
+ appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate19()));
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeConditionalSelect::s_opNames[4] = {
+ "csel", "csinc", "csinv", "csneg"
+};
+
+const char* A64DOpcodeConditionalSelect::format()
+{
+ if (sBit())
+ return A64DOpcode::format();
+
+ if (op2() & 0x2)
+ return A64DOpcode::format();
+
+ if (rn() == rm() && (opNum() == 1 || opNum() == 2)) {
+ if (rn() == 31) {
+ appendInstructionName((opNum() == 1) ? "cset" : "csetm");
+ appendRegisterName(rd(), is64Bit());
+ } else {
+ appendInstructionName((opNum() == 1) ? "cinc" : "cinv");
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendZROrRegisterName(rn(), is64Bit());
+ }
+ appendSeparator();
+ appendString(conditionName(condition() ^ 0x1));
+
+ return m_formatBuffer;
+ }
+
+ appendInstructionName(opName());
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendZROrRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendZROrRegisterName(rm(), is64Bit());
+ appendSeparator();
+ appendString(conditionName(condition()));
+
+ return m_formatBuffer;
+
+}
+
+const char* const A64DOpcodeDataProcessing2Source::s_opNames[8] = {
+ 0, 0, "udiv", "sdiv", "lsl", "lsr", "asr", "ror" // We use the pseudo-op names for the shift/rotate instructions
+};
+
+const char* A64DOpcodeDataProcessing2Source::format()
+{
+ if (sBit())
+ return A64DOpcode::format();
+
+ if (!(opCode() & 0x3e))
+ return A64DOpcode::format();
+
+ if (opCode() & 0x30)
+ return A64DOpcode::format();
+
+ if ((opCode() & 0x34) == 0x4)
+ return A64DOpcode::format();
+
+ appendInstructionName(opName());
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rm(), is64Bit());
+
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeDataProcessing3Source::s_opNames[16] = {
+ "madd", "msub", "smaddl", "smsubl", "smulh", 0, 0, 0,
+ 0, 0, "umaddl", "umsubl", "umulh", 0, 0, 0
+};
+
+const char* const A64DOpcodeDataProcessing3Source::s_pseudoOpNames[16] = {
+ "mul", "mneg", "smull", "smnegl", "smulh", 0, 0, 0,
+ 0, 0, "umull", "umnegl", "umulh", 0, 0, 0
+};
+
+const char* A64DOpcodeDataProcessing3Source::format()
+{
+ if (op54())
+ return A64DOpcode::format();
+
+ if (opNum() > 12)
+ return A64DOpcode::format();
+
+ if (!is64Bit() && opNum() > 1)
+ return A64DOpcode::format();
+
+ if (!opName())
+ return A64DOpcode::format();
+
+ appendInstructionName(opName());
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ bool srcOneAndTwoAre64Bit = is64Bit() & !(opNum() & 0x2);
+ appendRegisterName(rn(), srcOneAndTwoAre64Bit);
+ appendSeparator();
+ appendRegisterName(rm(), srcOneAndTwoAre64Bit);
+
+ if ((ra() != 31) || !(opNum() & 0x4)) {
+ appendSeparator();
+ appendRegisterName(ra(), is64Bit());
+ }
+
+ return m_formatBuffer;
+}
+
+const char* A64OpcodeExceptionGeneration::format()
+{
+ const char* opname = 0;
+ if (!op2()) {
+ switch (opc()) {
+ case 0x0: // SVC, HVC & SMC
+ switch (ll()) {
+ case 0x1:
+ opname = "svc";
+ break;
+ case 0x2:
+ opname = "hvc";
+ break;
+ case 0x3:
+ opname = "smc";
+ break;
+ }
+ break;
+ case 0x1: // BRK
+ if (!ll())
+ opname = "brk";
+ break;
+ case 0x2: // HLT
+ if (!ll())
+ opname = "hlt";
+ break;
+ case 0x5: // DPCS1-3
+ switch (ll()) {
+ case 0x1:
+ opname = "dpcs1";
+ break;
+ case 0x2:
+ opname = "dpcs2";
+ break;
+ case 0x3:
+ opname = "dpcs3";
+ break;
+ }
+ break;
+ }
+ }
+
+ if (!opname)
+ return A64DOpcode::format();
+
+ appendInstructionName(opname);
+ appendUnsignedImmediate(immediate16());
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeExtract::format()
+{
+ if (!op21() || !o0Bit())
+ return A64DOpcode::format();
+
+ if (is64Bit() != nBit())
+ return A64DOpcode::format();
+
+ if (is64Bit() && (immediateS() & 0x20))
+ return A64DOpcode::format();
+
+ const char* opName = (rn() == rm()) ? "ror" : "extr";
+
+ appendInstructionName(opName);
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rm(), is64Bit());
+ appendSeparator();
+ appendUnsignedImmediate(immediateS());
+
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeFloatingPointCompare::format()
+{
+ if (mBit())
+ return A64DOpcode::format();
+
+ if (sBit())
+ return A64DOpcode::format();
+
+ if (type() & 0x2)
+ return A64DOpcode::format();
+
+ if (op())
+ return A64DOpcode::format();
+
+ if (opCode2() & 0x7)
+ return A64DOpcode::format();
+
+ appendInstructionName(opName());
+ unsigned registerSize = type() + 2;
+ appendFPRegisterName(rn(), registerSize);
+ appendSeparator();
+ if (opCode2() & 0x8)
+ bufferPrintf("#0.0");
+ else
+ appendFPRegisterName(rm(), registerSize);
+
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeFloatingPointDataProcessing1Source::s_opNames[16] = {
+ "fmov", "fabs", "fneg", "fsqrt", "fcvt", "fcvt", 0, "fcvt",
+ "frintn", "frintp", "frintm", "frintz", "frinta", 0, "frintx", "frinti"
+};
+
+const char* A64DOpcodeFloatingPointDataProcessing1Source::format()
+{
+ if (mBit())
+ return A64DOpcode::format();
+
+ if (sBit())
+ return A64DOpcode::format();
+
+ if (opNum() > 16)
+ return A64DOpcode::format();
+
+ switch (type()) {
+ case 0:
+ if ((opNum() == 0x4) || (opNum() == 0x6) || (opNum() == 0xd))
+ return A64DOpcode::format();
+ break;
+ case 1:
+ if ((opNum() == 0x5) || (opNum() == 0x6) || (opNum() == 0xd))
+ return A64DOpcode::format();
+ break;
+ case 2:
+ return A64DOpcode::format();
+ case 3:
+ if ((opNum() < 0x4) || (opNum() > 0x5))
+ return A64DOpcode::format();
+ break;
+ }
+
+ appendInstructionName(opName());
+ if ((opNum() >= 0x4) && (opNum() <= 0x7)) {
+ unsigned srcRegisterSize = type() ^ 0x2; // 0:s, 1:d & 3:h
+ unsigned destRegisterSize = (opNum() & 0x3) ^ 0x2;
+ appendFPRegisterName(rd(), destRegisterSize);
+ appendSeparator();
+ appendFPRegisterName(rn(), srcRegisterSize);
+ } else {
+ unsigned registerSize = type() + 2;
+ appendFPRegisterName(rd(), registerSize);
+ appendSeparator();
+ appendFPRegisterName(rn(), registerSize);
+ }
+
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeFloatingPointDataProcessing2Source::s_opNames[16] = {
+ "fmul", "fdiv", "fadd", "fsub", "fmax", "fmin", "fmaxnm", "fminnm", "fnmul"
+};
+
+const char* A64DOpcodeFloatingPointDataProcessing2Source::format()
+{
+ if (mBit())
+ return A64DOpcode::format();
+
+ if (sBit())
+ return A64DOpcode::format();
+
+ if (type() & 0x2)
+ return A64DOpcode::format();
+
+ if (opNum() > 8)
+ return A64DOpcode::format();
+
+ appendInstructionName(opName());
+ unsigned registerSize = type() + 2;
+ appendFPRegisterName(rd(), registerSize);
+ appendSeparator();
+ appendFPRegisterName(rn(), registerSize);
+ appendSeparator();
+ appendFPRegisterName(rm(), registerSize);
+
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeFloatingFixedPointConversions::s_opNames[4] = {
+ "fcvtzs", "fcvtzu", "scvtf", "ucvtf"
+};
+
+const char* A64DOpcodeFloatingFixedPointConversions::format()
+{
+ if (sBit())
+ return A64DOpcode::format();
+
+ if (type() & 0x2)
+ return A64DOpcode::format();
+
+ if (opcode() & 0x4)
+ return A64DOpcode::format();
+
+ if (!(rmode() & 0x1) && !(opcode() & 0x6))
+ return A64DOpcode::format();
+
+ if ((rmode() & 0x1) && (opcode() & 0x6) == 0x2)
+ return A64DOpcode::format();
+
+ if (!(rmode() & 0x2) && !(opcode() & 0x6))
+ return A64DOpcode::format();
+
+ if ((rmode() & 0x2) && (opcode() & 0x6) == 0x2)
+ return A64DOpcode::format();
+
+ if (!is64Bit() && scale() >= 32)
+ return A64DOpcode::format();
+
+ appendInstructionName(opName());
+ unsigned FPRegisterSize = type() + 2;
+ bool destIsFP = !rmode();
+
+ if (destIsFP) {
+ appendFPRegisterName(rd(), FPRegisterSize);
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ } else {
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendFPRegisterName(rn(), FPRegisterSize);
+ }
+ appendSeparator();
+ appendUnsignedImmediate(64 - scale());
+
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeFloatingPointIntegerConversions::s_opNames[32] = {
+ "fcvtns", "fcvtnu", "scvtf", "ucvtf", "fcvtas", "fcvtau", "fmov", "fmov",
+ "fcvtps", "fcvtpu", 0, 0, 0, 0, "fmov", "fmov",
+ "fcvtms", "fcvtmu", 0, 0, 0, 0, 0, 0,
+ "fcvtzs", "fcvtzu", 0, 0, 0, 0, 0, 0
+};
+
+const char* A64DOpcodeFloatingPointIntegerConversions::format()
+{
+ if (sBit())
+ return A64DOpcode::format();
+
+ if (type() == 0x3)
+ return A64DOpcode::format();
+
+ if (((rmode() & 0x1) || (rmode() & 0x2)) && (((opcode() & 0x6) == 0x2) || ((opcode() & 0x6) == 0x4)))
+ return A64DOpcode::format();
+
+ if ((type() == 0x2) && (!(opcode() & 0x4) || ((opcode() & 0x6) == 0x4)))
+ return A64DOpcode::format();
+
+ if (!type() && (rmode() & 0x1) && ((opcode() & 0x6) == 0x6))
+ return A64DOpcode::format();
+
+ if (is64Bit() && type() == 0x2 && ((opNum() & 0xe) == 0x6))
+ return A64DOpcode::format();
+
+ if (!opName())
+ return A64DOpcode::format();
+
+ if ((opNum() & 0x1e) == 0xe) {
+ // Handle fmov to/from upper half of quad separately
+ if (!is64Bit() || (type() != 0x2))
+ return A64DOpcode::format();
+
+ appendInstructionName(opName());
+ if (opcode() & 0x1) {
+ // fmov Vd.D[1], Xn
+ bufferPrintf("V%u.D[1]", rd());
+ appendSeparator();
+ appendRegisterName(rn());
+ } else {
+ // fmov Xd, Vn.D[1]
+ appendRegisterName(rd());
+ appendSeparator();
+ bufferPrintf("V%u.D[1]", rn());
+ }
+
+ return m_formatBuffer;
+ }
+
+ appendInstructionName(opName());
+ unsigned FPRegisterSize = type() + 2;
+ bool destIsFP = ((opNum() == 2) || (opNum() == 3) || (opNum() == 7));
+
+ if (destIsFP) {
+ appendFPRegisterName(rd(), FPRegisterSize);
+ appendSeparator();
+ appendRegisterName(rn(), is64Bit());
+ } else {
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendFPRegisterName(rn(), FPRegisterSize);
+ }
+
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeHint::s_opNames[6] = {
+ "nop", "yield", "wfe", "wfi", "sev", "sevl"
+};
+
+const char* A64DOpcodeHint::format()
+{
+ appendInstructionName(opName());
+
+ if (immediate7() > 5)
+ appendUnsignedImmediate(immediate7());
+
+ return m_formatBuffer;
+}
+
+// A zero in an entry of the table means the instruction is Unallocated
+const char* const A64DOpcodeLoadStore::s_opNames[32] = {
+ "strb", "ldrb", "ldrsb", "ldrsb", "str", "ldr", "str", "ldr",
+ "strh", "ldrh", "ldrsh", "ldrsh", "str", "ldr", 0, 0,
+ "str", "ldr", "ldrsw", 0, "str", "ldr", 0, 0,
+ "str", "ldr", 0, 0, "str", "ldr", 0, 0
+};
+
+// A zero in an entry of the table means the instruction is Unallocated
+const char* const A64DOpcodeLoadStoreImmediate::s_unprivilegedOpNames[32] = {
+ "sttrb", "ldtrb", "ldtrsb", "ldtrsb", 0, 0, 0, 0,
+ "sttrh", "ldtrh", "ldtrsh", "ldtrsh", 0, 0, 0, 0,
+ "sttr", "ldtr", "ldtrsw", 0, 0, 0, 0, 0,
+ "sttr", "ldtr", 0, 0, 0, 0, 0, 0
+};
+
+// A zero in an entry of the table means the instruction is Unallocated
+const char* const A64DOpcodeLoadStoreImmediate::s_unscaledOpNames[32] = {
+ "sturb", "ldurb", "ldursb", "ldursb", "stur", "ldur", "stur", "ldur",
+ "sturh", "ldurh", "ldursh", "ldursh", "stur", "ldur", 0, 0,
+ "stur", "ldur", "ldursw", 0, "stur", "ldur", 0, 0,
+ "stur", "ldur", "prfum", 0, "stur", "ldur", 0, 0
+};
+
+const char* A64DOpcodeLoadStoreImmediate::format()
+{
+ const char* thisOpName;
+
+ if (type() & 0x1)
+ thisOpName = opName();
+ else if (!type())
+ thisOpName = unscaledOpName();
+ else
+ thisOpName = unprivilegedOpName();
+
+ if (!thisOpName)
+ return A64DOpcode::format();
+
+ appendInstructionName(thisOpName);
+ if (vBit())
+ appendFPRegisterName(rt(), size());
+ else
+ appendRegisterName(rt(), is64BitRT());
+ appendSeparator();
+ appendCharacter('[');
+ appendSPOrRegisterName(rn());
+
+ switch (type()) {
+ case 0: // Unscaled Immediate
+ if (immediate9()) {
+ appendSeparator();
+ appendSignedImmediate(immediate9());
+ }
+ appendCharacter(']');
+ break;
+ case 1: // Immediate Post-Indexed
+ appendCharacter(']');
+ if (immediate9()) {
+ appendSeparator();
+ appendSignedImmediate(immediate9());
+ }
+ break;
+ case 2: // Unprivileged
+ if (immediate9()) {
+ appendSeparator();
+ appendSignedImmediate(immediate9());
+ }
+ appendCharacter(']');
+ break;
+ case 3: // Immediate Pre-Indexed
+ if (immediate9()) {
+ appendSeparator();
+ appendSignedImmediate(immediate9());
+ }
+ appendCharacter(']');
+ appendCharacter('!');
+ break;
+ }
+
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeLoadStoreRegisterOffset::format()
+{
+ const char* thisOpName = opName();
+
+ if (!thisOpName)
+ return A64DOpcode::format();
+
+ if (!(option() & 0x2))
+ return A64DOpcode::format();
+
+ appendInstructionName(thisOpName);
+ unsigned scale;
+ if (vBit()) {
+ appendFPRegisterName(rt(), size());
+ scale = ((opc() & 2)<<1) | size();
+ } else {
+ appendRegisterName(rt(), is64BitRT());
+ scale = size();
+ }
+ appendSeparator();
+ appendCharacter('[');
+ appendSPOrRegisterName(rn());
+ appendSeparator();
+ appendZROrRegisterName(rm(), (option() & 0x3) == 0x3);
+
+ unsigned shift = sBit() ? scale : 0;
+
+ if (option() == 0x3) {
+ if (shift) {
+ appendSeparator();
+ appendString("lsl ");
+ appendUnsignedImmediate(shift);
+ }
+ } else {
+ appendSeparator();
+ appendString(optionName());
+ if (shift)
+ appendUnsignedImmediate(shift);
+ }
+
+ appendCharacter(']');
+
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeLoadStoreRegisterPair::opName()
+{
+ if (!vBit() && lBit() && size() == 0x1)
+ return "ldpsw";
+ if (lBit())
+ return "ldp";
+ return "stp";
+}
+
+const char* A64DOpcodeLoadStoreRegisterPair::format()
+{
+ const char* thisOpName = opName();
+
+ if (size() == 0x3)
+ return A64DOpcode::format();
+
+ if ((offsetMode() < 0x1) || (offsetMode() > 0x3))
+ return A64DOpcode::format();
+
+ if ((offsetMode() == 0x1) && !vBit() && !lBit())
+ return A64DOpcode::format();
+
+ appendInstructionName(thisOpName);
+ unsigned offsetShift;
+ if (vBit()) {
+ appendFPRegisterName(rt(), size());
+ appendSeparator();
+ appendFPRegisterName(rt2(), size());
+ offsetShift = size() + 2;
+ } else {
+ appendRegisterName(rt(), is64Bit());
+ appendSeparator();
+ appendRegisterName(rt2(), is64Bit());
+ offsetShift = (size() >> 1) + 2;
+ }
+
+ appendSeparator();
+ appendCharacter('[');
+ appendSPOrRegisterName(rn());
+
+ int offset = immediate7() << offsetShift;
+
+ if (offsetMode() == 1) {
+ appendCharacter(']');
+ appendSeparator();
+ appendSignedImmediate(offset);
+ } else {
+ appendSeparator();
+ appendSignedImmediate(offset);
+ appendCharacter(']');
+ if (offsetMode() == 0x3)
+ appendCharacter('!');
+ }
+
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeLoadStoreUnsignedImmediate::format()
+{
+ const char* thisOpName = opName();
+
+ if (!thisOpName)
+ return A64DOpcode::format();
+
+ appendInstructionName(thisOpName);
+ unsigned scale;
+ if (vBit()) {
+ appendFPRegisterName(rt(), size());
+ scale = ((opc() & 2)<<1) | size();
+ } else {
+ appendRegisterName(rt(), is64BitRT());
+ scale = size();
+ }
+ appendSeparator();
+ appendCharacter('[');
+ appendSPOrRegisterName(rn());
+
+ if (immediate12()) {
+ appendSeparator();
+ appendUnsignedImmediate(immediate12() << scale);
+ }
+
+ appendCharacter(']');
+
+ return m_formatBuffer;
+}
+
+// A zero in an entry of the table means the instruction is Unallocated
+const char* const A64DOpcodeLogical::s_opNames[8] = {
+ "and", "bic", "orr", "orn", "eor", "eon", "ands", "bics"
+};
+
+const char* A64DOpcodeLogicalShiftedRegister::format()
+{
+ if (!is64Bit() && immediate6() & 0x20)
+ return A64DOpcode::format();
+
+ if (isTst())
+ appendInstructionName("tst");
+ else {
+ if (isMov())
+ appendInstructionName("mov");
+ else
+ appendInstructionName(opName(opNumber()));
+ appendSPOrRegisterName(rd(), is64Bit());
+ appendSeparator();
+ }
+
+ if (!isMov()) {
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ }
+
+ appendZROrRegisterName(rm(), is64Bit());
+ if (immediate6()) {
+ appendSeparator();
+ appendShiftType(shift());
+ appendUnsignedImmediate(immediate6());
+ }
+
+ return m_formatBuffer;
+}
+
+static unsigned highestBitSet(unsigned value)
+{
+ unsigned result = 0;
+
+ while (value >>= 1)
+ result++;
+
+ return result;
+}
+
+static uint64_t rotateRight(uint64_t value, unsigned width, unsigned shift)
+{
+ uint64_t result = value;
+
+ if (shift)
+ result = (value >> (shift % width)) | (value << (width - shift));
+
+ return result;
+}
+
+static uint64_t replicate(uint64_t value, unsigned width)
+{
+ uint64_t result = 0;
+
+ for (unsigned totalBits = 0; totalBits < 64; totalBits += width)
+ result = (result << width) | value;
+
+ return result;
+}
+
+const char* A64DOpcodeLogicalImmediate::format()
+{
+ if (!is64Bit() && nBit())
+ return A64DOpcode::format();
+
+ unsigned len = highestBitSet(nBit() << 6 | (immediateS() ^ 0x3f));
+ unsigned levels = (1 << len) - 1; // len number of 1 bits starting at LSB
+
+ if ((immediateS() & levels) == levels)
+ return A64DOpcode::format();
+
+ unsigned r = immediateR() & levels;
+ unsigned s = immediateS() & levels;
+ unsigned eSize = 1 << len;
+ uint64_t pattern = rotateRight((1ull << (s + 1)) - 1, eSize, r);
+
+ uint64_t immediate = replicate(pattern, eSize);
+
+ if (!is64Bit())
+ immediate &= 0xffffffffull;
+
+ if (isTst())
+ appendInstructionName("tst");
+ else {
+ if (isMov())
+ appendInstructionName("mov");
+ else
+ appendInstructionName(opName(opNumber()));
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ }
+ if (!isMov()) {
+ appendRegisterName(rn(), is64Bit());
+ appendSeparator();
+ }
+ appendUnsignedImmediate64(immediate);
+
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeMoveWide::s_opNames[4] = { "movn", "", "movz", "movk" };
+
+const char* A64DOpcodeMoveWide::format()
+{
+ if (opc() == 1)
+ return A64DOpcode::format();
+ if (!size() && hw() >= 2)
+ return A64DOpcode::format();
+
+ appendInstructionName(opName());
+ appendRegisterName(rd(), is64Bit());
+ appendSeparator();
+ appendUnsignedImmediate(immediate16());
+ if (hw()) {
+ appendSeparator();
+ appendShiftAmount(hw());
+ }
+
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeTestAndBranchImmediate::format()
+{
+ appendInstructionName(opBit() ? "tbnz" : "tbz");
+ appendRegisterName(rt());
+ appendSeparator();
+ appendUnsignedImmediate(bitNumber());
+ appendSeparator();
+ appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate14()));
+ return m_formatBuffer;
+}
+
+const char* A64DOpcodeUnconditionalBranchImmediate::format()
+{
+ appendInstructionName(op() ? "bl" : "b");
+ appendPCRelativeOffset(m_currentPC, static_cast<int32_t>(immediate26()));
+ return m_formatBuffer;
+}
+
+const char* const A64DOpcodeUnconditionalBranchRegister::s_opNames[8] = { "br", "blr", "ret", "", "eret", "drps", "", "" };
+
+const char* A64DOpcodeUnconditionalBranchRegister::format()
+{
+ unsigned opcValue = opc();
+ if (opcValue == 3 || opcValue > 5)
+ return A64DOpcode::format();
+ if (((opcValue & 0xe) == 0x4) && rn() != 0x1f)
+ return A64DOpcode::format();
+ appendInstructionName(opName());
+ if (opcValue <= 2)
+ appendRegisterName(rn());
+ return m_formatBuffer;
+}
+
+} } // namespace JSC::ARM64Disassembler
+
+#endif // USE(ARM64_DISASSEMBLER)
diff --git a/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.h b/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.h
new file mode 100644
index 000000000..5bb7db9f1
--- /dev/null
+++ b/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.h
@@ -0,0 +1,708 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef A64DOpcode_h
+#define A64DOpcode_h
+
+#include <wtf/Assertions.h>
+#include <stdint.h>
+
+namespace JSC { namespace ARM64Disassembler {
+
+class A64DOpcode {
+private:
+ class OpcodeGroup {
+ public:
+ OpcodeGroup(uint32_t opcodeMask, uint32_t opcodePattern, const char* (*format)(A64DOpcode*))
+ : m_opcodeMask(opcodeMask)
+ , m_opcodePattern(opcodePattern)
+ , m_format(format)
+ , m_next(0)
+ {
+ }
+
+ void setNext(OpcodeGroup* next)
+ {
+ m_next = next;
+ }
+
+ OpcodeGroup* next()
+ {
+ return m_next;
+ }
+
+ bool matches(uint32_t opcode)
+ {
+ return (opcode & m_opcodeMask) == m_opcodePattern;
+ }
+
+ const char* format(A64DOpcode* thisObj)
+ {
+ return m_format(thisObj);
+ }
+
+ private:
+ uint32_t m_opcodeMask;
+ uint32_t m_opcodePattern;
+ const char* (*m_format)(A64DOpcode*);
+ OpcodeGroup* m_next;
+ };
+
+public:
+ static void init();
+
+ A64DOpcode()
+ : m_opcode(0)
+ , m_bufferOffset(0)
+ {
+ init();
+ m_formatBuffer[0] = '\0';
+ }
+
+ const char* disassemble(uint32_t* currentPC);
+
+protected:
+ void setPCAndOpcode(uint32_t*, uint32_t);
+ const char* format();
+
+ static const char* const s_conditionNames[16];
+ static const char* const s_shiftNames[4];
+ static const char* const s_optionName[8];
+ static const char s_FPRegisterPrefix[5];
+
+ static const char* conditionName(unsigned condition) { return s_conditionNames[condition & 0xf]; }
+ static const char* shiftName(unsigned shiftValue) { return s_shiftNames[shiftValue & 0x3]; }
+ const char* optionName() { return s_optionName[option()]; }
+ static char FPRegisterPrefix(unsigned FPRegisterSize)
+ {
+ if (FPRegisterSize > 4)
+ FPRegisterSize = 4;
+ return s_FPRegisterPrefix[FPRegisterSize];
+ }
+
+ unsigned opcodeGroupNumber(uint32_t opcode) { return (opcode >> 24) & 0x1f; }
+
+ bool is64Bit() { return m_opcode & 0x80000000; }
+ unsigned size() { return m_opcode >> 30; }
+ unsigned option() { return (m_opcode >> 13) & 0x7; }
+ unsigned rd() { return m_opcode & 0x1f; }
+ unsigned rt() { return m_opcode & 0x1f; }
+ unsigned rn() { return (m_opcode >> 5) & 0x1f; }
+ unsigned rm() { return (m_opcode >> 16) & 0x1f; }
+
+ void bufferPrintf(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
+
+ void appendInstructionName(const char* instructionName)
+ {
+ bufferPrintf(" %-7.7s", instructionName);
+ }
+
+ void appendRegisterName(unsigned registerNumber, bool is64Bit = true);
+ void appendSPOrRegisterName(unsigned registerNumber, bool is64Bit = true)
+ {
+ if (registerNumber == 31) {
+ bufferPrintf(is64Bit ? "sp" : "wsp");
+ return;
+ }
+ appendRegisterName(registerNumber, is64Bit);
+ }
+
+ void appendZROrRegisterName(unsigned registerNumber, bool is64Bit = true)
+ {
+ if (registerNumber == 31) {
+ bufferPrintf(is64Bit ? "xzr" : "wzr");
+ return;
+ }
+ appendRegisterName(registerNumber, is64Bit);
+ }
+
+ void appendFPRegisterName(unsigned registerNumber, unsigned registerSize);
+
+ void appendSeparator()
+ {
+ bufferPrintf(", ");
+ }
+
+ void appendCharacter(const char c)
+ {
+ bufferPrintf("%c", c);
+ }
+
+ void appendString(const char* string)
+ {
+ bufferPrintf("%s", string);
+ }
+
+ void appendShiftType(unsigned shiftValue)
+ {
+ bufferPrintf("%s ", shiftName(shiftValue));
+ }
+
+ void appendSignedImmediate(int immediate)
+ {
+ bufferPrintf("#%d", immediate);
+ }
+
+ void appendUnsignedImmediate(unsigned immediate)
+ {
+ bufferPrintf("#%u", immediate);
+ }
+
+ void appendUnsignedImmediate64(uint64_t immediate)
+ {
+ bufferPrintf("#0x%" PRIx64, immediate);
+ }
+
+ void appendPCRelativeOffset(uint32_t* pc, int32_t immediate)
+ {
+ bufferPrintf("0x%" PRIx64, reinterpret_cast<uint64_t>(pc + immediate));
+ }
+
+ void appendShiftAmount(unsigned amount)
+ {
+ bufferPrintf("lsl #%u", 16 * amount);
+ }
+
+ static const int bufferSize = 81;
+
+ char m_formatBuffer[bufferSize];
+ uint32_t* m_currentPC;
+ uint32_t m_opcode;
+ int m_bufferOffset;
+
+private:
+ static OpcodeGroup* opcodeTable[32];
+
+ static bool s_initialized;
+};
+
+#define DEFINE_STATIC_FORMAT(klass, thisObj) \
+ static const char* format(A64DOpcode* thisObj) { return reinterpret_cast< klass *>(thisObj)->format(); }
+
+class A64DOpcodeAddSubtract : public A64DOpcode {
+private:
+ static const char* const s_opNames[4];
+
+public:
+ const char* opName() { return s_opNames[opAndS()]; }
+ const char* cmpName() { return op() ? "cmp" : "cmn"; }
+
+ bool isCMP() { return (sBit() && rd() == 31); }
+ unsigned op() { return (m_opcode >> 30) & 0x1; }
+ unsigned sBit() { return (m_opcode >> 29) & 0x1; }
+ unsigned opAndS() { return (m_opcode >> 29) & 0x3; }
+};
+
+class A64DOpcodeAddSubtractImmediate : public A64DOpcodeAddSubtract {
+public:
+ static const uint32_t mask = 0x1f000000;
+ static const uint32_t pattern = 0x11000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractImmediate, thisObj);
+
+ const char* format();
+
+ bool isMovSP() { return (!opAndS() && !immed12() && ((rd() == 31) || rn() == 31)); }
+ unsigned shift() { return (m_opcode >> 22) & 0x3; }
+ unsigned immed12() { return (m_opcode >> 10) & 0xfff; }
+};
+
+class A64DOpcodeAddSubtractExtendedRegister : public A64DOpcodeAddSubtract {
+public:
+ static const uint32_t mask = 0x1fe00000;
+ static const uint32_t pattern = 0x0b200000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractExtendedRegister, thisObj);
+
+ const char* format();
+
+ unsigned immediate3() { return (m_opcode >> 10) & 0x7; }
+};
+
+class A64DOpcodeAddSubtractShiftedRegister : public A64DOpcodeAddSubtract {
+public:
+ static const uint32_t mask = 0x1f200000;
+ static const uint32_t pattern = 0x0b000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeAddSubtractShiftedRegister, thisObj);
+
+ const char* format();
+
+ bool isNeg() { return (op() && rn() == 31); }
+ const char* negName() { return sBit() ? "negs" : "neg"; }
+ unsigned shift() { return (m_opcode >> 22) & 0x3; }
+ int immediate6() { return (static_cast<int>((m_opcode >> 10) & 0x3f) << 26) >> 26; }
+};
+
+class A64DOpcodeBitfield : public A64DOpcode {
+private:
+ static const char* const s_opNames[3];
+ static const char* const s_extendPseudoOpNames[3][3];
+ static const char* const s_insertOpNames[3];
+ static const char* const s_extractOpNames[3];
+
+public:
+ static const uint32_t mask = 0x1f800000;
+ static const uint32_t pattern = 0x13000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeBitfield, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opc()]; }
+ const char* extendPseudoOpNames(unsigned opSize) { return s_extendPseudoOpNames[opc()][opSize]; }
+ const char* insertOpNames() { return s_insertOpNames[opc()]; }
+ const char* extractOpNames() { return s_extractOpNames[opc()]; }
+
+ unsigned opc() { return (m_opcode >> 29) & 0x3; }
+ unsigned nBit() { return (m_opcode >> 22) & 0x1; }
+ unsigned immediateR() { return (m_opcode >> 16) & 0x3f; }
+ unsigned immediateS() { return (m_opcode >> 10) & 0x3f; }
+};
+
+class A64DOpcodeCompareAndBranchImmediate : public A64DOpcode {
+public:
+ static const uint32_t mask = 0x7e000000;
+ static const uint32_t pattern = 0x34000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeCompareAndBranchImmediate, thisObj);
+
+ const char* format();
+
+ unsigned opBit() { return (m_opcode >> 24) & 0x1; }
+ int immediate19() { return (static_cast<int>((m_opcode >> 5) & 0x7ffff) << 13) >> 13; }
+};
+
+class A64DOpcodeConditionalBranchImmediate : public A64DOpcode {
+public:
+ static const uint32_t mask = 0xff000010;
+ static const uint32_t pattern = 0x54000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeConditionalBranchImmediate, thisObj);
+
+ const char* format();
+
+ unsigned condition() { return m_opcode & 0xf; }
+ int immediate19() { return (static_cast<int>((m_opcode >> 5) & 0x7ffff) << 13) >> 13; }
+};
+
+class A64DOpcodeConditionalSelect : public A64DOpcode {
+private:
+ static const char* const s_opNames[4];
+
+public:
+ static const uint32_t mask = 0x1fe00010;
+ static const uint32_t pattern = 0x1a800000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeConditionalSelect, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNum()]; }
+ unsigned opNum() { return (op() << 1 | (op2() & 0x1)); }
+ unsigned op() { return (m_opcode >> 30) & 0x1; }
+ unsigned sBit() { return (m_opcode >> 29) & 0x1; }
+ unsigned condition() { return (m_opcode >> 12) & 0xf; }
+ unsigned op2() { return (m_opcode >> 10) & 0x3; }
+};
+
+class A64DOpcodeDataProcessing2Source : public A64DOpcode {
+private:
+ static const char* const s_opNames[8];
+
+public:
+ static const uint32_t mask = 0x5fe00000;
+ static const uint32_t pattern = 0x1ac00000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeDataProcessing2Source, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNameIndex()]; }
+ unsigned sBit() { return (m_opcode >> 29) & 0x1; }
+ unsigned opCode() { return (m_opcode >> 10) & 0x3f; }
+ unsigned opNameIndex() { return ((m_opcode >> 11) & 0x4) | ((m_opcode >> 10) & 0x3); }
+};
+
+class A64DOpcodeDataProcessing3Source : public A64DOpcode {
+private:
+ static const char* const s_opNames[16];
+ static const char* const s_pseudoOpNames[16];
+
+public:
+ static const uint32_t mask = 0x1f000000;
+ static const uint32_t pattern = 0x1b000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeDataProcessing3Source, thisObj);
+
+ const char* format();
+
+ const char* opName() { return ra() == 31 ? s_opNames[opNum() & 0xf] : s_pseudoOpNames[opNum() & 0xf]; }
+ unsigned ra() { return (m_opcode >> 10) & 0x1f; }
+ unsigned op54() { return (m_opcode >> 29) & 0x3; }
+ unsigned op31() { return (m_opcode >> 21) & 0x7; }
+ unsigned op0() { return (m_opcode >> 15) & 0x1; }
+ unsigned opNum() { return ((m_opcode >> 25) & 0x30) | ((m_opcode >> 20) & 0xe) | ((m_opcode >> 15) & 0x1); }
+};
+
+class A64OpcodeExceptionGeneration : public A64DOpcode {
+public:
+ static const uint32_t mask = 0xff000010;
+ static const uint32_t pattern = 0xd4000000;
+
+ DEFINE_STATIC_FORMAT(A64OpcodeExceptionGeneration, thisObj);
+
+ const char* format();
+
+ unsigned opc() { return (m_opcode>>21) & 0x7; }
+ unsigned op2() { return (m_opcode>>2) & 0x7; }
+ unsigned ll() { return m_opcode & 0x3; }
+ int immediate16() { return (static_cast<int>((m_opcode >> 5) & 0xffff) << 16) >> 16; }
+};
+
+class A64DOpcodeExtract : public A64DOpcode {
+public:
+ static const uint32_t mask = 0x1f800000;
+ static const uint32_t pattern = 0x13800000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeExtract, thisObj);
+
+ const char* format();
+
+ unsigned op21() { return (m_opcode >> 29) & 0x3; }
+ unsigned nBit() { return (m_opcode >> 22) & 0x1; }
+ unsigned o0Bit() { return (m_opcode >> 21) & 0x1; }
+ unsigned immediateS() { return (m_opcode >> 10) & 0x3f; }
+};
+
+class A64DOpcodeFloatingPointOps : public A64DOpcode {
+public:
+ unsigned mBit() { return (m_opcode >> 31) & 0x1; }
+ unsigned sBit() { return (m_opcode >> 29) & 0x1; }
+ unsigned type() { return (m_opcode >> 22) & 0x3; }
+};
+
+class A64DOpcodeFloatingPointCompare : public A64DOpcodeFloatingPointOps {
+private:
+ static const char* const s_opNames[16];
+
+public:
+ static const uint32_t mask = 0x5f203c00;
+ static const uint32_t pattern = 0x1e202000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointCompare, thisObj);
+
+ const char* format();
+
+ const char* opName() { return (opNum() & 0x2) ? "fcmpe" : "fcmp"; }
+
+ unsigned op() { return (m_opcode >> 14) & 0x3; }
+ unsigned opCode2() { return m_opcode & 0x1f; }
+ unsigned opNum() { return (m_opcode >> 3) & 0x3; }
+};
+
+class A64DOpcodeFloatingPointDataProcessing1Source : public A64DOpcodeFloatingPointOps {
+private:
+ static const char* const s_opNames[16];
+
+public:
+ static const uint32_t mask = 0x5f207c00;
+ static const uint32_t pattern = 0x1e204000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointDataProcessing1Source, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNum()]; }
+
+ unsigned opNum() { return (m_opcode >> 15) & 0x3f; }
+};
+
+class A64DOpcodeFloatingPointDataProcessing2Source : public A64DOpcodeFloatingPointOps {
+private:
+ static const char* const s_opNames[16];
+
+public:
+ static const uint32_t mask = 0x5f200800;
+ static const uint32_t pattern = 0x1e200800;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointDataProcessing2Source, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNum()]; }
+
+ unsigned opNum() { return (m_opcode >> 12) & 0xf; }
+};
+
+class A64DOpcodeFloatingFixedPointConversions : public A64DOpcodeFloatingPointOps {
+private:
+ static const char* const s_opNames[4];
+
+public:
+ static const uint32_t mask = 0x5f200000;
+ static const uint32_t pattern = 0x1e000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeFloatingFixedPointConversions, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNum()]; }
+ unsigned rmode() { return (m_opcode >> 19) & 0x3; }
+ unsigned opcode() { return (m_opcode >> 16) & 0x7; }
+ unsigned scale() { return (m_opcode >> 10) & 0x3f; }
+ unsigned opNum() { return (m_opcode >> 16) & 0x3; }
+};
+
+class A64DOpcodeFloatingPointIntegerConversions : public A64DOpcodeFloatingPointOps {
+private:
+ static const char* const s_opNames[32];
+
+public:
+ static const uint32_t mask = 0x5f20fc00;
+ static const uint32_t pattern = 0x1e200000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeFloatingPointIntegerConversions, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opNum()]; }
+ unsigned rmode() { return (m_opcode >> 19) & 0x3; }
+ unsigned opcode() { return (m_opcode >> 16) & 0x7; }
+ unsigned opNum() { return (m_opcode >> 16) & 0x1f; }
+};
+
+class A64DOpcodeHint : public A64DOpcode {
+private:
+ static const char* const s_opNames[6];
+
+public:
+ static const uint32_t mask = 0xfffff01f;
+ static const uint32_t pattern = 0xd503201f;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeHint, thisObj);
+
+ const char* format();
+
+ const char* opName() { return immediate7() <= 5 ? s_opNames[immediate7()] : "hint"; }
+ unsigned immediate7() { return (m_opcode >> 5) & 0x7f; }
+};
+
+class A64DOpcodeLoadStore : public A64DOpcode {
+private:
+ static const char* const s_opNames[32];
+
+protected:
+ const char* opName()
+ {
+ return s_opNames[opNumber()];
+ }
+
+ unsigned size() { return (m_opcode >> 30) & 0x3; }
+ unsigned vBit() { return (m_opcode >> 26) & 0x1; }
+ unsigned opc() { return (m_opcode >> 22) & 0x3; }
+ unsigned opNumber() { return (size() <<3 ) | (vBit() << 2) | opc(); }
+ bool is64BitRT() { return ((opNumber() & 0x17) == 0x02) || ((opNumber() & 0x1e) == 0x18); }
+};
+
+class A64DOpcodeLoadStoreImmediate : public A64DOpcodeLoadStore {
+private:
+ static const char* const s_unprivilegedOpNames[32];
+ static const char* const s_unscaledOpNames[32];
+
+public:
+ static const uint32_t mask = 0x3b200000;
+ static const uint32_t pattern = 0x38000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreImmediate, thisObj);
+
+ const char* format();
+
+ const char* unprivilegedOpName()
+ {
+ return s_unprivilegedOpNames[opNumber()];
+ }
+ const char* unscaledOpName()
+ {
+ return s_unscaledOpNames[opNumber()];
+ }
+ unsigned type() { return (m_opcode >> 10) & 0x3; }
+ int immediate9() { return (static_cast<int>((m_opcode >> 12) & 0x1ff) << 23) >> 23; }
+};
+
+class A64DOpcodeLoadStoreRegisterOffset : public A64DOpcodeLoadStore {
+public:
+ static const uint32_t mask = 0x3b200c00;
+ static const uint32_t pattern = 0x38200800;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreRegisterOffset, thisObj);
+
+ const char* format();
+
+ unsigned option() { return (m_opcode >> 13) & 0x7; }
+ int sBit() { return (m_opcode >> 12) & 0x1; }
+};
+
+class A64DOpcodeLoadStoreRegisterPair : public A64DOpcodeLoadStore {
+public:
+ static const uint32_t mask = 0x3a000000;
+ static const uint32_t pattern = 0x28000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreRegisterPair, thisObj);
+
+ const char* format();
+ const char* opName();
+
+ unsigned rt2() { return (m_opcode >> 10) & 0x1f; }
+ int immediate7() { return (static_cast<int>((m_opcode >> 15) & 0x7f) << 25) >> 25; }
+ unsigned offsetMode() { return (m_opcode >> 23) & 0x7; }
+ int lBit() { return (m_opcode >> 22) & 0x1; }
+};
+
+class A64DOpcodeLoadStoreUnsignedImmediate : public A64DOpcodeLoadStore {
+public:
+ static const uint32_t mask = 0x3b000000;
+ static const uint32_t pattern = 0x39000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreUnsignedImmediate, thisObj);
+
+ const char* format();
+
+ unsigned immediate12() { return (m_opcode >> 10) & 0xfff; }
+};
+
+class A64DOpcodeLogical : public A64DOpcode {
+private:
+ static const char* const s_opNames[8];
+
+public:
+ const char* opName(unsigned opNumber)
+ {
+ return s_opNames[opNumber & 0x7];
+ }
+
+ unsigned opc() { return (m_opcode >> 29) & 0x3; }
+ unsigned nBit() { return (m_opcode >> 21) & 0x1; }
+};
+
+class A64DOpcodeLogicalImmediate : public A64DOpcodeLogical {
+public:
+ static const uint32_t mask = 0x1f800000;
+ static const uint32_t pattern = 0x12000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLogicalImmediate, thisObj);
+
+ const char* format();
+
+ bool isTst() { return ((opNumber() == 6) && (rd() == 31)); }
+ bool isMov() { return ((opNumber() == 2) && (rn() == 31)); }
+ unsigned opNumber() { return opc() << 1; }
+ unsigned nBit() { return (m_opcode >> 22) & 0x1; }
+ unsigned immediateR() { return (m_opcode >> 16) & 0x3f; }
+ unsigned immediateS() { return (m_opcode >> 10) & 0x3f; }
+};
+
+class A64DOpcodeLogicalShiftedRegister : public A64DOpcodeLogical {
+public:
+ static const uint32_t mask = 0x1f000000;
+ static const uint32_t pattern = 0x0a000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeLogicalShiftedRegister, thisObj);
+
+ const char* format();
+
+ bool isTst() { return ((opNumber() == 6) && (rd() == 31)); }
+ bool isMov() { return ((opNumber() == 2) && (rn() == 31)); }
+ unsigned opNumber() { return (opc() << 1) | nBit(); }
+ unsigned shift() { return (m_opcode >> 22) & 0x3; }
+ int immediate6() { return (static_cast<int>((m_opcode >> 10) & 0x3f) << 26) >> 26; }
+};
+
+class A64DOpcodeMoveWide : public A64DOpcode {
+private:
+ static const char* const s_opNames[4];
+
+public:
+ static const uint32_t mask = 0x1f800000;
+ static const uint32_t pattern = 0x12800000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeMoveWide, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opc()]; }
+ unsigned opc() { return (m_opcode >> 29) & 0x3; }
+ unsigned hw() { return (m_opcode >> 21) & 0x3; }
+ unsigned immediate16() { return (m_opcode >> 5) & 0xffff; }
+};
+
+class A64DOpcodeTestAndBranchImmediate : public A64DOpcode {
+public:
+ static const uint32_t mask = 0x7e000000;
+ static const uint32_t pattern = 0x36000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeTestAndBranchImmediate, thisObj);
+
+ const char* format();
+
+ unsigned bitNumber() { return ((m_opcode >> 26) & 0x20) | ((m_opcode >> 19) & 0x1f); }
+ unsigned opBit() { return (m_opcode >> 24) & 0x1; }
+ int immediate14() { return (static_cast<int>((m_opcode >> 5) & 0x3fff) << 18) >> 18; }
+};
+
+class A64DOpcodeUnconditionalBranchImmediate : public A64DOpcode {
+public:
+ static const uint32_t mask = 0x7c000000;
+ static const uint32_t pattern = 0x14000000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeUnconditionalBranchImmediate, thisObj);
+
+ const char* format();
+
+ unsigned op() { return (m_opcode >> 31) & 0x1; }
+ int immediate26() { return (static_cast<int>(m_opcode & 0x3ffffff) << 6) >> 6; }
+};
+
+class A64DOpcodeUnconditionalBranchRegister : public A64DOpcode {
+private:
+ static const char* const s_opNames[8];
+
+public:
+ static const uint32_t mask = 0xfe1ffc1f;
+ static const uint32_t pattern = 0xd61f0000;
+
+ DEFINE_STATIC_FORMAT(A64DOpcodeUnconditionalBranchRegister, thisObj);
+
+ const char* format();
+
+ const char* opName() { return s_opNames[opc()]; }
+ unsigned opc() { return (m_opcode >> 21) & 0xf; }
+};
+
+} } // namespace JSC::ARM64Disassembler
+
+using JSC::ARM64Disassembler::A64DOpcode;
+
+#endif // A64DOpcode_h
diff --git a/Source/JavaScriptCore/disassembler/ARM64Disassembler.cpp b/Source/JavaScriptCore/disassembler/ARM64Disassembler.cpp
new file mode 100644
index 000000000..ac52213df
--- /dev/null
+++ b/Source/JavaScriptCore/disassembler/ARM64Disassembler.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012, 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Disassembler.h"
+
+#if USE(ARM64_DISASSEMBLER)
+
+#include "ARM64/A64DOpcode.h"
+#include "MacroAssemblerCodeRef.h"
+
+namespace JSC {
+
+bool tryToDisassemble(const MacroAssemblerCodePtr& codePtr, size_t size, const char* prefix, PrintStream& out)
+{
+ A64DOpcode arm64Opcode;
+
+ uint32_t* currentPC = reinterpret_cast<uint32_t*>(codePtr.executableAddress());
+ size_t byteCount = size;
+
+ while (byteCount) {
+ char pcString[20];
+ snprintf(pcString, sizeof(pcString), "0x%lx", reinterpret_cast<unsigned long>(currentPC));
+ out.printf("%s%16s: %s\n", prefix, pcString, arm64Opcode.disassemble(currentPC));
+ currentPC++;
+ byteCount -= sizeof(uint32_t);
+ }
+
+ return true;
+}
+
+} // namespace JSC
+
+#endif // USE(ARM64_DISASSEMBLER)
+
diff --git a/Source/JavaScriptCore/disassembler/ARMv7/ARMv7DOpcode.cpp b/Source/JavaScriptCore/disassembler/ARMv7/ARMv7DOpcode.cpp
index fb6e0db83..3175cccbd 100644
--- a/Source/JavaScriptCore/disassembler/ARMv7/ARMv7DOpcode.cpp
+++ b/Source/JavaScriptCore/disassembler/ARMv7/ARMv7DOpcode.cpp
@@ -32,6 +32,7 @@
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
+#include <string.h>
namespace JSC { namespace ARMv7Disassembler {
@@ -48,7 +49,7 @@ const char* const ARMv7DOpcode::s_optionName[8] = {
};
const char* const ARMv7DOpcode::s_shiftNames[4] = {
- "lsl", "lsr", "asl", "ror"
+ "lsl", "lsr", "asr", "ror"
};
const char* const ARMv7DOpcode::s_specialRegisterNames[3] = { "sp", "lr", "pc" };
@@ -90,8 +91,8 @@ static Opcode16GroupInitializer opcode16BitGroupList[] = {
OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte),
OPCODE_GROUP_ENTRY(0xe, ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte),
OPCODE_GROUP_ENTRY(0xf, ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte),
- OPCODE_GROUP_ENTRY(0x10, ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord),
- OPCODE_GROUP_ENTRY(0x11, ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord),
+ OPCODE_GROUP_ENTRY(0x10, ARMv7DOpcodeStoreRegisterImmediateHalfWord),
+ OPCODE_GROUP_ENTRY(0x11, ARMv7DOpcodeLoadRegisterImmediateHalfWord),
OPCODE_GROUP_ENTRY(0x12, ARMv7DOpcodeLoadStoreRegisterSPRelative),
OPCODE_GROUP_ENTRY(0x13, ARMv7DOpcodeLoadStoreRegisterSPRelative),
OPCODE_GROUP_ENTRY(0x14, ARMv7DOpcodeGeneratePCRelativeAddress),
@@ -112,11 +113,16 @@ static Opcode16GroupInitializer opcode16BitGroupList[] = {
};
static Opcode32GroupInitializer opcode32BitGroupList[] = {
+ OPCODE_GROUP_ENTRY(0x4, ARMv7DOpcodeDataPopMultiple),
+ OPCODE_GROUP_ENTRY(0x4, ARMv7DOpcodeDataPushMultiple),
OPCODE_GROUP_ENTRY(0x5, ARMv7DOpcodeDataProcessingShiftedReg),
+ OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeVLDR),
OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeVMOVSinglePrecision),
OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeVMOVDoublePrecision),
OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeFPTransfer),
OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVMSR),
+ OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVCMP),
+ OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVCVTBetweenFPAndInt),
OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeDataProcessingModifiedImmediate),
OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeConditionalBranchT3),
OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeBranchOrBranchLink),
@@ -132,6 +138,8 @@ static Opcode32GroupInitializer opcode32BitGroupList[] = {
OPCODE_GROUP_ENTRY(0xb, ARMv7DOpcodeBranchOrBranchLink),
OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeLoadRegister),
OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeDataPushPopSingle), // Should be before StoreSingle*
+ OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeDataPopMultiple),
+ OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeDataPushMultiple),
OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeStoreSingleRegister),
OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeStoreSingleImmediate12),
OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeStoreSingleImmediate8),
@@ -142,6 +150,9 @@ static Opcode32GroupInitializer opcode32BitGroupList[] = {
OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegExtend),
OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegParallel),
OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegMisc),
+ OPCODE_GROUP_ENTRY(0xe, ARMv7DOpcodeVLDR),
+ OPCODE_GROUP_ENTRY(0xf, ARMv7DOpcodeVCMP),
+ OPCODE_GROUP_ENTRY(0xf, ARMv7DOpcodeVCVTBetweenFPAndInt),
};
bool ARMv7DOpcode::s_initialized = false;
@@ -269,7 +280,7 @@ void ARMv7DOpcode::appendRegisterList(unsigned registers)
appendCharacter('{');
for (unsigned i = 0; i < 16; i++) {
- if (registers & i) {
+ if (registers & (1 << i)) {
if (numberPrinted++)
appendSeparator();
appendRegisterName(i);
@@ -513,6 +524,25 @@ const char* ARMv7DOpcodeLoadStoreRegisterImmediate::format()
return m_formatBuffer;
}
+unsigned ARMv7DOpcodeLoadStoreRegisterImmediate::scale()
+{
+ switch (op()) {
+ case 0:
+ case 1:
+ return 2;
+ case 2:
+ case 3:
+ return 0;
+ case 4:
+ case 5:
+ return 1;
+ default:
+ break;
+ }
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
const char* const ARMv7DOpcodeLoadStoreRegisterOffsetT1::s_opNames[8] = {
"str", "strh", "strb", "ldrsb", "ldr", "ldrh", "ldrb", "ldrsh"
};
@@ -1424,6 +1454,46 @@ const char* ARMv7DOpcodeDataPushPopSingle::format()
return m_formatBuffer;
}
+void ARMv7DOpcodeDataPushPopMultiple::appendRegisterList()
+{
+ unsigned registers = registerList();
+
+ appendCharacter('{');
+ bool needSeparator = false;
+
+ for (unsigned i = 0; i < 16; i++) {
+ if (registers & (1 << i)) {
+ if (needSeparator)
+ appendSeparator();
+ appendRegisterName(i);
+ needSeparator = true;
+ }
+ }
+ appendCharacter('}');
+}
+
+const char* ARMv7DOpcodeDataPopMultiple::format()
+{
+ if (condition() != 0xe)
+ bufferPrintf(" pop%-4.4s", conditionName(condition()));
+ else
+ appendInstructionName("pop");
+ appendRegisterList();
+
+ return m_formatBuffer;
+}
+
+const char* ARMv7DOpcodeDataPushMultiple::format()
+{
+ if (condition() != 0xe)
+ bufferPrintf(" push%-3.3s", conditionName(condition()));
+ else
+ appendInstructionName("push");
+ appendRegisterList();
+
+ return m_formatBuffer;
+}
+
const char* ARMv7DOpcodeStoreSingleImmediate12::format()
{
appendInstructionName(opName());
@@ -1493,6 +1563,104 @@ const char* ARMv7DOpcodeStoreSingleRegister::format()
return m_formatBuffer;
}
+const char* ARMv7DOpcodeVCMP::format()
+{
+ bufferPrintf(" vcmp");
+
+ if (eBit())
+ appendCharacter('e'); // Raise exception on qNaN
+
+ if (condition() != 0xe)
+ appendString(conditionName(condition()));
+
+ appendCharacter('.');
+ appendString(szBit() ? "f64" : "f32");
+ appendCharacter(' ');
+ if (szBit()) {
+ appendFPRegisterName('d', (dBit() << 4) | vd());
+ appendSeparator();
+ appendFPRegisterName('d', (mBit() << 4) | vm());
+ } else {
+ appendFPRegisterName('s', (vd() << 1) | dBit());
+ appendSeparator();
+ appendFPRegisterName('s', (vm() << 1) | mBit());
+ }
+
+ return m_formatBuffer;
+}
+
+const char* ARMv7DOpcodeVCVTBetweenFPAndInt::format()
+{
+ bufferPrintf(" vcvt");
+ bool convertToInteger = op2() & 0x4;
+
+ if (convertToInteger) {
+ if (!op())
+ appendCharacter('r'); // Round using mode in FPSCR
+ if (condition() != 0xe)
+ appendString(conditionName(condition()));
+ appendCharacter('.');
+ appendCharacter((op2() & 1) ? 's' : 'u');
+ appendString("32.f");
+ appendString(szBit() ? "64" : "32");
+ appendCharacter(' ');
+ appendFPRegisterName('s', (vd() << 1) | dBit());
+ appendSeparator();
+ if (szBit())
+ appendFPRegisterName('d', (mBit() << 4) | vm());
+ else
+ appendFPRegisterName('s', (vm() << 1) | mBit());
+ } else {
+ if (condition() != 0xe)
+ appendString(conditionName(condition()));
+ appendCharacter('.');
+ appendString(szBit() ? "f64." : "f32.");
+ appendString(op() ? "s32" : "u32");
+ appendCharacter(' ');
+ if (szBit())
+ appendFPRegisterName('d', (dBit() << 4) | vd());
+ else
+ appendFPRegisterName('s', (vd() << 1) | dBit());
+ appendSeparator();
+ appendFPRegisterName('s', (vm() << 1) | mBit());
+ }
+
+ return m_formatBuffer;
+}
+
+const char* ARMv7DOpcodeVLDR::format()
+{
+ if (condition() != 0xe)
+ bufferPrintf(" vldr%-3.3s", conditionName(condition()));
+ else
+ appendInstructionName("vldr");
+
+ appendFPRegisterName(doubleReg() ? 'd' : 's', vd());
+ appendSeparator();
+
+ int immediate = immediate8() * 4;
+
+ if (!uBit())
+ immediate = -immediate;
+
+ appendCharacter('[');
+
+ if (rn() == RegPC)
+ appendPCRelativeOffset(immediate);
+ else {
+ appendRegisterName(rn());
+
+ if (immediate) {
+ appendSeparator();
+ appendSignedImmediate(immediate);
+ }
+ }
+
+ appendCharacter(']');
+
+ return m_formatBuffer;
+}
+
const char* ARMv7DOpcodeVMOVDoublePrecision::format()
{
appendInstructionName("vmov");
diff --git a/Source/JavaScriptCore/disassembler/ARMv7/ARMv7DOpcode.h b/Source/JavaScriptCore/disassembler/ARMv7/ARMv7DOpcode.h
index 28bddd53e..13e209db7 100644
--- a/Source/JavaScriptCore/disassembler/ARMv7/ARMv7DOpcode.h
+++ b/Source/JavaScriptCore/disassembler/ARMv7/ARMv7DOpcode.h
@@ -275,7 +275,7 @@ protected:
const char* opName() { return s_opNames[op()]; }
unsigned op() { return (m_opcode >> 9) & 0x1; }
- unsigned immediate3() { return (m_opcode >> 6) & 0x3; }
+ unsigned immediate3() { return (m_opcode >> 6) & 0x7; }
unsigned rn() { return (m_opcode >> 3) & 0x7; }
};
@@ -441,7 +441,7 @@ protected:
unsigned immediate5() { return (m_opcode >> 6) & 0x01f; }
unsigned rn() { return (m_opcode >> 3) & 0x7; }
unsigned rt() { return m_opcode & 0x7; }
- unsigned scale() { return 2 - (op() >> 1); }
+ unsigned scale();
};
class ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte : public ARMv7DOpcodeLoadStoreRegisterImmediate {
@@ -452,7 +452,7 @@ public:
DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadStoreRegisterImmediate, thisObj);
};
-class ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord : public ARMv7DOpcodeLoadStoreRegisterImmediate {
+class ARMv7DOpcodeStoreRegisterImmediateHalfWord : public ARMv7DOpcodeLoadStoreRegisterImmediate {
public:
static const uint16_t s_mask = 0xf800;
static const uint16_t s_pattern = 0x8000;
@@ -460,6 +460,14 @@ public:
DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadStoreRegisterImmediate, thisObj);
};
+class ARMv7DOpcodeLoadRegisterImmediateHalfWord : public ARMv7DOpcodeLoadStoreRegisterImmediate {
+public:
+ static const uint16_t s_mask = 0xf800;
+ static const uint16_t s_pattern = 0x8800;
+
+ DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadStoreRegisterImmediate, thisObj);
+};
+
class ARMv7DOpcodeLoadStoreRegisterOffsetT1 : public ARMv7D16BitOpcode {
private:
static const char* const s_opNames[8];
@@ -621,7 +629,7 @@ protected:
const char* opName() { return op() ? "pop" : "push"; }
unsigned op() { return (m_opcode >> 11) & 0x1; }
- unsigned registerMask() { return ((m_opcode << 6) & 0x4000) | (m_opcode & 0x7f); }
+ unsigned registerMask() { return ((m_opcode << 6) & 0x4000) | (m_opcode & 0xff); }
};
class ARMv7DOpcodeMoveImmediateT1 : public ARMv7D16BitOpcode {
@@ -1011,6 +1019,36 @@ protected:
unsigned op() { return (m_opcode >> 20) & 0x1; }
};
+class ARMv7DOpcodeDataPushPopMultiple : public ARMv7D32BitOpcode {
+protected:
+ void appendRegisterList();
+
+ unsigned registerList() { return m_opcode & 0xffff; }
+ unsigned condition() { return m_opcode >> 28; }
+};
+
+class ARMv7DOpcodeDataPopMultiple : public ARMv7DOpcodeDataPushPopMultiple {
+public:
+ static const uint32_t s_mask = 0x0fff0000;
+ static const uint32_t s_pattern = 0x08bd0000;
+
+ DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataPopMultiple, thisObj);
+
+protected:
+ const char* format();
+};
+
+class ARMv7DOpcodeDataPushMultiple : public ARMv7DOpcodeDataPushPopMultiple {
+public:
+ static const uint32_t s_mask = 0xfe7f0000;
+ static const uint32_t s_pattern = 0xe82d0000;
+
+ DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataPushMultiple, thisObj);
+
+protected:
+ const char* format();
+};
+
class ARMv7DOpcodeDataStoreSingle : public ARMv7D32BitOpcode {
protected:
static const char* const s_opNames[4];
@@ -1086,6 +1124,63 @@ protected:
unsigned immediate16() { return ((m_opcode >> 4) & 0xf000) | ((m_opcode >> 15) & 0x0800) | ((m_opcode >> 4) & 0x0700) | (m_opcode & 0x00ff); }
};
+class ARMv7DOpcodeVCMP : public ARMv7D32BitOpcode {
+public:
+ static const uint32_t s_mask = 0x0fbf0e50;
+ static const uint32_t s_pattern = 0x0eb40a40;
+
+ DEFINE_STATIC_FORMAT32(ARMv7DOpcodeVCMP, thisObj);
+
+protected:
+ const char* format();
+
+ unsigned condition() { return m_opcode >> 28; }
+ unsigned dBit() { return (m_opcode >> 22) & 0x1; }
+ unsigned vd() { return (m_opcode >> 12) & 0xf; }
+ unsigned szBit() { return (m_opcode >> 8) & 0x1; }
+ unsigned eBit() { return (m_opcode >> 7) & 0x1; }
+ unsigned mBit() { return (m_opcode >> 5) & 0x1; }
+ unsigned vm() { return m_opcode & 0xf; }
+};
+
+class ARMv7DOpcodeVCVTBetweenFPAndInt : public ARMv7D32BitOpcode {
+public:
+ static const uint32_t s_mask = 0x0fb80e50;
+ static const uint32_t s_pattern = 0x0eb80a40;
+
+ DEFINE_STATIC_FORMAT32(ARMv7DOpcodeVCVTBetweenFPAndInt, thisObj);
+
+protected:
+ const char* format();
+
+ unsigned condition() { return m_opcode >> 28; }
+ unsigned dBit() { return (m_opcode >> 22) & 0x1; }
+ unsigned op2() { return (m_opcode >> 16) & 0x7; }
+ unsigned vd() { return (m_opcode >> 12) & 0xf; }
+ unsigned szBit() { return (m_opcode >> 8) & 0x1; }
+ unsigned op() { return (m_opcode >> 7) & 0x1; }
+ unsigned mBit() { return (m_opcode >> 5) & 0x1; }
+ unsigned vm() { return m_opcode & 0xf; }
+};
+
+class ARMv7DOpcodeVLDR : public ARMv7D32BitOpcode {
+public:
+ static const uint32_t s_mask = 0x0f300e00;
+ static const uint32_t s_pattern = 0x0d100a00;
+
+ DEFINE_STATIC_FORMAT32(ARMv7DOpcodeVLDR, thisObj);
+
+protected:
+ const char* format();
+
+ unsigned condition() { return m_opcode >> 28; }
+ unsigned uBit() { return (m_opcode >> 23) & 0x1; }
+ unsigned rn() { return (m_opcode >> 16) & 0xf; }
+ unsigned vd() { return ((m_opcode >> 18) & 0x10) | ((m_opcode >> 12) & 0xf); }
+ bool doubleReg() { return !!(m_opcode & 0x100); }
+ unsigned immediate8() { return m_opcode & 0xff; }
+};
+
class ARMv7DOpcodeVMOVDoublePrecision : public ARMv7D32BitOpcode {
public:
static const uint32_t s_mask = 0xffe00fd0;
diff --git a/Source/JavaScriptCore/disassembler/Disassembler.cpp b/Source/JavaScriptCore/disassembler/Disassembler.cpp
index 3fed2cdab..788a6c362 100644
--- a/Source/JavaScriptCore/disassembler/Disassembler.cpp
+++ b/Source/JavaScriptCore/disassembler/Disassembler.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,7 +27,13 @@
#include "Disassembler.h"
#include "MacroAssemblerCodeRef.h"
+#include <wtf/Condition.h>
#include <wtf/DataLog.h>
+#include <wtf/Deque.h>
+#include <wtf/Lock.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/StringPrintStream.h>
+#include <wtf/Threading.h>
namespace JSC {
@@ -39,5 +45,107 @@ void disassemble(const MacroAssemblerCodePtr& codePtr, size_t size, const char*
out.printf("%sdisassembly not available for range %p...%p\n", prefix, codePtr.executableAddress(), static_cast<char*>(codePtr.executableAddress()) + size);
}
+namespace {
+
+// This is really a struct, except that it should be a class because that's what the WTF_* macros
+// expect.
+class DisassemblyTask {
+ WTF_MAKE_NONCOPYABLE(DisassemblyTask);
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ DisassemblyTask()
+ {
+ }
+
+ ~DisassemblyTask()
+ {
+ if (header)
+ free(header); // free() because it would have been copied by strdup.
+ }
+
+ char* header { nullptr };
+ MacroAssemblerCodeRef codeRef;
+ size_t size { 0 };
+ const char* prefix { nullptr };
+};
+
+class AsynchronousDisassembler {
+public:
+ AsynchronousDisassembler()
+ {
+ createThread("Asynchronous Disassembler", [&] () { run(); });
+ }
+
+ void enqueue(std::unique_ptr<DisassemblyTask> task)
+ {
+ LockHolder locker(m_lock);
+ m_queue.append(WTFMove(task));
+ m_condition.notifyAll();
+ }
+
+ void waitUntilEmpty()
+ {
+ LockHolder locker(m_lock);
+ while (!m_queue.isEmpty() || m_working)
+ m_condition.wait(m_lock);
+ }
+
+private:
+ NO_RETURN void run()
+ {
+ for (;;) {
+ std::unique_ptr<DisassemblyTask> task;
+ {
+ LockHolder locker(m_lock);
+ m_working = false;
+ m_condition.notifyAll();
+ while (m_queue.isEmpty())
+ m_condition.wait(m_lock);
+ task = m_queue.takeFirst();
+ m_working = true;
+ }
+
+ dataLog(task->header);
+ disassemble(task->codeRef.code(), task->size, task->prefix, WTF::dataFile());
+ }
+ }
+
+ Lock m_lock;
+ Condition m_condition;
+ Deque<std::unique_ptr<DisassemblyTask>> m_queue;
+ bool m_working { false };
+};
+
+bool hadAnyAsynchronousDisassembly = false;
+
+AsynchronousDisassembler& asynchronousDisassembler()
+{
+ static NeverDestroyed<AsynchronousDisassembler> disassembler;
+ hadAnyAsynchronousDisassembly = true;
+ return disassembler.get();
+}
+
+} // anonymous namespace
+
+void disassembleAsynchronously(
+ const CString& header, const MacroAssemblerCodeRef& codeRef, size_t size, const char* prefix)
+{
+ std::unique_ptr<DisassemblyTask> task = std::make_unique<DisassemblyTask>();
+ task->header = strdup(header.data()); // Yuck! We need this because CString does racy refcounting.
+ task->codeRef = codeRef;
+ task->size = size;
+ task->prefix = prefix;
+
+ asynchronousDisassembler().enqueue(WTFMove(task));
+}
+
+void waitForAsynchronousDisassembly()
+{
+ if (!hadAnyAsynchronousDisassembly)
+ return;
+
+ asynchronousDisassembler().waitUntilEmpty();
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/disassembler/Disassembler.h b/Source/JavaScriptCore/disassembler/Disassembler.h
index a087a657b..ed47db89c 100644
--- a/Source/JavaScriptCore/disassembler/Disassembler.h
+++ b/Source/JavaScriptCore/disassembler/Disassembler.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,12 +26,15 @@
#ifndef Disassembler_h
#define Disassembler_h
-#include <wtf/Platform.h>
+#include "JSExportMacros.h"
+#include <functional>
#include <wtf/PrintStream.h>
+#include <wtf/text/CString.h>
namespace JSC {
class MacroAssemblerCodePtr;
+class MacroAssemblerCodeRef;
#if ENABLE(DISASSEMBLER)
bool tryToDisassemble(const MacroAssemblerCodePtr&, size_t, const char* prefix, PrintStream&);
@@ -46,6 +49,13 @@ inline bool tryToDisassemble(const MacroAssemblerCodePtr&, size_t, const char*,
// the range of machine code addresses.
void disassemble(const MacroAssemblerCodePtr&, size_t, const char* prefix, PrintStream& out);
+// Asynchronous disassembly. This happens on another thread, and calls the provided
+// callback when the disassembly is done.
+void disassembleAsynchronously(
+ const CString& header, const MacroAssemblerCodeRef&, size_t, const char* prefix);
+
+JS_EXPORT_PRIVATE void waitForAsynchronousDisassembly();
+
} // namespace JSC
#endif // Disassembler_h
diff --git a/Source/JavaScriptCore/disassembler/UDis86Disassembler.cpp b/Source/JavaScriptCore/disassembler/UDis86Disassembler.cpp
index 63c235b92..4093f13e4 100644
--- a/Source/JavaScriptCore/disassembler/UDis86Disassembler.cpp
+++ b/Source/JavaScriptCore/disassembler/UDis86Disassembler.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -24,7 +24,7 @@
*/
#include "config.h"
-#include "Disassembler.h"
+#include "UDis86Disassembler.h"
#if USE(UDIS86)
@@ -33,7 +33,7 @@
namespace JSC {
-bool tryToDisassemble(const MacroAssemblerCodePtr& codePtr, size_t size, const char* prefix, PrintStream& out)
+bool tryToDisassembleWithUDis86(const MacroAssemblerCodePtr& codePtr, size_t size, const char* prefix, PrintStream& out)
{
ud_t disassembler;
ud_init(&disassembler);
diff --git a/Source/JavaScriptCore/disassembler/UDis86Disassembler.h b/Source/JavaScriptCore/disassembler/UDis86Disassembler.h
new file mode 100644
index 000000000..2d5b3c44a
--- /dev/null
+++ b/Source/JavaScriptCore/disassembler/UDis86Disassembler.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UDis86Disassembler_h
+#define UDis86Disassembler_h
+
+#include "Disassembler.h"
+
+namespace JSC {
+
+#if USE(UDIS86)
+
+bool tryToDisassembleWithUDis86(const MacroAssemblerCodePtr& codePtr, size_t size, const char* prefix, PrintStream& out);
+
+#else // USE(UDIS86)
+
+inline bool tryToDisassembleWithUDis86(const MacroAssemblerCodePtr&, size_t, const char*, PrintStream&) { return false; }
+
+#endif // USE(UDIS86)
+
+} // namespace JSC
+
+#endif // UDis86Disassembler_h
+
diff --git a/Source/JavaScriptCore/disassembler/X86Disassembler.cpp b/Source/JavaScriptCore/disassembler/X86Disassembler.cpp
new file mode 100644
index 000000000..1f811beca
--- /dev/null
+++ b/Source/JavaScriptCore/disassembler/X86Disassembler.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Disassembler.h"
+
+#if ENABLE(DISASSEMBLER)
+#if USE(UDIS86)
+
+#include "MacroAssemblerCodeRef.h"
+#include "Options.h"
+#include "UDis86Disassembler.h"
+
+namespace JSC {
+
+bool tryToDisassemble(const MacroAssemblerCodePtr& codePtr, size_t size, const char* prefix, PrintStream& out)
+{
+ return tryToDisassembleWithUDis86(codePtr, size, prefix, out);
+}
+
+} // namespace JSC
+
+#endif // USE(UDIS86)
+#endif // ENABLE(DISASSEMBLER)
diff --git a/Source/JavaScriptCore/disassembler/udis86/itab.py b/Source/JavaScriptCore/disassembler/udis86/itab.py
index 90bd3e02c..3d50ad061 100644
--- a/Source/JavaScriptCore/disassembler/udis86/itab.py
+++ b/Source/JavaScriptCore/disassembler/udis86/itab.py
@@ -314,7 +314,7 @@ class UdItabGenerator( ud_opcode.UdOpcodeTables ):
self.ItabH.write( "\n" )
self.ItabH.write("\n/* itab entry operand definitions */\n");
- operands = list( self.OperandDict.keys() )
+ operands = self.OperandDict.keys()
operands.sort()
for o in operands:
self.ItabH.write("#define O_%-7s { %-12s %-8s }\n" %
diff --git a/Source/JavaScriptCore/disassembler/udis86/udis86_decode.c b/Source/JavaScriptCore/disassembler/udis86/udis86_decode.c
index 3d567b6df..579903642 100644
--- a/Source/JavaScriptCore/disassembler/udis86/udis86_decode.c
+++ b/Source/JavaScriptCore/disassembler/udis86/udis86_decode.c
@@ -459,6 +459,8 @@ decode_modrm_rm(struct ud *u,
rm = (REX_B(u->pfx_rex) << 3) | MODRM_RM(modrm(u));
reg = (REX_R(u->pfx_rex) << 3) | MODRM_REG(modrm(u));
+ UNUSED_PARAM(reg);
+
op->size = resolve_operand_size(u, size);
/*
@@ -650,7 +652,6 @@ decode_operand(struct ud *u,
case OP_E:
decode_modrm_rm(u, operand, T_GPR, size);
break;
- break;
case OP_G:
decode_modrm_reg(u, operand, T_GPR, size);
break;
diff --git a/Source/JavaScriptCore/disassembler/udis86/udis86_syn-att.c b/Source/JavaScriptCore/disassembler/udis86/udis86_syn-att.c
index 0d1c57d48..c9c84880a 100644
--- a/Source/JavaScriptCore/disassembler/udis86/udis86_syn-att.c
+++ b/Source/JavaScriptCore/disassembler/udis86/udis86_syn-att.c
@@ -66,14 +66,25 @@ gen_operand(struct ud* u, struct ud_operand* op)
if (op->offset == 8) {
if (op->lval.sbyte < 0)
mkasm(u, "-0x%x", (-op->lval.sbyte) & 0xff);
- else mkasm(u, "0x%x", op->lval.sbyte);
+ else
+ mkasm(u, "0x%x", op->lval.sbyte);
}
- else if (op->offset == 16)
- mkasm(u, "0x%x", op->lval.uword);
- else if (op->offset == 32)
- mkasm(u, "0x%lx", (unsigned long)op->lval.udword);
- else if (op->offset == 64)
- mkasm(u, "0x" FMT64 "x", op->lval.uqword);
+ else if (op->offset == 16) {
+ if (op->lval.sword < 0)
+ mkasm(u, "-0x%x", (-op->lval.sword) & 0xffff);
+ else
+ mkasm(u, "0x%x", op->lval.sword);
+ } else if (op->offset == 32) {
+ if (op->lval.sdword < 0)
+ mkasm(u, "-0x%x", (-op->lval.sdword) & 0xffffffff);
+ else
+ mkasm(u, "0x%x", op->lval.sdword);
+ } else if (op->offset == 64) {
+ if (op->lval.sdword < 0)
+ mkasm(u, "-0x" FMT64 "x", (uint64_t)-op->lval.sqword);
+ else
+ mkasm(u, "0x" FMT64 "x", (uint64_t)op->lval.sqword);
+ }
if (op->base)
mkasm(u, "(%%%s", ud_reg_tab[op->base - UD_R_AL]);
@@ -108,7 +119,7 @@ gen_operand(struct ud* u, struct ud_operand* op)
}
if ( sext_size < 64 )
sext_mask = ( 1ull << sext_size ) - 1;
- mkasm( u, "$0x" FMT64 "x", imm & sext_mask );
+ mkasm( u, "$0x" FMT64 "x", (uint64_t)(imm & sext_mask) );
break;
}
@@ -116,16 +127,16 @@ gen_operand(struct ud* u, struct ud_operand* op)
case UD_OP_JIMM:
switch (op->size) {
case 8:
- mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sbyte);
+ mkasm(u, "0x" FMT64 "x", (uint64_t)(u->pc + op->lval.sbyte));
break;
case 16:
- mkasm(u, "0x" FMT64 "x", (u->pc + op->lval.sword) & 0xffff );
+ mkasm(u, "0x" FMT64 "x", (uint64_t)((u->pc + op->lval.sword) & 0xffff) );
break;
case 32:
if (u->dis_mode == 32)
- mkasm(u, "0x" FMT64 "x", (u->pc + op->lval.sdword) & 0xffffffff);
+ mkasm(u, "0x" FMT64 "x", (uint64_t)((u->pc + op->lval.sdword) & 0xffffffff));
else
- mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sdword);
+ mkasm(u, "0x" FMT64 "x", (uint64_t)(u->pc + op->lval.sdword));
break;
default:break;
}
@@ -156,6 +167,7 @@ extern void
ud_translate_att(struct ud *u)
{
int size = 0;
+ unsigned i;
/* check if P_OSO prefix is used */
if (! P_OSO(u->itab_entry->prefix) && u->pfx_opr) {
@@ -218,19 +230,20 @@ ud_translate_att(struct ud *u)
mkasm(u, "%s", ud_lookup_mnemonic(u->mnemonic));
}
- if (u->c1)
- size = u->operand[0].size;
- else if (u->c2)
- size = u->operand[1].size;
- else if (u->c3)
- size = u->operand[2].size;
+ for (i = 3; i--;) {
+ if (u->operand[i].size > size
+ && u->operand[i].type != UD_OP_JIMM)
+ size = u->operand[i].size;
+ }
if (size == 8)
- mkasm(u, "b");
+ mkasm(u, "b");
else if (size == 16)
- mkasm(u, "w");
+ mkasm(u, "w");
+ else if (size == 32)
+ mkasm(u, "l");
else if (size == 64)
- mkasm(u, "q");
+ mkasm(u, "q");
mkasm(u, " ");
diff --git a/Source/JavaScriptCore/disassembler/udis86/udis86_syn-intel.c b/Source/JavaScriptCore/disassembler/udis86/udis86_syn-intel.c
index 38251db88..4ad42eb63 100644
--- a/Source/JavaScriptCore/disassembler/udis86/udis86_syn-intel.c
+++ b/Source/JavaScriptCore/disassembler/udis86/udis86_syn-intel.c
@@ -106,7 +106,7 @@ static void gen_operand(struct ud* u, struct ud_operand* op, int syn_cast)
else mkasm(u, "%s0x%lx", (op_f) ? "+" : "", (unsigned long)op->lval.udword);
}
else if (op->offset == 64)
- mkasm(u, "%s0x" FMT64 "x", (op_f) ? "+" : "", op->lval.uqword);
+ mkasm(u, "%s0x" FMT64 "x", (op_f) ? "+" : "", (uint64_t)op->lval.uqword);
mkasm(u, "]");
break;
@@ -133,7 +133,7 @@ static void gen_operand(struct ud* u, struct ud_operand* op, int syn_cast)
}
if ( sext_size < 64 )
sext_mask = ( 1ull << sext_size ) - 1;
- mkasm( u, "0x" FMT64 "x", imm & sext_mask );
+ mkasm( u, "0x" FMT64 "x", (uint64_t)(imm & sext_mask) );
break;
}
@@ -143,13 +143,13 @@ static void gen_operand(struct ud* u, struct ud_operand* op, int syn_cast)
if (syn_cast) opr_cast(u, op);
switch (op->size) {
case 8:
- mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sbyte);
+ mkasm(u, "0x" FMT64 "x", (uint64_t)(u->pc + op->lval.sbyte));
break;
case 16:
- mkasm(u, "0x" FMT64 "x", ( u->pc + op->lval.sword ) & 0xffff );
+ mkasm(u, "0x" FMT64 "x", (uint64_t)(( u->pc + op->lval.sword ) & 0xffff) );
break;
case 32:
- mkasm(u, "0x" FMT64 "x", ( u->pc + op->lval.sdword ) & 0xfffffffful );
+ mkasm(u, "0x" FMT64 "x", (uint64_t)(( u->pc + op->lval.sdword ) & 0xfffffffful) );
break;
default:break;
}
diff --git a/Source/JavaScriptCore/disassembler/udis86/udis86_types.h b/Source/JavaScriptCore/disassembler/udis86/udis86_types.h
index 320d1ca49..176bf6d73 100644
--- a/Source/JavaScriptCore/disassembler/udis86/udis86_types.h
+++ b/Source/JavaScriptCore/disassembler/udis86/udis86_types.h
@@ -48,7 +48,11 @@
typedef __int32 int32_t;
typedef __int64 int64_t;
#else
-# define FMT64 "%ll"
+# if defined(__GNU_LIBRARY__) && defined(__WORDSIZE) && (__WORDSIZE == 64)
+# define FMT64 "%l"
+# else
+# define FMT64 "%ll"
+# endif
# ifndef __UD_STANDALONE__
# include <inttypes.h>
# endif /* __UD_STANDALONE__ */