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