1/* 2 * Copyright (C) 2014 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "FTLDWARFDebugLineInfo.h" 28 29#if ENABLE(FTL_JIT) 30 31#include <wtf/DataLog.h> 32 33namespace JSC { namespace FTL { 34 35DebugLineInterpreter::DebugLineInterpreter(const char* program) 36 : m_program(program) 37 , m_logResults(false) 38{ 39 resetInterpreterState(); 40} 41 42template <typename T> inline T read(const char*& program) 43{ 44 T result = *reinterpret_cast<const T*>(program); 45 program += sizeof(T); 46 return result; 47} 48 49uint32_t DebugLineInterpreter::parseULEB128(const char*& offset) 50{ 51 uint32_t result = 0; 52 uint8_t byte; 53 unsigned shiftAmount = 0; 54 do { 55 byte = read<uint8_t>(offset); 56 result |= (byte & ~0x80) << shiftAmount; 57 shiftAmount += 7; 58 } while (byte & 0x80); 59 return result; 60} 61 62int32_t DebugLineInterpreter::parseSLEB128(const char*& offset) 63{ 64 int32_t result = 0; 65 uint8_t byte; 66 unsigned shiftAmount = 0; 67 do { 68 byte = read<uint8_t>(offset); 69 result |= (byte & ~0x80) << shiftAmount; 70 shiftAmount += 7; 71 } while (byte & 0x80); 72 73 // If the sign bit (in this case, the second MSB) on the last byte is set we need to zero extend. 74 if (byte & 0x40) 75 result |= -(1 << shiftAmount); 76 return result; 77} 78 79void DebugLineInterpreter::run() 80{ 81 parsePrologue(); 82 interpretStatementProgram(); 83 if (m_logResults) 84 printLineInfo(); 85} 86 87void DebugLineInterpreter::parsePrologue() 88{ 89 const char* currentProgramOffset = m_program; 90 m_prologue.totalLength = read<uint32_t>(currentProgramOffset); 91 if (m_prologue.totalLength == 0xffffffff) { 92 // This is 64-bit DWARF format. 93 m_prologue.format = SixtyFourBit; 94 m_prologue.totalLength = read<uint64_t>(currentProgramOffset); 95 } else 96 m_prologue.format = ThirtyTwoBit; 97 m_prologue.version = read<uint16_t>(currentProgramOffset); 98 99 if (m_prologue.format == ThirtyTwoBit) 100 m_prologue.prologueLength = read<uint32_t>(currentProgramOffset); 101 else 102 m_prologue.prologueLength = read<uint64_t>(currentProgramOffset); 103 const char* afterLengthOffset = currentProgramOffset; 104 105 m_prologue.minimumInstructionLength = read<uint8_t>(currentProgramOffset); 106 m_prologue.defaultIsStatement = read<uint8_t>(currentProgramOffset); 107 m_prologue.lineBase = read<int8_t>(currentProgramOffset); 108 m_prologue.lineRange = read<uint8_t>(currentProgramOffset); 109 m_prologue.opcodeBase = read<uint8_t>(currentProgramOffset); 110 for (unsigned i = 1; i < m_prologue.opcodeBase; ++i) 111 m_prologue.standardOpcodeLengths.append(read<uint8_t>(currentProgramOffset)); 112 parseIncludeDirectories(currentProgramOffset); 113 parseFileEntries(currentProgramOffset); 114 115 m_program = afterLengthOffset + m_prologue.prologueLength; 116 117 if (!m_logResults) 118 return; 119 120 dataLog("\nPrologue:\n"); 121 dataLog("totalLength = ", m_prologue.totalLength, "\n"); 122 dataLog("version = ", m_prologue.version, "\n"); 123 dataLog("prologueLength = ", m_prologue.prologueLength, "\n"); 124 dataLog("minimumInstructionLength = ", m_prologue.minimumInstructionLength, "\n"); 125 dataLog("defaultIsStatement = ", m_prologue.defaultIsStatement, "\n"); 126 dataLog("lineBase = ", m_prologue.lineBase, "\n"); 127 dataLog("lineRange = ", m_prologue.lineRange, "\n"); 128 dataLog("opcodeBase = ", m_prologue.opcodeBase, "\n"); 129 130 dataLog("\nStandard Opcode Lengths:\n"); 131 for (unsigned i = 1; i < m_prologue.opcodeBase; ++i) 132 dataLog("standardOpcodeLengths[", i - 1, "] = ", m_prologue.standardOpcodeLengths[i - 1], "\n"); 133 134 dataLog("\nInclude Directories:\n"); 135 for (unsigned i = 0; i < m_prologue.includeDirectories.size(); ++i) 136 dataLog("includeDirectories[", i, "] = ", m_prologue.includeDirectories[i], "\n"); 137 138 dataLog("\nFiles:\n"); 139 for (unsigned i = 0; i < m_prologue.fileEntries.size(); ++i) { 140 FileEntry& entry = m_prologue.fileEntries[i]; 141 dataLog("fileEntries[", i, "] = {name: \"", entry.name, "\", dir_index: ", entry.directoryIndex, ", last_modified: ", entry.lastModified, ", size: ", entry.size, "}\n"); 142 } 143} 144 145void DebugLineInterpreter::parseIncludeDirectories(const char*& offset) 146{ 147 size_t length = 0; 148 while ((length = strlen(offset))) { 149 m_prologue.includeDirectories.append(offset); 150 offset += length + 1; 151 } 152 153 // Extra increment to get past the last null byte. 154 offset += 1; 155} 156 157void DebugLineInterpreter::parseFileEntries(const char*& offset) 158{ 159 while (true) { 160 DebugLineInterpreter::FileEntry nextEntry; 161 if (!parseFileEntry(offset, nextEntry)) 162 break; 163 m_prologue.fileEntries.append(nextEntry); 164 } 165} 166 167bool DebugLineInterpreter::parseFileEntry(const char*& offset, FileEntry& entry) 168{ 169 size_t length = strlen(offset); 170 if (!length) { 171 offset += 1; 172 return false; 173 } 174 entry.name = offset; 175 offset += length + 1; 176 entry.directoryIndex = parseULEB128(offset); 177 entry.lastModified = parseULEB128(offset); 178 entry.size = parseULEB128(offset); 179 180 return true; 181} 182 183void DebugLineInterpreter::interpretStatementProgram() 184{ 185 const char* currentProgramOffset = m_program; 186 bool keepGoing = true; 187 do { 188 keepGoing = interpretOpcode(currentProgramOffset); 189 } while (keepGoing); 190} 191 192bool DebugLineInterpreter::interpretOpcode(const char*& offset) 193{ 194 uint8_t nextOpcode = read<uint8_t>(offset); 195 switch (nextOpcode) { 196 case ExtendedOpcodes: { 197 uint32_t length = parseULEB128(offset); 198 if (!length) 199 return false; 200 uint8_t extendedOpcode = read<uint8_t>(offset); 201 switch (extendedOpcode) { 202 case DW_LNE_end_sequence: { 203 m_currentState.endSequence = true; 204 m_lineInfoMatrix.append(m_currentState); 205 resetInterpreterState(); 206 break; 207 } 208 case DW_LNE_set_address: { 209 m_currentState.address = read<size_t>(offset); 210 break; 211 } 212 case DW_LNE_define_file: { 213 fprintf(stderr, "Unimplemented extended opcode DW_LNE_define_file.\n"); 214 RELEASE_ASSERT_NOT_REACHED(); 215 break; 216 } 217 default: { 218 fprintf(stderr, "Unknown extended opcode.\n"); 219 RELEASE_ASSERT_NOT_REACHED(); 220 break; 221 } 222 } 223 break; 224 } 225 /* Standard opcodes */ 226 case DW_LNS_copy: { 227 m_lineInfoMatrix.append(m_currentState); 228 m_currentState.isBasicBlock = false; 229 m_currentState.prologueEnd = false; 230 m_currentState.epilogueBegin = false; 231 break; 232 } 233 case DW_LNS_advance_pc: { 234 uint32_t advance = parseULEB128(offset); 235 m_currentState.address += advance * m_prologue.minimumInstructionLength; 236 break; 237 } 238 case DW_LNS_advance_line: { 239 int32_t advance = parseSLEB128(offset); 240 m_currentState.line += advance; 241 break; 242 } 243 case DW_LNS_set_file: { 244 uint32_t fileIndex = parseULEB128(offset); 245 m_currentState.file = fileIndex; 246 break; 247 } 248 case DW_LNS_set_column: { 249 m_currentState.column = parseULEB128(offset); 250 break; 251 } 252 case DW_LNS_negate_stmt: { 253 m_currentState.isStatement = !m_currentState.isStatement; 254 break; 255 } 256 case DW_LNS_set_basic_block: { 257 m_currentState.isBasicBlock = true; 258 break; 259 } 260 case DW_LNS_const_add_pc: { 261 uint8_t adjustedOpcode = nextOpcode - m_prologue.opcodeBase; 262 uint32_t addressIncrement = (adjustedOpcode / m_prologue.lineRange) * m_prologue.minimumInstructionLength; 263 m_currentState.address += addressIncrement; 264 break; 265 } 266 case DW_LNS_fixed_advance_pc: { 267 uint16_t advance = read<uint16_t>(offset); 268 m_currentState.address += advance; 269 break; 270 } 271 case DW_LNS_set_prologue_end: { 272 m_currentState.prologueEnd = true; 273 break; 274 } 275 case DW_LNS_set_epilogue_begin: { 276 m_currentState.epilogueBegin = true; 277 break; 278 } 279 case DW_LNS_set_isa: { 280 m_currentState.isa = parseULEB128(offset); 281 break; 282 } 283 /* Special opcodes */ 284 default: { 285 uint8_t adjustedOpcode = nextOpcode - m_prologue.opcodeBase; 286 uint32_t addressIncrement = (adjustedOpcode / m_prologue.lineRange) * m_prologue.minimumInstructionLength; 287 int32_t lineIncrement = m_prologue.lineBase + (adjustedOpcode % m_prologue.lineRange); 288 m_currentState.address += addressIncrement; 289 m_currentState.line += lineIncrement; 290 m_lineInfoMatrix.append(m_currentState); 291 m_currentState.isBasicBlock = false; 292 m_currentState.prologueEnd = false; 293 m_currentState.epilogueBegin = false; 294 break; 295 } 296 } 297 return true; 298} 299 300void DebugLineInterpreter::printLineInfo() 301{ 302 dataLog("\nLine Info Matrix:\n"); 303 for (unsigned i = 0; i < m_lineInfoMatrix.size(); ++i) 304 printLineInfo(m_lineInfoMatrix[i]); 305 dataLog("\n"); 306} 307 308void DebugLineInterpreter::printLineInfo(LineInfo& info) 309{ 310 dataLogF("address: %p", reinterpret_cast<void*>(info.address)); 311 dataLog(" file: ", info.file, " line: ", info.line, " column: ", info.column, " isa: ", info.isa, " "); 312 dataLog(" statement?: ", info.isStatement); 313 dataLog(" basic block?: ", info.isBasicBlock); 314 dataLog(" end sequence?: ", info.endSequence); 315 dataLog(" prologue end?: ", info.prologueEnd); 316 dataLog(" epilogue begin?: ", info.epilogueBegin); 317 dataLog("\n"); 318} 319 320void DebugLineInterpreter::resetInterpreterState() 321{ 322 m_currentState.address = 0; 323 m_currentState.file = 1; 324 m_currentState.line = 1; 325 m_currentState.column = 0; 326 m_currentState.isa = 0; 327 m_currentState.isStatement = false; 328 m_currentState.isBasicBlock = false; 329 m_currentState.endSequence = false; 330 m_currentState.prologueEnd = false; 331 m_currentState.epilogueBegin = false; 332} 333 334} } // namespace JSC::FTL 335 336#endif // ENABLE(FTL_JIT) 337 338