X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/4be4e30906bcb8ee30b4d189205cb70bad6707ce..81345200c95645a1b0d2635520f96ad55dfde63f:/ftl/FTLDWARFDebugLineInfo.cpp diff --git a/ftl/FTLDWARFDebugLineInfo.cpp b/ftl/FTLDWARFDebugLineInfo.cpp new file mode 100644 index 0000000..0a7a508 --- /dev/null +++ b/ftl/FTLDWARFDebugLineInfo.cpp @@ -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 + +namespace JSC { namespace FTL { + +DebugLineInterpreter::DebugLineInterpreter(const char* program) + : m_program(program) + , m_logResults(false) +{ + resetInterpreterState(); +} + +template inline T read(const char*& program) +{ + T result = *reinterpret_cast(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(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(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(currentProgramOffset); + if (m_prologue.totalLength == 0xffffffff) { + // This is 64-bit DWARF format. + m_prologue.format = SixtyFourBit; + m_prologue.totalLength = read(currentProgramOffset); + } else + m_prologue.format = ThirtyTwoBit; + m_prologue.version = read(currentProgramOffset); + + if (m_prologue.format == ThirtyTwoBit) + m_prologue.prologueLength = read(currentProgramOffset); + else + m_prologue.prologueLength = read(currentProgramOffset); + const char* afterLengthOffset = currentProgramOffset; + + m_prologue.minimumInstructionLength = read(currentProgramOffset); + m_prologue.defaultIsStatement = read(currentProgramOffset); + m_prologue.lineBase = read(currentProgramOffset); + m_prologue.lineRange = read(currentProgramOffset); + m_prologue.opcodeBase = read(currentProgramOffset); + for (unsigned i = 1; i < m_prologue.opcodeBase; ++i) + m_prologue.standardOpcodeLengths.append(read(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(offset); + switch (nextOpcode) { + case ExtendedOpcodes: { + uint32_t length = parseULEB128(offset); + if (!length) + return false; + uint8_t extendedOpcode = read(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(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(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(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) +