]>
Commit | Line | Data |
---|---|---|
81345200 A |
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 |