1 | //===-- LVCodeViewReader.cpp ----------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This implements the LVCodeViewReader class. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/DebugInfo/LogicalView/Readers/LVCodeViewReader.h" |
14 | #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" |
15 | #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" |
16 | #include "llvm/DebugInfo/CodeView/EnumTables.h" |
17 | #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" |
18 | #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" |
19 | #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h" |
20 | #include "llvm/DebugInfo/LogicalView/Core/LVLine.h" |
21 | #include "llvm/DebugInfo/LogicalView/Core/LVScope.h" |
22 | #include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h" |
23 | #include "llvm/DebugInfo/LogicalView/Core/LVType.h" |
24 | #include "llvm/DebugInfo/PDB/GenericError.h" |
25 | #include "llvm/DebugInfo/PDB/Native/DbiStream.h" |
26 | #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" |
27 | #include "llvm/DebugInfo/PDB/Native/InfoStream.h" |
28 | #include "llvm/DebugInfo/PDB/Native/LinePrinter.h" |
29 | #include "llvm/DebugInfo/PDB/Native/PDBFile.h" |
30 | #include "llvm/DebugInfo/PDB/Native/RawConstants.h" |
31 | #include "llvm/DebugInfo/PDB/Native/SymbolStream.h" |
32 | #include "llvm/DebugInfo/PDB/Native/TpiStream.h" |
33 | #include "llvm/Demangle/Demangle.h" |
34 | #include "llvm/Object/COFF.h" |
35 | #include "llvm/Support/Errc.h" |
36 | #include "llvm/Support/Error.h" |
37 | #include "llvm/Support/FormatAdapters.h" |
38 | #include "llvm/Support/FormatVariadic.h" |
39 | #include "llvm/Support/WithColor.h" |
40 | |
41 | using namespace llvm; |
42 | using namespace llvm::codeview; |
43 | using namespace llvm::logicalview; |
44 | using namespace llvm::msf; |
45 | using namespace llvm::object; |
46 | using namespace llvm::pdb; |
47 | |
48 | #define DEBUG_TYPE "CodeViewReader" |
49 | |
50 | StringRef LVCodeViewReader::getSymbolKindName(SymbolKind Kind) { |
51 | switch (Kind) { |
52 | #define SYMBOL_RECORD(EnumName, EnumVal, Name) \ |
53 | case EnumName: \ |
54 | return #EnumName; |
55 | #include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" |
56 | default: |
57 | return "UnknownSym" ; |
58 | } |
59 | llvm_unreachable("Unknown SymbolKind::Kind" ); |
60 | } |
61 | |
62 | std::string LVCodeViewReader::formatRegisterId(RegisterId Register, |
63 | CPUType CPU) { |
64 | #define RETURN_CASE(Enum, X, Ret) \ |
65 | case Enum::X: \ |
66 | return Ret; |
67 | |
68 | if (CPU == CPUType::ARMNT) { |
69 | switch (Register) { |
70 | #define CV_REGISTERS_ARM |
71 | #define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name) |
72 | #include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" |
73 | #undef CV_REGISTER |
74 | #undef CV_REGISTERS_ARM |
75 | |
76 | default: |
77 | break; |
78 | } |
79 | } else if (CPU == CPUType::ARM64) { |
80 | switch (Register) { |
81 | #define CV_REGISTERS_ARM64 |
82 | #define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name) |
83 | #include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" |
84 | #undef CV_REGISTER |
85 | #undef CV_REGISTERS_ARM64 |
86 | |
87 | default: |
88 | break; |
89 | } |
90 | } else { |
91 | switch (Register) { |
92 | #define CV_REGISTERS_X86 |
93 | #define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name) |
94 | #include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" |
95 | #undef CV_REGISTER |
96 | #undef CV_REGISTERS_X86 |
97 | |
98 | default: |
99 | break; |
100 | } |
101 | } |
102 | return "formatUnknownEnum(Id)" ; |
103 | } |
104 | |
105 | void LVCodeViewReader::printRelocatedField(StringRef Label, |
106 | const coff_section *CoffSection, |
107 | uint32_t RelocOffset, |
108 | uint32_t Offset, |
109 | StringRef *RelocSym) { |
110 | StringRef SymStorage; |
111 | StringRef &Symbol = RelocSym ? *RelocSym : SymStorage; |
112 | if (!resolveSymbolName(CoffSection, Offset: RelocOffset, Name&: Symbol)) |
113 | W.printSymbolOffset(Label, Symbol, Value: Offset); |
114 | else |
115 | W.printHex(Label, Value: RelocOffset); |
116 | } |
117 | |
118 | void LVCodeViewReader::getLinkageName(const coff_section *CoffSection, |
119 | uint32_t RelocOffset, uint32_t Offset, |
120 | StringRef *RelocSym) { |
121 | StringRef SymStorage; |
122 | StringRef &Symbol = RelocSym ? *RelocSym : SymStorage; |
123 | if (resolveSymbolName(CoffSection, Offset: RelocOffset, Name&: Symbol)) |
124 | Symbol = "" ; |
125 | } |
126 | |
127 | Expected<StringRef> |
128 | LVCodeViewReader::getFileNameForFileOffset(uint32_t FileOffset, |
129 | const SymbolGroup *SG) { |
130 | if (SG) { |
131 | Expected<StringRef> Filename = SG->getNameFromChecksums(Offset: FileOffset); |
132 | if (!Filename) { |
133 | consumeError(Err: Filename.takeError()); |
134 | return StringRef("" ); |
135 | } |
136 | return *Filename; |
137 | } |
138 | |
139 | // The file checksum subsection should precede all references to it. |
140 | if (!CVFileChecksumTable.valid() || !CVStringTable.valid()) |
141 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
142 | |
143 | VarStreamArray<FileChecksumEntry>::Iterator Iter = |
144 | CVFileChecksumTable.getArray().at(Offset: FileOffset); |
145 | |
146 | // Check if the file checksum table offset is valid. |
147 | if (Iter == CVFileChecksumTable.end()) |
148 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
149 | |
150 | Expected<StringRef> NameOrErr = CVStringTable.getString(Offset: Iter->FileNameOffset); |
151 | if (!NameOrErr) |
152 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
153 | return *NameOrErr; |
154 | } |
155 | |
156 | Error LVCodeViewReader::printFileNameForOffset(StringRef Label, |
157 | uint32_t FileOffset, |
158 | const SymbolGroup *SG) { |
159 | Expected<StringRef> NameOrErr = getFileNameForFileOffset(FileOffset, SG); |
160 | if (!NameOrErr) |
161 | return NameOrErr.takeError(); |
162 | W.printHex(Label, Str: *NameOrErr, Value: FileOffset); |
163 | return Error::success(); |
164 | } |
165 | |
166 | void LVCodeViewReader::cacheRelocations() { |
167 | for (const SectionRef &Section : getObj().sections()) { |
168 | const coff_section *CoffSection = getObj().getCOFFSection(Section); |
169 | |
170 | for (const RelocationRef &Relocacion : Section.relocations()) |
171 | RelocMap[CoffSection].push_back(x: Relocacion); |
172 | |
173 | // Sort relocations by address. |
174 | llvm::sort(C&: RelocMap[CoffSection], Comp: [](RelocationRef L, RelocationRef R) { |
175 | return L.getOffset() < R.getOffset(); |
176 | }); |
177 | } |
178 | } |
179 | |
180 | // Given a section and an offset into this section the function returns the |
181 | // symbol used for the relocation at the offset. |
182 | Error LVCodeViewReader::resolveSymbol(const coff_section *CoffSection, |
183 | uint64_t Offset, SymbolRef &Sym) { |
184 | const auto &Relocations = RelocMap[CoffSection]; |
185 | basic_symbol_iterator SymI = getObj().symbol_end(); |
186 | for (const RelocationRef &Relocation : Relocations) { |
187 | uint64_t RelocationOffset = Relocation.getOffset(); |
188 | |
189 | if (RelocationOffset == Offset) { |
190 | SymI = Relocation.getSymbol(); |
191 | break; |
192 | } |
193 | } |
194 | if (SymI == getObj().symbol_end()) |
195 | return make_error<StringError>(Args: "Unknown Symbol" , Args: inconvertibleErrorCode()); |
196 | Sym = *SymI; |
197 | return ErrorSuccess(); |
198 | } |
199 | |
200 | // Given a section and an offset into this section the function returns the |
201 | // name of the symbol used for the relocation at the offset. |
202 | Error LVCodeViewReader::resolveSymbolName(const coff_section *CoffSection, |
203 | uint64_t Offset, StringRef &Name) { |
204 | SymbolRef Symbol; |
205 | if (Error E = resolveSymbol(CoffSection, Offset, Sym&: Symbol)) |
206 | return E; |
207 | Expected<StringRef> NameOrErr = Symbol.getName(); |
208 | if (!NameOrErr) |
209 | return NameOrErr.takeError(); |
210 | Name = *NameOrErr; |
211 | return ErrorSuccess(); |
212 | } |
213 | |
214 | // CodeView and DWARF can have references to compiler generated elements, |
215 | // used for initialization. The MSVC includes in the PDBs, internal compile |
216 | // units, associated with the MS runtime support. We mark them as 'system' |
217 | // and they are printed only if the command line option 'internal=system'. |
218 | bool LVCodeViewReader::isSystemEntry(LVElement *Element, StringRef Name) const { |
219 | Name = Name.empty() ? Element->getName() : Name; |
220 | auto Find = [=](const char *String) -> bool { return Name.contains(Other: String); }; |
221 | auto Starts = [=](const char *Pattern) -> bool { |
222 | return Name.starts_with(Prefix: Pattern); |
223 | }; |
224 | auto CheckExclude = [&]() -> bool { |
225 | if (Starts("__" ) || Starts("_PMD" ) || Starts("_PMFN" )) |
226 | return true; |
227 | if (Find("_s__" )) |
228 | return true; |
229 | if (Find("_CatchableType" ) || Find("_TypeDescriptor" )) |
230 | return true; |
231 | if (Find("Intermediate\\vctools" )) |
232 | return true; |
233 | if (Find("$initializer$" ) || Find("dynamic initializer" )) |
234 | return true; |
235 | if (Find("`vftable'" ) || Find("_GLOBAL__sub" )) |
236 | return true; |
237 | return false; |
238 | }; |
239 | bool Excluded = CheckExclude(); |
240 | if (Excluded) |
241 | Element->setIsSystem(); |
242 | |
243 | return Excluded; |
244 | } |
245 | |
246 | Error LVCodeViewReader::collectInlineeInfo( |
247 | DebugInlineeLinesSubsectionRef &Lines, const llvm::pdb::SymbolGroup *SG) { |
248 | for (const InlineeSourceLine &Line : Lines) { |
249 | TypeIndex TIInlinee = Line.Header->Inlinee; |
250 | uint32_t LineNumber = Line.Header->SourceLineNum; |
251 | uint32_t FileOffset = Line.Header->FileID; |
252 | LLVM_DEBUG({ |
253 | DictScope S(W, "InlineeSourceLine" ); |
254 | LogicalVisitor.printTypeIndex("Inlinee" , TIInlinee, StreamTPI); |
255 | if (Error Err = printFileNameForOffset("FileID" , FileOffset, SG)) |
256 | return Err; |
257 | W.printNumber("SourceLineNum" , LineNumber); |
258 | |
259 | if (Lines.hasExtraFiles()) { |
260 | W.printNumber("ExtraFileCount" , Line.ExtraFiles.size()); |
261 | ListScope ExtraFiles(W, "ExtraFiles" ); |
262 | for (const ulittle32_t &FID : Line.ExtraFiles) |
263 | if (Error Err = printFileNameForOffset("FileID" , FID, SG)) |
264 | return Err; |
265 | } |
266 | }); |
267 | Expected<StringRef> NameOrErr = getFileNameForFileOffset(FileOffset, SG); |
268 | if (!NameOrErr) |
269 | return NameOrErr.takeError(); |
270 | LogicalVisitor.addInlineeInfo(TI: TIInlinee, LineNumber, Filename: *NameOrErr); |
271 | } |
272 | |
273 | return Error::success(); |
274 | } |
275 | |
276 | Error LVCodeViewReader::traverseInlineeLines(StringRef Subsection) { |
277 | BinaryStreamReader SR(Subsection, llvm::endianness::little); |
278 | DebugInlineeLinesSubsectionRef Lines; |
279 | if (Error E = Lines.initialize(Reader: SR)) |
280 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
281 | |
282 | return collectInlineeInfo(Lines); |
283 | } |
284 | |
285 | Error LVCodeViewReader::createLines( |
286 | const FixedStreamArray<LineNumberEntry> &LineNumbers, LVAddress Addendum, |
287 | uint32_t Segment, uint32_t Begin, uint32_t Size, uint32_t NameIndex, |
288 | const SymbolGroup *SG) { |
289 | LLVM_DEBUG({ |
290 | uint32_t End = Begin + Size; |
291 | W.getOStream() << formatv("{0:x-4}:{1:x-8}-{2:x-8}\n" , Segment, Begin, End); |
292 | }); |
293 | |
294 | for (const LineNumberEntry &Line : LineNumbers) { |
295 | if (Line.Offset >= Size) |
296 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
297 | |
298 | LineInfo LI(Line.Flags); |
299 | |
300 | LLVM_DEBUG({ |
301 | W.getOStream() << formatv( |
302 | "{0} {1:x-8}\n" , utostr(LI.getStartLine()), |
303 | fmt_align(Begin + Line.Offset, AlignStyle::Right, 8, '0')); |
304 | }); |
305 | |
306 | // The 'processLines()' function will move each created logical line |
307 | // to its enclosing logical scope, using the debug ranges information |
308 | // and they will be released when its scope parent is deleted. |
309 | LVLineDebug *LineDebug = createLineDebug(); |
310 | CULines.push_back(Elt: LineDebug); |
311 | LVAddress Address = linearAddress(Segment, Offset: Begin + Line.Offset); |
312 | LineDebug->setAddress(Address + Addendum); |
313 | |
314 | if (LI.isAlwaysStepInto()) |
315 | LineDebug->setIsAlwaysStepInto(); |
316 | else if (LI.isNeverStepInto()) |
317 | LineDebug->setIsNeverStepInto(); |
318 | else |
319 | LineDebug->setLineNumber(LI.getStartLine()); |
320 | |
321 | if (LI.isStatement()) |
322 | LineDebug->setIsNewStatement(); |
323 | |
324 | Expected<StringRef> NameOrErr = getFileNameForFileOffset(FileOffset: NameIndex, SG); |
325 | if (!NameOrErr) |
326 | return NameOrErr.takeError(); |
327 | LineDebug->setFilename(*NameOrErr); |
328 | } |
329 | |
330 | return Error::success(); |
331 | } |
332 | |
333 | Error LVCodeViewReader::initializeFileAndStringTables( |
334 | BinaryStreamReader &Reader) { |
335 | while (Reader.bytesRemaining() > 0 && |
336 | (!CVFileChecksumTable.valid() || !CVStringTable.valid())) { |
337 | // The section consists of a number of subsection in the following format: |
338 | // |SubSectionType|SubSectionSize|Contents...| |
339 | uint32_t SubType, SubSectionSize; |
340 | |
341 | if (Error E = Reader.readInteger(Dest&: SubType)) |
342 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
343 | if (Error E = Reader.readInteger(Dest&: SubSectionSize)) |
344 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
345 | |
346 | StringRef Contents; |
347 | if (Error E = Reader.readFixedString(Dest&: Contents, Length: SubSectionSize)) |
348 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
349 | |
350 | BinaryStreamRef ST(Contents, llvm::endianness::little); |
351 | switch (DebugSubsectionKind(SubType)) { |
352 | case DebugSubsectionKind::FileChecksums: |
353 | if (Error E = CVFileChecksumTable.initialize(Stream: ST)) |
354 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
355 | break; |
356 | case DebugSubsectionKind::StringTable: |
357 | if (Error E = CVStringTable.initialize(Contents: ST)) |
358 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
359 | break; |
360 | default: |
361 | break; |
362 | } |
363 | |
364 | uint32_t PaddedSize = alignTo(Value: SubSectionSize, Align: 4); |
365 | if (Error E = Reader.skip(Amount: PaddedSize - SubSectionSize)) |
366 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
367 | } |
368 | |
369 | return Error::success(); |
370 | } |
371 | |
372 | Error LVCodeViewReader::loadTypeServer(TypeServer2Record &TS) { |
373 | LLVM_DEBUG({ |
374 | W.printString("Guid" , formatv("{0}" , TS.getGuid()).str()); |
375 | W.printNumber("Age" , TS.getAge()); |
376 | W.printString("Name" , TS.getName()); |
377 | }); |
378 | |
379 | SmallString<128> ServerName(TS.getName()); |
380 | BuffOrErr = MemoryBuffer::getFile(Filename: ServerName); |
381 | if (BuffOrErr.getError()) { |
382 | // The server name does not exist. Try in the same directory as the |
383 | // input file. |
384 | ServerName = createAlternativePath(From: ServerName); |
385 | BuffOrErr = MemoryBuffer::getFile(Filename: ServerName); |
386 | if (BuffOrErr.getError()) { |
387 | // For the error message, use the original type server name. |
388 | return createStringError(EC: errc::bad_file_descriptor, |
389 | Fmt: "File '%s' does not exist." , |
390 | Vals: TS.getName().str().c_str()); |
391 | } |
392 | } |
393 | MemBuffer = std::move(BuffOrErr.get()); |
394 | |
395 | // Check if the buffer corresponds to a PDB file. |
396 | assert(identify_magic((*MemBuffer).getBuffer()) == file_magic::pdb && |
397 | "Invalid PDB file." ); |
398 | |
399 | if (Error Err = loadDataForPDB(Type: PDB_ReaderType::Native, Path: ServerName, Session)) |
400 | return createStringError(EC: errorToErrorCode(Err: std::move(Err)), Fmt: "%s" , |
401 | Vals: ServerName.c_str()); |
402 | |
403 | PdbSession.reset(p: static_cast<NativeSession *>(Session.release())); |
404 | PDBFile &Pdb = PdbSession->getPDBFile(); |
405 | |
406 | // Just because a file with a matching name was found and it was an actual |
407 | // PDB file doesn't mean it matches. For it to match the InfoStream's GUID |
408 | // must match the GUID specified in the TypeServer2 record. |
409 | Expected<InfoStream &> expectedInfo = Pdb.getPDBInfoStream(); |
410 | if (!expectedInfo || expectedInfo->getGuid() != TS.getGuid()) |
411 | return createStringError(EC: errc::invalid_argument, S: "signature_out_of_date" ); |
412 | |
413 | // The reader needs to switch to a type server, to process the types from |
414 | // the server. We need to keep the original input source, as reading other |
415 | // sections will require the input associated with the loaded object file. |
416 | TypeServer = std::make_shared<InputFile>(args: &Pdb); |
417 | LogicalVisitor.setInput(TypeServer); |
418 | |
419 | LazyRandomTypeCollection &Types = types(); |
420 | LazyRandomTypeCollection &Ids = ids(); |
421 | if (Error Err = traverseTypes(Pdb, Types, Ids)) |
422 | return Err; |
423 | |
424 | return Error::success(); |
425 | } |
426 | |
427 | Error LVCodeViewReader::loadPrecompiledObject(PrecompRecord &Precomp, |
428 | CVTypeArray &CVTypesObj) { |
429 | LLVM_DEBUG({ |
430 | W.printHex("Count" , Precomp.getTypesCount()); |
431 | W.printHex("Signature" , Precomp.getSignature()); |
432 | W.printString("PrecompFile" , Precomp.getPrecompFilePath()); |
433 | }); |
434 | |
435 | SmallString<128> ServerName(Precomp.getPrecompFilePath()); |
436 | BuffOrErr = MemoryBuffer::getFile(Filename: ServerName); |
437 | if (BuffOrErr.getError()) { |
438 | // The server name does not exist. Try in the directory as the input file. |
439 | ServerName = createAlternativePath(From: ServerName); |
440 | if (BuffOrErr.getError()) { |
441 | // For the error message, use the original type server name. |
442 | return createStringError(EC: errc::bad_file_descriptor, |
443 | Fmt: "File '%s' does not exist." , |
444 | Vals: Precomp.getPrecompFilePath().str().c_str()); |
445 | } |
446 | } |
447 | MemBuffer = std::move(BuffOrErr.get()); |
448 | |
449 | Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Source: *MemBuffer); |
450 | if (errorToErrorCode(Err: BinOrErr.takeError())) |
451 | return createStringError(EC: errc::not_supported, |
452 | Fmt: "Binary object format in '%s' is not supported." , |
453 | Vals: ServerName.c_str()); |
454 | |
455 | Binary &BinaryObj = *BinOrErr.get(); |
456 | if (!BinaryObj.isCOFF()) |
457 | return createStringError(EC: errc::not_supported, Fmt: "'%s' is not a COFF object." , |
458 | Vals: ServerName.c_str()); |
459 | |
460 | Builder = std::make_unique<AppendingTypeTableBuilder>(args&: BuilderAllocator); |
461 | |
462 | // The MSVC precompiled header object file, should contain just a single |
463 | // ".debug$P" section. |
464 | COFFObjectFile &Obj = *cast<COFFObjectFile>(Val: &BinaryObj); |
465 | for (const SectionRef &Section : Obj.sections()) { |
466 | Expected<StringRef> SectionNameOrErr = Section.getName(); |
467 | if (!SectionNameOrErr) |
468 | return SectionNameOrErr.takeError(); |
469 | if (*SectionNameOrErr == ".debug$P" ) { |
470 | Expected<StringRef> DataOrErr = Section.getContents(); |
471 | if (!DataOrErr) |
472 | return DataOrErr.takeError(); |
473 | uint32_t Magic; |
474 | if (Error Err = consume(Data&: *DataOrErr, Item&: Magic)) |
475 | return Err; |
476 | if (Magic != COFF::DEBUG_SECTION_MAGIC) |
477 | return errorCodeToError(EC: object_error::parse_failed); |
478 | |
479 | ReaderPrecomp = std::make_unique<BinaryStreamReader>( |
480 | args&: *DataOrErr, args: llvm::endianness::little); |
481 | cantFail( |
482 | Err: ReaderPrecomp->readArray(Array&: CVTypesPrecomp, Size: ReaderPrecomp->getLength())); |
483 | |
484 | // Append all the type records up to the LF_ENDPRECOMP marker and |
485 | // check if the signatures match. |
486 | for (const CVType &Type : CVTypesPrecomp) { |
487 | ArrayRef<uint8_t> TypeData = Type.data(); |
488 | if (Type.kind() == LF_ENDPRECOMP) { |
489 | EndPrecompRecord EndPrecomp = cantFail( |
490 | ValOrErr: TypeDeserializer::deserializeAs<EndPrecompRecord>(Data: TypeData)); |
491 | if (Precomp.getSignature() != EndPrecomp.getSignature()) |
492 | return createStringError(EC: errc::invalid_argument, S: "no matching pch" ); |
493 | break; |
494 | } |
495 | Builder->insertRecordBytes(Record&: TypeData); |
496 | } |
497 | // Done processing .debug$P, break out of section loop. |
498 | break; |
499 | } |
500 | } |
501 | |
502 | // Append all the type records, skipping the first record which is the |
503 | // reference to the precompiled header object information. |
504 | for (const CVType &Type : CVTypesObj) { |
505 | ArrayRef<uint8_t> TypeData = Type.data(); |
506 | if (Type.kind() != LF_PRECOMP) |
507 | Builder->insertRecordBytes(Record&: TypeData); |
508 | } |
509 | |
510 | // Set up a type stream that refers to the added type records. |
511 | Builder->ForEachRecord( |
512 | Func: [&](TypeIndex TI, const CVType &Type) { TypeArray.push_back(x: Type); }); |
513 | |
514 | ItemStream = |
515 | std::make_unique<BinaryItemStream<CVType>>(args: llvm::endianness::little); |
516 | ItemStream->setItems(TypeArray); |
517 | TypeStream.setUnderlyingStream(NewStream: *ItemStream); |
518 | |
519 | PrecompHeader = |
520 | std::make_shared<LazyRandomTypeCollection>(args&: TypeStream, args: TypeArray.size()); |
521 | |
522 | // Change the original input source to use the collected type records. |
523 | LogicalVisitor.setInput(PrecompHeader); |
524 | |
525 | LazyRandomTypeCollection &Types = types(); |
526 | LazyRandomTypeCollection &Ids = ids(); |
527 | LVTypeVisitor TDV(W, &LogicalVisitor, Types, Ids, StreamTPI, |
528 | LogicalVisitor.getShared()); |
529 | return visitTypeStream(Types, Callbacks&: TDV); |
530 | } |
531 | |
532 | Error LVCodeViewReader::traverseTypeSection(StringRef SectionName, |
533 | const SectionRef &Section) { |
534 | LLVM_DEBUG({ |
535 | ListScope D(W, "CodeViewTypes" ); |
536 | W.printNumber("Section" , SectionName, getObj().getSectionID(Section)); |
537 | }); |
538 | |
539 | Expected<StringRef> DataOrErr = Section.getContents(); |
540 | if (!DataOrErr) |
541 | return DataOrErr.takeError(); |
542 | uint32_t Magic; |
543 | if (Error Err = consume(Data&: *DataOrErr, Item&: Magic)) |
544 | return Err; |
545 | if (Magic != COFF::DEBUG_SECTION_MAGIC) |
546 | return errorCodeToError(EC: object_error::parse_failed); |
547 | |
548 | // Get the first type record. It will indicate if this object uses a type |
549 | // server (/Zi) or a PCH file (/Yu). |
550 | CVTypeArray CVTypes; |
551 | BinaryStreamReader Reader(*DataOrErr, llvm::endianness::little); |
552 | cantFail(Err: Reader.readArray(Array&: CVTypes, Size: Reader.getLength())); |
553 | CVTypeArray::Iterator FirstType = CVTypes.begin(); |
554 | |
555 | // The object was compiled with /Zi. It uses types from a type server PDB. |
556 | if (FirstType->kind() == LF_TYPESERVER2) { |
557 | TypeServer2Record TS = cantFail( |
558 | ValOrErr: TypeDeserializer::deserializeAs<TypeServer2Record>(Data: FirstType->data())); |
559 | return loadTypeServer(TS); |
560 | } |
561 | |
562 | // The object was compiled with /Yc or /Yu. It uses types from another |
563 | // object file with a matching signature. |
564 | if (FirstType->kind() == LF_PRECOMP) { |
565 | PrecompRecord Precomp = cantFail( |
566 | ValOrErr: TypeDeserializer::deserializeAs<PrecompRecord>(Data: FirstType->data())); |
567 | return loadPrecompiledObject(Precomp, CVTypesObj&: CVTypes); |
568 | } |
569 | |
570 | LazyRandomTypeCollection &Types = types(); |
571 | LazyRandomTypeCollection &Ids = ids(); |
572 | Types.reset(Data: *DataOrErr, RecordCountHint: 100); |
573 | LVTypeVisitor TDV(W, &LogicalVisitor, Types, Ids, StreamTPI, |
574 | LogicalVisitor.getShared()); |
575 | return visitTypeStream(Types, Callbacks&: TDV); |
576 | } |
577 | |
578 | Error LVCodeViewReader::traverseTypes(PDBFile &Pdb, |
579 | LazyRandomTypeCollection &Types, |
580 | LazyRandomTypeCollection &Ids) { |
581 | // Traverse types (TPI and IPI). |
582 | auto VisitTypes = [&](LazyRandomTypeCollection &Types, |
583 | LazyRandomTypeCollection &Ids, |
584 | SpecialStream StreamIdx) -> Error { |
585 | LVTypeVisitor TDV(W, &LogicalVisitor, Types, Ids, StreamIdx, |
586 | LogicalVisitor.getShared()); |
587 | return visitTypeStream(Types, Callbacks&: TDV); |
588 | }; |
589 | |
590 | Expected<TpiStream &> StreamTpiOrErr = Pdb.getPDBTpiStream(); |
591 | if (!StreamTpiOrErr) |
592 | return StreamTpiOrErr.takeError(); |
593 | TpiStream &StreamTpi = *StreamTpiOrErr; |
594 | StreamTpi.buildHashMap(); |
595 | LLVM_DEBUG({ |
596 | W.getOStream() << formatv("Showing {0:N} TPI records\n" , |
597 | StreamTpi.getNumTypeRecords()); |
598 | }); |
599 | if (Error Err = VisitTypes(Types, Ids, StreamTPI)) |
600 | return Err; |
601 | |
602 | Expected<TpiStream &> StreamIpiOrErr = Pdb.getPDBIpiStream(); |
603 | if (!StreamIpiOrErr) |
604 | return StreamIpiOrErr.takeError(); |
605 | TpiStream &StreamIpi = *StreamIpiOrErr; |
606 | StreamIpi.buildHashMap(); |
607 | LLVM_DEBUG({ |
608 | W.getOStream() << formatv("Showing {0:N} IPI records\n" , |
609 | StreamIpi.getNumTypeRecords()); |
610 | }); |
611 | return VisitTypes(Ids, Ids, StreamIPI); |
612 | } |
613 | |
614 | Error LVCodeViewReader::traverseSymbolsSubsection(StringRef Subsection, |
615 | const SectionRef &Section, |
616 | StringRef SectionContents) { |
617 | ArrayRef<uint8_t> BinaryData(Subsection.bytes_begin(), |
618 | Subsection.bytes_end()); |
619 | LVSymbolVisitorDelegate VisitorDelegate(this, Section, &getObj(), |
620 | SectionContents); |
621 | CVSymbolArray Symbols; |
622 | BinaryStreamReader Reader(BinaryData, llvm::endianness::little); |
623 | if (Error E = Reader.readArray(Array&: Symbols, Size: Reader.getLength())) |
624 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
625 | |
626 | LazyRandomTypeCollection &Types = types(); |
627 | LazyRandomTypeCollection &Ids = ids(); |
628 | SymbolVisitorCallbackPipeline Pipeline; |
629 | SymbolDeserializer Deserializer(&VisitorDelegate, |
630 | CodeViewContainer::ObjectFile); |
631 | // As we are processing a COFF format, use TPI as IPI, so the generic code |
632 | // to process the CodeView format does not contain any additional checks. |
633 | LVSymbolVisitor Traverser(this, W, &LogicalVisitor, Types, Ids, |
634 | &VisitorDelegate, LogicalVisitor.getShared()); |
635 | |
636 | Pipeline.addCallbackToPipeline(Callbacks&: Deserializer); |
637 | Pipeline.addCallbackToPipeline(Callbacks&: Traverser); |
638 | CVSymbolVisitor Visitor(Pipeline); |
639 | return Visitor.visitSymbolStream(Symbols); |
640 | } |
641 | |
642 | Error LVCodeViewReader::traverseSymbolSection(StringRef SectionName, |
643 | const SectionRef &Section) { |
644 | LLVM_DEBUG({ |
645 | ListScope D(W, "CodeViewDebugInfo" ); |
646 | W.printNumber("Section" , SectionName, getObj().getSectionID(Section)); |
647 | }); |
648 | |
649 | Expected<StringRef> SectionOrErr = Section.getContents(); |
650 | if (!SectionOrErr) |
651 | return SectionOrErr.takeError(); |
652 | StringRef SectionContents = *SectionOrErr; |
653 | StringRef Data = SectionContents; |
654 | |
655 | SmallVector<StringRef, 10> SymbolNames; |
656 | StringMap<StringRef> FunctionLineTables; |
657 | |
658 | uint32_t Magic; |
659 | if (Error E = consume(Data, Item&: Magic)) |
660 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
661 | |
662 | if (Magic != COFF::DEBUG_SECTION_MAGIC) |
663 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
664 | |
665 | BinaryStreamReader FSReader(Data, llvm::endianness::little); |
666 | if (Error Err = initializeFileAndStringTables(Reader&: FSReader)) |
667 | return Err; |
668 | |
669 | while (!Data.empty()) { |
670 | // The section consists of a number of subsection in the following format: |
671 | // |SubSectionType|SubSectionSize|Contents...| |
672 | uint32_t SubType, SubSectionSize; |
673 | if (Error E = consume(Data, Item&: SubType)) |
674 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
675 | if (Error E = consume(Data, Item&: SubSectionSize)) |
676 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
677 | |
678 | // Process the subsection as normal even if the ignore bit is set. |
679 | SubType &= ~SubsectionIgnoreFlag; |
680 | |
681 | // Get the contents of the subsection. |
682 | if (SubSectionSize > Data.size()) |
683 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
684 | StringRef Contents = Data.substr(Start: 0, N: SubSectionSize); |
685 | |
686 | // Add SubSectionSize to the current offset and align that offset |
687 | // to find the next subsection. |
688 | size_t SectionOffset = Data.data() - SectionContents.data(); |
689 | size_t NextOffset = SectionOffset + SubSectionSize; |
690 | NextOffset = alignTo(Value: NextOffset, Align: 4); |
691 | if (NextOffset > SectionContents.size()) |
692 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
693 | Data = SectionContents.drop_front(N: NextOffset); |
694 | |
695 | switch (DebugSubsectionKind(SubType)) { |
696 | case DebugSubsectionKind::Symbols: |
697 | if (Error Err = |
698 | traverseSymbolsSubsection(Subsection: Contents, Section, SectionContents)) |
699 | return Err; |
700 | break; |
701 | |
702 | case DebugSubsectionKind::InlineeLines: |
703 | if (Error Err = traverseInlineeLines(Subsection: Contents)) |
704 | return Err; |
705 | break; |
706 | |
707 | case DebugSubsectionKind::Lines: |
708 | // Holds a PC to file:line table. Some data to parse this subsection |
709 | // is stored in the other subsections, so just check sanity and store |
710 | // the pointers for deferred processing. |
711 | |
712 | // Collect function and ranges only if we need to print logical lines. |
713 | if (options().getGeneralCollectRanges()) { |
714 | |
715 | if (SubSectionSize < 12) { |
716 | // There should be at least three words to store two function |
717 | // relocations and size of the code. |
718 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
719 | } |
720 | |
721 | StringRef SymbolName; |
722 | if (Error Err = resolveSymbolName(CoffSection: getObj().getCOFFSection(Section), |
723 | Offset: SectionOffset, Name&: SymbolName)) |
724 | return createStringError(EC: errorToErrorCode(Err: std::move(Err)), |
725 | S: getFileName()); |
726 | |
727 | LLVM_DEBUG({ W.printString("Symbol Name" , SymbolName); }); |
728 | if (FunctionLineTables.count(Key: SymbolName) != 0) { |
729 | // Saw debug info for this function already? |
730 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
731 | } |
732 | |
733 | FunctionLineTables[SymbolName] = Contents; |
734 | SymbolNames.push_back(Elt: SymbolName); |
735 | } |
736 | break; |
737 | |
738 | // Do nothing for unrecognized subsections. |
739 | default: |
740 | break; |
741 | } |
742 | W.flush(); |
743 | } |
744 | |
745 | // Traverse the line tables now that we've read all the subsections and |
746 | // know all the required information. |
747 | for (StringRef SymbolName : SymbolNames) { |
748 | LLVM_DEBUG({ |
749 | ListScope S(W, "FunctionLineTable" ); |
750 | W.printString("Symbol Name" , SymbolName); |
751 | }); |
752 | |
753 | BinaryStreamReader Reader(FunctionLineTables[SymbolName], |
754 | llvm::endianness::little); |
755 | |
756 | DebugLinesSubsectionRef Lines; |
757 | if (Error E = Lines.initialize(Reader)) |
758 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
759 | |
760 | // Find the associated symbol table information. |
761 | LVSymbolTableEntry SymbolTableEntry = getSymbolTableEntry(Name: SymbolName); |
762 | LVScope *Function = SymbolTableEntry.Scope; |
763 | if (!Function) |
764 | continue; |
765 | |
766 | LVAddress Addendum = SymbolTableEntry.Address; |
767 | LVSectionIndex SectionIndex = SymbolTableEntry.SectionIndex; |
768 | |
769 | // The given scope represents the function that contains the line numbers. |
770 | // Collect all generated debug lines associated with the function. |
771 | CULines.clear(); |
772 | |
773 | // For the given scope, collect all scopes ranges. |
774 | LVRange *ScopesWithRanges = getSectionRanges(SectionIndex); |
775 | ScopesWithRanges->clear(); |
776 | Function->getRanges(RangeList&: *ScopesWithRanges); |
777 | ScopesWithRanges->sort(); |
778 | |
779 | uint16_t Segment = Lines.header()->RelocSegment; |
780 | uint32_t Begin = Lines.header()->RelocOffset; |
781 | uint32_t Size = Lines.header()->CodeSize; |
782 | for (const LineColumnEntry &Block : Lines) |
783 | if (Error Err = createLines(LineNumbers: Block.LineNumbers, Addendum, Segment, Begin, |
784 | Size, NameIndex: Block.NameIndex)) |
785 | return Err; |
786 | |
787 | // Include lines from any inlined functions within the current function. |
788 | includeInlineeLines(SectionIndex, Function); |
789 | |
790 | if (Error Err = createInstructions(Function, SectionIndex)) |
791 | return Err; |
792 | |
793 | processLines(DebugLines: &CULines, SectionIndex, Function); |
794 | } |
795 | |
796 | return Error::success(); |
797 | } |
798 | |
799 | void LVCodeViewReader::sortScopes() { Root->sort(); } |
800 | |
801 | void LVCodeViewReader::print(raw_ostream &OS) const { |
802 | LLVM_DEBUG(dbgs() << "CreateReaders\n" ); |
803 | } |
804 | |
805 | void LVCodeViewReader::mapRangeAddress(const ObjectFile &Obj, |
806 | const SectionRef &Section, |
807 | bool IsComdat) { |
808 | if (!Obj.isCOFF()) |
809 | return; |
810 | |
811 | const COFFObjectFile *Object = cast<COFFObjectFile>(Val: &Obj); |
812 | |
813 | for (const SymbolRef &Sym : Object->symbols()) { |
814 | if (!Section.containsSymbol(S: Sym)) |
815 | continue; |
816 | |
817 | COFFSymbolRef Symbol = Object->getCOFFSymbol(Symbol: Sym); |
818 | if (Symbol.getComplexType() != llvm::COFF::IMAGE_SYM_DTYPE_FUNCTION) |
819 | continue; |
820 | |
821 | StringRef SymbolName; |
822 | Expected<StringRef> SymNameOrErr = Object->getSymbolName(Symbol); |
823 | if (!SymNameOrErr) { |
824 | W.startLine() << "Invalid symbol name: " << Symbol.getSectionNumber() |
825 | << "\n" ; |
826 | consumeError(Err: SymNameOrErr.takeError()); |
827 | continue; |
828 | } |
829 | SymbolName = *SymNameOrErr; |
830 | |
831 | LLVM_DEBUG({ |
832 | Expected<const coff_section *> SectionOrErr = |
833 | Object->getSection(Symbol.getSectionNumber()); |
834 | if (!SectionOrErr) { |
835 | W.startLine() << "Invalid section number: " << Symbol.getSectionNumber() |
836 | << "\n" ; |
837 | consumeError(SectionOrErr.takeError()); |
838 | return; |
839 | } |
840 | W.printNumber("Section #" , Symbol.getSectionNumber()); |
841 | W.printString("Name" , SymbolName); |
842 | W.printHex("Value" , Symbol.getValue()); |
843 | }); |
844 | |
845 | // Record the symbol name (linkage) and its loading address. |
846 | addToSymbolTable(Name: SymbolName, Address: Symbol.getValue(), SectionIndex: Symbol.getSectionNumber(), |
847 | IsComdat); |
848 | } |
849 | } |
850 | |
851 | Error LVCodeViewReader::createScopes(COFFObjectFile &Obj) { |
852 | if (Error Err = loadTargetInfo(Obj)) |
853 | return Err; |
854 | |
855 | // Initialization required when processing a COFF file: |
856 | // Cache the symbols relocations. |
857 | // Create a mapping for virtual addresses. |
858 | // Get the functions entry points. |
859 | cacheRelocations(); |
860 | mapVirtualAddress(COFFObj: Obj); |
861 | |
862 | for (const SectionRef &Section : Obj.sections()) { |
863 | Expected<StringRef> SectionNameOrErr = Section.getName(); |
864 | if (!SectionNameOrErr) |
865 | return SectionNameOrErr.takeError(); |
866 | // .debug$T is a standard CodeView type section, while .debug$P is the |
867 | // same format but used for MSVC precompiled header object files. |
868 | if (*SectionNameOrErr == ".debug$T" || *SectionNameOrErr == ".debug$P" ) |
869 | if (Error Err = traverseTypeSection(SectionName: *SectionNameOrErr, Section)) |
870 | return Err; |
871 | } |
872 | |
873 | // Process collected namespaces. |
874 | LogicalVisitor.processNamespaces(); |
875 | |
876 | for (const SectionRef &Section : Obj.sections()) { |
877 | Expected<StringRef> SectionNameOrErr = Section.getName(); |
878 | if (!SectionNameOrErr) |
879 | return SectionNameOrErr.takeError(); |
880 | if (*SectionNameOrErr == ".debug$S" ) |
881 | if (Error Err = traverseSymbolSection(SectionName: *SectionNameOrErr, Section)) |
882 | return Err; |
883 | } |
884 | |
885 | // Check if we have to close the Compile Unit scope. |
886 | LogicalVisitor.closeScope(); |
887 | |
888 | // Traverse the strings recorded and transform them into filenames. |
889 | LogicalVisitor.processFiles(); |
890 | |
891 | // Process collected element lines. |
892 | LogicalVisitor.processLines(); |
893 | |
894 | // Translate composite names into a single component. |
895 | Root->transformScopedName(); |
896 | return Error::success(); |
897 | } |
898 | |
899 | Error LVCodeViewReader::createScopes(PDBFile &Pdb) { |
900 | if (Error Err = loadTargetInfo(Pdb)) |
901 | return Err; |
902 | |
903 | if (!Pdb.hasPDBTpiStream() || !Pdb.hasPDBDbiStream()) |
904 | return Error::success(); |
905 | |
906 | // Open the executable associated with the PDB file and get the section |
907 | // addresses used to calculate linear addresses for CodeView Symbols. |
908 | if (!ExePath.empty()) { |
909 | ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr = |
910 | MemoryBuffer::getFileOrSTDIN(Filename: ExePath); |
911 | if (BuffOrErr.getError()) { |
912 | return createStringError(EC: errc::bad_file_descriptor, |
913 | Fmt: "File '%s' does not exist." , Vals: ExePath.c_str()); |
914 | } |
915 | BinaryBuffer = std::move(BuffOrErr.get()); |
916 | |
917 | // Check if the buffer corresponds to a PECOFF executable. |
918 | assert(identify_magic(BinaryBuffer->getBuffer()) == |
919 | file_magic::pecoff_executable && |
920 | "Invalid PECOFF executable file." ); |
921 | |
922 | Expected<std::unique_ptr<Binary>> BinOrErr = |
923 | createBinary(Source: BinaryBuffer->getMemBufferRef()); |
924 | if (errorToErrorCode(Err: BinOrErr.takeError())) { |
925 | return createStringError(EC: errc::not_supported, |
926 | Fmt: "Binary object format in '%s' is not supported." , |
927 | Vals: ExePath.c_str()); |
928 | } |
929 | BinaryExecutable = std::move(*BinOrErr); |
930 | if (COFFObjectFile *COFFObject = |
931 | dyn_cast<COFFObjectFile>(Val: BinaryExecutable.get())) |
932 | mapVirtualAddress(COFFObj: *COFFObject); |
933 | } |
934 | |
935 | // In order to generate a full logical view, we have to traverse both |
936 | // streams TPI and IPI if they are present. The following table gives |
937 | // the stream where a specified type is located. If the IPI stream is |
938 | // not present, all the types are located in the TPI stream. |
939 | // |
940 | // TPI Stream: |
941 | // LF_POINTER LF_MODIFIER LF_PROCEDURE LF_MFUNCTION |
942 | // LF_LABEL LF_ARGLIST LF_FIELDLIST LF_ARRAY |
943 | // LF_CLASS LF_STRUCTURE LF_INTERFACE LF_UNION |
944 | // LF_ENUM LF_TYPESERVER2 LF_VFTABLE LF_VTSHAPE |
945 | // LF_BITFIELD LF_METHODLIST LF_PRECOMP LF_ENDPRECOMP |
946 | // |
947 | // IPI stream: |
948 | // LF_FUNC_ID LF_MFUNC_ID LF_BUILDINFO |
949 | // LF_SUBSTR_LIST LF_STRING_ID LF_UDT_SRC_LINE |
950 | // LF_UDT_MOD_SRC_LINE |
951 | |
952 | LazyRandomTypeCollection &Types = types(); |
953 | LazyRandomTypeCollection &Ids = ids(); |
954 | if (Error Err = traverseTypes(Pdb, Types, Ids)) |
955 | return Err; |
956 | |
957 | // Process collected namespaces. |
958 | LogicalVisitor.processNamespaces(); |
959 | |
960 | LLVM_DEBUG({ W.getOStream() << "Traversing inlined lines\n" ; }); |
961 | |
962 | auto VisitInlineeLines = [&](int32_t Modi, const SymbolGroup &SG, |
963 | DebugInlineeLinesSubsectionRef &Lines) -> Error { |
964 | return collectInlineeInfo(Lines, SG: &SG); |
965 | }; |
966 | |
967 | FilterOptions Filters = {}; |
968 | LinePrinter Printer(/*Indent=*/2, false, nulls(), Filters); |
969 | const PrintScope (Printer, /*IndentLevel=*/2); |
970 | if (Error Err = iterateModuleSubsections<DebugInlineeLinesSubsectionRef>( |
971 | File&: Input, HeaderScope, Callback: VisitInlineeLines)) |
972 | return Err; |
973 | |
974 | // Traverse global symbols. |
975 | LLVM_DEBUG({ W.getOStream() << "Traversing global symbols\n" ; }); |
976 | if (Pdb.hasPDBGlobalsStream()) { |
977 | Expected<GlobalsStream &> GlobalsOrErr = Pdb.getPDBGlobalsStream(); |
978 | if (!GlobalsOrErr) |
979 | return GlobalsOrErr.takeError(); |
980 | GlobalsStream &Globals = *GlobalsOrErr; |
981 | const GSIHashTable &Table = Globals.getGlobalsTable(); |
982 | Expected<SymbolStream &> ExpectedSyms = Pdb.getPDBSymbolStream(); |
983 | if (ExpectedSyms) { |
984 | |
985 | SymbolVisitorCallbackPipeline Pipeline; |
986 | SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); |
987 | LVSymbolVisitor Traverser(this, W, &LogicalVisitor, Types, Ids, nullptr, |
988 | LogicalVisitor.getShared()); |
989 | |
990 | // As the global symbols do not have an associated Compile Unit, create |
991 | // one, as the container for all global symbols. |
992 | RecordPrefix Prefix(SymbolKind::S_COMPILE3); |
993 | CVSymbol Symbol(&Prefix, sizeof(Prefix)); |
994 | uint32_t Offset = 0; |
995 | if (Error Err = Traverser.visitSymbolBegin(Record&: Symbol, Offset)) |
996 | consumeError(Err: std::move(Err)); |
997 | else { |
998 | // The CodeView compile unit containing the global symbols does not |
999 | // have a name; generate one using its parent name (object filename) |
1000 | // follow by the '_global' string. |
1001 | std::string Name(CompileUnit->getParentScope()->getName()); |
1002 | CompileUnit->setName(Name.append(s: "_global" )); |
1003 | |
1004 | Pipeline.addCallbackToPipeline(Callbacks&: Deserializer); |
1005 | Pipeline.addCallbackToPipeline(Callbacks&: Traverser); |
1006 | CVSymbolVisitor Visitor(Pipeline); |
1007 | |
1008 | BinaryStreamRef SymStream = |
1009 | ExpectedSyms->getSymbolArray().getUnderlyingStream(); |
1010 | for (uint32_t PubSymOff : Table) { |
1011 | Expected<CVSymbol> Sym = readSymbolFromStream(Stream: SymStream, Offset: PubSymOff); |
1012 | if (Sym) { |
1013 | if (Error Err = Visitor.visitSymbolRecord(Record&: *Sym, Offset: PubSymOff)) |
1014 | return createStringError(EC: errorToErrorCode(Err: std::move(Err)), |
1015 | S: getFileName()); |
1016 | } else { |
1017 | consumeError(Err: Sym.takeError()); |
1018 | } |
1019 | } |
1020 | } |
1021 | |
1022 | LogicalVisitor.closeScope(); |
1023 | } else { |
1024 | consumeError(Err: ExpectedSyms.takeError()); |
1025 | } |
1026 | } |
1027 | |
1028 | // Traverse symbols (DBI). |
1029 | LLVM_DEBUG({ W.getOStream() << "Traversing symbol groups\n" ; }); |
1030 | |
1031 | auto VisitSymbolGroup = [&](uint32_t Modi, const SymbolGroup &SG) -> Error { |
1032 | Expected<ModuleDebugStreamRef> ExpectedModS = |
1033 | getModuleDebugStream(File&: Pdb, Index: Modi); |
1034 | if (ExpectedModS) { |
1035 | ModuleDebugStreamRef &ModS = *ExpectedModS; |
1036 | |
1037 | LLVM_DEBUG({ |
1038 | W.getOStream() << formatv("Traversing Group: Mod {0:4}\n" , Modi); |
1039 | }); |
1040 | |
1041 | SymbolVisitorCallbackPipeline Pipeline; |
1042 | SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); |
1043 | LVSymbolVisitor Traverser(this, W, &LogicalVisitor, Types, Ids, nullptr, |
1044 | LogicalVisitor.getShared()); |
1045 | |
1046 | Pipeline.addCallbackToPipeline(Callbacks&: Deserializer); |
1047 | Pipeline.addCallbackToPipeline(Callbacks&: Traverser); |
1048 | CVSymbolVisitor Visitor(Pipeline); |
1049 | BinarySubstreamRef SS = ModS.getSymbolsSubstream(); |
1050 | if (Error Err = |
1051 | Visitor.visitSymbolStream(Symbols: ModS.getSymbolArray(), InitialOffset: SS.Offset)) |
1052 | return createStringError(EC: errorToErrorCode(Err: std::move(Err)), |
1053 | S: getFileName()); |
1054 | } else { |
1055 | // If the module stream does not exist, it is not an error condition. |
1056 | consumeError(Err: ExpectedModS.takeError()); |
1057 | } |
1058 | |
1059 | return Error::success(); |
1060 | }; |
1061 | |
1062 | if (Error Err = iterateSymbolGroups(Input, HeaderScope, Callback: VisitSymbolGroup)) |
1063 | return Err; |
1064 | |
1065 | // At this stage, the logical view contains all scopes, symbols and types. |
1066 | // For PDBs we can use the module id, to access its specific compile unit. |
1067 | // The line record addresses has been already resolved, so we can apply the |
1068 | // flow as when processing DWARF. |
1069 | |
1070 | LLVM_DEBUG({ W.getOStream() << "Traversing lines\n" ; }); |
1071 | |
1072 | // Record all line records for a Compile Unit. |
1073 | CULines.clear(); |
1074 | |
1075 | auto VisitDebugLines = [this](int32_t Modi, const SymbolGroup &SG, |
1076 | DebugLinesSubsectionRef &Lines) -> Error { |
1077 | if (!options().getPrintLines()) |
1078 | return Error::success(); |
1079 | |
1080 | uint16_t Segment = Lines.header()->RelocSegment; |
1081 | uint32_t Begin = Lines.header()->RelocOffset; |
1082 | uint32_t Size = Lines.header()->CodeSize; |
1083 | |
1084 | LLVM_DEBUG({ W.getOStream() << formatv("Modi = {0}\n" , Modi); }); |
1085 | |
1086 | // We have line information for a new module; finish processing the |
1087 | // collected information for the current module. Once it is done, start |
1088 | // recording the line information for the new module. |
1089 | if (CurrentModule != Modi) { |
1090 | if (Error Err = processModule()) |
1091 | return Err; |
1092 | CULines.clear(); |
1093 | CurrentModule = Modi; |
1094 | } |
1095 | |
1096 | for (const LineColumnEntry &Block : Lines) |
1097 | if (Error Err = createLines(LineNumbers: Block.LineNumbers, /*Addendum=*/0, Segment, |
1098 | Begin, Size, NameIndex: Block.NameIndex, SG: &SG)) |
1099 | return Err; |
1100 | |
1101 | return Error::success(); |
1102 | }; |
1103 | |
1104 | if (Error Err = iterateModuleSubsections<DebugLinesSubsectionRef>( |
1105 | File&: Input, HeaderScope, Callback: VisitDebugLines)) |
1106 | return Err; |
1107 | |
1108 | // Check if we have to close the Compile Unit scope. |
1109 | LogicalVisitor.closeScope(); |
1110 | |
1111 | // Process collected element lines. |
1112 | LogicalVisitor.processLines(); |
1113 | |
1114 | // Translate composite names into a single component. |
1115 | Root->transformScopedName(); |
1116 | return Error::success(); |
1117 | } |
1118 | |
1119 | Error LVCodeViewReader::processModule() { |
1120 | if (LVScope *Scope = getScopeForModule(Modi: CurrentModule)) { |
1121 | CompileUnit = static_cast<LVScopeCompileUnit *>(Scope); |
1122 | |
1123 | LLVM_DEBUG({ dbgs() << "Processing Scope: " << Scope->getName() << "\n" ; }); |
1124 | |
1125 | // For the given compile unit, collect all scopes ranges. |
1126 | // For a complete ranges and lines mapping, the logical view support |
1127 | // needs for the compile unit to have a low and high pc values. We |
1128 | // can traverse the 'Modules' section and get the information for the |
1129 | // specific module. Another option, is from all the ranges collected |
1130 | // to take the first and last values. |
1131 | LVSectionIndex SectionIndex = DotTextSectionIndex; |
1132 | LVRange *ScopesWithRanges = getSectionRanges(SectionIndex); |
1133 | ScopesWithRanges->clear(); |
1134 | CompileUnit->getRanges(RangeList&: *ScopesWithRanges); |
1135 | if (!ScopesWithRanges->empty()) |
1136 | CompileUnit->addObject(LowerAddress: ScopesWithRanges->getLower(), |
1137 | UpperAddress: ScopesWithRanges->getUpper()); |
1138 | ScopesWithRanges->sort(); |
1139 | |
1140 | if (Error Err = createInstructions()) |
1141 | return Err; |
1142 | |
1143 | // Include lines from any inlined functions within the current function. |
1144 | includeInlineeLines(SectionIndex, Function: Scope); |
1145 | |
1146 | processLines(DebugLines: &CULines, SectionIndex, Function: nullptr); |
1147 | } |
1148 | |
1149 | return Error::success(); |
1150 | } |
1151 | |
1152 | // In order to create the scopes, the CodeView Reader will: |
1153 | // = Traverse the TPI/IPI stream (Type visitor): |
1154 | // Collect forward references, scoped names, type indexes that will represent |
1155 | // a logical element, strings, line records, linkage names. |
1156 | // = Traverse the symbols section (Symbol visitor): |
1157 | // Create the scopes tree and creates the required logical elements, by |
1158 | // using the collected indexes from the type visitor. |
1159 | Error LVCodeViewReader::createScopes() { |
1160 | LLVM_DEBUG({ |
1161 | W.startLine() << "\n" ; |
1162 | W.printString("File" , getFileName().str()); |
1163 | W.printString("Exe" , ExePath); |
1164 | W.printString("Format" , FileFormatName); |
1165 | }); |
1166 | |
1167 | if (Error Err = LVReader::createScopes()) |
1168 | return Err; |
1169 | |
1170 | LogicalVisitor.setRoot(Root); |
1171 | |
1172 | if (isObj()) { |
1173 | if (Error Err = createScopes(Obj&: getObj())) |
1174 | return Err; |
1175 | } else { |
1176 | if (Error Err = createScopes(Pdb&: getPdb())) |
1177 | return Err; |
1178 | } |
1179 | |
1180 | return Error::success(); |
1181 | } |
1182 | |
1183 | Error LVCodeViewReader::loadTargetInfo(const ObjectFile &Obj) { |
1184 | // Detect the architecture from the object file. We usually don't need OS |
1185 | // info to lookup a target and create register info. |
1186 | Triple TT; |
1187 | TT.setArch(Kind: Triple::ArchType(Obj.getArch())); |
1188 | TT.setVendor(Triple::UnknownVendor); |
1189 | TT.setOS(Triple::UnknownOS); |
1190 | |
1191 | // Features to be passed to target/subtarget |
1192 | Expected<SubtargetFeatures> Features = Obj.getFeatures(); |
1193 | SubtargetFeatures FeaturesValue; |
1194 | if (!Features) { |
1195 | consumeError(Err: Features.takeError()); |
1196 | FeaturesValue = SubtargetFeatures(); |
1197 | } |
1198 | FeaturesValue = *Features; |
1199 | return loadGenericTargetInfo(TheTriple: TT.str(), TheFeatures: FeaturesValue.getString()); |
1200 | } |
1201 | |
1202 | Error LVCodeViewReader::loadTargetInfo(const PDBFile &Pdb) { |
1203 | Triple TT; |
1204 | TT.setArch(Kind: Triple::ArchType::x86_64); |
1205 | TT.setVendor(Triple::UnknownVendor); |
1206 | TT.setOS(Triple::Win32); |
1207 | |
1208 | StringRef TheFeature = "" ; |
1209 | |
1210 | return loadGenericTargetInfo(TheTriple: TT.str(), TheFeatures: TheFeature); |
1211 | } |
1212 | |
1213 | std::string LVCodeViewReader::getRegisterName(LVSmall Opcode, |
1214 | ArrayRef<uint64_t> Operands) { |
1215 | // Get Compilation Unit CPU Type. |
1216 | CPUType CPU = getCompileUnitCPUType(); |
1217 | // For CodeView the register always is in Operands[0]; |
1218 | RegisterId Register = (RegisterId(Operands[0])); |
1219 | return formatRegisterId(Register, CPU); |
1220 | } |
1221 | |