1 //===- CodeViewYAMLDebugSections.cpp - CodeView YAMLIO debug sections -----===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines classes for handling the YAML representation of CodeView
13 //===----------------------------------------------------------------------===//
15 #include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/BinaryFormat/COFF.h"
20 #include "llvm/DebugInfo/CodeView/CodeView.h"
21 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
22 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
23 #include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
24 #include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
25 #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
26 #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
27 #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
28 #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
29 #include "llvm/DebugInfo/CodeView/DebugSubsection.h"
30 #include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"
31 #include "llvm/DebugInfo/CodeView/DebugSymbolRVASubsection.h"
32 #include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
33 #include "llvm/DebugInfo/CodeView/Line.h"
34 #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
35 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
36 #include "llvm/ObjectYAML/CodeViewYAMLSymbols.h"
37 #include "llvm/Support/Allocator.h"
38 #include "llvm/Support/BinaryStreamReader.h"
39 #include "llvm/Support/Endian.h"
40 #include "llvm/Support/Error.h"
41 #include "llvm/Support/ErrorHandling.h"
42 #include "llvm/Support/YAMLTraits.h"
43 #include "llvm/Support/raw_ostream.h"
53 using namespace llvm::codeview
;
54 using namespace llvm::CodeViewYAML
;
55 using namespace llvm::CodeViewYAML::detail
;
56 using namespace llvm::yaml
;
58 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceFileChecksumEntry
)
59 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineEntry
)
60 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceColumnEntry
)
61 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineBlock
)
62 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineInfo
)
63 LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeSite
)
64 LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeInfo
)
65 LLVM_YAML_IS_SEQUENCE_VECTOR(CrossModuleExport
)
66 LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLCrossModuleImport
)
67 LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLFrameData
)
69 LLVM_YAML_DECLARE_SCALAR_TRAITS(HexFormattedString
, QuotingType::None
)
70 LLVM_YAML_DECLARE_ENUM_TRAITS(DebugSubsectionKind
)
71 LLVM_YAML_DECLARE_ENUM_TRAITS(FileChecksumKind
)
72 LLVM_YAML_DECLARE_BITSET_TRAITS(LineFlags
)
74 LLVM_YAML_DECLARE_MAPPING_TRAITS(CrossModuleExport
)
75 LLVM_YAML_DECLARE_MAPPING_TRAITS(YAMLFrameData
)
76 LLVM_YAML_DECLARE_MAPPING_TRAITS(YAMLCrossModuleImport
)
77 LLVM_YAML_DECLARE_MAPPING_TRAITS(CrossModuleImportItem
)
78 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineEntry
)
79 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceColumnEntry
)
80 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceFileChecksumEntry
)
81 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineBlock
)
82 LLVM_YAML_DECLARE_MAPPING_TRAITS(InlineeSite
)
85 namespace CodeViewYAML
{
88 struct YAMLSubsectionBase
{
89 explicit YAMLSubsectionBase(DebugSubsectionKind Kind
) : Kind(Kind
) {}
90 virtual ~YAMLSubsectionBase() = default;
92 virtual void map(IO
&IO
) = 0;
93 virtual std::shared_ptr
<DebugSubsection
>
94 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
95 const codeview::StringsAndChecksums
&SC
) const = 0;
97 DebugSubsectionKind Kind
;
100 } // end namespace detail
101 } // end namespace CodeViewYAML
102 } // end namespace llvm
106 struct YAMLChecksumsSubsection
: public YAMLSubsectionBase
{
107 YAMLChecksumsSubsection()
108 : YAMLSubsectionBase(DebugSubsectionKind::FileChecksums
) {}
110 void map(IO
&IO
) override
;
111 std::shared_ptr
<DebugSubsection
>
112 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
113 const codeview::StringsAndChecksums
&SC
) const override
;
114 static Expected
<std::shared_ptr
<YAMLChecksumsSubsection
>>
115 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
,
116 const DebugChecksumsSubsectionRef
&FC
);
118 std::vector
<SourceFileChecksumEntry
> Checksums
;
121 struct YAMLLinesSubsection
: public YAMLSubsectionBase
{
122 YAMLLinesSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Lines
) {}
124 void map(IO
&IO
) override
;
125 std::shared_ptr
<DebugSubsection
>
126 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
127 const codeview::StringsAndChecksums
&SC
) const override
;
128 static Expected
<std::shared_ptr
<YAMLLinesSubsection
>>
129 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
,
130 const DebugChecksumsSubsectionRef
&Checksums
,
131 const DebugLinesSubsectionRef
&Lines
);
133 SourceLineInfo Lines
;
136 struct YAMLInlineeLinesSubsection
: public YAMLSubsectionBase
{
137 YAMLInlineeLinesSubsection()
138 : YAMLSubsectionBase(DebugSubsectionKind::InlineeLines
) {}
140 void map(IO
&IO
) override
;
141 std::shared_ptr
<DebugSubsection
>
142 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
143 const codeview::StringsAndChecksums
&SC
) const override
;
144 static Expected
<std::shared_ptr
<YAMLInlineeLinesSubsection
>>
145 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
,
146 const DebugChecksumsSubsectionRef
&Checksums
,
147 const DebugInlineeLinesSubsectionRef
&Lines
);
149 InlineeInfo InlineeLines
;
152 struct YAMLCrossModuleExportsSubsection
: public YAMLSubsectionBase
{
153 YAMLCrossModuleExportsSubsection()
154 : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeExports
) {}
156 void map(IO
&IO
) override
;
157 std::shared_ptr
<DebugSubsection
>
158 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
159 const codeview::StringsAndChecksums
&SC
) const override
;
160 static Expected
<std::shared_ptr
<YAMLCrossModuleExportsSubsection
>>
161 fromCodeViewSubsection(const DebugCrossModuleExportsSubsectionRef
&Exports
);
163 std::vector
<CrossModuleExport
> Exports
;
166 struct YAMLCrossModuleImportsSubsection
: public YAMLSubsectionBase
{
167 YAMLCrossModuleImportsSubsection()
168 : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeImports
) {}
170 void map(IO
&IO
) override
;
171 std::shared_ptr
<DebugSubsection
>
172 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
173 const codeview::StringsAndChecksums
&SC
) const override
;
174 static Expected
<std::shared_ptr
<YAMLCrossModuleImportsSubsection
>>
175 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
,
176 const DebugCrossModuleImportsSubsectionRef
&Imports
);
178 std::vector
<YAMLCrossModuleImport
> Imports
;
181 struct YAMLSymbolsSubsection
: public YAMLSubsectionBase
{
182 YAMLSymbolsSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Symbols
) {}
184 void map(IO
&IO
) override
;
185 std::shared_ptr
<DebugSubsection
>
186 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
187 const codeview::StringsAndChecksums
&SC
) const override
;
188 static Expected
<std::shared_ptr
<YAMLSymbolsSubsection
>>
189 fromCodeViewSubsection(const DebugSymbolsSubsectionRef
&Symbols
);
191 std::vector
<CodeViewYAML::SymbolRecord
> Symbols
;
194 struct YAMLStringTableSubsection
: public YAMLSubsectionBase
{
195 YAMLStringTableSubsection()
196 : YAMLSubsectionBase(DebugSubsectionKind::StringTable
) {}
198 void map(IO
&IO
) override
;
199 std::shared_ptr
<DebugSubsection
>
200 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
201 const codeview::StringsAndChecksums
&SC
) const override
;
202 static Expected
<std::shared_ptr
<YAMLStringTableSubsection
>>
203 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
);
205 std::vector
<StringRef
> Strings
;
208 struct YAMLFrameDataSubsection
: public YAMLSubsectionBase
{
209 YAMLFrameDataSubsection()
210 : YAMLSubsectionBase(DebugSubsectionKind::FrameData
) {}
212 void map(IO
&IO
) override
;
213 std::shared_ptr
<DebugSubsection
>
214 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
215 const codeview::StringsAndChecksums
&SC
) const override
;
216 static Expected
<std::shared_ptr
<YAMLFrameDataSubsection
>>
217 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
,
218 const DebugFrameDataSubsectionRef
&Frames
);
220 std::vector
<YAMLFrameData
> Frames
;
223 struct YAMLCoffSymbolRVASubsection
: public YAMLSubsectionBase
{
224 YAMLCoffSymbolRVASubsection()
225 : YAMLSubsectionBase(DebugSubsectionKind::CoffSymbolRVA
) {}
227 void map(IO
&IO
) override
;
228 std::shared_ptr
<DebugSubsection
>
229 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
230 const codeview::StringsAndChecksums
&SC
) const override
;
231 static Expected
<std::shared_ptr
<YAMLCoffSymbolRVASubsection
>>
232 fromCodeViewSubsection(const DebugSymbolRVASubsectionRef
&RVAs
);
234 std::vector
<uint32_t> RVAs
;
237 } // end anonymous namespace
239 void ScalarBitSetTraits
<LineFlags
>::bitset(IO
&io
, LineFlags
&Flags
) {
240 io
.bitSetCase(Flags
, "HasColumnInfo", LF_HaveColumns
);
241 io
.enumFallback
<Hex16
>(Flags
);
244 void ScalarEnumerationTraits
<FileChecksumKind
>::enumeration(
245 IO
&io
, FileChecksumKind
&Kind
) {
246 io
.enumCase(Kind
, "None", FileChecksumKind::None
);
247 io
.enumCase(Kind
, "MD5", FileChecksumKind::MD5
);
248 io
.enumCase(Kind
, "SHA1", FileChecksumKind::SHA1
);
249 io
.enumCase(Kind
, "SHA256", FileChecksumKind::SHA256
);
252 void ScalarTraits
<HexFormattedString
>::output(const HexFormattedString
&Value
,
253 void *ctx
, raw_ostream
&Out
) {
254 StringRef
Bytes(reinterpret_cast<const char *>(Value
.Bytes
.data()),
259 StringRef ScalarTraits
<HexFormattedString
>::input(StringRef Scalar
, void *ctxt
,
260 HexFormattedString
&Value
) {
261 std::string H
= fromHex(Scalar
);
262 Value
.Bytes
.assign(H
.begin(), H
.end());
266 void MappingTraits
<SourceLineEntry
>::mapping(IO
&IO
, SourceLineEntry
&Obj
) {
267 IO
.mapRequired("Offset", Obj
.Offset
);
268 IO
.mapRequired("LineStart", Obj
.LineStart
);
269 IO
.mapRequired("IsStatement", Obj
.IsStatement
);
270 IO
.mapRequired("EndDelta", Obj
.EndDelta
);
273 void MappingTraits
<SourceColumnEntry
>::mapping(IO
&IO
, SourceColumnEntry
&Obj
) {
274 IO
.mapRequired("StartColumn", Obj
.StartColumn
);
275 IO
.mapRequired("EndColumn", Obj
.EndColumn
);
278 void MappingTraits
<SourceLineBlock
>::mapping(IO
&IO
, SourceLineBlock
&Obj
) {
279 IO
.mapRequired("FileName", Obj
.FileName
);
280 IO
.mapRequired("Lines", Obj
.Lines
);
281 IO
.mapRequired("Columns", Obj
.Columns
);
284 void MappingTraits
<CrossModuleExport
>::mapping(IO
&IO
, CrossModuleExport
&Obj
) {
285 IO
.mapRequired("LocalId", Obj
.Local
);
286 IO
.mapRequired("GlobalId", Obj
.Global
);
289 void MappingTraits
<YAMLCrossModuleImport
>::mapping(IO
&IO
,
290 YAMLCrossModuleImport
&Obj
) {
291 IO
.mapRequired("Module", Obj
.ModuleName
);
292 IO
.mapRequired("Imports", Obj
.ImportIds
);
295 void MappingTraits
<SourceFileChecksumEntry
>::mapping(
296 IO
&IO
, SourceFileChecksumEntry
&Obj
) {
297 IO
.mapRequired("FileName", Obj
.FileName
);
298 IO
.mapRequired("Kind", Obj
.Kind
);
299 IO
.mapRequired("Checksum", Obj
.ChecksumBytes
);
302 void MappingTraits
<InlineeSite
>::mapping(IO
&IO
, InlineeSite
&Obj
) {
303 IO
.mapRequired("FileName", Obj
.FileName
);
304 IO
.mapRequired("LineNum", Obj
.SourceLineNum
);
305 IO
.mapRequired("Inlinee", Obj
.Inlinee
);
306 IO
.mapOptional("ExtraFiles", Obj
.ExtraFiles
);
309 void MappingTraits
<YAMLFrameData
>::mapping(IO
&IO
, YAMLFrameData
&Obj
) {
310 IO
.mapRequired("CodeSize", Obj
.CodeSize
);
311 IO
.mapRequired("FrameFunc", Obj
.FrameFunc
);
312 IO
.mapRequired("LocalSize", Obj
.LocalSize
);
313 IO
.mapOptional("MaxStackSize", Obj
.MaxStackSize
);
314 IO
.mapOptional("ParamsSize", Obj
.ParamsSize
);
315 IO
.mapOptional("PrologSize", Obj
.PrologSize
);
316 IO
.mapOptional("RvaStart", Obj
.RvaStart
);
317 IO
.mapOptional("SavedRegsSize", Obj
.SavedRegsSize
);
320 void YAMLChecksumsSubsection::map(IO
&IO
) {
321 IO
.mapTag("!FileChecksums", true);
322 IO
.mapRequired("Checksums", Checksums
);
325 void YAMLLinesSubsection::map(IO
&IO
) {
326 IO
.mapTag("!Lines", true);
327 IO
.mapRequired("CodeSize", Lines
.CodeSize
);
329 IO
.mapRequired("Flags", Lines
.Flags
);
330 IO
.mapRequired("RelocOffset", Lines
.RelocOffset
);
331 IO
.mapRequired("RelocSegment", Lines
.RelocSegment
);
332 IO
.mapRequired("Blocks", Lines
.Blocks
);
335 void YAMLInlineeLinesSubsection::map(IO
&IO
) {
336 IO
.mapTag("!InlineeLines", true);
337 IO
.mapRequired("HasExtraFiles", InlineeLines
.HasExtraFiles
);
338 IO
.mapRequired("Sites", InlineeLines
.Sites
);
341 void YAMLCrossModuleExportsSubsection::map(IO
&IO
) {
342 IO
.mapTag("!CrossModuleExports", true);
343 IO
.mapOptional("Exports", Exports
);
346 void YAMLCrossModuleImportsSubsection::map(IO
&IO
) {
347 IO
.mapTag("!CrossModuleImports", true);
348 IO
.mapOptional("Imports", Imports
);
351 void YAMLSymbolsSubsection::map(IO
&IO
) {
352 IO
.mapTag("!Symbols", true);
353 IO
.mapRequired("Records", Symbols
);
356 void YAMLStringTableSubsection::map(IO
&IO
) {
357 IO
.mapTag("!StringTable", true);
358 IO
.mapRequired("Strings", Strings
);
361 void YAMLFrameDataSubsection::map(IO
&IO
) {
362 IO
.mapTag("!FrameData", true);
363 IO
.mapRequired("Frames", Frames
);
366 void YAMLCoffSymbolRVASubsection::map(IO
&IO
) {
367 IO
.mapTag("!COFFSymbolRVAs", true);
368 IO
.mapRequired("RVAs", RVAs
);
371 void MappingTraits
<YAMLDebugSubsection
>::mapping(
372 IO
&IO
, YAMLDebugSubsection
&Subsection
) {
373 if (!IO
.outputting()) {
374 if (IO
.mapTag("!FileChecksums")) {
375 auto SS
= std::make_shared
<YAMLChecksumsSubsection
>();
376 Subsection
.Subsection
= SS
;
377 } else if (IO
.mapTag("!Lines")) {
378 Subsection
.Subsection
= std::make_shared
<YAMLLinesSubsection
>();
379 } else if (IO
.mapTag("!InlineeLines")) {
380 Subsection
.Subsection
= std::make_shared
<YAMLInlineeLinesSubsection
>();
381 } else if (IO
.mapTag("!CrossModuleExports")) {
382 Subsection
.Subsection
=
383 std::make_shared
<YAMLCrossModuleExportsSubsection
>();
384 } else if (IO
.mapTag("!CrossModuleImports")) {
385 Subsection
.Subsection
=
386 std::make_shared
<YAMLCrossModuleImportsSubsection
>();
387 } else if (IO
.mapTag("!Symbols")) {
388 Subsection
.Subsection
= std::make_shared
<YAMLSymbolsSubsection
>();
389 } else if (IO
.mapTag("!StringTable")) {
390 Subsection
.Subsection
= std::make_shared
<YAMLStringTableSubsection
>();
391 } else if (IO
.mapTag("!FrameData")) {
392 Subsection
.Subsection
= std::make_shared
<YAMLFrameDataSubsection
>();
393 } else if (IO
.mapTag("!COFFSymbolRVAs")) {
394 Subsection
.Subsection
= std::make_shared
<YAMLCoffSymbolRVASubsection
>();
396 llvm_unreachable("Unexpected subsection tag!");
399 Subsection
.Subsection
->map(IO
);
402 std::shared_ptr
<DebugSubsection
> YAMLChecksumsSubsection::toCodeViewSubsection(
403 BumpPtrAllocator
&Allocator
,
404 const codeview::StringsAndChecksums
&SC
) const {
405 assert(SC
.hasStrings());
406 auto Result
= std::make_shared
<DebugChecksumsSubsection
>(*SC
.strings());
407 for (const auto &CS
: Checksums
) {
408 Result
->addChecksum(CS
.FileName
, CS
.Kind
, CS
.ChecksumBytes
.Bytes
);
413 std::shared_ptr
<DebugSubsection
> YAMLLinesSubsection::toCodeViewSubsection(
414 BumpPtrAllocator
&Allocator
,
415 const codeview::StringsAndChecksums
&SC
) const {
416 assert(SC
.hasStrings() && SC
.hasChecksums());
418 std::make_shared
<DebugLinesSubsection
>(*SC
.checksums(), *SC
.strings());
419 Result
->setCodeSize(Lines
.CodeSize
);
420 Result
->setRelocationAddress(Lines
.RelocSegment
, Lines
.RelocOffset
);
421 Result
->setFlags(Lines
.Flags
);
422 for (const auto &LC
: Lines
.Blocks
) {
423 Result
->createBlock(LC
.FileName
);
424 if (Result
->hasColumnInfo()) {
425 for (const auto &Item
: zip(LC
.Lines
, LC
.Columns
)) {
426 auto &L
= std::get
<0>(Item
);
427 auto &C
= std::get
<1>(Item
);
428 uint32_t LE
= L
.LineStart
+ L
.EndDelta
;
429 Result
->addLineAndColumnInfo(L
.Offset
,
430 LineInfo(L
.LineStart
, LE
, L
.IsStatement
),
431 C
.StartColumn
, C
.EndColumn
);
434 for (const auto &L
: LC
.Lines
) {
435 uint32_t LE
= L
.LineStart
+ L
.EndDelta
;
436 Result
->addLineInfo(L
.Offset
, LineInfo(L
.LineStart
, LE
, L
.IsStatement
));
443 std::shared_ptr
<DebugSubsection
>
444 YAMLInlineeLinesSubsection::toCodeViewSubsection(
445 BumpPtrAllocator
&Allocator
,
446 const codeview::StringsAndChecksums
&SC
) const {
447 assert(SC
.hasChecksums());
448 auto Result
= std::make_shared
<DebugInlineeLinesSubsection
>(
449 *SC
.checksums(), InlineeLines
.HasExtraFiles
);
451 for (const auto &Site
: InlineeLines
.Sites
) {
452 Result
->addInlineSite(TypeIndex(Site
.Inlinee
), Site
.FileName
,
454 if (!InlineeLines
.HasExtraFiles
)
457 for (auto EF
: Site
.ExtraFiles
) {
458 Result
->addExtraFile(EF
);
464 std::shared_ptr
<DebugSubsection
>
465 YAMLCrossModuleExportsSubsection::toCodeViewSubsection(
466 BumpPtrAllocator
&Allocator
,
467 const codeview::StringsAndChecksums
&SC
) const {
468 auto Result
= std::make_shared
<DebugCrossModuleExportsSubsection
>();
469 for (const auto &M
: Exports
)
470 Result
->addMapping(M
.Local
, M
.Global
);
474 std::shared_ptr
<DebugSubsection
>
475 YAMLCrossModuleImportsSubsection::toCodeViewSubsection(
476 BumpPtrAllocator
&Allocator
,
477 const codeview::StringsAndChecksums
&SC
) const {
478 assert(SC
.hasStrings());
481 std::make_shared
<DebugCrossModuleImportsSubsection
>(*SC
.strings());
482 for (const auto &M
: Imports
) {
483 for (const auto Id
: M
.ImportIds
)
484 Result
->addImport(M
.ModuleName
, Id
);
489 std::shared_ptr
<DebugSubsection
> YAMLSymbolsSubsection::toCodeViewSubsection(
490 BumpPtrAllocator
&Allocator
,
491 const codeview::StringsAndChecksums
&SC
) const {
492 auto Result
= std::make_shared
<DebugSymbolsSubsection
>();
493 for (const auto &Sym
: Symbols
)
495 Sym
.toCodeViewSymbol(Allocator
, CodeViewContainer::ObjectFile
));
499 std::shared_ptr
<DebugSubsection
>
500 YAMLStringTableSubsection::toCodeViewSubsection(
501 BumpPtrAllocator
&Allocator
,
502 const codeview::StringsAndChecksums
&SC
) const {
503 auto Result
= std::make_shared
<DebugStringTableSubsection
>();
504 for (const auto &Str
: this->Strings
)
509 std::shared_ptr
<DebugSubsection
> YAMLFrameDataSubsection::toCodeViewSubsection(
510 BumpPtrAllocator
&Allocator
,
511 const codeview::StringsAndChecksums
&SC
) const {
512 assert(SC
.hasStrings());
514 auto Result
= std::make_shared
<DebugFrameDataSubsection
>(true);
515 for (const auto &YF
: Frames
) {
516 codeview::FrameData F
;
517 F
.CodeSize
= YF
.CodeSize
;
519 F
.LocalSize
= YF
.LocalSize
;
520 F
.MaxStackSize
= YF
.MaxStackSize
;
521 F
.ParamsSize
= YF
.ParamsSize
;
522 F
.PrologSize
= YF
.PrologSize
;
523 F
.RvaStart
= YF
.RvaStart
;
524 F
.SavedRegsSize
= YF
.SavedRegsSize
;
525 F
.FrameFunc
= SC
.strings()->insert(YF
.FrameFunc
);
526 Result
->addFrameData(F
);
531 std::shared_ptr
<DebugSubsection
>
532 YAMLCoffSymbolRVASubsection::toCodeViewSubsection(
533 BumpPtrAllocator
&Allocator
,
534 const codeview::StringsAndChecksums
&SC
) const {
535 auto Result
= std::make_shared
<DebugSymbolRVASubsection
>();
536 for (const auto &RVA
: RVAs
)
541 static Expected
<SourceFileChecksumEntry
>
542 convertOneChecksum(const DebugStringTableSubsectionRef
&Strings
,
543 const FileChecksumEntry
&CS
) {
544 auto ExpectedString
= Strings
.getString(CS
.FileNameOffset
);
546 return ExpectedString
.takeError();
548 SourceFileChecksumEntry Result
;
549 Result
.ChecksumBytes
.Bytes
= CS
.Checksum
;
550 Result
.Kind
= CS
.Kind
;
551 Result
.FileName
= *ExpectedString
;
555 static Expected
<StringRef
>
556 getFileName(const DebugStringTableSubsectionRef
&Strings
,
557 const DebugChecksumsSubsectionRef
&Checksums
, uint32_t FileID
) {
558 auto Iter
= Checksums
.getArray().at(FileID
);
559 if (Iter
== Checksums
.getArray().end())
560 return make_error
<CodeViewError
>(cv_error_code::no_records
);
561 uint32_t Offset
= Iter
->FileNameOffset
;
562 return Strings
.getString(Offset
);
565 Expected
<std::shared_ptr
<YAMLChecksumsSubsection
>>
566 YAMLChecksumsSubsection::fromCodeViewSubsection(
567 const DebugStringTableSubsectionRef
&Strings
,
568 const DebugChecksumsSubsectionRef
&FC
) {
569 auto Result
= std::make_shared
<YAMLChecksumsSubsection
>();
571 for (const auto &CS
: FC
) {
572 auto ConvertedCS
= convertOneChecksum(Strings
, CS
);
574 return ConvertedCS
.takeError();
575 Result
->Checksums
.push_back(*ConvertedCS
);
580 Expected
<std::shared_ptr
<YAMLLinesSubsection
>>
581 YAMLLinesSubsection::fromCodeViewSubsection(
582 const DebugStringTableSubsectionRef
&Strings
,
583 const DebugChecksumsSubsectionRef
&Checksums
,
584 const DebugLinesSubsectionRef
&Lines
) {
585 auto Result
= std::make_shared
<YAMLLinesSubsection
>();
586 Result
->Lines
.CodeSize
= Lines
.header()->CodeSize
;
587 Result
->Lines
.RelocOffset
= Lines
.header()->RelocOffset
;
588 Result
->Lines
.RelocSegment
= Lines
.header()->RelocSegment
;
589 Result
->Lines
.Flags
= static_cast<LineFlags
>(uint16_t(Lines
.header()->Flags
));
590 for (const auto &L
: Lines
) {
591 SourceLineBlock Block
;
592 auto EF
= getFileName(Strings
, Checksums
, L
.NameIndex
);
594 return EF
.takeError();
595 Block
.FileName
= *EF
;
596 if (Lines
.hasColumnInfo()) {
597 for (const auto &C
: L
.Columns
) {
598 SourceColumnEntry SCE
;
599 SCE
.EndColumn
= C
.EndColumn
;
600 SCE
.StartColumn
= C
.StartColumn
;
601 Block
.Columns
.push_back(SCE
);
604 for (const auto &LN
: L
.LineNumbers
) {
606 LineInfo
LI(LN
.Flags
);
607 SLE
.Offset
= LN
.Offset
;
608 SLE
.LineStart
= LI
.getStartLine();
609 SLE
.EndDelta
= LI
.getLineDelta();
610 SLE
.IsStatement
= LI
.isStatement();
611 Block
.Lines
.push_back(SLE
);
613 Result
->Lines
.Blocks
.push_back(Block
);
618 Expected
<std::shared_ptr
<YAMLInlineeLinesSubsection
>>
619 YAMLInlineeLinesSubsection::fromCodeViewSubsection(
620 const DebugStringTableSubsectionRef
&Strings
,
621 const DebugChecksumsSubsectionRef
&Checksums
,
622 const DebugInlineeLinesSubsectionRef
&Lines
) {
623 auto Result
= std::make_shared
<YAMLInlineeLinesSubsection
>();
625 Result
->InlineeLines
.HasExtraFiles
= Lines
.hasExtraFiles();
626 for (const auto &IL
: Lines
) {
628 auto ExpF
= getFileName(Strings
, Checksums
, IL
.Header
->FileID
);
630 return ExpF
.takeError();
631 Site
.FileName
= *ExpF
;
632 Site
.Inlinee
= IL
.Header
->Inlinee
.getIndex();
633 Site
.SourceLineNum
= IL
.Header
->SourceLineNum
;
634 if (Lines
.hasExtraFiles()) {
635 for (const auto EF
: IL
.ExtraFiles
) {
636 auto ExpF2
= getFileName(Strings
, Checksums
, EF
);
638 return ExpF2
.takeError();
639 Site
.ExtraFiles
.push_back(*ExpF2
);
642 Result
->InlineeLines
.Sites
.push_back(Site
);
647 Expected
<std::shared_ptr
<YAMLCrossModuleExportsSubsection
>>
648 YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(
649 const DebugCrossModuleExportsSubsectionRef
&Exports
) {
650 auto Result
= std::make_shared
<YAMLCrossModuleExportsSubsection
>();
651 Result
->Exports
.assign(Exports
.begin(), Exports
.end());
655 Expected
<std::shared_ptr
<YAMLCrossModuleImportsSubsection
>>
656 YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(
657 const DebugStringTableSubsectionRef
&Strings
,
658 const DebugCrossModuleImportsSubsectionRef
&Imports
) {
659 auto Result
= std::make_shared
<YAMLCrossModuleImportsSubsection
>();
660 for (const auto &CMI
: Imports
) {
661 YAMLCrossModuleImport YCMI
;
662 auto ExpectedStr
= Strings
.getString(CMI
.Header
->ModuleNameOffset
);
664 return ExpectedStr
.takeError();
665 YCMI
.ModuleName
= *ExpectedStr
;
666 YCMI
.ImportIds
.assign(CMI
.Imports
.begin(), CMI
.Imports
.end());
667 Result
->Imports
.push_back(YCMI
);
672 Expected
<std::shared_ptr
<YAMLSymbolsSubsection
>>
673 YAMLSymbolsSubsection::fromCodeViewSubsection(
674 const DebugSymbolsSubsectionRef
&Symbols
) {
675 auto Result
= std::make_shared
<YAMLSymbolsSubsection
>();
676 for (const auto &Sym
: Symbols
) {
677 auto S
= CodeViewYAML::SymbolRecord::fromCodeViewSymbol(Sym
);
679 return joinErrors(make_error
<CodeViewError
>(
680 cv_error_code::corrupt_record
,
681 "Invalid CodeView Symbol Record in SymbolRecord "
682 "subsection of .debug$S while converting to YAML!"),
685 Result
->Symbols
.push_back(*S
);
690 Expected
<std::shared_ptr
<YAMLStringTableSubsection
>>
691 YAMLStringTableSubsection::fromCodeViewSubsection(
692 const DebugStringTableSubsectionRef
&Strings
) {
693 auto Result
= std::make_shared
<YAMLStringTableSubsection
>();
694 BinaryStreamReader
Reader(Strings
.getBuffer());
696 // First item is a single null string, skip it.
697 if (auto EC
= Reader
.readCString(S
))
698 return std::move(EC
);
700 while (Reader
.bytesRemaining() > 0) {
701 if (auto EC
= Reader
.readCString(S
))
702 return std::move(EC
);
703 Result
->Strings
.push_back(S
);
708 Expected
<std::shared_ptr
<YAMLFrameDataSubsection
>>
709 YAMLFrameDataSubsection::fromCodeViewSubsection(
710 const DebugStringTableSubsectionRef
&Strings
,
711 const DebugFrameDataSubsectionRef
&Frames
) {
712 auto Result
= std::make_shared
<YAMLFrameDataSubsection
>();
713 for (const auto &F
: Frames
) {
715 YF
.CodeSize
= F
.CodeSize
;
717 YF
.LocalSize
= F
.LocalSize
;
718 YF
.MaxStackSize
= F
.MaxStackSize
;
719 YF
.ParamsSize
= F
.ParamsSize
;
720 YF
.PrologSize
= F
.PrologSize
;
721 YF
.RvaStart
= F
.RvaStart
;
722 YF
.SavedRegsSize
= F
.SavedRegsSize
;
724 auto ES
= Strings
.getString(F
.FrameFunc
);
727 make_error
<CodeViewError
>(
728 cv_error_code::no_records
,
729 "Could not find string for string id while mapping FrameData!"),
732 Result
->Frames
.push_back(YF
);
737 Expected
<std::shared_ptr
<YAMLCoffSymbolRVASubsection
>>
738 YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(
739 const DebugSymbolRVASubsectionRef
&Section
) {
740 auto Result
= std::make_shared
<YAMLCoffSymbolRVASubsection
>();
741 for (const auto &RVA
: Section
) {
742 Result
->RVAs
.push_back(RVA
);
747 Expected
<std::vector
<std::shared_ptr
<DebugSubsection
>>>
748 llvm::CodeViewYAML::toCodeViewSubsectionList(
749 BumpPtrAllocator
&Allocator
, ArrayRef
<YAMLDebugSubsection
> Subsections
,
750 const codeview::StringsAndChecksums
&SC
) {
751 std::vector
<std::shared_ptr
<DebugSubsection
>> Result
;
752 if (Subsections
.empty())
753 return std::move(Result
);
755 for (const auto &SS
: Subsections
) {
756 std::shared_ptr
<DebugSubsection
> CVS
;
757 CVS
= SS
.Subsection
->toCodeViewSubsection(Allocator
, SC
);
758 assert(CVS
!= nullptr);
759 Result
.push_back(std::move(CVS
));
761 return std::move(Result
);
766 struct SubsectionConversionVisitor
: public DebugSubsectionVisitor
{
767 SubsectionConversionVisitor() = default;
769 Error
visitUnknown(DebugUnknownSubsectionRef
&Unknown
) override
;
770 Error
visitLines(DebugLinesSubsectionRef
&Lines
,
771 const StringsAndChecksumsRef
&State
) override
;
772 Error
visitFileChecksums(DebugChecksumsSubsectionRef
&Checksums
,
773 const StringsAndChecksumsRef
&State
) override
;
774 Error
visitInlineeLines(DebugInlineeLinesSubsectionRef
&Inlinees
,
775 const StringsAndChecksumsRef
&State
) override
;
776 Error
visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef
&Checksums
,
777 const StringsAndChecksumsRef
&State
) override
;
778 Error
visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef
&Inlinees
,
779 const StringsAndChecksumsRef
&State
) override
;
780 Error
visitStringTable(DebugStringTableSubsectionRef
&ST
,
781 const StringsAndChecksumsRef
&State
) override
;
782 Error
visitSymbols(DebugSymbolsSubsectionRef
&Symbols
,
783 const StringsAndChecksumsRef
&State
) override
;
784 Error
visitFrameData(DebugFrameDataSubsectionRef
&Symbols
,
785 const StringsAndChecksumsRef
&State
) override
;
786 Error
visitCOFFSymbolRVAs(DebugSymbolRVASubsectionRef
&Symbols
,
787 const StringsAndChecksumsRef
&State
) override
;
789 YAMLDebugSubsection Subsection
;
792 } // end anonymous namespace
794 Error
SubsectionConversionVisitor::visitUnknown(
795 DebugUnknownSubsectionRef
&Unknown
) {
796 return make_error
<CodeViewError
>(cv_error_code::operation_unsupported
);
799 Error
SubsectionConversionVisitor::visitLines(
800 DebugLinesSubsectionRef
&Lines
, const StringsAndChecksumsRef
&State
) {
801 auto Result
= YAMLLinesSubsection::fromCodeViewSubsection(
802 State
.strings(), State
.checksums(), Lines
);
804 return Result
.takeError();
805 Subsection
.Subsection
= *Result
;
806 return Error::success();
809 Error
SubsectionConversionVisitor::visitFileChecksums(
810 DebugChecksumsSubsectionRef
&Checksums
,
811 const StringsAndChecksumsRef
&State
) {
812 auto Result
= YAMLChecksumsSubsection::fromCodeViewSubsection(State
.strings(),
815 return Result
.takeError();
816 Subsection
.Subsection
= *Result
;
817 return Error::success();
820 Error
SubsectionConversionVisitor::visitInlineeLines(
821 DebugInlineeLinesSubsectionRef
&Inlinees
,
822 const StringsAndChecksumsRef
&State
) {
823 auto Result
= YAMLInlineeLinesSubsection::fromCodeViewSubsection(
824 State
.strings(), State
.checksums(), Inlinees
);
826 return Result
.takeError();
827 Subsection
.Subsection
= *Result
;
828 return Error::success();
831 Error
SubsectionConversionVisitor::visitCrossModuleExports(
832 DebugCrossModuleExportsSubsectionRef
&Exports
,
833 const StringsAndChecksumsRef
&State
) {
835 YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(Exports
);
837 return Result
.takeError();
838 Subsection
.Subsection
= *Result
;
839 return Error::success();
842 Error
SubsectionConversionVisitor::visitCrossModuleImports(
843 DebugCrossModuleImportsSubsectionRef
&Imports
,
844 const StringsAndChecksumsRef
&State
) {
845 auto Result
= YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(
846 State
.strings(), Imports
);
848 return Result
.takeError();
849 Subsection
.Subsection
= *Result
;
850 return Error::success();
853 Error
SubsectionConversionVisitor::visitStringTable(
854 DebugStringTableSubsectionRef
&Strings
,
855 const StringsAndChecksumsRef
&State
) {
856 auto Result
= YAMLStringTableSubsection::fromCodeViewSubsection(Strings
);
858 return Result
.takeError();
859 Subsection
.Subsection
= *Result
;
860 return Error::success();
863 Error
SubsectionConversionVisitor::visitSymbols(
864 DebugSymbolsSubsectionRef
&Symbols
, const StringsAndChecksumsRef
&State
) {
865 auto Result
= YAMLSymbolsSubsection::fromCodeViewSubsection(Symbols
);
867 return Result
.takeError();
868 Subsection
.Subsection
= *Result
;
869 return Error::success();
872 Error
SubsectionConversionVisitor::visitFrameData(
873 DebugFrameDataSubsectionRef
&Frames
, const StringsAndChecksumsRef
&State
) {
875 YAMLFrameDataSubsection::fromCodeViewSubsection(State
.strings(), Frames
);
877 return Result
.takeError();
878 Subsection
.Subsection
= *Result
;
879 return Error::success();
882 Error
SubsectionConversionVisitor::visitCOFFSymbolRVAs(
883 DebugSymbolRVASubsectionRef
&RVAs
, const StringsAndChecksumsRef
&State
) {
884 auto Result
= YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(RVAs
);
886 return Result
.takeError();
887 Subsection
.Subsection
= *Result
;
888 return Error::success();
891 Expected
<YAMLDebugSubsection
>
892 YAMLDebugSubsection::fromCodeViewSubection(const StringsAndChecksumsRef
&SC
,
893 const DebugSubsectionRecord
&SS
) {
894 SubsectionConversionVisitor V
;
895 if (auto EC
= visitDebugSubsection(SS
, V
, SC
))
896 return std::move(EC
);
901 std::vector
<YAMLDebugSubsection
>
902 llvm::CodeViewYAML::fromDebugS(ArrayRef
<uint8_t> Data
,
903 const StringsAndChecksumsRef
&SC
) {
904 BinaryStreamReader
Reader(Data
, support::little
);
907 ExitOnError
Err("Invalid .debug$S section!");
908 Err(Reader
.readInteger(Magic
));
909 assert(Magic
== COFF::DEBUG_SECTION_MAGIC
&& "Invalid .debug$S section!");
911 DebugSubsectionArray Subsections
;
912 Err(Reader
.readArray(Subsections
, Reader
.bytesRemaining()));
914 std::vector
<YAMLDebugSubsection
> Result
;
916 for (const auto &SS
: Subsections
) {
917 auto YamlSS
= Err(YAMLDebugSubsection::fromCodeViewSubection(SC
, SS
));
918 Result
.push_back(YamlSS
);
923 void llvm::CodeViewYAML::initializeStringsAndChecksums(
924 ArrayRef
<YAMLDebugSubsection
> Sections
, codeview::StringsAndChecksums
&SC
) {
925 // String Table and Checksums subsections don't use the allocator.
926 BumpPtrAllocator Allocator
;
928 // It's possible for checksums and strings to even appear in different debug$S
929 // sections, so we have to make this a stateful function that can build up
930 // the strings and checksums field over multiple iterations.
932 // File Checksums require the string table, but may become before it, so we
933 // have to scan for strings first, then scan for checksums again from the
935 if (!SC
.hasStrings()) {
936 for (const auto &SS
: Sections
) {
937 if (SS
.Subsection
->Kind
!= DebugSubsectionKind::StringTable
)
940 auto Result
= SS
.Subsection
->toCodeViewSubsection(Allocator
, SC
);
942 std::static_pointer_cast
<DebugStringTableSubsection
>(Result
));
947 if (SC
.hasStrings() && !SC
.hasChecksums()) {
948 for (const auto &SS
: Sections
) {
949 if (SS
.Subsection
->Kind
!= DebugSubsectionKind::FileChecksums
)
952 auto Result
= SS
.Subsection
->toCodeViewSubsection(Allocator
, SC
);
954 std::static_pointer_cast
<DebugChecksumsSubsection
>(Result
));