diff options
author | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2017-05-30 12:48:17 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2017-05-30 12:48:17 +0200 |
commit | 881da28418d380042aa95a97f0cbd42560a64f7c (patch) | |
tree | a794dff3274695e99c651902dde93d934ea7a5af /Source/JavaScriptCore/disassembler | |
parent | 7e104c57a70fdf551bb3d22a5d637cdcbc69dbea (diff) | |
parent | 0fcedcd17cc00d3dd44c718b3cb36c1033319671 (diff) | |
download | qtwebkit-881da28418d380042aa95a97f0cbd42560a64f7c.tar.gz |
Merge 'wip/next' into dev
Change-Id: Iff9ee5e23bb326c4371ec8ed81d56f2f05d680e9
Diffstat (limited to 'Source/JavaScriptCore/disassembler')
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__ */ |