1 //===- CodeViewYAMLDebugSections.cpp - CodeView YAMLIO debug sections -----===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines classes for handling the YAML representation of CodeView
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/StringExtras.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/BinaryFormat/COFF.h"
19 #include "llvm/DebugInfo/CodeView/CodeView.h"
20 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
21 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
22 #include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
23 #include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
24 #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
25 #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
26 #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
27 #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
28 #include "llvm/DebugInfo/CodeView/DebugSubsection.h"
29 #include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"
30 #include "llvm/DebugInfo/CodeView/DebugSymbolRVASubsection.h"
31 #include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
32 #include "llvm/DebugInfo/CodeView/Line.h"
33 #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
34 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
35 #include "llvm/ObjectYAML/CodeViewYAMLSymbols.h"
36 #include "llvm/Support/Allocator.h"
37 #include "llvm/Support/BinaryStreamReader.h"
38 #include "llvm/Support/Endian.h"
39 #include "llvm/Support/Error.h"
40 #include "llvm/Support/ErrorHandling.h"
41 #include "llvm/Support/YAMLTraits.h"
42 #include "llvm/Support/raw_ostream.h"
50 using namespace llvm::codeview
;
51 using namespace llvm::CodeViewYAML
;
52 using namespace llvm::CodeViewYAML::detail
;
53 using namespace llvm::yaml
;
55 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceFileChecksumEntry
)
56 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineEntry
)
57 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceColumnEntry
)
58 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineBlock
)
59 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineInfo
)
60 LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeSite
)
61 LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeInfo
)
62 LLVM_YAML_IS_SEQUENCE_VECTOR(CrossModuleExport
)
63 LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLCrossModuleImport
)
64 LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLFrameData
)
66 LLVM_YAML_DECLARE_SCALAR_TRAITS(HexFormattedString
, QuotingType::None
)
67 LLVM_YAML_DECLARE_ENUM_TRAITS(DebugSubsectionKind
)
68 LLVM_YAML_DECLARE_ENUM_TRAITS(FileChecksumKind
)
69 LLVM_YAML_DECLARE_BITSET_TRAITS(LineFlags
)
71 LLVM_YAML_DECLARE_MAPPING_TRAITS(CrossModuleExport
)
72 LLVM_YAML_DECLARE_MAPPING_TRAITS(YAMLFrameData
)
73 LLVM_YAML_DECLARE_MAPPING_TRAITS(YAMLCrossModuleImport
)
74 LLVM_YAML_DECLARE_MAPPING_TRAITS(CrossModuleImportItem
)
75 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineEntry
)
76 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceColumnEntry
)
77 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceFileChecksumEntry
)
78 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineBlock
)
79 LLVM_YAML_DECLARE_MAPPING_TRAITS(InlineeSite
)
82 namespace CodeViewYAML
{
85 struct YAMLSubsectionBase
{
86 explicit YAMLSubsectionBase(DebugSubsectionKind Kind
) : Kind(Kind
) {}
87 virtual ~YAMLSubsectionBase() = default;
89 virtual void map(IO
&IO
) = 0;
90 virtual std::shared_ptr
<DebugSubsection
>
91 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
92 const codeview::StringsAndChecksums
&SC
) const = 0;
94 DebugSubsectionKind Kind
;
97 } // end namespace detail
98 } // end namespace CodeViewYAML
99 } // end namespace llvm
103 struct YAMLChecksumsSubsection
: public YAMLSubsectionBase
{
104 YAMLChecksumsSubsection()
105 : YAMLSubsectionBase(DebugSubsectionKind::FileChecksums
) {}
107 void map(IO
&IO
) override
;
108 std::shared_ptr
<DebugSubsection
>
109 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
110 const codeview::StringsAndChecksums
&SC
) const override
;
111 static Expected
<std::shared_ptr
<YAMLChecksumsSubsection
>>
112 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
,
113 const DebugChecksumsSubsectionRef
&FC
);
115 std::vector
<SourceFileChecksumEntry
> Checksums
;
118 struct YAMLLinesSubsection
: public YAMLSubsectionBase
{
119 YAMLLinesSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Lines
) {}
121 void map(IO
&IO
) override
;
122 std::shared_ptr
<DebugSubsection
>
123 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
124 const codeview::StringsAndChecksums
&SC
) const override
;
125 static Expected
<std::shared_ptr
<YAMLLinesSubsection
>>
126 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
,
127 const DebugChecksumsSubsectionRef
&Checksums
,
128 const DebugLinesSubsectionRef
&Lines
);
130 SourceLineInfo Lines
;
133 struct YAMLInlineeLinesSubsection
: public YAMLSubsectionBase
{
134 YAMLInlineeLinesSubsection()
135 : YAMLSubsectionBase(DebugSubsectionKind::InlineeLines
) {}
137 void map(IO
&IO
) override
;
138 std::shared_ptr
<DebugSubsection
>
139 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
140 const codeview::StringsAndChecksums
&SC
) const override
;
141 static Expected
<std::shared_ptr
<YAMLInlineeLinesSubsection
>>
142 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
,
143 const DebugChecksumsSubsectionRef
&Checksums
,
144 const DebugInlineeLinesSubsectionRef
&Lines
);
146 InlineeInfo InlineeLines
;
149 struct YAMLCrossModuleExportsSubsection
: public YAMLSubsectionBase
{
150 YAMLCrossModuleExportsSubsection()
151 : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeExports
) {}
153 void map(IO
&IO
) override
;
154 std::shared_ptr
<DebugSubsection
>
155 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
156 const codeview::StringsAndChecksums
&SC
) const override
;
157 static Expected
<std::shared_ptr
<YAMLCrossModuleExportsSubsection
>>
158 fromCodeViewSubsection(const DebugCrossModuleExportsSubsectionRef
&Exports
);
160 std::vector
<CrossModuleExport
> Exports
;
163 struct YAMLCrossModuleImportsSubsection
: public YAMLSubsectionBase
{
164 YAMLCrossModuleImportsSubsection()
165 : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeImports
) {}
167 void map(IO
&IO
) override
;
168 std::shared_ptr
<DebugSubsection
>
169 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
170 const codeview::StringsAndChecksums
&SC
) const override
;
171 static Expected
<std::shared_ptr
<YAMLCrossModuleImportsSubsection
>>
172 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
,
173 const DebugCrossModuleImportsSubsectionRef
&Imports
);
175 std::vector
<YAMLCrossModuleImport
> Imports
;
178 struct YAMLSymbolsSubsection
: public YAMLSubsectionBase
{
179 YAMLSymbolsSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Symbols
) {}
181 void map(IO
&IO
) override
;
182 std::shared_ptr
<DebugSubsection
>
183 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
184 const codeview::StringsAndChecksums
&SC
) const override
;
185 static Expected
<std::shared_ptr
<YAMLSymbolsSubsection
>>
186 fromCodeViewSubsection(const DebugSymbolsSubsectionRef
&Symbols
);
188 std::vector
<CodeViewYAML::SymbolRecord
> Symbols
;
191 struct YAMLStringTableSubsection
: public YAMLSubsectionBase
{
192 YAMLStringTableSubsection()
193 : YAMLSubsectionBase(DebugSubsectionKind::StringTable
) {}
195 void map(IO
&IO
) override
;
196 std::shared_ptr
<DebugSubsection
>
197 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
198 const codeview::StringsAndChecksums
&SC
) const override
;
199 static Expected
<std::shared_ptr
<YAMLStringTableSubsection
>>
200 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
);
202 std::vector
<StringRef
> Strings
;
205 struct YAMLFrameDataSubsection
: public YAMLSubsectionBase
{
206 YAMLFrameDataSubsection()
207 : YAMLSubsectionBase(DebugSubsectionKind::FrameData
) {}
209 void map(IO
&IO
) override
;
210 std::shared_ptr
<DebugSubsection
>
211 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
212 const codeview::StringsAndChecksums
&SC
) const override
;
213 static Expected
<std::shared_ptr
<YAMLFrameDataSubsection
>>
214 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
,
215 const DebugFrameDataSubsectionRef
&Frames
);
217 std::vector
<YAMLFrameData
> Frames
;
220 struct YAMLCoffSymbolRVASubsection
: public YAMLSubsectionBase
{
221 YAMLCoffSymbolRVASubsection()
222 : YAMLSubsectionBase(DebugSubsectionKind::CoffSymbolRVA
) {}
224 void map(IO
&IO
) override
;
225 std::shared_ptr
<DebugSubsection
>
226 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
227 const codeview::StringsAndChecksums
&SC
) const override
;
228 static Expected
<std::shared_ptr
<YAMLCoffSymbolRVASubsection
>>
229 fromCodeViewSubsection(const DebugSymbolRVASubsectionRef
&RVAs
);
231 std::vector
<uint32_t> RVAs
;
234 } // end anonymous namespace
236 void ScalarBitSetTraits
<LineFlags
>::bitset(IO
&io
, LineFlags
&Flags
) {
237 io
.bitSetCase(Flags
, "HasColumnInfo", LF_HaveColumns
);
238 io
.enumFallback
<Hex16
>(Flags
);
241 void ScalarEnumerationTraits
<FileChecksumKind
>::enumeration(
242 IO
&io
, FileChecksumKind
&Kind
) {
243 io
.enumCase(Kind
, "None", FileChecksumKind::None
);
244 io
.enumCase(Kind
, "MD5", FileChecksumKind::MD5
);
245 io
.enumCase(Kind
, "SHA1", FileChecksumKind::SHA1
);
246 io
.enumCase(Kind
, "SHA256", FileChecksumKind::SHA256
);
249 void ScalarTraits
<HexFormattedString
>::output(const HexFormattedString
&Value
,
250 void *ctx
, raw_ostream
&Out
) {
251 StringRef
Bytes(reinterpret_cast<const char *>(Value
.Bytes
.data()),
256 StringRef ScalarTraits
<HexFormattedString
>::input(StringRef Scalar
, void *ctxt
,
257 HexFormattedString
&Value
) {
258 std::string H
= fromHex(Scalar
);
259 Value
.Bytes
.assign(H
.begin(), H
.end());
263 void MappingTraits
<SourceLineEntry
>::mapping(IO
&IO
, SourceLineEntry
&Obj
) {
264 IO
.mapRequired("Offset", Obj
.Offset
);
265 IO
.mapRequired("LineStart", Obj
.LineStart
);
266 IO
.mapRequired("IsStatement", Obj
.IsStatement
);
267 IO
.mapRequired("EndDelta", Obj
.EndDelta
);
270 void MappingTraits
<SourceColumnEntry
>::mapping(IO
&IO
, SourceColumnEntry
&Obj
) {
271 IO
.mapRequired("StartColumn", Obj
.StartColumn
);
272 IO
.mapRequired("EndColumn", Obj
.EndColumn
);
275 void MappingTraits
<SourceLineBlock
>::mapping(IO
&IO
, SourceLineBlock
&Obj
) {
276 IO
.mapRequired("FileName", Obj
.FileName
);
277 IO
.mapRequired("Lines", Obj
.Lines
);
278 IO
.mapRequired("Columns", Obj
.Columns
);
281 void MappingTraits
<CrossModuleExport
>::mapping(IO
&IO
, CrossModuleExport
&Obj
) {
282 IO
.mapRequired("LocalId", Obj
.Local
);
283 IO
.mapRequired("GlobalId", Obj
.Global
);
286 void MappingTraits
<YAMLCrossModuleImport
>::mapping(IO
&IO
,
287 YAMLCrossModuleImport
&Obj
) {
288 IO
.mapRequired("Module", Obj
.ModuleName
);
289 IO
.mapRequired("Imports", Obj
.ImportIds
);
292 void MappingTraits
<SourceFileChecksumEntry
>::mapping(
293 IO
&IO
, SourceFileChecksumEntry
&Obj
) {
294 IO
.mapRequired("FileName", Obj
.FileName
);
295 IO
.mapRequired("Kind", Obj
.Kind
);
296 IO
.mapRequired("Checksum", Obj
.ChecksumBytes
);
299 void MappingTraits
<InlineeSite
>::mapping(IO
&IO
, InlineeSite
&Obj
) {
300 IO
.mapRequired("FileName", Obj
.FileName
);
301 IO
.mapRequired("LineNum", Obj
.SourceLineNum
);
302 IO
.mapRequired("Inlinee", Obj
.Inlinee
);
303 IO
.mapOptional("ExtraFiles", Obj
.ExtraFiles
);
306 void MappingTraits
<YAMLFrameData
>::mapping(IO
&IO
, YAMLFrameData
&Obj
) {
307 IO
.mapRequired("CodeSize", Obj
.CodeSize
);
308 IO
.mapRequired("FrameFunc", Obj
.FrameFunc
);
309 IO
.mapRequired("LocalSize", Obj
.LocalSize
);
310 IO
.mapOptional("MaxStackSize", Obj
.MaxStackSize
);
311 IO
.mapOptional("ParamsSize", Obj
.ParamsSize
);
312 IO
.mapOptional("PrologSize", Obj
.PrologSize
);
313 IO
.mapOptional("RvaStart", Obj
.RvaStart
);
314 IO
.mapOptional("SavedRegsSize", Obj
.SavedRegsSize
);
317 void YAMLChecksumsSubsection::map(IO
&IO
) {
318 IO
.mapTag("!FileChecksums", true);
319 IO
.mapRequired("Checksums", Checksums
);
322 void YAMLLinesSubsection::map(IO
&IO
) {
323 IO
.mapTag("!Lines", true);
324 IO
.mapRequired("CodeSize", Lines
.CodeSize
);
326 IO
.mapRequired("Flags", Lines
.Flags
);
327 IO
.mapRequired("RelocOffset", Lines
.RelocOffset
);
328 IO
.mapRequired("RelocSegment", Lines
.RelocSegment
);
329 IO
.mapRequired("Blocks", Lines
.Blocks
);
332 void YAMLInlineeLinesSubsection::map(IO
&IO
) {
333 IO
.mapTag("!InlineeLines", true);
334 IO
.mapRequired("HasExtraFiles", InlineeLines
.HasExtraFiles
);
335 IO
.mapRequired("Sites", InlineeLines
.Sites
);
338 void YAMLCrossModuleExportsSubsection::map(IO
&IO
) {
339 IO
.mapTag("!CrossModuleExports", true);
340 IO
.mapOptional("Exports", Exports
);
343 void YAMLCrossModuleImportsSubsection::map(IO
&IO
) {
344 IO
.mapTag("!CrossModuleImports", true);
345 IO
.mapOptional("Imports", Imports
);
348 void YAMLSymbolsSubsection::map(IO
&IO
) {
349 IO
.mapTag("!Symbols", true);
350 IO
.mapRequired("Records", Symbols
);
353 void YAMLStringTableSubsection::map(IO
&IO
) {
354 IO
.mapTag("!StringTable", true);
355 IO
.mapRequired("Strings", Strings
);
358 void YAMLFrameDataSubsection::map(IO
&IO
) {
359 IO
.mapTag("!FrameData", true);
360 IO
.mapRequired("Frames", Frames
);
363 void YAMLCoffSymbolRVASubsection::map(IO
&IO
) {
364 IO
.mapTag("!COFFSymbolRVAs", true);
365 IO
.mapRequired("RVAs", RVAs
);
368 void MappingTraits
<YAMLDebugSubsection
>::mapping(
369 IO
&IO
, YAMLDebugSubsection
&Subsection
) {
370 if (!IO
.outputting()) {
371 if (IO
.mapTag("!FileChecksums")) {
372 auto SS
= std::make_shared
<YAMLChecksumsSubsection
>();
373 Subsection
.Subsection
= SS
;
374 } else if (IO
.mapTag("!Lines")) {
375 Subsection
.Subsection
= std::make_shared
<YAMLLinesSubsection
>();
376 } else if (IO
.mapTag("!InlineeLines")) {
377 Subsection
.Subsection
= std::make_shared
<YAMLInlineeLinesSubsection
>();
378 } else if (IO
.mapTag("!CrossModuleExports")) {
379 Subsection
.Subsection
=
380 std::make_shared
<YAMLCrossModuleExportsSubsection
>();
381 } else if (IO
.mapTag("!CrossModuleImports")) {
382 Subsection
.Subsection
=
383 std::make_shared
<YAMLCrossModuleImportsSubsection
>();
384 } else if (IO
.mapTag("!Symbols")) {
385 Subsection
.Subsection
= std::make_shared
<YAMLSymbolsSubsection
>();
386 } else if (IO
.mapTag("!StringTable")) {
387 Subsection
.Subsection
= std::make_shared
<YAMLStringTableSubsection
>();
388 } else if (IO
.mapTag("!FrameData")) {
389 Subsection
.Subsection
= std::make_shared
<YAMLFrameDataSubsection
>();
390 } else if (IO
.mapTag("!COFFSymbolRVAs")) {
391 Subsection
.Subsection
= std::make_shared
<YAMLCoffSymbolRVASubsection
>();
393 llvm_unreachable("Unexpected subsection tag!");
396 Subsection
.Subsection
->map(IO
);
399 std::shared_ptr
<DebugSubsection
> YAMLChecksumsSubsection::toCodeViewSubsection(
400 BumpPtrAllocator
&Allocator
,
401 const codeview::StringsAndChecksums
&SC
) const {
402 assert(SC
.hasStrings());
403 auto Result
= std::make_shared
<DebugChecksumsSubsection
>(*SC
.strings());
404 for (const auto &CS
: Checksums
) {
405 Result
->addChecksum(CS
.FileName
, CS
.Kind
, CS
.ChecksumBytes
.Bytes
);
410 std::shared_ptr
<DebugSubsection
> YAMLLinesSubsection::toCodeViewSubsection(
411 BumpPtrAllocator
&Allocator
,
412 const codeview::StringsAndChecksums
&SC
) const {
413 assert(SC
.hasStrings() && SC
.hasChecksums());
415 std::make_shared
<DebugLinesSubsection
>(*SC
.checksums(), *SC
.strings());
416 Result
->setCodeSize(Lines
.CodeSize
);
417 Result
->setRelocationAddress(Lines
.RelocSegment
, Lines
.RelocOffset
);
418 Result
->setFlags(Lines
.Flags
);
419 for (const auto &LC
: Lines
.Blocks
) {
420 Result
->createBlock(LC
.FileName
);
421 if (Result
->hasColumnInfo()) {
422 for (auto Item
: zip(LC
.Lines
, LC
.Columns
)) {
423 auto &L
= std::get
<0>(Item
);
424 auto &C
= std::get
<1>(Item
);
425 uint32_t LE
= L
.LineStart
+ L
.EndDelta
;
426 Result
->addLineAndColumnInfo(L
.Offset
,
427 LineInfo(L
.LineStart
, LE
, L
.IsStatement
),
428 C
.StartColumn
, C
.EndColumn
);
431 for (const auto &L
: LC
.Lines
) {
432 uint32_t LE
= L
.LineStart
+ L
.EndDelta
;
433 Result
->addLineInfo(L
.Offset
, LineInfo(L
.LineStart
, LE
, L
.IsStatement
));
440 std::shared_ptr
<DebugSubsection
>
441 YAMLInlineeLinesSubsection::toCodeViewSubsection(
442 BumpPtrAllocator
&Allocator
,
443 const codeview::StringsAndChecksums
&SC
) const {
444 assert(SC
.hasChecksums());
445 auto Result
= std::make_shared
<DebugInlineeLinesSubsection
>(
446 *SC
.checksums(), InlineeLines
.HasExtraFiles
);
448 for (const auto &Site
: InlineeLines
.Sites
) {
449 Result
->addInlineSite(TypeIndex(Site
.Inlinee
), Site
.FileName
,
451 if (!InlineeLines
.HasExtraFiles
)
454 for (auto EF
: Site
.ExtraFiles
) {
455 Result
->addExtraFile(EF
);
461 std::shared_ptr
<DebugSubsection
>
462 YAMLCrossModuleExportsSubsection::toCodeViewSubsection(
463 BumpPtrAllocator
&Allocator
,
464 const codeview::StringsAndChecksums
&SC
) const {
465 auto Result
= std::make_shared
<DebugCrossModuleExportsSubsection
>();
466 for (const auto &M
: Exports
)
467 Result
->addMapping(M
.Local
, M
.Global
);
471 std::shared_ptr
<DebugSubsection
>
472 YAMLCrossModuleImportsSubsection::toCodeViewSubsection(
473 BumpPtrAllocator
&Allocator
,
474 const codeview::StringsAndChecksums
&SC
) const {
475 assert(SC
.hasStrings());
478 std::make_shared
<DebugCrossModuleImportsSubsection
>(*SC
.strings());
479 for (const auto &M
: Imports
) {
480 for (const auto Id
: M
.ImportIds
)
481 Result
->addImport(M
.ModuleName
, Id
);
486 std::shared_ptr
<DebugSubsection
> YAMLSymbolsSubsection::toCodeViewSubsection(
487 BumpPtrAllocator
&Allocator
,
488 const codeview::StringsAndChecksums
&SC
) const {
489 auto Result
= std::make_shared
<DebugSymbolsSubsection
>();
490 for (const auto &Sym
: Symbols
)
492 Sym
.toCodeViewSymbol(Allocator
, CodeViewContainer::ObjectFile
));
496 std::shared_ptr
<DebugSubsection
>
497 YAMLStringTableSubsection::toCodeViewSubsection(
498 BumpPtrAllocator
&Allocator
,
499 const codeview::StringsAndChecksums
&SC
) const {
500 auto Result
= std::make_shared
<DebugStringTableSubsection
>();
501 for (const auto &Str
: this->Strings
)
506 std::shared_ptr
<DebugSubsection
> YAMLFrameDataSubsection::toCodeViewSubsection(
507 BumpPtrAllocator
&Allocator
,
508 const codeview::StringsAndChecksums
&SC
) const {
509 assert(SC
.hasStrings());
511 auto Result
= std::make_shared
<DebugFrameDataSubsection
>(true);
512 for (const auto &YF
: Frames
) {
513 codeview::FrameData F
;
514 F
.CodeSize
= YF
.CodeSize
;
516 F
.LocalSize
= YF
.LocalSize
;
517 F
.MaxStackSize
= YF
.MaxStackSize
;
518 F
.ParamsSize
= YF
.ParamsSize
;
519 F
.PrologSize
= YF
.PrologSize
;
520 F
.RvaStart
= YF
.RvaStart
;
521 F
.SavedRegsSize
= YF
.SavedRegsSize
;
522 F
.FrameFunc
= SC
.strings()->insert(YF
.FrameFunc
);
523 Result
->addFrameData(F
);
528 std::shared_ptr
<DebugSubsection
>
529 YAMLCoffSymbolRVASubsection::toCodeViewSubsection(
530 BumpPtrAllocator
&Allocator
,
531 const codeview::StringsAndChecksums
&SC
) const {
532 auto Result
= std::make_shared
<DebugSymbolRVASubsection
>();
533 for (const auto &RVA
: RVAs
)
538 static Expected
<SourceFileChecksumEntry
>
539 convertOneChecksum(const DebugStringTableSubsectionRef
&Strings
,
540 const FileChecksumEntry
&CS
) {
541 auto ExpectedString
= Strings
.getString(CS
.FileNameOffset
);
543 return ExpectedString
.takeError();
545 SourceFileChecksumEntry Result
;
546 Result
.ChecksumBytes
.Bytes
= CS
.Checksum
;
547 Result
.Kind
= CS
.Kind
;
548 Result
.FileName
= *ExpectedString
;
552 static Expected
<StringRef
>
553 getFileName(const DebugStringTableSubsectionRef
&Strings
,
554 const DebugChecksumsSubsectionRef
&Checksums
, uint32_t FileID
) {
555 auto Iter
= Checksums
.getArray().at(FileID
);
556 if (Iter
== Checksums
.getArray().end())
557 return make_error
<CodeViewError
>(cv_error_code::no_records
);
558 uint32_t Offset
= Iter
->FileNameOffset
;
559 return Strings
.getString(Offset
);
562 Expected
<std::shared_ptr
<YAMLChecksumsSubsection
>>
563 YAMLChecksumsSubsection::fromCodeViewSubsection(
564 const DebugStringTableSubsectionRef
&Strings
,
565 const DebugChecksumsSubsectionRef
&FC
) {
566 auto Result
= std::make_shared
<YAMLChecksumsSubsection
>();
568 for (const auto &CS
: FC
) {
569 auto ConvertedCS
= convertOneChecksum(Strings
, CS
);
571 return ConvertedCS
.takeError();
572 Result
->Checksums
.push_back(*ConvertedCS
);
577 Expected
<std::shared_ptr
<YAMLLinesSubsection
>>
578 YAMLLinesSubsection::fromCodeViewSubsection(
579 const DebugStringTableSubsectionRef
&Strings
,
580 const DebugChecksumsSubsectionRef
&Checksums
,
581 const DebugLinesSubsectionRef
&Lines
) {
582 auto Result
= std::make_shared
<YAMLLinesSubsection
>();
583 Result
->Lines
.CodeSize
= Lines
.header()->CodeSize
;
584 Result
->Lines
.RelocOffset
= Lines
.header()->RelocOffset
;
585 Result
->Lines
.RelocSegment
= Lines
.header()->RelocSegment
;
586 Result
->Lines
.Flags
= static_cast<LineFlags
>(uint16_t(Lines
.header()->Flags
));
587 for (const auto &L
: Lines
) {
588 SourceLineBlock Block
;
589 auto EF
= getFileName(Strings
, Checksums
, L
.NameIndex
);
591 return EF
.takeError();
592 Block
.FileName
= *EF
;
593 if (Lines
.hasColumnInfo()) {
594 for (const auto &C
: L
.Columns
) {
595 SourceColumnEntry SCE
;
596 SCE
.EndColumn
= C
.EndColumn
;
597 SCE
.StartColumn
= C
.StartColumn
;
598 Block
.Columns
.push_back(SCE
);
601 for (const auto &LN
: L
.LineNumbers
) {
603 LineInfo
LI(LN
.Flags
);
604 SLE
.Offset
= LN
.Offset
;
605 SLE
.LineStart
= LI
.getStartLine();
606 SLE
.EndDelta
= LI
.getLineDelta();
607 SLE
.IsStatement
= LI
.isStatement();
608 Block
.Lines
.push_back(SLE
);
610 Result
->Lines
.Blocks
.push_back(Block
);
615 Expected
<std::shared_ptr
<YAMLInlineeLinesSubsection
>>
616 YAMLInlineeLinesSubsection::fromCodeViewSubsection(
617 const DebugStringTableSubsectionRef
&Strings
,
618 const DebugChecksumsSubsectionRef
&Checksums
,
619 const DebugInlineeLinesSubsectionRef
&Lines
) {
620 auto Result
= std::make_shared
<YAMLInlineeLinesSubsection
>();
622 Result
->InlineeLines
.HasExtraFiles
= Lines
.hasExtraFiles();
623 for (const auto &IL
: Lines
) {
625 auto ExpF
= getFileName(Strings
, Checksums
, IL
.Header
->FileID
);
627 return ExpF
.takeError();
628 Site
.FileName
= *ExpF
;
629 Site
.Inlinee
= IL
.Header
->Inlinee
.getIndex();
630 Site
.SourceLineNum
= IL
.Header
->SourceLineNum
;
631 if (Lines
.hasExtraFiles()) {
632 for (const auto EF
: IL
.ExtraFiles
) {
633 auto ExpF2
= getFileName(Strings
, Checksums
, EF
);
635 return ExpF2
.takeError();
636 Site
.ExtraFiles
.push_back(*ExpF2
);
639 Result
->InlineeLines
.Sites
.push_back(Site
);
644 Expected
<std::shared_ptr
<YAMLCrossModuleExportsSubsection
>>
645 YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(
646 const DebugCrossModuleExportsSubsectionRef
&Exports
) {
647 auto Result
= std::make_shared
<YAMLCrossModuleExportsSubsection
>();
648 Result
->Exports
.assign(Exports
.begin(), Exports
.end());
652 Expected
<std::shared_ptr
<YAMLCrossModuleImportsSubsection
>>
653 YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(
654 const DebugStringTableSubsectionRef
&Strings
,
655 const DebugCrossModuleImportsSubsectionRef
&Imports
) {
656 auto Result
= std::make_shared
<YAMLCrossModuleImportsSubsection
>();
657 for (const auto &CMI
: Imports
) {
658 YAMLCrossModuleImport YCMI
;
659 auto ExpectedStr
= Strings
.getString(CMI
.Header
->ModuleNameOffset
);
661 return ExpectedStr
.takeError();
662 YCMI
.ModuleName
= *ExpectedStr
;
663 YCMI
.ImportIds
.assign(CMI
.Imports
.begin(), CMI
.Imports
.end());
664 Result
->Imports
.push_back(YCMI
);
669 Expected
<std::shared_ptr
<YAMLSymbolsSubsection
>>
670 YAMLSymbolsSubsection::fromCodeViewSubsection(
671 const DebugSymbolsSubsectionRef
&Symbols
) {
672 auto Result
= std::make_shared
<YAMLSymbolsSubsection
>();
673 for (const auto &Sym
: Symbols
) {
674 auto S
= CodeViewYAML::SymbolRecord::fromCodeViewSymbol(Sym
);
676 return joinErrors(make_error
<CodeViewError
>(
677 cv_error_code::corrupt_record
,
678 "Invalid CodeView Symbol Record in SymbolRecord "
679 "subsection of .debug$S while converting to YAML!"),
682 Result
->Symbols
.push_back(*S
);
687 Expected
<std::shared_ptr
<YAMLStringTableSubsection
>>
688 YAMLStringTableSubsection::fromCodeViewSubsection(
689 const DebugStringTableSubsectionRef
&Strings
) {
690 auto Result
= std::make_shared
<YAMLStringTableSubsection
>();
691 BinaryStreamReader
Reader(Strings
.getBuffer());
693 // First item is a single null string, skip it.
694 if (auto EC
= Reader
.readCString(S
))
695 return std::move(EC
);
697 while (Reader
.bytesRemaining() > 0) {
698 if (auto EC
= Reader
.readCString(S
))
699 return std::move(EC
);
700 Result
->Strings
.push_back(S
);
705 Expected
<std::shared_ptr
<YAMLFrameDataSubsection
>>
706 YAMLFrameDataSubsection::fromCodeViewSubsection(
707 const DebugStringTableSubsectionRef
&Strings
,
708 const DebugFrameDataSubsectionRef
&Frames
) {
709 auto Result
= std::make_shared
<YAMLFrameDataSubsection
>();
710 for (const auto &F
: Frames
) {
712 YF
.CodeSize
= F
.CodeSize
;
714 YF
.LocalSize
= F
.LocalSize
;
715 YF
.MaxStackSize
= F
.MaxStackSize
;
716 YF
.ParamsSize
= F
.ParamsSize
;
717 YF
.PrologSize
= F
.PrologSize
;
718 YF
.RvaStart
= F
.RvaStart
;
719 YF
.SavedRegsSize
= F
.SavedRegsSize
;
721 auto ES
= Strings
.getString(F
.FrameFunc
);
724 make_error
<CodeViewError
>(
725 cv_error_code::no_records
,
726 "Could not find string for string id while mapping FrameData!"),
729 Result
->Frames
.push_back(YF
);
734 Expected
<std::shared_ptr
<YAMLCoffSymbolRVASubsection
>>
735 YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(
736 const DebugSymbolRVASubsectionRef
&Section
) {
737 auto Result
= std::make_shared
<YAMLCoffSymbolRVASubsection
>();
738 for (const auto &RVA
: Section
) {
739 Result
->RVAs
.push_back(RVA
);
744 Expected
<std::vector
<std::shared_ptr
<DebugSubsection
>>>
745 llvm::CodeViewYAML::toCodeViewSubsectionList(
746 BumpPtrAllocator
&Allocator
, ArrayRef
<YAMLDebugSubsection
> Subsections
,
747 const codeview::StringsAndChecksums
&SC
) {
748 std::vector
<std::shared_ptr
<DebugSubsection
>> Result
;
749 if (Subsections
.empty())
750 return std::move(Result
);
752 for (const auto &SS
: Subsections
) {
753 std::shared_ptr
<DebugSubsection
> CVS
;
754 CVS
= SS
.Subsection
->toCodeViewSubsection(Allocator
, SC
);
755 assert(CVS
!= nullptr);
756 Result
.push_back(std::move(CVS
));
758 return std::move(Result
);
763 struct SubsectionConversionVisitor
: public DebugSubsectionVisitor
{
764 SubsectionConversionVisitor() = default;
766 Error
visitUnknown(DebugUnknownSubsectionRef
&Unknown
) override
;
767 Error
visitLines(DebugLinesSubsectionRef
&Lines
,
768 const StringsAndChecksumsRef
&State
) override
;
769 Error
visitFileChecksums(DebugChecksumsSubsectionRef
&Checksums
,
770 const StringsAndChecksumsRef
&State
) override
;
771 Error
visitInlineeLines(DebugInlineeLinesSubsectionRef
&Inlinees
,
772 const StringsAndChecksumsRef
&State
) override
;
773 Error
visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef
&Checksums
,
774 const StringsAndChecksumsRef
&State
) override
;
775 Error
visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef
&Inlinees
,
776 const StringsAndChecksumsRef
&State
) override
;
777 Error
visitStringTable(DebugStringTableSubsectionRef
&ST
,
778 const StringsAndChecksumsRef
&State
) override
;
779 Error
visitSymbols(DebugSymbolsSubsectionRef
&Symbols
,
780 const StringsAndChecksumsRef
&State
) override
;
781 Error
visitFrameData(DebugFrameDataSubsectionRef
&Symbols
,
782 const StringsAndChecksumsRef
&State
) override
;
783 Error
visitCOFFSymbolRVAs(DebugSymbolRVASubsectionRef
&Symbols
,
784 const StringsAndChecksumsRef
&State
) override
;
786 YAMLDebugSubsection Subsection
;
789 } // end anonymous namespace
791 Error
SubsectionConversionVisitor::visitUnknown(
792 DebugUnknownSubsectionRef
&Unknown
) {
793 return make_error
<CodeViewError
>(cv_error_code::operation_unsupported
);
796 Error
SubsectionConversionVisitor::visitLines(
797 DebugLinesSubsectionRef
&Lines
, const StringsAndChecksumsRef
&State
) {
798 auto Result
= YAMLLinesSubsection::fromCodeViewSubsection(
799 State
.strings(), State
.checksums(), Lines
);
801 return Result
.takeError();
802 Subsection
.Subsection
= *Result
;
803 return Error::success();
806 Error
SubsectionConversionVisitor::visitFileChecksums(
807 DebugChecksumsSubsectionRef
&Checksums
,
808 const StringsAndChecksumsRef
&State
) {
809 auto Result
= YAMLChecksumsSubsection::fromCodeViewSubsection(State
.strings(),
812 return Result
.takeError();
813 Subsection
.Subsection
= *Result
;
814 return Error::success();
817 Error
SubsectionConversionVisitor::visitInlineeLines(
818 DebugInlineeLinesSubsectionRef
&Inlinees
,
819 const StringsAndChecksumsRef
&State
) {
820 auto Result
= YAMLInlineeLinesSubsection::fromCodeViewSubsection(
821 State
.strings(), State
.checksums(), Inlinees
);
823 return Result
.takeError();
824 Subsection
.Subsection
= *Result
;
825 return Error::success();
828 Error
SubsectionConversionVisitor::visitCrossModuleExports(
829 DebugCrossModuleExportsSubsectionRef
&Exports
,
830 const StringsAndChecksumsRef
&State
) {
832 YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(Exports
);
834 return Result
.takeError();
835 Subsection
.Subsection
= *Result
;
836 return Error::success();
839 Error
SubsectionConversionVisitor::visitCrossModuleImports(
840 DebugCrossModuleImportsSubsectionRef
&Imports
,
841 const StringsAndChecksumsRef
&State
) {
842 auto Result
= YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(
843 State
.strings(), Imports
);
845 return Result
.takeError();
846 Subsection
.Subsection
= *Result
;
847 return Error::success();
850 Error
SubsectionConversionVisitor::visitStringTable(
851 DebugStringTableSubsectionRef
&Strings
,
852 const StringsAndChecksumsRef
&State
) {
853 auto Result
= YAMLStringTableSubsection::fromCodeViewSubsection(Strings
);
855 return Result
.takeError();
856 Subsection
.Subsection
= *Result
;
857 return Error::success();
860 Error
SubsectionConversionVisitor::visitSymbols(
861 DebugSymbolsSubsectionRef
&Symbols
, const StringsAndChecksumsRef
&State
) {
862 auto Result
= YAMLSymbolsSubsection::fromCodeViewSubsection(Symbols
);
864 return Result
.takeError();
865 Subsection
.Subsection
= *Result
;
866 return Error::success();
869 Error
SubsectionConversionVisitor::visitFrameData(
870 DebugFrameDataSubsectionRef
&Frames
, const StringsAndChecksumsRef
&State
) {
872 YAMLFrameDataSubsection::fromCodeViewSubsection(State
.strings(), Frames
);
874 return Result
.takeError();
875 Subsection
.Subsection
= *Result
;
876 return Error::success();
879 Error
SubsectionConversionVisitor::visitCOFFSymbolRVAs(
880 DebugSymbolRVASubsectionRef
&RVAs
, const StringsAndChecksumsRef
&State
) {
881 auto Result
= YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(RVAs
);
883 return Result
.takeError();
884 Subsection
.Subsection
= *Result
;
885 return Error::success();
888 Expected
<YAMLDebugSubsection
>
889 YAMLDebugSubsection::fromCodeViewSubection(const StringsAndChecksumsRef
&SC
,
890 const DebugSubsectionRecord
&SS
) {
891 SubsectionConversionVisitor V
;
892 if (auto EC
= visitDebugSubsection(SS
, V
, SC
))
893 return std::move(EC
);
898 std::vector
<YAMLDebugSubsection
>
899 llvm::CodeViewYAML::fromDebugS(ArrayRef
<uint8_t> Data
,
900 const StringsAndChecksumsRef
&SC
) {
901 BinaryStreamReader
Reader(Data
, llvm::endianness::little
);
904 ExitOnError
Err("Invalid .debug$S section!");
905 Err(Reader
.readInteger(Magic
));
906 assert(Magic
== COFF::DEBUG_SECTION_MAGIC
&& "Invalid .debug$S section!");
908 DebugSubsectionArray Subsections
;
909 Err(Reader
.readArray(Subsections
, Reader
.bytesRemaining()));
911 std::vector
<YAMLDebugSubsection
> Result
;
913 for (const auto &SS
: Subsections
) {
914 auto YamlSS
= Err(YAMLDebugSubsection::fromCodeViewSubection(SC
, SS
));
915 Result
.push_back(YamlSS
);
920 void llvm::CodeViewYAML::initializeStringsAndChecksums(
921 ArrayRef
<YAMLDebugSubsection
> Sections
, codeview::StringsAndChecksums
&SC
) {
922 // String Table and Checksums subsections don't use the allocator.
923 BumpPtrAllocator Allocator
;
925 // It's possible for checksums and strings to even appear in different debug$S
926 // sections, so we have to make this a stateful function that can build up
927 // the strings and checksums field over multiple iterations.
929 // File Checksums require the string table, but may become before it, so we
930 // have to scan for strings first, then scan for checksums again from the
932 if (!SC
.hasStrings()) {
933 for (const auto &SS
: Sections
) {
934 if (SS
.Subsection
->Kind
!= DebugSubsectionKind::StringTable
)
937 auto Result
= SS
.Subsection
->toCodeViewSubsection(Allocator
, SC
);
939 std::static_pointer_cast
<DebugStringTableSubsection
>(Result
));
944 if (SC
.hasStrings() && !SC
.hasChecksums()) {
945 for (const auto &SS
: Sections
) {
946 if (SS
.Subsection
->Kind
!= DebugSubsectionKind::FileChecksums
)
949 auto Result
= SS
.Subsection
->toCodeViewSubsection(Allocator
, SC
);
951 std::static_pointer_cast
<DebugChecksumsSubsection
>(Result
));