2 * Copyright (C) 2014 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "FTLDWARFDebugLineInfo.h"
31 #include <wtf/DataLog.h>
33 namespace JSC
{ namespace FTL
{
35 DebugLineInterpreter::DebugLineInterpreter(const char* program
)
39 resetInterpreterState();
42 template <typename T
> inline T
read(const char*& program
)
44 T result
= *reinterpret_cast<const T
*>(program
);
49 uint32_t DebugLineInterpreter::parseULEB128(const char*& offset
)
53 unsigned shiftAmount
= 0;
55 byte
= read
<uint8_t>(offset
);
56 result
|= (byte
& ~0x80) << shiftAmount
;
58 } while (byte
& 0x80);
62 int32_t DebugLineInterpreter::parseSLEB128(const char*& offset
)
66 unsigned shiftAmount
= 0;
68 byte
= read
<uint8_t>(offset
);
69 result
|= (byte
& ~0x80) << shiftAmount
;
71 } while (byte
& 0x80);
73 // If the sign bit (in this case, the second MSB) on the last byte is set we need to zero extend.
75 result
|= -(1 << shiftAmount
);
79 void DebugLineInterpreter::run()
82 interpretStatementProgram();
87 void DebugLineInterpreter::parsePrologue()
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
);
96 m_prologue
.format
= ThirtyTwoBit
;
97 m_prologue
.version
= read
<uint16_t>(currentProgramOffset
);
99 if (m_prologue
.format
== ThirtyTwoBit
)
100 m_prologue
.prologueLength
= read
<uint32_t>(currentProgramOffset
);
102 m_prologue
.prologueLength
= read
<uint64_t>(currentProgramOffset
);
103 const char* afterLengthOffset
= currentProgramOffset
;
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
);
115 m_program
= afterLengthOffset
+ m_prologue
.prologueLength
;
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");
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");
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");
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");
145 void DebugLineInterpreter::parseIncludeDirectories(const char*& offset
)
148 while ((length
= strlen(offset
))) {
149 m_prologue
.includeDirectories
.append(offset
);
150 offset
+= length
+ 1;
153 // Extra increment to get past the last null byte.
157 void DebugLineInterpreter::parseFileEntries(const char*& offset
)
160 DebugLineInterpreter::FileEntry nextEntry
;
161 if (!parseFileEntry(offset
, nextEntry
))
163 m_prologue
.fileEntries
.append(nextEntry
);
167 bool DebugLineInterpreter::parseFileEntry(const char*& offset
, FileEntry
& entry
)
169 size_t length
= strlen(offset
);
175 offset
+= length
+ 1;
176 entry
.directoryIndex
= parseULEB128(offset
);
177 entry
.lastModified
= parseULEB128(offset
);
178 entry
.size
= parseULEB128(offset
);
183 void DebugLineInterpreter::interpretStatementProgram()
185 const char* currentProgramOffset
= m_program
;
186 bool keepGoing
= true;
188 keepGoing
= interpretOpcode(currentProgramOffset
);
192 bool DebugLineInterpreter::interpretOpcode(const char*& offset
)
194 uint8_t nextOpcode
= read
<uint8_t>(offset
);
195 switch (nextOpcode
) {
196 case ExtendedOpcodes
: {
197 uint32_t length
= parseULEB128(offset
);
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();
208 case DW_LNE_set_address
: {
209 m_currentState
.address
= read
<size_t>(offset
);
212 case DW_LNE_define_file
: {
213 fprintf(stderr
, "Unimplemented extended opcode DW_LNE_define_file.\n");
214 RELEASE_ASSERT_NOT_REACHED();
218 fprintf(stderr
, "Unknown extended opcode.\n");
219 RELEASE_ASSERT_NOT_REACHED();
225 /* Standard opcodes */
227 m_lineInfoMatrix
.append(m_currentState
);
228 m_currentState
.isBasicBlock
= false;
229 m_currentState
.prologueEnd
= false;
230 m_currentState
.epilogueBegin
= false;
233 case DW_LNS_advance_pc
: {
234 uint32_t advance
= parseULEB128(offset
);
235 m_currentState
.address
+= advance
* m_prologue
.minimumInstructionLength
;
238 case DW_LNS_advance_line
: {
239 int32_t advance
= parseSLEB128(offset
);
240 m_currentState
.line
+= advance
;
243 case DW_LNS_set_file
: {
244 uint32_t fileIndex
= parseULEB128(offset
);
245 m_currentState
.file
= fileIndex
;
248 case DW_LNS_set_column
: {
249 m_currentState
.column
= parseULEB128(offset
);
252 case DW_LNS_negate_stmt
: {
253 m_currentState
.isStatement
= !m_currentState
.isStatement
;
256 case DW_LNS_set_basic_block
: {
257 m_currentState
.isBasicBlock
= true;
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
;
266 case DW_LNS_fixed_advance_pc
: {
267 uint16_t advance
= read
<uint16_t>(offset
);
268 m_currentState
.address
+= advance
;
271 case DW_LNS_set_prologue_end
: {
272 m_currentState
.prologueEnd
= true;
275 case DW_LNS_set_epilogue_begin
: {
276 m_currentState
.epilogueBegin
= true;
279 case DW_LNS_set_isa
: {
280 m_currentState
.isa
= parseULEB128(offset
);
283 /* Special opcodes */
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;
300 void DebugLineInterpreter::printLineInfo()
302 dataLog("\nLine Info Matrix:\n");
303 for (unsigned i
= 0; i
< m_lineInfoMatrix
.size(); ++i
)
304 printLineInfo(m_lineInfoMatrix
[i
]);
308 void DebugLineInterpreter::printLineInfo(LineInfo
& info
)
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
);
320 void DebugLineInterpreter::resetInterpreterState()
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;
334 } } // namespace JSC::FTL
336 #endif // ENABLE(FTL_JIT)