From 36a5530cc9e04ed0ea381ebd1e2b1517eaa50a9f Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 3 Oct 2013 13:03:18 +0200 Subject: [PATCH] Add support for showing disassembled ARM JIT code Ported the ARM disassembler from upstream trunk. QtQml needs to be configured with qmake CONFIG+=disassembler and QV4_SHOW_ASM=1 enables the dump at run-time. Change-Id: Ia13a98835829fde0d3c5a795cb8f6ef9de951807 Reviewed-by: Lars Knoll Reviewed-by: Simon Hausmann --- .../masm/disassembler/ARMv7/ARMv7DOpcode.cpp | 1566 ++++++++++++++++++++ .../masm/disassembler/ARMv7/ARMv7DOpcode.h | 1142 ++++++++++++++ .../masm/disassembler/ARMv7Disassembler.cpp | 55 + src/3rdparty/masm/masm-defs.pri | 8 +- src/3rdparty/masm/masm.pri | 5 + src/3rdparty/masm/wtf/Platform.h | 2 +- src/qml/compiler/qv4isel_masm.cpp | 2 +- 7 files changed, 2776 insertions(+), 4 deletions(-) create mode 100644 src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp create mode 100644 src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h create mode 100644 src/3rdparty/masm/disassembler/ARMv7Disassembler.cpp diff --git a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp new file mode 100644 index 0000000..0494873 --- /dev/null +++ b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp @@ -0,0 +1,1566 @@ +/* + * 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. + */ + +#include "config.h" + +#if USE(ARMV7_DISASSEMBLER) + +#include "ARMv7DOpcode.h" + +#include +#include +#include +#include + +namespace JSC { namespace ARMv7Disassembler { + +ARMv7D16BitOpcode::OpcodeGroup* ARMv7D16BitOpcode::opcodeTable[32]; +ARMv7D32BitOpcode::OpcodeGroup* ARMv7D32BitOpcode::opcodeTable[16]; + +const char* const ARMv7DOpcode::s_conditionNames[16] = { + "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", "gt", "le", "al", "al" +}; + +const char* const ARMv7DOpcode::s_optionName[8] = { + "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx" +}; + +const char* const ARMv7DOpcode::s_shiftNames[4] = { + "lsl", "lsr", "asl", "ror" +}; + +const char* const ARMv7DOpcode::s_specialRegisterNames[3] = { "sp", "lr", "pc" }; + +template +struct OpcodeGroupInitializer { + unsigned m_opcodeGroupNumber; + InstructionType m_mask; + InstructionType m_pattern; + const char* (*m_format)(OpcodeType*); +}; + +#define OPCODE_GROUP_ENTRY(groupIndex, groupClass) \ +{ groupIndex, groupClass::s_mask, groupClass::s_pattern, groupClass::format } + +typedef OpcodeGroupInitializer Opcode16GroupInitializer; +typedef OpcodeGroupInitializer Opcode32GroupInitializer; + +static Opcode16GroupInitializer opcode16BitGroupList[] = { + OPCODE_GROUP_ENTRY(0x0, ARMv7DOpcodeLogicalImmediateT1), + OPCODE_GROUP_ENTRY(0x1, ARMv7DOpcodeLogicalImmediateT1), + OPCODE_GROUP_ENTRY(0x2, ARMv7DOpcodeLogicalImmediateT1), + OPCODE_GROUP_ENTRY(0x3, ARMv7DOpcodeAddSubtractT1), + OPCODE_GROUP_ENTRY(0x3, ARMv7DOpcodeAddSubtractImmediate3), + OPCODE_GROUP_ENTRY(0x4, ARMv7DOpcodeMoveImmediateT1), + OPCODE_GROUP_ENTRY(0x5, ARMv7DOpcodeCompareImmediateT1), + OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeAddSubtractImmediate8), + OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeAddSubtractImmediate8), + OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeDataProcessingRegisterT1), + OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeAddRegisterT2), + OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeCompareRegisterT2), + OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeCompareRegisterT1), + OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeMoveRegisterT1), + OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeBranchExchangeT1), + OPCODE_GROUP_ENTRY(0x9, ARMv7DOpcodeLoadFromLiteralPool), + OPCODE_GROUP_ENTRY(0xa, ARMv7DOpcodeLoadStoreRegisterOffsetT1), + OPCODE_GROUP_ENTRY(0xb, ARMv7DOpcodeLoadStoreRegisterOffsetT1), + OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte), + 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(0x12, ARMv7DOpcodeLoadStoreRegisterSPRelative), + OPCODE_GROUP_ENTRY(0x13, ARMv7DOpcodeLoadStoreRegisterSPRelative), + OPCODE_GROUP_ENTRY(0x14, ARMv7DOpcodeGeneratePCRelativeAddress), + OPCODE_GROUP_ENTRY(0x15, ARMv7DOpcodeAddSPPlusImmediate), + OPCODE_GROUP_ENTRY(0x16, ARMv7DOpcodeMiscCompareAndBranch), + OPCODE_GROUP_ENTRY(0x16, ARMv7DOpcodeMiscByteHalfwordOps), + OPCODE_GROUP_ENTRY(0x16, ARMv7DOpcodeMiscPushPop), + OPCODE_GROUP_ENTRY(0x16, ARMv7DOpcodeMiscAddSubSP), + OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscHint16), // Needs to be before IfThenT1 + OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscIfThenT1), + OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscByteHalfwordOps), + OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscCompareAndBranch), + OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscPushPop), + OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscBreakpointT1), + OPCODE_GROUP_ENTRY(0x1a, ARMv7DOpcodeBranchConditionalT1), + OPCODE_GROUP_ENTRY(0x1b, ARMv7DOpcodeBranchConditionalT1), + OPCODE_GROUP_ENTRY(0x1c, ARMv7DOpcodeBranchT2) +}; + +static Opcode32GroupInitializer opcode32BitGroupList[] = { + OPCODE_GROUP_ENTRY(0x5, ARMv7DOpcodeDataProcessingShiftedReg), + OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeVMOVSinglePrecision), + OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeVMOVDoublePrecision), + OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeFPTransfer), + OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVMSR), + OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeDataProcessingModifiedImmediate), + OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeConditionalBranchT3), + OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeBranchOrBranchLink), + OPCODE_GROUP_ENTRY(0x9, ARMv7DOpcodeUnmodifiedImmediate), + OPCODE_GROUP_ENTRY(0x9, ARMv7DOpcodeHint32), + OPCODE_GROUP_ENTRY(0x9, ARMv7DOpcodeConditionalBranchT3), + OPCODE_GROUP_ENTRY(0x9, ARMv7DOpcodeBranchOrBranchLink), + OPCODE_GROUP_ENTRY(0xa, ARMv7DOpcodeDataProcessingModifiedImmediate), + OPCODE_GROUP_ENTRY(0xa, ARMv7DOpcodeConditionalBranchT3), + OPCODE_GROUP_ENTRY(0xa, ARMv7DOpcodeBranchOrBranchLink), + OPCODE_GROUP_ENTRY(0xb, ARMv7DOpcodeUnmodifiedImmediate), + OPCODE_GROUP_ENTRY(0xb, ARMv7DOpcodeConditionalBranchT3), + OPCODE_GROUP_ENTRY(0xb, ARMv7DOpcodeBranchOrBranchLink), + OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeLoadRegister), + OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeDataPushPopSingle), // Should be before StoreSingle* + OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeStoreSingleRegister), + OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeStoreSingleImmediate12), + OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeStoreSingleImmediate8), + OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeLoadSignedImmediate), + OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeLoadUnsignedImmediate), + OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeLongMultipleDivide), + OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegShift), + OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegExtend), + OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegParallel), + OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegMisc), +}; + +bool ARMv7DOpcode::s_initialized = false; + +void ARMv7DOpcode::init() +{ + if (s_initialized) + return; + + ARMv7D16BitOpcode::init(); + ARMv7D32BitOpcode::init(); + + s_initialized = true; +} + +void ARMv7DOpcode::startITBlock(unsigned blocksize, unsigned firstCondition) +{ + ASSERT(blocksize > 0 && blocksize <= MaxITBlockSize); + m_ITBlocksize = blocksize; + m_ITConditionIndex = m_ITBlocksize + 1; + m_currentITCondition = 0; + m_ifThenConditions[0] = firstCondition; +} + +void ARMv7DOpcode::saveITConditionAt(unsigned blockPosition, unsigned condition) +{ + if (blockPosition < m_ITBlocksize) + m_ifThenConditions[blockPosition] = static_cast(condition); +} + +void ARMv7DOpcode::fetchOpcode(uint16_t*& newPC) +{ + m_bufferOffset = 0; + m_formatBuffer[0] = '\0'; + m_currentPC = newPC; + + m_opcode = *newPC++; + + if (is32BitInstruction()) { + m_opcode <<= 16; + m_opcode |= *newPC++; + } + + if (m_ITConditionIndex < m_ITBlocksize) + m_currentITCondition = m_ifThenConditions[m_ITConditionIndex]; + else + m_currentITCondition = CondNone; +} + +const char* ARMv7DOpcode::disassemble(uint16_t*& currentPC) +{ + const char* result; + fetchOpcode(currentPC); + + if (is32BitInstruction()) + result = reinterpret_cast(this)->doDisassemble(); + else + result = reinterpret_cast(this)->doDisassemble(); + + if (startingITBlock()) + m_ITConditionIndex = 0; + else if (inITBlock() && (++m_ITConditionIndex >= m_ITBlocksize)) + endITBlock(); + + return result; +} + +void ARMv7DOpcode::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); +} + +void ARMv7DOpcode::appendInstructionName(const char* instructionName, bool addS) +{ + if (!inITBlock() && !addS) { + appendInstructionNameNoITBlock(instructionName); + + return; + } + + const char sevenSpaces[8] = " "; + + unsigned length = strlen(instructionName); + + bufferPrintf(" %s", instructionName); + if (inITBlock()) { + const char* condition = conditionName(m_currentITCondition); + length += strlen(condition); + appendString(condition); + } else if (addS) { + length++; + appendCharacter('s'); + } + + if (length >= 7) + length = 6; + + appendString(sevenSpaces + length); +} + +void ARMv7DOpcode::appendRegisterName(unsigned registerNumber) +{ + registerNumber &= 0xf; + + if (registerNumber > 12) { + appendString(s_specialRegisterNames[registerNumber - 13]); + return; + } + + bufferPrintf("r%u", registerNumber); +} + +void ARMv7DOpcode::appendRegisterList(unsigned registers) +{ + unsigned numberPrinted = 0; + + appendCharacter('{'); + + for (unsigned i = 0; i < 16; i++) { + if (registers & i) { + if (numberPrinted++) + appendSeparator(); + appendRegisterName(i); + } + } + + appendCharacter('}'); +} + +void ARMv7DOpcode::appendFPRegisterName(char registerPrefix, unsigned registerNumber) +{ + bufferPrintf("%c%u", registerPrefix, registerNumber); +} + +// 16 Bit Instructions + +void ARMv7D16BitOpcode::init() +{ + OpcodeGroup* lastGroups[OpcodeGroup::opcodeTableSize]; + + for (unsigned i = 0; i < OpcodeGroup::opcodeTableSize; i++) { + opcodeTable[i] = 0; + lastGroups[i] = 0; + } + + for (unsigned i = 0; i < sizeof(opcode16BitGroupList) / sizeof(Opcode16GroupInitializer); i++) { + OpcodeGroup* newOpcodeGroup = new OpcodeGroup(opcode16BitGroupList[i].m_mask, opcode16BitGroupList[i].m_pattern, opcode16BitGroupList[i].m_format); + uint16_t opcodeGroupNumber = opcode16BitGroupList[i].m_opcodeGroupNumber; + + if (!opcodeTable[opcodeGroupNumber]) + opcodeTable[opcodeGroupNumber] = newOpcodeGroup; + else + lastGroups[opcodeGroupNumber]->setNext(newOpcodeGroup); + lastGroups[opcodeGroupNumber] = newOpcodeGroup; + } +} + +const char* ARMv7D16BitOpcode::doDisassemble() +{ + OpcodeGroup* opGroup = opcodeTable[opcodeGroupNumber(m_opcode)]; + + while (opGroup) { + if (opGroup->matches(static_cast(m_opcode))) + return opGroup->format(this); + opGroup = opGroup->next(); + } + + return defaultFormat(); +} + +const char* ARMv7D16BitOpcode::defaultFormat() +{ + bufferPrintf(" .word %04x", m_opcode); + return m_formatBuffer; +} + +const char* ARMv7DOpcodeAddRegisterT2::format() +{ + appendInstructionName("add"); + appendRegisterName(rdn()); + appendSeparator(); + appendRegisterName(rm()); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeAddSPPlusImmediate::format() +{ + appendInstructionName("add"); + appendRegisterName(rd()); + appendSeparator(); + appendRegisterName(RegSP); + appendSeparator(); + appendUnsignedImmediate(immediate8()); + + return m_formatBuffer; +} + +const char* const ARMv7DOpcodeAddSubtract::s_opNames[2] = { "add", "sub" }; + +const char* ARMv7DOpcodeAddSubtractT1::format() +{ + appendInstructionName(opName(), !inITBlock()); + appendRegisterName(rd()); + appendSeparator(); + appendRegisterName(rn()); + appendSeparator(); + appendRegisterName(rm()); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeAddSubtractImmediate3::format() +{ + appendInstructionName(opName(), !inITBlock()); + appendRegisterName(rd()); + appendSeparator(); + appendRegisterName(rn()); + appendSeparator(); + appendUnsignedImmediate(immediate3()); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeAddSubtractImmediate8::format() +{ + appendInstructionName(opName(), !inITBlock()); + appendRegisterName(rdn()); + appendSeparator(); + appendUnsignedImmediate(immediate8()); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeBranchConditionalT1::format() +{ + if (condition() == 0xe) + return defaultFormat(); + + if (condition() == 0xf) { + appendInstructionName("svc"); + appendUnsignedImmediate(offset()); + + return m_formatBuffer; + } + + bufferPrintf(" b%-6.6s", conditionName(condition())); + appendPCRelativeOffset(static_cast(offset()) + 2); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeBranchExchangeT1::format() +{ + appendInstructionName(opName()); + appendRegisterName(rm()); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeBranchT2::format() +{ + appendInstructionName("b"); + appendPCRelativeOffset(static_cast(immediate11()) + 2); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeCompareImmediateT1::format() +{ + appendInstructionName("cmp"); + appendRegisterName(rn()); + appendSeparator(); + appendUnsignedImmediate(immediate8()); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeCompareRegisterT1::format() +{ + appendInstructionName("cmp"); + appendRegisterName(rn()); + appendSeparator(); + appendRegisterName(rm()); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeCompareRegisterT2::format() +{ + appendInstructionName("compare"); + appendRegisterName(rn()); + appendSeparator(); + appendRegisterName(rm()); + + return m_formatBuffer; +} + +const char* const ARMv7DOpcodeDataProcessingRegisterT1::s_opNames[16] = { + "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror", "tst", "rsb", "cmp", "cmn", "orr", "mul", "bic", "mvn" +}; + +const char* ARMv7DOpcodeDataProcessingRegisterT1::format() +{ + appendInstructionName(opName(), inITBlock() && (!(op() == 0x8) || (op() == 0xa) || (op() == 0xb))); + appendRegisterName(rdn()); + appendSeparator(); + appendRegisterName(rm()); + if (op() == 0x9) // rsb T1 + appendString(", #0"); + else if (op() == 0xd) { // mul T1 + appendSeparator(); + appendRegisterName(rdn()); + } + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeGeneratePCRelativeAddress::format() +{ + appendInstructionName("adr"); + appendRegisterName(rd()); + appendSeparator(); + appendPCRelativeOffset(static_cast(immediate8())); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeLoadFromLiteralPool::format() +{ + appendInstructionName("ldr"); + appendRegisterName(rt()); + appendSeparator(); + appendPCRelativeOffset(static_cast(immediate8())); + + return m_formatBuffer; +} + +const char* const ARMv7DOpcodeLoadStoreRegisterImmediate::s_opNames[6] = { + "str", "ldr", "strb", "ldrb", "strh", "ldrh" +}; + +const char* ARMv7DOpcodeLoadStoreRegisterImmediate::format() +{ + const char* instructionName = opName(); + + if (!instructionName) + return defaultFormat(); + + appendInstructionName(opName()); + appendRegisterName(rt()); + appendSeparator(); + appendCharacter('['); + appendRegisterName(rn()); + if (immediate5()) { + appendSeparator(); + appendUnsignedImmediate(immediate5() << scale()); + } + appendCharacter(']'); + + return m_formatBuffer; +} + +const char* const ARMv7DOpcodeLoadStoreRegisterOffsetT1::s_opNames[8] = { + "str", "strh", "strb", "ldrsb", "ldr", "ldrh", "ldrb", "ldrsh" +}; + +const char* ARMv7DOpcodeLoadStoreRegisterOffsetT1::format() +{ + appendInstructionName(opName()); + appendRegisterName(rt()); + appendSeparator(); + appendCharacter('['); + appendRegisterName(rn()); + appendSeparator(); + appendRegisterName(rm()); + appendCharacter(']'); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeLoadStoreRegisterSPRelative::format() +{ + appendInstructionName(opName()); + appendRegisterName(rt()); + appendSeparator(); + appendCharacter('['); + appendRegisterName(RegSP); + if (immediate8()) { + appendSeparator(); + appendUnsignedImmediate(immediate8() << 2); + } + appendCharacter(']'); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeLogicalImmediateT1::format() +{ + if (!op() && !immediate5()) { + // mov T2 + appendInstructionName("movs"); + appendRegisterName(rd()); + appendSeparator(); + appendRegisterName(rm()); + + return m_formatBuffer; + } + + appendInstructionName(opName(), !inITBlock()); + appendRegisterName(rd()); + appendSeparator(); + appendRegisterName(rm()); + appendSeparator(); + appendUnsignedImmediate((op() && !immediate5()) ? 32 : immediate5()); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeMiscAddSubSP::format() +{ + appendInstructionName(opName()); + appendRegisterName(RegSP); + appendSeparator(); + appendRegisterName(RegSP); + appendSeparator(); + appendUnsignedImmediate(immediate7()); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeMiscBreakpointT1::format() +{ + appendInstructionNameNoITBlock("bkpt"); + appendUnsignedImmediate(immediate8()); + + return m_formatBuffer; +} + +const char* const ARMv7DOpcodeMiscByteHalfwordOps::s_opNames[8] = { + "sxth", "sxb", "uxth", "uxtb", "rev", "rev16", "revsh" +}; + +const char* ARMv7DOpcodeMiscByteHalfwordOps::format() +{ + const char* instructionName = opName(); + + if (!instructionName) + return defaultFormat(); + + appendInstructionName(instructionName); + appendRegisterName(rd()); + appendSeparator(); + appendRegisterName(rm()); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeMiscCompareAndBranch::format() +{ + appendInstructionName(opName()); + appendPCRelativeOffset(immediate6() + 2); + + return m_formatBuffer; +} + +const char* const ARMv7DOpcodeMiscHint16::s_opNames[16] = { + "nop", "yield", "wfe", "wfi", "sev" +}; + +const char* ARMv7DOpcodeMiscHint16::format() +{ + if (opA() > 4) + return defaultFormat(); + + appendInstructionName(opName()); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeMiscIfThenT1::format() +{ + char opName[6]; + opName[0] = 'i'; + opName[1] = 't'; + + unsigned condition = firstCondition(); + unsigned maskBits = mask(); + unsigned blockLength = 0; + + for (unsigned i = 0; i < 4; ++i) { + if (maskBits & (1 << i)) { + blockLength = 4 - i; + break; + } + } + + startITBlock(blockLength, condition); + + for (unsigned i = 1; i < blockLength; ++i) { + unsigned currMaskBit = (maskBits >> (4-i)) & 0x1; + opName[i + 1] = (currMaskBit ^ (condition & 1)) ? 'e' : 't'; + saveITConditionAt(i, (condition & ~1) | currMaskBit); + } + opName[blockLength + 1] = '\0'; + + appendInstructionNameNoITBlock(opName); + appendString(conditionName(condition)); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeMiscPushPop::format() +{ + appendInstructionName(opName()); + appendRegisterList(registerMask()); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeMoveImmediateT1::format() +{ + appendInstructionName("mov", !inITBlock()); + appendRegisterName(rd()); + appendSeparator(); + appendUnsignedImmediate(immediate8()); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeMoveRegisterT1::format() +{ + appendInstructionName("mov"); + appendRegisterName(rd()); + appendSeparator(); + appendRegisterName(rm()); + + return m_formatBuffer; +} + +// 32 bit Intructions + +void ARMv7D32BitOpcode::init() +{ + OpcodeGroup* lastGroups[OpcodeGroup::opcodeTableSize]; + + for (unsigned i = 0; i < OpcodeGroup::opcodeTableSize; i++) { + opcodeTable[i] = 0; + lastGroups[i] = 0; + } + + for (unsigned i = 0; i < sizeof(opcode32BitGroupList) / sizeof(Opcode32GroupInitializer); i++) { + OpcodeGroup* newOpcodeGroup = new OpcodeGroup(opcode32BitGroupList[i].m_mask, opcode32BitGroupList[i].m_pattern, opcode32BitGroupList[i].m_format); + uint16_t opcodeGroupNumber = opcode32BitGroupList[i].m_opcodeGroupNumber; + + if (!opcodeTable[opcodeGroupNumber]) + opcodeTable[opcodeGroupNumber] = newOpcodeGroup; + else + lastGroups[opcodeGroupNumber]->setNext(newOpcodeGroup); + lastGroups[opcodeGroupNumber] = newOpcodeGroup; + } +} + +const char* ARMv7D32BitOpcode::doDisassemble() +{ + OpcodeGroup* opGroup = opcodeTable[opcodeGroupNumber(m_opcode)]; + + while (opGroup) { + if (opGroup->matches(m_opcode)) + return opGroup->format(this); + opGroup = opGroup->next(); + } + + return defaultFormat(); +} + +const char* ARMv7D32BitOpcode::defaultFormat() +{ + bufferPrintf(" .long %08x", m_opcode); + return m_formatBuffer; +} + +const char* ARMv7DOpcodeConditionalBranchT3::format() +{ + if (condition() < 0xe) + bufferPrintf(" b%-6.6s", conditionName(condition())); + else + appendInstructionName("b"); + appendPCRelativeOffset(offset() + 2); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeBranchOrBranchLink::format() +{ + appendInstructionName(isBL() ? "bl" : "b"); + appendPCRelativeOffset(offset() + 2); + + return m_formatBuffer; +} + +const char* const ARMv7DOpcodeDataProcessingLogicalAndRithmetic::s_opNames[16] = { + "and", "bic", "orr", "orn", "eor", 0, "pkh", 0, "add", 0, "adc", "sbc", 0, "sub", "rsb", 0 +}; + +void ARMv7DOpcodeDataProcessingModifiedImmediate::appendModifiedImmediate(unsigned immediate12) +{ + if (!(immediate12 & 0xc00)) { + unsigned immediate = 0; + unsigned lower8Bits = immediate12 & 0xff; + + switch ((immediate12 >> 8) & 3) { + case 0: + immediate = lower8Bits; + break; + case 1: + immediate = (lower8Bits << 16) | lower8Bits; + break; + case 2: + immediate = (lower8Bits << 24) | (lower8Bits << 8); + break; + case 3: + immediate = (lower8Bits << 24) | (lower8Bits << 16) | (lower8Bits << 8) | lower8Bits; + break; + } + appendUnsignedImmediate(immediate); + return; + } + + unsigned immediate8 = 0x80 | (immediate12 & 0x7f); + unsigned shiftAmount = 32 - ((immediate12 >> 7) & 0x1f); + + appendUnsignedImmediate(immediate8 << shiftAmount); +} + +const char* ARMv7DOpcodeDataProcessingModifiedImmediate::format() +{ + if ((op() == 0x5) || (op() == 0x6) || (op() == 0x7) || (op() == 0x9) || (op() == 0xc) || (op() == 0xf)) + return defaultFormat(); + + const char* instructionName = opName(); + + if (rn() == 15) { + if (op() == 2) { + // MOV T2 + instructionName = sBit() ? "movs" : "mov"; + appendInstructionName(instructionName); + appendRegisterName(rd()); + appendSeparator(); + appendModifiedImmediate(immediate12()); + + return m_formatBuffer; + } + + if (op() == 3) { + // MVN T1 + instructionName = sBit() ? "mvns" : "mvn"; + appendInstructionName(instructionName); + appendRegisterName(rd()); + appendSeparator(); + appendModifiedImmediate(immediate12()); + + return m_formatBuffer; + } + } + + if (rd() == 15) { + if (sBit()) { + bool testOrCmpInstruction = false; + + switch (op()) { + case 0x0: + instructionName = "tst"; + testOrCmpInstruction = true; + break; + case 0x4: + instructionName = "teq"; + testOrCmpInstruction = true; + break; + case 0x8: + instructionName = "cmn"; + testOrCmpInstruction = true; + break; + case 0xd: + instructionName = "cmp"; + testOrCmpInstruction = true; + break; + } + + if (testOrCmpInstruction) { + appendInstructionName(instructionName); + appendRegisterName(rn()); + appendSeparator(); + appendModifiedImmediate(immediate12()); + + return m_formatBuffer; + } + } + } + + appendInstructionName(instructionName); + appendRegisterName(rd()); + appendSeparator(); + appendRegisterName(rn()); + appendSeparator(); + appendModifiedImmediate(immediate12()); + + return m_formatBuffer; +} + +void ARMv7DOpcodeDataProcessingShiftedReg::appendImmShift(unsigned type, unsigned immediate) +{ + if (type || immediate) { + appendSeparator(); + + if (!immediate) { + switch (type) { + case 1: + case 2: + immediate = 32; + break; + case 3: + appendString("rrx"); + return; + } + } + + appendShiftType(type); + appendUnsignedImmediate(immediate); + } +} + +const char* ARMv7DOpcodeDataProcessingShiftedReg::format() +{ + if ((op() == 0x5) || (op() == 0x7) || (op() == 0x9) || (op() == 0xc) || (op() == 0xf)) + return defaultFormat(); + + if (op() == 6) { + // pkhbt or pkhtb + if (sBit() || tBit()) + return defaultFormat(); + + if (tbBit()) + appendInstructionName("pkhtb"); + else + appendInstructionName("pkhbt"); + appendRegisterName(rd()); + appendSeparator(); + appendRegisterName(rn()); + appendSeparator(); + appendRegisterName(rm()); + appendImmShift(tbBit() << 1, immediate5()); + + return m_formatBuffer; + } + + const char* instructionName = opName(); + + if (rn() == 15) { + if (op() == 2) { + if (!type() && !immediate5()) { + // MOV T3 + instructionName = sBit() ? "movs" : "mov"; + appendInstructionName(instructionName); + appendRegisterName(rd()); + appendSeparator(); + appendRegisterName(rm()); + + return m_formatBuffer; + } + + if (type() == 3 && !immediate5()) { + // RRX T1 + instructionName = sBit() ? "rrx" : "rrx"; + appendInstructionName(instructionName); + appendRegisterName(rd()); + appendSeparator(); + appendRegisterName(rm()); + + return m_formatBuffer; + } + + // Logical + if (sBit()) + bufferPrintf("%ss ", shiftName(type())); + else + appendInstructionName(shiftName(type())); + appendRegisterName(rd()); + appendSeparator(); + appendRegisterName(rm()); + appendSeparator(); + appendUnsignedImmediate(immediate5()); + + return m_formatBuffer; + } + + if (op() == 3) { + // MVN T2 + instructionName = sBit() ? "mvns" : "mvn"; + appendInstructionName(instructionName); + appendRegisterName(rd()); + appendSeparator(); + appendRegisterName(rm()); + appendImmShift(type(), immediate5()); + + return m_formatBuffer; + } + } + + if (rd() == 15) { + if (sBit()) { + bool testOrCmpInstruction = false; + + switch (op()) { + case 0x0: + instructionName = "tst"; + testOrCmpInstruction = true; + break; + case 0x4: + instructionName = "teq"; + testOrCmpInstruction = true; + break; + case 0x8: + instructionName = "cmn"; + testOrCmpInstruction = true; + break; + case 0xd: + instructionName = "cmp"; + testOrCmpInstruction = true; + break; + } + + if (testOrCmpInstruction) { + appendInstructionName(instructionName); + appendRegisterName(rn()); + appendSeparator(); + appendRegisterName(rm()); + appendImmShift(type(), immediate5()); + + return m_formatBuffer; + } + } + } + + appendInstructionName(instructionName); + appendRegisterName(rd()); + appendSeparator(); + appendRegisterName(rn()); + appendSeparator(); + appendRegisterName(rm()); + appendImmShift(type(), immediate5()); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeFPTransfer::format() +{ + appendInstructionName("vmov"); + + if (opL()) { + appendFPRegister(); + appendSeparator(); + } + + appendRegisterName(rt()); + + if (!opL()) { + appendSeparator(); + appendFPRegister(); + } + + return m_formatBuffer; +} + +void ARMv7DOpcodeFPTransfer::appendFPRegister() +{ + if (opC()) { + appendFPRegisterName('d', vd()); + bufferPrintf("[%u]", opH()); + } else + appendFPRegisterName('s', vn()); +} + +const char* ARMv7DOpcodeDataProcessingRegShift::format() +{ + appendInstructionName(opName()); + appendRegisterName(rd()); + appendSeparator(); + appendRegisterName(rn()); + appendSeparator(); + appendRegisterName(rm()); + + return m_formatBuffer; +} + +const char* const ARMv7DOpcodeDataProcessingRegExtend::s_opExtendNames[8] = { + "sxth", "uxth", "sxtb16", "uxtb16", "sxtb", "uxtb" +}; + +const char* const ARMv7DOpcodeDataProcessingRegExtend::s_opExtendAndAddNames[8] = { + "sxtah", "uxtah", "sxtab16", "uxtab16", "sxtab", "uxtab" +}; + +const char* ARMv7DOpcodeDataProcessingRegExtend::format() +{ + const char* instructionName; + + if (rn() == 0xf) + instructionName = opExtendName(); + else + instructionName = opExtendAndAddName(); + + if (!instructionName) + return defaultFormat(); + + appendInstructionName(instructionName); + appendRegisterName(rd()); + appendSeparator(); + appendRegisterName(rn()); + appendSeparator(); + appendRegisterName(rm()); + + if (rotate()) { + appendSeparator(); + appendString("ror "); + appendUnsignedImmediate(rotate() * 8); + } + + return m_formatBuffer; +} + +const char* const ARMv7DOpcodeDataProcessingRegParallel::s_opNames[16] = { + "sadd8", "sadd16", "sasx", 0, "ssub8", "ssub16", "ssax", 0, + "qadd8", "qadd16", "qasx", 0, "qsub8", "qsub16", "qsax", 0 +}; + +const char* ARMv7DOpcodeDataProcessingRegParallel::format() +{ + const char* instructionName; + + instructionName = opName(); + + if (!instructionName) + return defaultFormat(); + + appendInstructionName(instructionName); + appendRegisterName(rd()); + appendSeparator(); + appendRegisterName(rn()); + appendSeparator(); + appendRegisterName(rm()); + + return m_formatBuffer; +} + +const char* const ARMv7DOpcodeDataProcessingRegMisc::s_opNames[16] = { + "qadd", "qdadd", "qsub", "qdsub", "rev", "rev16", "rbit", "revsh", + "sel", 0, 0, 0, "clz" +}; + +const char* ARMv7DOpcodeDataProcessingRegMisc::format() +{ + const char* instructionName; + + instructionName = opName(); + + if (!instructionName) + return defaultFormat(); + + if ((op1() & 0x1) && (rn() != rm())) + return defaultFormat(); + + appendInstructionName(instructionName); + appendRegisterName(rd()); + appendSeparator(); + + if (op1() == 0x2) { // sel + appendRegisterName(rn()); + appendSeparator(); + appendRegisterName(rm()); + + return m_formatBuffer; + } + + appendRegisterName(rm()); + + if (!(op1() & 0x1)) { + appendSeparator(); + appendRegisterName(rn()); + } + + return m_formatBuffer; +} + +const char* const ARMv7DOpcodeHint32::s_opNames[8] = { + "nop", "yield", "wfe", "wfi", "sev" +}; + +const char* ARMv7DOpcodeHint32::format() +{ + if (isDebugHint()) { + appendInstructionName("debug"); + appendUnsignedImmediate(debugOption()); + + return m_formatBuffer; + } + + if (op() > 0x4) + return defaultFormat(); + + appendInstructionName(opName()); + + return m_formatBuffer; +} + +const char* const ARMv7DOpcodeDataLoad::s_opNames[8] = { + "ldrb", "ldrh", "ldr", 0, "ldrsb", "ldrsh" +}; + +const char* ARMv7DOpcodeLoadRegister::format() +{ + appendInstructionName(opName()); + appendRegisterName(rt()); + appendSeparator(); + appendCharacter('['); + appendRegisterName(rn()); + appendSeparator(); + appendRegisterName(rm()); + if (immediate2()) { + appendSeparator(); + appendUnsignedImmediate(immediate2()); + } + appendCharacter(']'); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeLoadSignedImmediate::format() +{ + appendInstructionName(opName()); + appendRegisterName(rt()); + appendSeparator(); + appendCharacter('['); + appendRegisterName(rn()); + if (pBit()) { + if (wBit() || immediate8()) { + appendSeparator(); + if (uBit()) + appendUnsignedImmediate(immediate8()); + else + appendSignedImmediate(0 - static_cast(immediate8())); + } + appendCharacter(']'); + if (wBit()) + appendCharacter('!'); + } else { + appendCharacter(']'); + appendSeparator(); + if (uBit()) + appendUnsignedImmediate(immediate8()); + else + appendSignedImmediate(0 - static_cast(immediate8())); + } + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeLoadUnsignedImmediate::format() +{ + appendInstructionName(opName()); + appendRegisterName(rt()); + appendSeparator(); + appendCharacter('['); + appendRegisterName(rn()); + if (immediate12()) { + appendSeparator(); + appendUnsignedImmediate(immediate12()); + } + appendCharacter(']'); + + return m_formatBuffer; +} + +const char* const ARMv7DOpcodeLongMultipleDivide::s_opNames[8] = { + "smull", "sdiv", "umull", "udiv", "smlal", "smlsld", "umlal", 0 +}; + +const char* const ARMv7DOpcodeLongMultipleDivide::s_smlalOpNames[4] = { + "smlalbb", "smlalbt", "smlaltb", "smlaltt" +}; + +const char* const ARMv7DOpcodeLongMultipleDivide::s_smlaldOpNames[2] = { + "smlald", "smlaldx" +}; + +const char* const ARMv7DOpcodeLongMultipleDivide::s_smlsldOpNames[2] = { + "smlsld", "smlsldx" +}; + +const char* ARMv7DOpcodeLongMultipleDivide::format() +{ + const char* instructionName = opName(); + + switch (op1()) { + case 0x0: + case 0x2: + if (op2()) + return defaultFormat(); + break; + case 0x1: + case 0x3: + if (op2() != 0xf) + return defaultFormat(); + break; + case 0x4: + if ((op2() & 0xc) == 0x8) + instructionName = smlalOpName(); + else if ((op2() & 0xe) == 0xc) + instructionName = smlaldOpName(); + else if (op2()) + return defaultFormat(); + break; + case 0x5: + if ((op2() & 0xe) == 0xc) + instructionName = smlaldOpName(); + else + return defaultFormat(); + break; + case 0x6: + if (op2() == 0x5) + instructionName = "umaal"; + else if (op2()) + return defaultFormat(); + break; + case 0x7: + return defaultFormat(); + break; + } + + appendInstructionName(instructionName); + if ((op1() & 0x5) == 0x1) { // sdiv and udiv + if (rt() != 0xf) + return defaultFormat(); + } else { + appendRegisterName(rdLo()); + appendSeparator(); + } + appendRegisterName(rdHi()); + appendSeparator(); + appendRegisterName(rn()); + appendSeparator(); + appendRegisterName(rm()); + + return m_formatBuffer; +} + +const char* const ARMv7DOpcodeUnmodifiedImmediate::s_opNames[16] = { + "addw", 0, "movw", 0, 0, "subw", "movt", 0, + "ssat", "ssat16", "sbfx", "bfi", "usat" , "usat16", "ubfx", 0 +}; + +const char* ARMv7DOpcodeUnmodifiedImmediate::format() +{ + const char* instructionName = opName(); + + switch (op() >> 1) { + case 0x0: + case 0x5: + if (rn() == 0xf) + instructionName = "adr"; + break; + case 0x9: + if (immediate5()) + instructionName = "ssat"; + break; + case 0xb: + if (rn() == 0xf) + instructionName = "bfc"; + break; + case 0xd: + if (immediate5()) + instructionName = "usat"; + break; + } + + if (!instructionName) + return defaultFormat(); + + appendInstructionName(instructionName); + appendRegisterName(rd()); + appendSeparator(); + + if ((op() & 0x17) == 0x4) { // movw or movt + appendUnsignedImmediate(immediate16()); + + return m_formatBuffer; + } + + if (!op() || (op() == 0xa)) { // addw, subw and adr + if (rn() == 0xf) { + int32_t offset; + + if ((op() == 0xa) && (rn() == 0xf)) + offset = 0 - static_cast(immediate12()); + else + offset = static_cast(immediate12()); + + appendPCRelativeOffset(offset); + + return m_formatBuffer; + } + + appendRegisterName(rn()); + appendSeparator(); + appendUnsignedImmediate(immediate12()); + + return m_formatBuffer; + } + + if (((op() & 0x15) == 0x10) || (((op() & 0x17) == 0x12) && immediate5())) { // ssat, usat, ssat16 & usat16 + appendSeparator(); + appendUnsignedImmediate(bitNumOrSatImmediate() + 1); + appendSeparator(); + appendRegisterName(rn()); + if (shBit() || immediate5()) { + appendSeparator(); + appendShiftType(shBit() << 1); + appendUnsignedImmediate(immediate5()); + } + + return m_formatBuffer; + } + + if (op() == 0x16) { // bfi or bfc + int width = static_cast(bitNumOrSatImmediate()) - static_cast(immediate5()) + 1; + + if (width < 0) + return defaultFormat(); + + if (rn() != 0xf) { + appendSeparator(); + appendRegisterName(rn()); + } + appendSeparator(); + appendUnsignedImmediate(immediate5()); + appendSeparator(); + appendSignedImmediate(width); + + return m_formatBuffer; + } + + // Must be sbfx or ubfx + appendSeparator(); + appendRegisterName(rn()); + appendSeparator(); + appendUnsignedImmediate(immediate5()); + appendSeparator(); + appendUnsignedImmediate(bitNumOrSatImmediate() + 1); + + return m_formatBuffer; +} + +const char* const ARMv7DOpcodeDataStoreSingle::s_opNames[4] = { + "strb", "strh", "str", 0 +}; + +const char* ARMv7DOpcodeDataPushPopSingle::format() +{ + appendInstructionName(opName()); + appendRegisterName(rt()); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeStoreSingleImmediate12::format() +{ + appendInstructionName(opName()); + appendRegisterName(rt()); + appendSeparator(); + appendCharacter('['); + appendRegisterName(rn()); + if (immediate12()) { + appendSeparator(); + appendUnsignedImmediate(immediate12()); + } + appendCharacter(']'); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeStoreSingleImmediate8::format() +{ + if (pBit() && uBit() && !wBit()) // Really undecoded strt + return defaultFormat(); + + if ((rn() == 0xf) || (!pBit() && !wBit())) + return defaultFormat(); + + appendInstructionName(opName()); + appendRegisterName(rt()); + appendSeparator(); + appendCharacter('['); + appendRegisterName(rn()); + + if (!pBit()) { + appendCharacter(']'); + appendSeparator(); + appendSignedImmediate(uBit() ? static_cast(immediate8()) : (0 - static_cast(immediate8()))); + + return m_formatBuffer; + } + + if (immediate8()) { + appendSeparator(); + appendSignedImmediate(uBit() ? static_cast(immediate8()) : (0 - static_cast(immediate8()))); + } + appendCharacter(']'); + + if (wBit()) + appendCharacter('!'); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeStoreSingleRegister::format() +{ + appendInstructionName(opName()); + appendRegisterName(rt()); + appendSeparator(); + appendCharacter('['); + appendRegisterName(rn()); + appendSeparator(); + appendRegisterName(rm()); + if (immediate2()) { + appendSeparator(); + appendString("lsl "); + appendUnsignedImmediate(immediate2()); + } + appendCharacter(']'); + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeVMOVDoublePrecision::format() +{ + appendInstructionName("vmov"); + if (op()) { + appendRegisterName(rt()); + appendSeparator(); + appendRegisterName(rt2()); + appendSeparator(); + } + + appendFPRegisterName('d', vm()); + + if (!op()) { + appendSeparator(); + appendRegisterName(rt()); + appendSeparator(); + appendRegisterName(rt2()); + } + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeVMOVSinglePrecision::format() +{ + appendInstructionName("vmov"); + if (op()) { + appendRegisterName(rt()); + appendSeparator(); + appendRegisterName(rt2()); + appendSeparator(); + } + + appendFPRegisterName('s', vm()); + appendSeparator(); + appendFPRegisterName('s', (vm() + 1) % 32); + + if (!op()) { + appendSeparator(); + appendRegisterName(rt()); + appendSeparator(); + appendRegisterName(rt2()); + } + + return m_formatBuffer; +} + +const char* ARMv7DOpcodeVMSR::format() +{ + appendInstructionName("vmrs"); + if (opL()) { + if (rt() == 0xf) + appendString("apsr_nzcv"); + else + appendRegisterName(rt()); + appendSeparator(); + } + + appendString("fpscr"); + + if (!opL()) { + appendSeparator(); + appendRegisterName(rt()); + } + + return m_formatBuffer; +} + +} } // namespace JSC::ARMv7Disassembler + +#endif // #if USE(ARMV7_DISASSEMBLER) diff --git a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h new file mode 100644 index 0000000..0b84842 --- /dev/null +++ b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h @@ -0,0 +1,1142 @@ +/* + * 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 ARMv7DOpcode_h +#define ARMv7DOpcode_h + +#if USE(ARMV7_DISASSEMBLER) + +#include +#include + +namespace JSC { namespace ARMv7Disassembler { + +class ARMv7DOpcode { +public: + static void init(); + + ARMv7DOpcode() + : m_opcode(0) + , m_bufferOffset(0) + { + init(); + + for (unsigned i = 0; i < 4; i++) + m_ifThenConditions[i] = CondNone; + + endITBlock(); + + m_formatBuffer[0] = '\0'; + } + + const char* disassemble(uint16_t*& currentPC); + +protected: + static const unsigned RegSP = 0xd; + static const unsigned RegLR = 0xe; + static const unsigned RegPC = 0xf; + + void fetchOpcode(uint16_t*&); + bool is32BitInstruction() { return (m_opcode & 0xfffff800) > 0xe000; } + bool isFPInstruction() { return (m_opcode & 0xfc000e00) == 0xec000a00; } + + static const char* const s_conditionNames[16]; + static const char* const s_shiftNames[4]; + static const char* const s_optionName[8]; + static const char* const s_specialRegisterNames[3]; + + static const char* conditionName(unsigned condition) { return s_conditionNames[condition & 0xf]; } + static const char* shiftName(unsigned shiftValue) { return s_shiftNames[shiftValue & 0x3]; } + + bool inITBlock() { return m_ITConditionIndex < m_ITBlocksize; } + bool startingITBlock() { return m_ITConditionIndex == m_ITBlocksize + 1; } + + void startITBlock(unsigned, unsigned); + void saveITConditionAt(unsigned, unsigned); + void endITBlock() + { + m_currentITCondition = CondNone; + m_ITConditionIndex = 0; + m_ITBlocksize = 0; + } + + void bufferPrintf(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3); + void appendInstructionName(const char*, bool addS = false); + + void appendInstructionNameNoITBlock(const char* instructionName) + { + bufferPrintf(" %-7.7s", instructionName); + } + + void appendRegisterName(unsigned); + void appendRegisterList(unsigned); + void appendFPRegisterName(char, unsigned); + + 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 appendPCRelativeOffset(int32_t immediate) + { + bufferPrintf("0x%x", reinterpret_cast(m_currentPC + immediate)); + } + + void appendShiftAmount(unsigned amount) + { + bufferPrintf("lsl #%u", 16 * amount); + } + + static const int bufferSize = 81; + static const unsigned char CondNone = 0xe; + static const unsigned MaxITBlockSize = 4; + + char m_formatBuffer[bufferSize]; + unsigned char m_ifThenConditions[MaxITBlockSize]; + uint16_t* m_currentPC; + uint32_t m_opcode; + int m_bufferOffset; + int m_currentITCondition; + unsigned m_ITConditionIndex; + unsigned m_ITBlocksize; + +private: + static bool s_initialized; +}; + +#define DEFINE_STATIC_FORMAT16(klass, thisObj) \ + static const char* format(ARMv7D16BitOpcode* thisObj) { return reinterpret_cast< klass *>(thisObj)->format(); } + +class ARMv7D16BitOpcode : public ARMv7DOpcode { +private: + class OpcodeGroup { + public: + OpcodeGroup(uint16_t opcodeMask, uint16_t opcodePattern, const char* (*format)(ARMv7D16BitOpcode*)) + : 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(uint16_t opcode) + { + return (opcode & m_opcodeMask) == m_opcodePattern; + } + + const char* format(ARMv7D16BitOpcode* thisObj) + { + return m_format(thisObj); + } + + public: + static const unsigned opcodeTableSize = 32; + static const unsigned opcodeTableMask = opcodeTableSize-1; + + // private: + uint16_t m_opcodeMask; + uint16_t m_opcodePattern; + const char* (*m_format)(ARMv7D16BitOpcode*); + OpcodeGroup* m_next; + }; + +public: + static void init(); + + const char* defaultFormat(); + const char* doDisassemble(); + +protected: + unsigned rm() { return (m_opcode >> 3) & 0x7; } + unsigned rd() { return m_opcode & 0x7; } + unsigned opcodeGroupNumber(unsigned opcode) { return (opcode >> 11) & OpcodeGroup::opcodeTableMask; } + +private: + static OpcodeGroup* opcodeTable[OpcodeGroup::opcodeTableSize]; +}; + +class ARMv7DOpcodeAddRegisterT2 : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xff00; + static const uint16_t s_pattern = 0x4400; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeAddRegisterT2, thisObj); + +protected: + const char* format(); + + unsigned rdn() { return ((m_opcode >> 4) & 0x8) | (m_opcode & 0x7); } + unsigned rm() { return ((m_opcode >> 3) & 0xf); } +}; + +class ARMv7DOpcodeAddSPPlusImmediate : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xf800; + static const uint16_t s_pattern = 0xc800; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeAddSPPlusImmediate, thisObj); + +protected: + const char* format(); + + unsigned rd() { return (m_opcode >> 8) & 0x7; } + unsigned immediate8() { return m_opcode & 0x0ff; } +}; + +class ARMv7DOpcodeAddSubtract : public ARMv7D16BitOpcode { +protected: + static const char* const s_opNames[2]; +}; + +class ARMv7DOpcodeAddSubtractT1 : public ARMv7DOpcodeAddSubtract { +public: + static const uint16_t s_mask = 0xfc00; + static const uint16_t s_pattern = 0x1800; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeAddSubtractT1, thisObj); + +protected: + const char* format(); + + const char* opName() { return s_opNames[op()]; } + + unsigned op() { return (m_opcode >> 9) & 0x1; } + unsigned rm() { return (m_opcode >> 6) & 0x7; } + unsigned rn() { return (m_opcode >> 3) & 0x7; } +}; + +class ARMv7DOpcodeAddSubtractImmediate3 : public ARMv7DOpcodeAddSubtract { +public: + static const uint16_t s_mask = 0xfc00; + static const uint16_t s_pattern = 0x1c00; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeAddSubtractImmediate3, thisObj); + +protected: + const char* format(); + + const char* opName() { return s_opNames[op()]; } + + unsigned op() { return (m_opcode >> 9) & 0x1; } + unsigned immediate3() { return (m_opcode >> 6) & 0x3; } + unsigned rn() { return (m_opcode >> 3) & 0x7; } +}; + +class ARMv7DOpcodeAddSubtractImmediate8 : public ARMv7DOpcodeAddSubtract { +public: + static const uint16_t s_mask = 0xf000; + static const uint16_t s_pattern = 0x3000; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeAddSubtractImmediate8, thisObj); + +protected: + const char* format(); + + const char* opName() { return s_opNames[op()]; } + + unsigned op() { return (m_opcode >> 11) & 0x1; } + unsigned rdn() { return (m_opcode >> 8) & 0x7; } + unsigned immediate8() { return m_opcode & 0xff; } +}; + +class ARMv7DOpcodeBranchConditionalT1 : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xf000; + static const uint16_t s_pattern = 0xd000; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeBranchConditionalT1, thisObj); + +protected: + const char* format(); + + unsigned condition() { return (m_opcode >> 8) & 0xf; } + int offset() { return static_cast(m_opcode & 0xff); } +}; + +class ARMv7DOpcodeBranchExchangeT1 : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xff00; + static const uint16_t s_pattern = 0x4700; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeBranchExchangeT1, thisObj); + +protected: + const char* format(); + + const char* opName() { return (m_opcode & 0x80) ? "blx" : "bx"; } + unsigned rm() { return ((m_opcode >> 3) & 0xf); } +}; + +class ARMv7DOpcodeBranchT2 : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xf800; + static const uint16_t s_pattern = 0xe000; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeBranchT2, thisObj); + +protected: + const char* format(); + + int immediate11() { return static_cast(m_opcode & 0x7ff); } +}; + +class ARMv7DOpcodeCompareImmediateT1 : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xf800; + static const uint16_t s_pattern = 0x2800; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeCompareImmediateT1, thisObj); + +protected: + const char* format(); + + unsigned rn() { return (m_opcode >> 8) & 0x3; } + unsigned immediate8() { return m_opcode & 0xff; } +}; + +class ARMv7DOpcodeCompareRegisterT1 : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xffc0; + static const uint16_t s_pattern = 0x4280; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeCompareRegisterT1, thisObj); + +protected: + const char* format(); + + unsigned rn() { return m_opcode & 0x7; } +}; + +class ARMv7DOpcodeCompareRegisterT2 : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xff00; + static const uint16_t s_pattern = 0x4500; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeCompareRegisterT2, thisObj); + +protected: + const char* format(); + + unsigned rn() { return ((m_opcode >> 4) & 0x8) | (m_opcode & 0x7); } + unsigned rm() { return ((m_opcode >> 3) & 0xf); } +}; + +class ARMv7DOpcodeDataProcessingRegisterT1 : public ARMv7D16BitOpcode { +private: + static const char* const s_opNames[16]; + +public: + static const uint16_t s_mask = 0xfc00; + static const uint16_t s_pattern = 0x4000; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeDataProcessingRegisterT1, thisObj); + +protected: + const char* format(); + + const char* opName() { return s_opNames[op()]; } + + unsigned op() { return (m_opcode >> 6) & 0xf; } + + unsigned rm() { return (m_opcode >> 3) & 0x7; } + unsigned rdn() { return m_opcode & 0x7; } +}; + +class ARMv7DOpcodeGeneratePCRelativeAddress : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xf800; + static const uint16_t s_pattern = 0xa000; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeGeneratePCRelativeAddress, thisObj); + +protected: + const char* format(); + + unsigned rd() { return (m_opcode >> 8) & 0x7; } + unsigned immediate8() { return m_opcode & 0x0ff; } +}; + +class ARMv7DOpcodeLoadFromLiteralPool : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xf800; + static const uint16_t s_pattern = 0x4800; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadFromLiteralPool, thisObj); + +protected: + const char* format(); + + unsigned rt() { return (m_opcode >> 8) & 0x7; } + unsigned immediate8() { return m_opcode & 0x0ff; } +}; + +class ARMv7DOpcodeLoadStoreRegisterImmediate : public ARMv7D16BitOpcode { +private: + static const char* const s_opNames[6]; + +public: + const char* format(); + +protected: + const char* opName() { return s_opNames[op()]; } + + unsigned op() { return ((m_opcode >> 11) & 0x1f) - 0xc; } + 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); } +}; + +class ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte : public ARMv7DOpcodeLoadStoreRegisterImmediate { +public: + static const uint16_t s_mask = 0xe000; + static const uint16_t s_pattern = 0x6000; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadStoreRegisterImmediate, thisObj); +}; + +class ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord : public ARMv7DOpcodeLoadStoreRegisterImmediate { +public: + static const uint16_t s_mask = 0xf800; + static const uint16_t s_pattern = 0x8000; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadStoreRegisterImmediate, thisObj); +}; + +class ARMv7DOpcodeLoadStoreRegisterOffsetT1 : public ARMv7D16BitOpcode { +private: + static const char* const s_opNames[8]; + +public: + static const uint16_t s_mask = 0xf000; + static const uint16_t s_pattern = 0x5000; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadStoreRegisterOffsetT1, thisObj); + +protected: + const char* format(); + + const char* opName() { return s_opNames[opB()]; } + + unsigned opB() { return (m_opcode >> 9) & 0x7; } + unsigned rm() { return (m_opcode >> 6) & 0x7; } + unsigned rn() { return (m_opcode >> 3) & 0x7; } + unsigned rt() { return m_opcode & 0x7; } +}; + +class ARMv7DOpcodeLoadStoreRegisterSPRelative : public ARMv7D16BitOpcode { +private: + static const char* const s_opNames[8]; + +public: + static const uint16_t s_mask = 0xf000; + static const uint16_t s_pattern = 0x9000; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadStoreRegisterSPRelative, thisObj); + +protected: + const char* format(); + + const char* opName() { return op() ? "ldr" : "str"; } + + unsigned op() { return (m_opcode >> 11) & 0x1; } + unsigned rt() { return (m_opcode >> 8) & 0x7; } + unsigned immediate8() { return m_opcode & 0xff; } +}; + +class ARMv7DOpcodeLogicalImmediateT1 : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xe000; + static const uint16_t s_pattern = 0x0000; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLogicalImmediateT1, thisObj); + +protected: + const char* format(); + + const char* opName() { return shiftName(op()); } + + unsigned op() { return (m_opcode >> 12) & 0x3; } + unsigned immediate5() { return (m_opcode >> 6) & 0x1f; } +}; + +class ARMv7DOpcodeMiscAddSubSP : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xff00; + static const uint16_t s_pattern = 0xb000; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMiscAddSubSP, thisObj); + +protected: + const char* format(); + + const char* opName() { return op() ? "sub" : "add"; } + unsigned op() { return (m_opcode >> 7) & 0x1; } + unsigned immediate7() { return m_opcode & 0x7f; } +}; + +class ARMv7DOpcodeMiscByteHalfwordOps : public ARMv7D16BitOpcode { +private: + static const char* const s_opNames[8]; + +public: + static const uint16_t s_mask = 0xf700; + static const uint16_t s_pattern = 0xb200; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMiscByteHalfwordOps, thisObj); + +protected: + const char* format(); + + const char* opName() { return s_opNames[op()]; } + unsigned op() { return ((m_opcode >> 9) & 0x4) || ((m_opcode >> 6) & 0x3); } +}; + +class ARMv7DOpcodeMiscBreakpointT1 : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xff00; + static const uint16_t s_pattern = 0xbe00; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMiscBreakpointT1, thisObj); + +protected: + const char* format(); + + unsigned immediate8() { return m_opcode & 0xff; } +}; + +class ARMv7DOpcodeMiscCompareAndBranch : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xf500; + static const uint16_t s_pattern = 0xb100; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMiscCompareAndBranch, thisObj); + +protected: + const char* format(); + + const char* opName() { return op() ? "cbnz" : "cbz"; } + unsigned op() { return (m_opcode >> 11) & 0x1; } + int32_t immediate6() { return ((m_opcode >> 4) & 0x20) | ((m_opcode >> 3) & 0x1f); } + unsigned rn() { return m_opcode & 0x7; } +}; + +class ARMv7DOpcodeMiscHint16 : public ARMv7D16BitOpcode { +private: + static const char* const s_opNames[16]; + +public: + static const uint16_t s_mask = 0xff0f; + static const uint16_t s_pattern = 0xbf00; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMiscHint16, thisObj); + +protected: + const char* format(); + + const char* opName() { return s_opNames[opA()]; } + unsigned opA() { return (m_opcode >> 4) & 0xf; } +}; + +class ARMv7DOpcodeMiscIfThenT1 : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xff00; + static const uint16_t s_pattern = 0xbf00; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMiscIfThenT1, thisObj); + +protected: + const char* format(); + + unsigned firstCondition() { return (m_opcode >> 4) & 0xf; } + unsigned mask() { return m_opcode & 0xf; } +}; + +class ARMv7DOpcodeMiscPushPop : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xf600; + static const uint16_t s_pattern = 0xb400; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMiscPushPop, thisObj); + +protected: + const char* format(); + + const char* opName() { return op() ? "pop" : "push"; } + unsigned op() { return (m_opcode >> 11) & 0x1; } + unsigned registerMask() { return ((m_opcode << 6) & 0x4000) | (m_opcode & 0x7f); } +}; + +class ARMv7DOpcodeMoveImmediateT1 : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xf800; + static const uint16_t s_pattern = 0x2000; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMoveImmediateT1, thisObj); + +protected: + const char* format(); + + unsigned rd() { return (m_opcode >> 8) & 0x3; } + unsigned immediate8() { return m_opcode & 0xff; } +}; + +class ARMv7DOpcodeMoveRegisterT1 : public ARMv7D16BitOpcode { +public: + static const uint16_t s_mask = 0xff00; + static const uint16_t s_pattern = 0x4600; + + DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMoveRegisterT1, thisObj); + +protected: + const char* format(); + + unsigned rd() { return ((m_opcode >> 4) & 0x8) | (m_opcode & 0x7); } + unsigned rm() { return ((m_opcode >> 3) & 0xf); } +}; + +// 32 Bit instructions + +#define DEFINE_STATIC_FORMAT32(klass, thisObj) \ + static const char* format(ARMv7D32BitOpcode* thisObj) { return reinterpret_cast< klass *>(thisObj)->format(); } + +class ARMv7D32BitOpcode : public ARMv7DOpcode { +private: + class OpcodeGroup { + public: + OpcodeGroup(uint32_t opcodeMask, uint32_t opcodePattern, const char* (*format)(ARMv7D32BitOpcode*)) + : 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(ARMv7D32BitOpcode* thisObj) + { + return m_format(thisObj); + } + + public: + static const unsigned opcodeTableSize = 16; + static const unsigned opcodeTableMask = opcodeTableSize-1; + + private: + uint32_t m_opcodeMask; + uint32_t m_opcodePattern; + const char* (*m_format)(ARMv7D32BitOpcode*); + OpcodeGroup* m_next; + }; + +public: + static void init(); + + const char* defaultFormat(); + const char* doDisassemble(); + +protected: + unsigned rd() { return (m_opcode >> 8) & 0xf; } + unsigned rm() { return m_opcode & 0xf; } + unsigned rn() { return (m_opcode >> 16) & 0xf; } + unsigned rt() { return (m_opcode >> 12) & 0xf; } + + unsigned opcodeGroupNumber(unsigned opcode) { return (opcode >> 25) & OpcodeGroup::opcodeTableMask; } + +private: + static OpcodeGroup* opcodeTable[OpcodeGroup::opcodeTableSize]; +}; + +class ARMv7DOpcodeBranchRelative : public ARMv7D32BitOpcode { +protected: + unsigned sBit() { return (m_opcode >> 26) & 0x1; } + unsigned j1() { return (m_opcode >> 13) & 0x1; } + unsigned j2() { return (m_opcode >> 11) & 0x1; } + unsigned immediate11() { return m_opcode & 0x7ff; } +}; + +class ARMv7DOpcodeConditionalBranchT3 : public ARMv7DOpcodeBranchRelative { +public: + static const uint32_t s_mask = 0xf800d000; + static const uint32_t s_pattern = 0xf0008000; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeConditionalBranchT3, thisObj); + +protected: + const char* format(); + + int32_t offset() { return ((static_cast(sBit() << 31)) >> 12) | static_cast((j1() << 18) | (j2() << 17) | (immediate6() << 11) | immediate11()); } + unsigned condition() { return (m_opcode >> 22) & 0xf; } + unsigned immediate6() { return (m_opcode >> 16) & 0x3f; } +}; + +class ARMv7DOpcodeBranchOrBranchLink : public ARMv7DOpcodeBranchRelative { +public: + static const uint32_t s_mask = 0xf8009000; + static const uint32_t s_pattern = 0xf0009000; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeBranchOrBranchLink, thisObj); + +protected: + const char* format(); + + int32_t offset() { return ((static_cast(sBit() << 31)) >> 8) | static_cast((~(j1() ^ sBit()) << 22) | (~(j2() ^ sBit()) << 21) | (immediate10() << 11) | immediate11()); } + unsigned immediate10() { return (m_opcode >> 16) & 0x3ff; } + bool isBL() { return !!((m_opcode >> 14) & 0x1); } +}; + +class ARMv7DOpcodeDataProcessingLogicalAndRithmetic : public ARMv7D32BitOpcode { +protected: + static const char* const s_opNames[16]; +}; + +class ARMv7DOpcodeDataProcessingModifiedImmediate : public ARMv7DOpcodeDataProcessingLogicalAndRithmetic { +private: + void appendImmShift(unsigned, unsigned); + +public: + static const uint32_t s_mask = 0xfa008000; + static const uint32_t s_pattern = 0xf0000000; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataProcessingModifiedImmediate, thisObj); + +protected: + const char* format(); + void appendModifiedImmediate(unsigned); + + const char* opName() { return s_opNames[op()]; } + + unsigned op() { return (m_opcode >> 21) & 0xf; } + unsigned sBit() { return (m_opcode >> 20) & 0x1; } + unsigned immediate12() { return ((m_opcode >> 15) & 0x0800) | ((m_opcode >> 4) & 0x0700) | (m_opcode & 0x00ff); } +}; + +class ARMv7DOpcodeDataProcessingShiftedReg : public ARMv7DOpcodeDataProcessingLogicalAndRithmetic { +private: + void appendImmShift(unsigned, unsigned); + +public: + static const uint32_t s_mask = 0xfe000000; + static const uint32_t s_pattern = 0xea000000; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataProcessingShiftedReg, thisObj); + +protected: + const char* format(); + + const char* opName() { return s_opNames[op()]; } + + unsigned sBit() { return (m_opcode >> 20) & 0x1; } + unsigned op() { return (m_opcode >> 21) & 0xf; } + unsigned immediate5() { return ((m_opcode >> 10) & 0x1c) | ((m_opcode >> 6) & 0x3); } + unsigned type() { return (m_opcode >> 4) & 0x3; } + unsigned tbBit() { return (m_opcode >> 5) & 0x1; } + unsigned tBit() { return (m_opcode >> 4) & 0x1; } +}; + +class ARMv7DOpcodeDataProcessingReg : public ARMv7D32BitOpcode { +protected: + unsigned op1() { return (m_opcode >> 20) & 0xf; } + unsigned op2() { return (m_opcode >> 4) & 0xf; } +}; + +class ARMv7DOpcodeDataProcessingRegShift : public ARMv7DOpcodeDataProcessingReg { +public: + static const uint32_t s_mask = 0xffe0f0f0; + static const uint32_t s_pattern = 0xfa00f000; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataProcessingRegShift, thisObj); + +protected: + const char* format(); + + const char* opName() { return shiftName((op1() >> 1) & 0x3); } +}; + +class ARMv7DOpcodeDataProcessingRegExtend : public ARMv7DOpcodeDataProcessingReg { +private: + static const char* const s_opExtendNames[8]; + static const char* const s_opExtendAndAddNames[8]; + +public: + static const uint32_t s_mask = 0xff80f0c0; + static const uint32_t s_pattern = 0xfa00f080; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataProcessingRegExtend, thisObj); + +protected: + const char* format(); + + const char* opExtendName() { return s_opExtendNames[op1()]; } + const char* opExtendAndAddName() { return s_opExtendAndAddNames[op1()]; } + unsigned rotate() { return (m_opcode >> 4) & 0x3; } +}; + +class ARMv7DOpcodeDataProcessingRegParallel : public ARMv7DOpcodeDataProcessingReg { +private: + static const char* const s_opNames[16]; + +public: + static const uint32_t s_mask = 0xff80f0e0; + static const uint32_t s_pattern = 0xfa00f000; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataProcessingRegParallel, thisObj); + +protected: + const char* format(); + + const char* opName() { return s_opNames[((op1() & 0x7) << 1) | (op2() & 0x1)]; } +}; + +class ARMv7DOpcodeDataProcessingRegMisc : public ARMv7DOpcodeDataProcessingReg { +private: + static const char* const s_opNames[16]; + +public: + static const uint32_t s_mask = 0xffc0f0c0; + static const uint32_t s_pattern = 0xfa80f080; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataProcessingRegMisc, thisObj); + +protected: + const char* format(); + + const char* opName() { return s_opNames[((op1() & 0x3) << 2) | (op2() & 0x3)]; } +}; + +class ARMv7DOpcodeHint32 : public ARMv7D32BitOpcode { +private: + static const char* const s_opNames[8]; + +public: + static const uint32_t s_mask = 0xfff0d000; + static const uint32_t s_pattern = 0xf3a08000; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeHint32, thisObj); + +protected: + const char* format(); + + const char* opName() { return s_opNames[op()]; } + + bool isDebugHint() { return (m_opcode & 0xf0) == 0xf0; } + unsigned debugOption() { return m_opcode & 0xf; } + unsigned op() { return m_opcode & 0x7; } +}; + +class ARMv7DOpcodeFPTransfer : public ARMv7D32BitOpcode { +public: + static const uint32_t s_mask = 0xffc00e7f; + static const uint32_t s_pattern = 0xee000a10; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeFPTransfer, thisObj); + +protected: + const char* format(); + + void appendFPRegister(); + + unsigned opH() { return (m_opcode >> 21) & 0x1; } + unsigned opL() { return (m_opcode >> 20) & 0x1; } + unsigned rt() { return (m_opcode >> 12) & 0xf; } + unsigned opC() { return (m_opcode >> 8) & 0x1; } + unsigned opB() { return (m_opcode >> 5) & 0x3; } + unsigned vd() { return ((m_opcode >> 3) & 0x10) | ((m_opcode >> 16) & 0xf); } + unsigned vn() { return ((m_opcode >> 7) & 0x1) | ((m_opcode >> 15) & 0x1e); } +}; + +class ARMv7DOpcodeDataLoad : public ARMv7D32BitOpcode { +protected: + static const char* const s_opNames[8]; + +protected: + const char* opName() { return s_opNames[op()]; } + + unsigned op() { return ((m_opcode >> 22) & 0x4) | ((m_opcode >> 21) & 0x3); } +}; + +class ARMv7DOpcodeLoadRegister : public ARMv7DOpcodeDataLoad { +public: + static const uint32_t s_mask = 0xfe900800; + static const uint32_t s_pattern = 0xf8100000; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeLoadRegister, thisObj); + +protected: + const char* format(); + + unsigned immediate2() { return (m_opcode >> 4) & 0x3; } +}; + +class ARMv7DOpcodeLoadSignedImmediate : public ARMv7DOpcodeDataLoad { +public: + static const uint32_t s_mask = 0xfe900800; + static const uint32_t s_pattern = 0xf8100800; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeLoadSignedImmediate, thisObj); + +protected: + const char* format(); + + unsigned pBit() { return (m_opcode >> 10) & 0x1; } + unsigned uBit() { return (m_opcode >> 9) & 0x1; } + unsigned wBit() { return (m_opcode >> 8) & 0x1; } + unsigned immediate8() { return m_opcode & 0xff; } +}; + +class ARMv7DOpcodeLoadUnsignedImmediate : public ARMv7DOpcodeDataLoad { +public: + static const uint32_t s_mask = 0xfe900000; + static const uint32_t s_pattern = 0xf8900000; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeLoadUnsignedImmediate, thisObj); + +protected: + const char* format(); + + unsigned immediate12() { return m_opcode & 0xfff; } +}; + +class ARMv7DOpcodeLongMultipleDivide : public ARMv7D32BitOpcode { +protected: + static const char* const s_opNames[8]; + static const char* const s_smlalOpNames[4]; + static const char* const s_smlaldOpNames[2]; + static const char* const s_smlsldOpNames[2]; + +public: + static const uint32_t s_mask = 0xff800000; + static const uint32_t s_pattern = 0xfb800000; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeLongMultipleDivide, thisObj); + +protected: + const char* format(); + + const char* opName() { return s_opNames[op1()]; } + const char* smlalOpName() { return s_smlalOpNames[(nBit() << 1) | mBit()]; } + const char* smlaldOpName() { return s_smlaldOpNames[mBit()]; } + const char* smlsldOpName() { return s_smlsldOpNames[mBit()]; } + + unsigned rdLo() { return rt(); } + unsigned rdHi() { return rd(); } + unsigned op1() { return (m_opcode >> 20) & 0x7; } + unsigned op2() { return (m_opcode >> 4) & 0xf; } + unsigned nBit() { return (m_opcode >> 5) & 0x1; } + unsigned mBit() { return (m_opcode >> 4) & 0x1; } +}; + +class ARMv7DOpcodeDataPushPopSingle : public ARMv7D32BitOpcode { +public: + static const uint32_t s_mask = 0xffef0fff; + static const uint32_t s_pattern = 0xf84d0d04; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataPushPopSingle, thisObj); + +protected: + const char* format(); + + const char* opName() { return op() ? "pop" : "push"; } + unsigned op() { return (m_opcode >> 20) & 0x1; } +}; + +class ARMv7DOpcodeDataStoreSingle : public ARMv7D32BitOpcode { +protected: + static const char* const s_opNames[4]; + +protected: + const char* opName() { return s_opNames[op()]; } + + unsigned op() { return (m_opcode >> 21) & 0x3; } +}; + +class ARMv7DOpcodeStoreSingleImmediate12 : public ARMv7DOpcodeDataStoreSingle { +public: + static const uint32_t s_mask = 0xfff00000; + static const uint32_t s_pattern = 0xf8c00000; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeStoreSingleImmediate12, thisObj); + + const char* format(); + +protected: + unsigned immediate12() { return m_opcode & 0xfff; } +}; + +class ARMv7DOpcodeStoreSingleImmediate8 : public ARMv7DOpcodeDataStoreSingle { +public: + static const uint32_t s_mask = 0xfff00800; + static const uint32_t s_pattern = 0xf8400800; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeStoreSingleImmediate8, thisObj); + + const char* format(); + +protected: + unsigned pBit() { return (m_opcode >> 10) & 0x1; } + unsigned uBit() { return (m_opcode >> 9) & 0x1; } + unsigned wBit() { return (m_opcode >> 8) & 0x1; } + unsigned immediate8() { return m_opcode & 0xff; } +}; + +class ARMv7DOpcodeStoreSingleRegister : public ARMv7DOpcodeDataStoreSingle { +public: + static const uint32_t s_mask = 0xfff00fc0; + static const uint32_t s_pattern = 0xf8400000; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeStoreSingleRegister, thisObj); + +protected: + const char* format(); + + unsigned immediate2() { return (m_opcode >> 4) & 0x3; } +}; + +class ARMv7DOpcodeUnmodifiedImmediate : public ARMv7D32BitOpcode { +protected: + static const char* const s_opNames[16]; + +public: + static const uint32_t s_mask = 0xfa008000; + static const uint32_t s_pattern = 0xf2000000; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeUnmodifiedImmediate, thisObj); + +protected: + const char* format(); + + const char* opName() { return s_opNames[op() >> 1]; } + + unsigned op() { return (m_opcode >> 20) & 0x1f; } + unsigned shBit() { return (m_opcode >> 21) & 0x1; } + unsigned bitNumOrSatImmediate() { return m_opcode & 0x1f; } + unsigned immediate5() { return ((m_opcode >> 9) & 0x1c) | ((m_opcode >> 6) & 0x3); } + unsigned immediate12() { return ((m_opcode >> 15) & 0x0800) | ((m_opcode >> 4) & 0x0700) | (m_opcode & 0x00ff); } + unsigned immediate16() { return ((m_opcode >> 4) & 0xf000) | ((m_opcode >> 15) & 0x0800) | ((m_opcode >> 4) & 0x0700) | (m_opcode & 0x00ff); } +}; + +class ARMv7DOpcodeVMOVDoublePrecision : public ARMv7D32BitOpcode { +public: + static const uint32_t s_mask = 0xffe00fd0; + static const uint32_t s_pattern = 0xec400b10; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeVMOVDoublePrecision, thisObj); + +protected: + const char* format(); + + unsigned op() { return (m_opcode >> 20) & 0x1; } + unsigned rt2() { return (m_opcode >> 16) & 0xf; } + unsigned rt() { return (m_opcode >> 16) & 0xf; } + unsigned vm() { return (m_opcode & 0xf) | ((m_opcode >> 1) & 0x10); } +}; + +class ARMv7DOpcodeVMOVSinglePrecision : public ARMv7D32BitOpcode { +public: + static const uint32_t s_mask = 0xffe00fd0; + static const uint32_t s_pattern = 0xec400a10; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeVMOVSinglePrecision, thisObj); + +protected: + const char* format(); + + unsigned op() { return (m_opcode >> 20) & 0x1; } + unsigned rt2() { return (m_opcode >> 16) & 0xf; } + unsigned rt() { return (m_opcode >> 16) & 0xf; } + unsigned vm() { return ((m_opcode << 1) & 0x1e) | ((m_opcode >> 5) & 0x1); } +}; + +class ARMv7DOpcodeVMSR : public ARMv7D32BitOpcode { +public: + static const uint32_t s_mask = 0xffef0fff; + static const uint32_t s_pattern = 0xeee10a10; + + DEFINE_STATIC_FORMAT32(ARMv7DOpcodeVMSR, thisObj); + +protected: + const char* format(); + + unsigned opL() { return (m_opcode >> 20) & 0x1; } + unsigned rt() { return (m_opcode >> 12) & 0xf; } +}; + + +} } // namespace JSC::ARMv7Disassembler + +using JSC::ARMv7Disassembler::ARMv7DOpcode; + +#endif // #if USE(ARMV7_DISASSEMBLER) + +#endif // ARMv7DOpcode_h diff --git a/src/3rdparty/masm/disassembler/ARMv7Disassembler.cpp b/src/3rdparty/masm/disassembler/ARMv7Disassembler.cpp new file mode 100644 index 0000000..bfb4895 --- /dev/null +++ b/src/3rdparty/masm/disassembler/ARMv7Disassembler.cpp @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#include "config.h" +#include "Disassembler.h" + +#if USE(ARMV7_DISASSEMBLER) + +#include "ARMv7/ARMv7DOpcode.h" +#include "MacroAssemblerCodeRef.h" + +namespace JSC { + +bool tryToDisassemble(const MacroAssemblerCodePtr& codePtr, size_t size, const char* prefix, PrintStream& out) +{ + ARMv7DOpcode armOpcode; + + uint16_t* currentPC = reinterpret_cast(reinterpret_cast(codePtr.executableAddress())&~1); + uint16_t* endPC = currentPC + (size / sizeof(uint16_t)); + + while (currentPC < endPC) { + char pcString[12]; + snprintf(pcString, sizeof(pcString), "0x%x", reinterpret_cast(currentPC)); + out.printf("%s%10s: %s\n", prefix, pcString, armOpcode.disassemble(currentPC)); + } + + return true; +} + +} // namespace JSC + +#endif // USE(ARMV7_DISASSEMBLER) + diff --git a/src/3rdparty/masm/masm-defs.pri b/src/3rdparty/masm/masm-defs.pri index ef9f79a..aa6acc9 100644 --- a/src/3rdparty/masm/masm-defs.pri +++ b/src/3rdparty/masm/masm-defs.pri @@ -35,8 +35,12 @@ INCLUDEPATH += $$PWD/stubs INCLUDEPATH += $$PWD/stubs/wtf INCLUDEPATH += $$PWD -disassembler:if(isEqual(QT_ARCH, "i386")|isEqual(QT_ARCH, "x86_64")):!win*: DEFINES += WTF_USE_UDIS86=1 -else: DEFINES += WTF_USE_UDIS86=0 +disassembler { + if(isEqual(QT_ARCH, "i386")|isEqual(QT_ARCH, "x86_64")):!win*: DEFINES += WTF_USE_UDIS86=1 + if(isEqual(QT_ARCH, "arm")):contains(DEFINES, V4_ENABLE_JIT): DEFINES += WTF_USE_ARMV7_DISASSEMBLER=1 +} else { + DEFINES += WTF_USE_UDIS86=0 +} INCLUDEPATH += $$PWD/disassembler INCLUDEPATH += $$PWD/disassembler/udis86 diff --git a/src/3rdparty/masm/masm.pri b/src/3rdparty/masm/masm.pri index 99c364e..63537f2 100644 --- a/src/3rdparty/masm/masm.pri +++ b/src/3rdparty/masm/masm.pri @@ -59,6 +59,11 @@ contains(DEFINES, WTF_USE_UDIS86=1) { QMAKE_EXTRA_TARGETS += udis86_tab_cfile } +# We can always compile these, they have ifdef guards inside +SOURCES += $$PWD/disassembler/ARMv7Disassembler.cpp +SOURCES += $$PWD/disassembler/ARMv7/ARMv7DOpcode.cpp +HEADERS += $$PWD/disassembler/ARMv7/ARMv7DOpcode.h + SOURCES += $$PWD/yarr/*.cpp HEADERS += $$PWD/yarr/*.h diff --git a/src/3rdparty/masm/wtf/Platform.h b/src/3rdparty/masm/wtf/Platform.h index 68f6f66..b8402a9 100644 --- a/src/3rdparty/masm/wtf/Platform.h +++ b/src/3rdparty/masm/wtf/Platform.h @@ -725,7 +725,7 @@ #define WTF_USE_UDIS86 1 #endif -#if !defined(ENABLE_DISASSEMBLER) && USE(UDIS86) +#if !defined(ENABLE_DISASSEMBLER) && (USE(UDIS86) || USE(ARMV7_DISASSEMBLER)) #define ENABLE_DISASSEMBLER 1 #endif diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp index 2665356..7df64b3 100644 --- a/src/qml/compiler/qv4isel_masm.cpp +++ b/src/qml/compiler/qv4isel_masm.cpp @@ -611,7 +611,7 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) # if OS(MAC_OS_X) char *disasmOutput = memStream.buf.data(); # endif -# if CPU(X86) || CPU(X86_64) +# if CPU(X86) || CPU(X86_64) || CPU(ARM) QHash idents; printDisassembledOutputWithCalls(disasmOutput, functions); # endif -- 2.7.4