]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - ftl/FTLDWARFDebugLineInfo.cpp
JavaScriptCore-7600.1.4.9.tar.gz
[apple/javascriptcore.git] / ftl / FTLDWARFDebugLineInfo.cpp
diff --git a/ftl/FTLDWARFDebugLineInfo.cpp b/ftl/FTLDWARFDebugLineInfo.cpp
new file mode 100644 (file)
index 0000000..0a7a508
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 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. AND ITS CONTRIBUTORS ``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 ITS 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 "FTLDWARFDebugLineInfo.h"
+
+#if ENABLE(FTL_JIT)
+
+#include <wtf/DataLog.h>
+
+namespace JSC { namespace FTL {
+
+DebugLineInterpreter::DebugLineInterpreter(const char* program)
+    : m_program(program)
+    , m_logResults(false)
+{
+    resetInterpreterState();
+}
+
+template <typename T> inline T read(const char*& program)
+{
+    T result = *reinterpret_cast<const T*>(program);
+    program += sizeof(T);
+    return result;
+}
+
+uint32_t DebugLineInterpreter::parseULEB128(const char*& offset)
+{
+    uint32_t result = 0;
+    uint8_t byte;
+    unsigned shiftAmount = 0;
+    do {
+        byte = read<uint8_t>(offset);
+        result |= (byte & ~0x80) << shiftAmount;
+        shiftAmount += 7;
+    } while (byte & 0x80);
+    return result;
+}
+
+int32_t DebugLineInterpreter::parseSLEB128(const char*& offset)
+{
+    int32_t result = 0;
+    uint8_t byte;
+    unsigned shiftAmount = 0;
+    do {
+        byte = read<uint8_t>(offset);
+        result |= (byte & ~0x80) << shiftAmount;
+        shiftAmount += 7;
+    } while (byte & 0x80);
+    
+    // If the sign bit (in this case, the second MSB) on the last byte is set we need to zero extend.
+    if (byte & 0x40)
+        result |= -(1 << shiftAmount);
+    return result;
+}
+
+void DebugLineInterpreter::run()
+{
+    parsePrologue();
+    interpretStatementProgram();
+    if (m_logResults)
+        printLineInfo();
+}
+
+void DebugLineInterpreter::parsePrologue()
+{
+    const char* currentProgramOffset = m_program;
+    m_prologue.totalLength = read<uint32_t>(currentProgramOffset);
+    if (m_prologue.totalLength == 0xffffffff) {
+        // This is 64-bit DWARF format.
+        m_prologue.format = SixtyFourBit;
+        m_prologue.totalLength = read<uint64_t>(currentProgramOffset);
+    } else
+        m_prologue.format = ThirtyTwoBit;
+    m_prologue.version = read<uint16_t>(currentProgramOffset);
+    
+    if (m_prologue.format == ThirtyTwoBit)
+        m_prologue.prologueLength = read<uint32_t>(currentProgramOffset);
+    else
+        m_prologue.prologueLength = read<uint64_t>(currentProgramOffset);
+    const char* afterLengthOffset = currentProgramOffset;
+    
+    m_prologue.minimumInstructionLength = read<uint8_t>(currentProgramOffset);
+    m_prologue.defaultIsStatement = read<uint8_t>(currentProgramOffset);
+    m_prologue.lineBase = read<int8_t>(currentProgramOffset);
+    m_prologue.lineRange = read<uint8_t>(currentProgramOffset);
+    m_prologue.opcodeBase = read<uint8_t>(currentProgramOffset);
+    for (unsigned i = 1; i < m_prologue.opcodeBase; ++i)
+        m_prologue.standardOpcodeLengths.append(read<uint8_t>(currentProgramOffset));
+    parseIncludeDirectories(currentProgramOffset);
+    parseFileEntries(currentProgramOffset);
+    
+    m_program = afterLengthOffset + m_prologue.prologueLength;
+
+    if (!m_logResults)
+        return;
+
+    dataLog("\nPrologue:\n");
+    dataLog("totalLength = ", m_prologue.totalLength, "\n");
+    dataLog("version = ", m_prologue.version, "\n");
+    dataLog("prologueLength = ", m_prologue.prologueLength, "\n");
+    dataLog("minimumInstructionLength = ", m_prologue.minimumInstructionLength, "\n");
+    dataLog("defaultIsStatement = ", m_prologue.defaultIsStatement, "\n");
+    dataLog("lineBase = ", m_prologue.lineBase, "\n");
+    dataLog("lineRange = ", m_prologue.lineRange, "\n");
+    dataLog("opcodeBase = ", m_prologue.opcodeBase, "\n");
+    
+    dataLog("\nStandard Opcode Lengths:\n");
+    for (unsigned i = 1; i < m_prologue.opcodeBase; ++i)
+        dataLog("standardOpcodeLengths[", i - 1, "] = ", m_prologue.standardOpcodeLengths[i - 1], "\n");
+    
+    dataLog("\nInclude Directories:\n");
+    for (unsigned i = 0; i < m_prologue.includeDirectories.size(); ++i)
+        dataLog("includeDirectories[", i, "] = ", m_prologue.includeDirectories[i], "\n");
+    
+    dataLog("\nFiles:\n");
+    for (unsigned i = 0; i < m_prologue.fileEntries.size(); ++i) {
+        FileEntry& entry = m_prologue.fileEntries[i];
+        dataLog("fileEntries[", i, "] = {name: \"", entry.name, "\", dir_index: ", entry.directoryIndex, ", last_modified: ", entry.lastModified, ", size: ", entry.size, "}\n");
+    }
+}
+
+void DebugLineInterpreter::parseIncludeDirectories(const char*& offset)
+{
+    size_t length = 0;
+    while ((length = strlen(offset))) {
+        m_prologue.includeDirectories.append(offset);
+        offset += length + 1;
+    }
+    
+    // Extra increment to get past the last null byte.
+    offset += 1;
+}
+
+void DebugLineInterpreter::parseFileEntries(const char*& offset)
+{
+    while (true) {
+        DebugLineInterpreter::FileEntry nextEntry;
+        if (!parseFileEntry(offset, nextEntry))
+            break;
+        m_prologue.fileEntries.append(nextEntry);
+    }
+}
+
+bool DebugLineInterpreter::parseFileEntry(const char*& offset, FileEntry& entry)
+{
+    size_t length = strlen(offset);
+    if (!length) {
+        offset += 1;
+        return false;
+    }
+    entry.name = offset;
+    offset += length + 1;
+    entry.directoryIndex = parseULEB128(offset);
+    entry.lastModified = parseULEB128(offset);
+    entry.size = parseULEB128(offset);
+    
+    return true;
+}
+
+void DebugLineInterpreter::interpretStatementProgram()
+{
+    const char* currentProgramOffset = m_program;
+    bool keepGoing = true;
+    do {
+        keepGoing = interpretOpcode(currentProgramOffset);
+    } while (keepGoing);
+}
+
+bool DebugLineInterpreter::interpretOpcode(const char*& offset)
+{
+    uint8_t nextOpcode = read<uint8_t>(offset);
+    switch (nextOpcode) {
+    case ExtendedOpcodes: {
+        uint32_t length = parseULEB128(offset);
+        if (!length)
+            return false;
+        uint8_t extendedOpcode = read<uint8_t>(offset);
+        switch (extendedOpcode) {
+        case DW_LNE_end_sequence: {
+            m_currentState.endSequence = true;
+            m_lineInfoMatrix.append(m_currentState);
+            resetInterpreterState();
+            break;
+        }
+        case DW_LNE_set_address: {
+            m_currentState.address = read<size_t>(offset);
+            break;
+        }
+        case DW_LNE_define_file: {
+            fprintf(stderr, "Unimplemented extended opcode DW_LNE_define_file.\n");
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+        default: {
+            fprintf(stderr, "Unknown extended opcode.\n");
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+        }
+        break;
+    }
+        /* Standard opcodes */
+    case DW_LNS_copy: {
+        m_lineInfoMatrix.append(m_currentState);
+        m_currentState.isBasicBlock = false;
+        m_currentState.prologueEnd = false;
+        m_currentState.epilogueBegin = false;
+        break;
+    }
+    case DW_LNS_advance_pc: {
+        uint32_t advance = parseULEB128(offset);
+        m_currentState.address += advance * m_prologue.minimumInstructionLength;
+        break;
+    }
+    case DW_LNS_advance_line: {
+        int32_t advance = parseSLEB128(offset);
+        m_currentState.line += advance;
+        break;
+    }
+    case DW_LNS_set_file: {
+        uint32_t fileIndex = parseULEB128(offset);
+        m_currentState.file = fileIndex;
+        break;
+    }
+    case DW_LNS_set_column: {
+        m_currentState.column = parseULEB128(offset);
+        break;
+    }
+    case DW_LNS_negate_stmt: {
+        m_currentState.isStatement = !m_currentState.isStatement;
+        break;
+    }
+    case DW_LNS_set_basic_block: {
+        m_currentState.isBasicBlock = true;
+        break;
+    }
+    case DW_LNS_const_add_pc: {
+        uint8_t adjustedOpcode = nextOpcode - m_prologue.opcodeBase;
+        uint32_t addressIncrement = (adjustedOpcode / m_prologue.lineRange) * m_prologue.minimumInstructionLength;
+        m_currentState.address += addressIncrement;
+        break;
+    }
+    case DW_LNS_fixed_advance_pc: {
+        uint16_t advance = read<uint16_t>(offset);
+        m_currentState.address += advance;
+        break;
+    }
+    case DW_LNS_set_prologue_end: {
+        m_currentState.prologueEnd = true;
+        break;
+    }
+    case DW_LNS_set_epilogue_begin: {
+        m_currentState.epilogueBegin = true;
+        break;
+    }
+    case DW_LNS_set_isa: {
+        m_currentState.isa = parseULEB128(offset);
+        break;
+    }
+        /* Special opcodes */
+    default: {
+        uint8_t adjustedOpcode = nextOpcode - m_prologue.opcodeBase;
+        uint32_t addressIncrement = (adjustedOpcode / m_prologue.lineRange) * m_prologue.minimumInstructionLength;
+        int32_t lineIncrement = m_prologue.lineBase + (adjustedOpcode % m_prologue.lineRange);
+        m_currentState.address += addressIncrement;
+        m_currentState.line += lineIncrement;
+        m_lineInfoMatrix.append(m_currentState);
+        m_currentState.isBasicBlock = false;
+        m_currentState.prologueEnd = false;
+        m_currentState.epilogueBegin = false;
+        break;
+    }
+    }
+    return true;
+}
+
+void DebugLineInterpreter::printLineInfo()
+{
+    dataLog("\nLine Info Matrix:\n");
+    for (unsigned i = 0; i < m_lineInfoMatrix.size(); ++i)
+        printLineInfo(m_lineInfoMatrix[i]);
+    dataLog("\n");
+}
+
+void DebugLineInterpreter::printLineInfo(LineInfo& info)
+{
+    dataLogF("address: %p", reinterpret_cast<void*>(info.address));
+    dataLog("  file: ", info.file, "  line: ", info.line, "  column: ", info.column, "  isa: ", info.isa, "  ");
+    dataLog("  statement?: ", info.isStatement);
+    dataLog("  basic block?: ", info.isBasicBlock);
+    dataLog("  end sequence?: ", info.endSequence);
+    dataLog("  prologue end?: ", info.prologueEnd);
+    dataLog("  epilogue begin?: ", info.epilogueBegin);
+    dataLog("\n");
+}
+
+void DebugLineInterpreter::resetInterpreterState()
+{
+    m_currentState.address = 0;
+    m_currentState.file = 1;
+    m_currentState.line = 1;
+    m_currentState.column = 0;
+    m_currentState.isa = 0;
+    m_currentState.isStatement = false;
+    m_currentState.isBasicBlock = false;
+    m_currentState.endSequence = false;
+    m_currentState.prologueEnd = false;
+    m_currentState.epilogueBegin = false;
+}
+
+} } // namespace JSC::FTL
+
+#endif // ENABLE(FTL_JIT)
+