]> git.saurik.com Git - apple/javascriptcore.git/blob - ftl/FTLDWARFDebugLineInfo.cpp
JavaScriptCore-7600.1.4.16.1.tar.gz
[apple/javascriptcore.git] / ftl / FTLDWARFDebugLineInfo.cpp
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
33 namespace JSC { namespace FTL {
34
35 DebugLineInterpreter::DebugLineInterpreter(const char* program)
36 : m_program(program)
37 , m_logResults(false)
38 {
39 resetInterpreterState();
40 }
41
42 template <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
49 uint32_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
62 int32_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
79 void DebugLineInterpreter::run()
80 {
81 parsePrologue();
82 interpretStatementProgram();
83 if (m_logResults)
84 printLineInfo();
85 }
86
87 void 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
145 void 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
157 void 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
167 bool 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
183 void DebugLineInterpreter::interpretStatementProgram()
184 {
185 const char* currentProgramOffset = m_program;
186 bool keepGoing = true;
187 do {
188 keepGoing = interpretOpcode(currentProgramOffset);
189 } while (keepGoing);
190 }
191
192 bool 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
300 void 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
308 void 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
320 void 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