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"
52 using namespace llvm::codeview
;
53 using namespace llvm::CodeViewYAML
;
54 using namespace llvm::CodeViewYAML::detail
;
55 using namespace llvm::yaml
;
57 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceFileChecksumEntry
)
58 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineEntry
)
59 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceColumnEntry
)
60 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineBlock
)
61 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineInfo
)
62 LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeSite
)
63 LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeInfo
)
64 LLVM_YAML_IS_SEQUENCE_VECTOR(CrossModuleExport
)
65 LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLCrossModuleImport
)
66 LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLFrameData
)
68 LLVM_YAML_DECLARE_SCALAR_TRAITS(HexFormattedString
, QuotingType::None
)
69 LLVM_YAML_DECLARE_ENUM_TRAITS(DebugSubsectionKind
)
70 LLVM_YAML_DECLARE_ENUM_TRAITS(FileChecksumKind
)
71 LLVM_YAML_DECLARE_BITSET_TRAITS(LineFlags
)
73 LLVM_YAML_DECLARE_MAPPING_TRAITS(CrossModuleExport
)
74 LLVM_YAML_DECLARE_MAPPING_TRAITS(YAMLFrameData
)
75 LLVM_YAML_DECLARE_MAPPING_TRAITS(YAMLCrossModuleImport
)
76 LLVM_YAML_DECLARE_MAPPING_TRAITS(CrossModuleImportItem
)
77 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineEntry
)
78 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceColumnEntry
)
79 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceFileChecksumEntry
)
80 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineBlock
)
81 LLVM_YAML_DECLARE_MAPPING_TRAITS(InlineeSite
)
84 namespace CodeViewYAML
{
87 struct YAMLSubsectionBase
{
88 explicit YAMLSubsectionBase(DebugSubsectionKind Kind
) : Kind(Kind
) {}
89 virtual ~YAMLSubsectionBase() = default;
91 virtual void map(IO
&IO
) = 0;
92 virtual std::shared_ptr
<DebugSubsection
>
93 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
94 const codeview::StringsAndChecksums
&SC
) const = 0;
96 DebugSubsectionKind Kind
;
99 } // end namespace detail
100 } // end namespace CodeViewYAML
101 } // end namespace llvm
105 struct YAMLChecksumsSubsection
: public YAMLSubsectionBase
{
106 YAMLChecksumsSubsection()
107 : YAMLSubsectionBase(DebugSubsectionKind::FileChecksums
) {}
109 void map(IO
&IO
) override
;
110 std::shared_ptr
<DebugSubsection
>
111 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
112 const codeview::StringsAndChecksums
&SC
) const override
;
113 static Expected
<std::shared_ptr
<YAMLChecksumsSubsection
>>
114 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
,
115 const DebugChecksumsSubsectionRef
&FC
);
117 std::vector
<SourceFileChecksumEntry
> Checksums
;
120 struct YAMLLinesSubsection
: public YAMLSubsectionBase
{
121 YAMLLinesSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Lines
) {}
123 void map(IO
&IO
) override
;
124 std::shared_ptr
<DebugSubsection
>
125 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
126 const codeview::StringsAndChecksums
&SC
) const override
;
127 static Expected
<std::shared_ptr
<YAMLLinesSubsection
>>
128 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
,
129 const DebugChecksumsSubsectionRef
&Checksums
,
130 const DebugLinesSubsectionRef
&Lines
);
132 SourceLineInfo Lines
;
135 struct YAMLInlineeLinesSubsection
: public YAMLSubsectionBase
{
136 YAMLInlineeLinesSubsection()
137 : YAMLSubsectionBase(DebugSubsectionKind::InlineeLines
) {}
139 void map(IO
&IO
) override
;
140 std::shared_ptr
<DebugSubsection
>
141 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
142 const codeview::StringsAndChecksums
&SC
) const override
;
143 static Expected
<std::shared_ptr
<YAMLInlineeLinesSubsection
>>
144 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
,
145 const DebugChecksumsSubsectionRef
&Checksums
,
146 const DebugInlineeLinesSubsectionRef
&Lines
);
148 InlineeInfo InlineeLines
;
151 struct YAMLCrossModuleExportsSubsection
: public YAMLSubsectionBase
{
152 YAMLCrossModuleExportsSubsection()
153 : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeExports
) {}
155 void map(IO
&IO
) override
;
156 std::shared_ptr
<DebugSubsection
>
157 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
158 const codeview::StringsAndChecksums
&SC
) const override
;
159 static Expected
<std::shared_ptr
<YAMLCrossModuleExportsSubsection
>>
160 fromCodeViewSubsection(const DebugCrossModuleExportsSubsectionRef
&Exports
);
162 std::vector
<CrossModuleExport
> Exports
;
165 struct YAMLCrossModuleImportsSubsection
: public YAMLSubsectionBase
{
166 YAMLCrossModuleImportsSubsection()
167 : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeImports
) {}
169 void map(IO
&IO
) override
;
170 std::shared_ptr
<DebugSubsection
>
171 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
172 const codeview::StringsAndChecksums
&SC
) const override
;
173 static Expected
<std::shared_ptr
<YAMLCrossModuleImportsSubsection
>>
174 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
,
175 const DebugCrossModuleImportsSubsectionRef
&Imports
);
177 std::vector
<YAMLCrossModuleImport
> Imports
;
180 struct YAMLSymbolsSubsection
: public YAMLSubsectionBase
{
181 YAMLSymbolsSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Symbols
) {}
183 void map(IO
&IO
) override
;
184 std::shared_ptr
<DebugSubsection
>
185 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
186 const codeview::StringsAndChecksums
&SC
) const override
;
187 static Expected
<std::shared_ptr
<YAMLSymbolsSubsection
>>
188 fromCodeViewSubsection(const DebugSymbolsSubsectionRef
&Symbols
);
190 std::vector
<CodeViewYAML::SymbolRecord
> Symbols
;
193 struct YAMLStringTableSubsection
: public YAMLSubsectionBase
{
194 YAMLStringTableSubsection()
195 : YAMLSubsectionBase(DebugSubsectionKind::StringTable
) {}
197 void map(IO
&IO
) override
;
198 std::shared_ptr
<DebugSubsection
>
199 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
200 const codeview::StringsAndChecksums
&SC
) const override
;
201 static Expected
<std::shared_ptr
<YAMLStringTableSubsection
>>
202 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
);
204 std::vector
<StringRef
> Strings
;
207 struct YAMLFrameDataSubsection
: public YAMLSubsectionBase
{
208 YAMLFrameDataSubsection()
209 : YAMLSubsectionBase(DebugSubsectionKind::FrameData
) {}
211 void map(IO
&IO
) override
;
212 std::shared_ptr
<DebugSubsection
>
213 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
214 const codeview::StringsAndChecksums
&SC
) const override
;
215 static Expected
<std::shared_ptr
<YAMLFrameDataSubsection
>>
216 fromCodeViewSubsection(const DebugStringTableSubsectionRef
&Strings
,
217 const DebugFrameDataSubsectionRef
&Frames
);
219 std::vector
<YAMLFrameData
> Frames
;
222 struct YAMLCoffSymbolRVASubsection
: public YAMLSubsectionBase
{
223 YAMLCoffSymbolRVASubsection()
224 : YAMLSubsectionBase(DebugSubsectionKind::CoffSymbolRVA
) {}
226 void map(IO
&IO
) override
;
227 std::shared_ptr
<DebugSubsection
>
228 toCodeViewSubsection(BumpPtrAllocator
&Allocator
,
229 const codeview::StringsAndChecksums
&SC
) const override
;
230 static Expected
<std::shared_ptr
<YAMLCoffSymbolRVASubsection
>>
231 fromCodeViewSubsection(const DebugSymbolRVASubsectionRef
&RVAs
);
233 std::vector
<uint32_t> RVAs
;
236 } // end anonymous namespace
238 void ScalarBitSetTraits
<LineFlags
>::bitset(IO
&io
, LineFlags
&Flags
) {
239 io
.bitSetCase(Flags
, "HasColumnInfo", LF_HaveColumns
);
240 io
.enumFallback
<Hex16
>(Flags
);
243 void ScalarEnumerationTraits
<FileChecksumKind
>::enumeration(
244 IO
&io
, FileChecksumKind
&Kind
) {
245 io
.enumCase(Kind
, "None", FileChecksumKind::None
);
246 io
.enumCase(Kind
, "MD5", FileChecksumKind::MD5
);
247 io
.enumCase(Kind
, "SHA1", FileChecksumKind::SHA1
);
248 io
.enumCase(Kind
, "SHA256", FileChecksumKind::SHA256
);
251 void ScalarTraits
<HexFormattedString
>::output(const HexFormattedString
&Value
,
252 void *ctx
, raw_ostream
&Out
) {
253 StringRef
Bytes(reinterpret_cast<const char *>(Value
.Bytes
.data()),
258 StringRef ScalarTraits
<HexFormattedString
>::input(StringRef Scalar
, void *ctxt
,
259 HexFormattedString
&Value
) {
260 std::string H
= fromHex(Scalar
);
261 Value
.Bytes
.assign(H
.begin(), H
.end());
265 void MappingTraits
<SourceLineEntry
>::mapping(IO
&IO
, SourceLineEntry
&Obj
) {
266 IO
.mapRequired("Offset", Obj
.Offset
);
267 IO
.mapRequired("LineStart", Obj
.LineStart
);
268 IO
.mapRequired("IsStatement", Obj
.IsStatement
);
269 IO
.mapRequired("EndDelta", Obj
.EndDelta
);
272 void MappingTraits
<SourceColumnEntry
>::mapping(IO
&IO
, SourceColumnEntry
&Obj
) {
273 IO
.mapRequired("StartColumn", Obj
.StartColumn
);
274 IO
.mapRequired("EndColumn", Obj
.EndColumn
);
277 void MappingTraits
<SourceLineBlock
>::mapping(IO
&IO
, SourceLineBlock
&Obj
) {
278 IO
.mapRequired("FileName", Obj
.FileName
);
279 IO
.mapRequired("Lines", Obj
.Lines
);
280 IO
.mapRequired("Columns", Obj
.Columns
);
283 void MappingTraits
<CrossModuleExport
>::mapping(IO
&IO
, CrossModuleExport
&Obj
) {
284 IO
.mapRequired("LocalId", Obj
.Local
);
285 IO
.mapRequired("GlobalId", Obj
.Global
);
288 void MappingTraits
<YAMLCrossModuleImport
>::mapping(IO
&IO
,
289 YAMLCrossModuleImport
&Obj
) {
290 IO
.mapRequired("Module", Obj
.ModuleName
);
291 IO
.mapRequired("Imports", Obj
.ImportIds
);
294 void MappingTraits
<SourceFileChecksumEntry
>::mapping(
295 IO
&IO
, SourceFileChecksumEntry
&Obj
) {
296 IO
.mapRequired("FileName", Obj
.FileName
);
297 IO
.mapRequired("Kind", Obj
.Kind
);
298 IO
.mapRequired("Checksum", Obj
.ChecksumBytes
);
301 void MappingTraits
<InlineeSite
>::mapping(IO
&IO
, InlineeSite
&Obj
) {
302 IO
.mapRequired("FileName", Obj
.FileName
);
303 IO
.mapRequired("LineNum", Obj
.SourceLineNum
);
304 IO
.mapRequired("Inlinee", Obj
.Inlinee
);
305 IO
.mapOptional("ExtraFiles", Obj
.ExtraFiles
);
308 void MappingTraits
<YAMLFrameData
>::mapping(IO
&IO
, YAMLFrameData
&Obj
) {
309 IO
.mapRequired("CodeSize", Obj
.CodeSize
);
310 IO
.mapRequired("FrameFunc", Obj
.FrameFunc
);
311 IO
.mapRequired("LocalSize", Obj
.LocalSize
);
312 IO
.mapOptional("MaxStackSize", Obj
.MaxStackSize
);
313 IO
.mapOptional("ParamsSize", Obj
.ParamsSize
);
314 IO
.mapOptional("PrologSize", Obj
.PrologSize
);
315 IO
.mapOptional("RvaStart", Obj
.RvaStart
);
316 IO
.mapOptional("SavedRegsSize", Obj
.SavedRegsSize
);
319 void YAMLChecksumsSubsection::map(IO
&IO
) {
320 IO
.mapTag("!FileChecksums", true);
321 IO
.mapRequired("Checksums", Checksums
);
324 void YAMLLinesSubsection::map(IO
&IO
) {
325 IO
.mapTag("!Lines", true);
326 IO
.mapRequired("CodeSize", Lines
.CodeSize
);
328 IO
.mapRequired("Flags", Lines
.Flags
);
329 IO
.mapRequired("RelocOffset", Lines
.RelocOffset
);
330 IO
.mapRequired("RelocSegment", Lines
.RelocSegment
);
331 IO
.mapRequired("Blocks", Lines
.Blocks
);
334 void YAMLInlineeLinesSubsection::map(IO
&IO
) {
335 IO
.mapTag("!InlineeLines", true);
336 IO
.mapRequired("HasExtraFiles", InlineeLines
.HasExtraFiles
);
337 IO
.mapRequired("Sites", InlineeLines
.Sites
);
340 void YAMLCrossModuleExportsSubsection::map(IO
&IO
) {
341 IO
.mapTag("!CrossModuleExports", true);
342 IO
.mapOptional("Exports", Exports
);
345 void YAMLCrossModuleImportsSubsection::map(IO
&IO
) {
346 IO
.mapTag("!CrossModuleImports", true);
347 IO
.mapOptional("Imports", Imports
);
350 void YAMLSymbolsSubsection::map(IO
&IO
) {
351 IO
.mapTag("!Symbols", true);
352 IO
.mapRequired("Records", Symbols
);
355 void YAMLStringTableSubsection::map(IO
&IO
) {
356 IO
.mapTag("!StringTable", true);
357 IO
.mapRequired("Strings", Strings
);
360 void YAMLFrameDataSubsection::map(IO
&IO
) {
361 IO
.mapTag("!FrameData", true);
362 IO
.mapRequired("Frames", Frames
);
365 void YAMLCoffSymbolRVASubsection::map(IO
&IO
) {
366 IO
.mapTag("!COFFSymbolRVAs", true);
367 IO
.mapRequired("RVAs", RVAs
);
370 void MappingTraits
<YAMLDebugSubsection
>::mapping(
371 IO
&IO
, YAMLDebugSubsection
&Subsection
) {
372 if (!IO
.outputting()) {
373 if (IO
.mapTag("!FileChecksums")) {
374 auto SS
= std::make_shared
<YAMLChecksumsSubsection
>();
375 Subsection
.Subsection
= SS
;
376 } else if (IO
.mapTag("!Lines")) {
377 Subsection
.Subsection
= std::make_shared
<YAMLLinesSubsection
>();
378 } else if (IO
.mapTag("!InlineeLines")) {
379 Subsection
.Subsection
= std::make_shared
<YAMLInlineeLinesSubsection
>();
380 } else if (IO
.mapTag("!CrossModuleExports")) {
381 Subsection
.Subsection
=
382 std::make_shared
<YAMLCrossModuleExportsSubsection
>();
383 } else if (IO
.mapTag("!CrossModuleImports")) {
384 Subsection
.Subsection
=
385 std::make_shared
<YAMLCrossModuleImportsSubsection
>();
386 } else if (IO
.mapTag("!Symbols")) {
387 Subsection
.Subsection
= std::make_shared
<YAMLSymbolsSubsection
>();
388 } else if (IO
.mapTag("!StringTable")) {
389 Subsection
.Subsection
= std::make_shared
<YAMLStringTableSubsection
>();
390 } else if (IO
.mapTag("!FrameData")) {
391 Subsection
.Subsection
= std::make_shared
<YAMLFrameDataSubsection
>();
392 } else if (IO
.mapTag("!COFFSymbolRVAs")) {
393 Subsection
.Subsection
= std::make_shared
<YAMLCoffSymbolRVASubsection
>();
395 llvm_unreachable("Unexpected subsection tag!");
398 Subsection
.Subsection
->map(IO
);
401 std::shared_ptr
<DebugSubsection
> YAMLChecksumsSubsection::toCodeViewSubsection(
402 BumpPtrAllocator
&Allocator
,
403 const codeview::StringsAndChecksums
&SC
) const {
404 assert(SC
.hasStrings());
405 auto Result
= std::make_shared
<DebugChecksumsSubsection
>(*SC
.strings());
406 for (const auto &CS
: Checksums
) {
407 Result
->addChecksum(CS
.FileName
, CS
.Kind
, CS
.ChecksumBytes
.Bytes
);
412 std::shared_ptr
<DebugSubsection
> YAMLLinesSubsection::toCodeViewSubsection(
413 BumpPtrAllocator
&Allocator
,
414 const codeview::StringsAndChecksums
&SC
) const {
415 assert(SC
.hasStrings() && SC
.hasChecksums());
417 std::make_shared
<DebugLinesSubsection
>(*SC
.checksums(), *SC
.strings());
418 Result
->setCodeSize(Lines
.CodeSize
);
419 Result
->setRelocationAddress(Lines
.RelocSegment
, Lines
.RelocOffset
);
420 Result
->setFlags(Lines
.Flags
);
421 for (const auto &LC
: Lines
.Blocks
) {
422 Result
->createBlock(LC
.FileName
);
423 if (Result
->hasColumnInfo()) {
424 for (const auto &Item
: zip(LC
.Lines
, LC
.Columns
)) {
425 auto &L
= std::get
<0>(Item
);
426 auto &C
= std::get
<1>(Item
);
427 uint32_t LE
= L
.LineStart
+ L
.EndDelta
;
428 Result
->addLineAndColumnInfo(L
.Offset
,
429 LineInfo(L
.LineStart
, LE
, L
.IsStatement
),
430 C
.StartColumn
, C
.EndColumn
);
433 for (const auto &L
: LC
.Lines
) {
434 uint32_t LE
= L
.LineStart
+ L
.EndDelta
;
435 Result
->addLineInfo(L
.Offset
, LineInfo(L
.LineStart
, LE
, L
.IsStatement
));
442 std::shared_ptr
<DebugSubsection
>
443 YAMLInlineeLinesSubsection::toCodeViewSubsection(
444 BumpPtrAllocator
&Allocator
,
445 const codeview::StringsAndChecksums
&SC
) const {
446 assert(SC
.hasChecksums());
447 auto Result
= std::make_shared
<DebugInlineeLinesSubsection
>(
448 *SC
.checksums(), InlineeLines
.HasExtraFiles
);
450 for (const auto &Site
: InlineeLines
.Sites
) {
451 Result
->addInlineSite(TypeIndex(Site
.Inlinee
), Site
.FileName
,
453 if (!InlineeLines
.HasExtraFiles
)
456 for (auto EF
: Site
.ExtraFiles
) {
457 Result
->addExtraFile(EF
);
463 std::shared_ptr
<DebugSubsection
>
464 YAMLCrossModuleExportsSubsection::toCodeViewSubsection(
465 BumpPtrAllocator
&Allocator
,
466 const codeview::StringsAndChecksums
&SC
) const {
467 auto Result
= std::make_shared
<DebugCrossModuleExportsSubsection
>();
468 for (const auto &M
: Exports
)
469 Result
->addMapping(M
.Local
, M
.Global
);
473 std::shared_ptr
<DebugSubsection
>
474 YAMLCrossModuleImportsSubsection::toCodeViewSubsection(
475 BumpPtrAllocator
&Allocator
,
476 const codeview::StringsAndChecksums
&SC
) const {
477 assert(SC
.hasStrings());
480 std::make_shared
<DebugCrossModuleImportsSubsection
>(*SC
.strings());
481 for (const auto &M
: Imports
) {
482 for (const auto Id
: M
.ImportIds
)
483 Result
->addImport(M
.ModuleName
, Id
);
488 std::shared_ptr
<DebugSubsection
> YAMLSymbolsSubsection::toCodeViewSubsection(
489 BumpPtrAllocator
&Allocator
,
490 const codeview::StringsAndChecksums
&SC
) const {
491 auto Result
= std::make_shared
<DebugSymbolsSubsection
>();
492 for (const auto &Sym
: Symbols
)
494 Sym
.toCodeViewSymbol(Allocator
, CodeViewContainer::ObjectFile
));
498 std::shared_ptr
<DebugSubsection
>
499 YAMLStringTableSubsection::toCodeViewSubsection(
500 BumpPtrAllocator
&Allocator
,
501 const codeview::StringsAndChecksums
&SC
) const {
502 auto Result
= std::make_shared
<DebugStringTableSubsection
>();
503 for (const auto &Str
: this->Strings
)
508 std::shared_ptr
<DebugSubsection
> YAMLFrameDataSubsection::toCodeViewSubsection(
509 BumpPtrAllocator
&Allocator
,
510 const codeview::StringsAndChecksums
&SC
) const {
511 assert(SC
.hasStrings());
513 auto Result
= std::make_shared
<DebugFrameDataSubsection
>(true);
514 for (const auto &YF
: Frames
) {
515 codeview::FrameData F
;
516 F
.CodeSize
= YF
.CodeSize
;
518 F
.LocalSize
= YF
.LocalSize
;
519 F
.MaxStackSize
= YF
.MaxStackSize
;
520 F
.ParamsSize
= YF
.ParamsSize
;
521 F
.PrologSize
= YF
.PrologSize
;
522 F
.RvaStart
= YF
.RvaStart
;
523 F
.SavedRegsSize
= YF
.SavedRegsSize
;
524 F
.FrameFunc
= SC
.strings()->insert(YF
.FrameFunc
);
525 Result
->addFrameData(F
);
530 std::shared_ptr
<DebugSubsection
>
531 YAMLCoffSymbolRVASubsection::toCodeViewSubsection(
532 BumpPtrAllocator
&Allocator
,
533 const codeview::StringsAndChecksums
&SC
) const {
534 auto Result
= std::make_shared
<DebugSymbolRVASubsection
>();
535 for (const auto &RVA
: RVAs
)
540 static Expected
<SourceFileChecksumEntry
>
541 convertOneChecksum(const DebugStringTableSubsectionRef
&Strings
,
542 const FileChecksumEntry
&CS
) {
543 auto ExpectedString
= Strings
.getString(CS
.FileNameOffset
);
545 return ExpectedString
.takeError();
547 SourceFileChecksumEntry Result
;
548 Result
.ChecksumBytes
.Bytes
= CS
.Checksum
;
549 Result
.Kind
= CS
.Kind
;
550 Result
.FileName
= *ExpectedString
;
554 static Expected
<StringRef
>
555 getFileName(const DebugStringTableSubsectionRef
&Strings
,
556 const DebugChecksumsSubsectionRef
&Checksums
, uint32_t FileID
) {
557 auto Iter
= Checksums
.getArray().at(FileID
);
558 if (Iter
== Checksums
.getArray().end())
559 return make_error
<CodeViewError
>(cv_error_code::no_records
);
560 uint32_t Offset
= Iter
->FileNameOffset
;
561 return Strings
.getString(Offset
);
564 Expected
<std::shared_ptr
<YAMLChecksumsSubsection
>>
565 YAMLChecksumsSubsection::fromCodeViewSubsection(
566 const DebugStringTableSubsectionRef
&Strings
,
567 const DebugChecksumsSubsectionRef
&FC
) {
568 auto Result
= std::make_shared
<YAMLChecksumsSubsection
>();
570 for (const auto &CS
: FC
) {
571 auto ConvertedCS
= convertOneChecksum(Strings
, CS
);
573 return ConvertedCS
.takeError();
574 Result
->Checksums
.push_back(*ConvertedCS
);
579 Expected
<std::shared_ptr
<YAMLLinesSubsection
>>
580 YAMLLinesSubsection::fromCodeViewSubsection(
581 const DebugStringTableSubsectionRef
&Strings
,
582 const DebugChecksumsSubsectionRef
&Checksums
,
583 const DebugLinesSubsectionRef
&Lines
) {
584 auto Result
= std::make_shared
<YAMLLinesSubsection
>();
585 Result
->Lines
.CodeSize
= Lines
.header()->CodeSize
;
586 Result
->Lines
.RelocOffset
= Lines
.header()->RelocOffset
;
587 Result
->Lines
.RelocSegment
= Lines
.header()->RelocSegment
;
588 Result
->Lines
.Flags
= static_cast<LineFlags
>(uint16_t(Lines
.header()->Flags
));
589 for (const auto &L
: Lines
) {
590 SourceLineBlock Block
;
591 auto EF
= getFileName(Strings
, Checksums
, L
.NameIndex
);
593 return EF
.takeError();
594 Block
.FileName
= *EF
;
595 if (Lines
.hasColumnInfo()) {
596 for (const auto &C
: L
.Columns
) {
597 SourceColumnEntry SCE
;
598 SCE
.EndColumn
= C
.EndColumn
;
599 SCE
.StartColumn
= C
.StartColumn
;
600 Block
.Columns
.push_back(SCE
);
603 for (const auto &LN
: L
.LineNumbers
) {
605 LineInfo
LI(LN
.Flags
);
606 SLE
.Offset
= LN
.Offset
;
607 SLE
.LineStart
= LI
.getStartLine();
608 SLE
.EndDelta
= LI
.getLineDelta();
609 SLE
.IsStatement
= LI
.isStatement();
610 Block
.Lines
.push_back(SLE
);
612 Result
->Lines
.Blocks
.push_back(Block
);
617 Expected
<std::shared_ptr
<YAMLInlineeLinesSubsection
>>
618 YAMLInlineeLinesSubsection::fromCodeViewSubsection(
619 const DebugStringTableSubsectionRef
&Strings
,
620 const DebugChecksumsSubsectionRef
&Checksums
,
621 const DebugInlineeLinesSubsectionRef
&Lines
) {
622 auto Result
= std::make_shared
<YAMLInlineeLinesSubsection
>();
624 Result
->InlineeLines
.HasExtraFiles
= Lines
.hasExtraFiles();
625 for (const auto &IL
: Lines
) {
627 auto ExpF
= getFileName(Strings
, Checksums
, IL
.Header
->FileID
);
629 return ExpF
.takeError();
630 Site
.FileName
= *ExpF
;
631 Site
.Inlinee
= IL
.Header
->Inlinee
.getIndex();
632 Site
.SourceLineNum
= IL
.Header
->SourceLineNum
;
633 if (Lines
.hasExtraFiles()) {
634 for (const auto EF
: IL
.ExtraFiles
) {
635 auto ExpF2
= getFileName(Strings
, Checksums
, EF
);
637 return ExpF2
.takeError();
638 Site
.ExtraFiles
.push_back(*ExpF2
);
641 Result
->InlineeLines
.Sites
.push_back(Site
);
646 Expected
<std::shared_ptr
<YAMLCrossModuleExportsSubsection
>>
647 YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(
648 const DebugCrossModuleExportsSubsectionRef
&Exports
) {
649 auto Result
= std::make_shared
<YAMLCrossModuleExportsSubsection
>();
650 Result
->Exports
.assign(Exports
.begin(), Exports
.end());
654 Expected
<std::shared_ptr
<YAMLCrossModuleImportsSubsection
>>
655 YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(
656 const DebugStringTableSubsectionRef
&Strings
,
657 const DebugCrossModuleImportsSubsectionRef
&Imports
) {
658 auto Result
= std::make_shared
<YAMLCrossModuleImportsSubsection
>();
659 for (const auto &CMI
: Imports
) {
660 YAMLCrossModuleImport YCMI
;
661 auto ExpectedStr
= Strings
.getString(CMI
.Header
->ModuleNameOffset
);
663 return ExpectedStr
.takeError();
664 YCMI
.ModuleName
= *ExpectedStr
;
665 YCMI
.ImportIds
.assign(CMI
.Imports
.begin(), CMI
.Imports
.end());
666 Result
->Imports
.push_back(YCMI
);
671 Expected
<std::shared_ptr
<YAMLSymbolsSubsection
>>
672 YAMLSymbolsSubsection::fromCodeViewSubsection(
673 const DebugSymbolsSubsectionRef
&Symbols
) {
674 auto Result
= std::make_shared
<YAMLSymbolsSubsection
>();
675 for (const auto &Sym
: Symbols
) {
676 auto S
= CodeViewYAML::SymbolRecord::fromCodeViewSymbol(Sym
);
678 return joinErrors(make_error
<CodeViewError
>(
679 cv_error_code::corrupt_record
,
680 "Invalid CodeView Symbol Record in SymbolRecord "
681 "subsection of .debug$S while converting to YAML!"),
684 Result
->Symbols
.push_back(*S
);
689 Expected
<std::shared_ptr
<YAMLStringTableSubsection
>>
690 YAMLStringTableSubsection::fromCodeViewSubsection(
691 const DebugStringTableSubsectionRef
&Strings
) {
692 auto Result
= std::make_shared
<YAMLStringTableSubsection
>();
693 BinaryStreamReader
Reader(Strings
.getBuffer());
695 // First item is a single null string, skip it.
696 if (auto EC
= Reader
.readCString(S
))
697 return std::move(EC
);
699 while (Reader
.bytesRemaining() > 0) {
700 if (auto EC
= Reader
.readCString(S
))
701 return std::move(EC
);
702 Result
->Strings
.push_back(S
);
707 Expected
<std::shared_ptr
<YAMLFrameDataSubsection
>>
708 YAMLFrameDataSubsection::fromCodeViewSubsection(
709 const DebugStringTableSubsectionRef
&Strings
,
710 const DebugFrameDataSubsectionRef
&Frames
) {
711 auto Result
= std::make_shared
<YAMLFrameDataSubsection
>();
712 for (const auto &F
: Frames
) {
714 YF
.CodeSize
= F
.CodeSize
;
716 YF
.LocalSize
= F
.LocalSize
;
717 YF
.MaxStackSize
= F
.MaxStackSize
;
718 YF
.ParamsSize
= F
.ParamsSize
;
719 YF
.PrologSize
= F
.PrologSize
;
720 YF
.RvaStart
= F
.RvaStart
;
721 YF
.SavedRegsSize
= F
.SavedRegsSize
;
723 auto ES
= Strings
.getString(F
.FrameFunc
);
726 make_error
<CodeViewError
>(
727 cv_error_code::no_records
,
728 "Could not find string for string id while mapping FrameData!"),
731 Result
->Frames
.push_back(YF
);
736 Expected
<std::shared_ptr
<YAMLCoffSymbolRVASubsection
>>
737 YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(
738 const DebugSymbolRVASubsectionRef
&Section
) {
739 auto Result
= std::make_shared
<YAMLCoffSymbolRVASubsection
>();
740 for (const auto &RVA
: Section
) {
741 Result
->RVAs
.push_back(RVA
);
746 Expected
<std::vector
<std::shared_ptr
<DebugSubsection
>>>
747 llvm::CodeViewYAML::toCodeViewSubsectionList(
748 BumpPtrAllocator
&Allocator
, ArrayRef
<YAMLDebugSubsection
> Subsections
,
749 const codeview::StringsAndChecksums
&SC
) {
750 std::vector
<std::shared_ptr
<DebugSubsection
>> Result
;
751 if (Subsections
.empty())
752 return std::move(Result
);
754 for (const auto &SS
: Subsections
) {
755 std::shared_ptr
<DebugSubsection
> CVS
;
756 CVS
= SS
.Subsection
->toCodeViewSubsection(Allocator
, SC
);
757 assert(CVS
!= nullptr);
758 Result
.push_back(std::move(CVS
));
760 return std::move(Result
);
765 struct SubsectionConversionVisitor
: public DebugSubsectionVisitor
{
766 SubsectionConversionVisitor() = default;
768 Error
visitUnknown(DebugUnknownSubsectionRef
&Unknown
) override
;
769 Error
visitLines(DebugLinesSubsectionRef
&Lines
,
770 const StringsAndChecksumsRef
&State
) override
;
771 Error
visitFileChecksums(DebugChecksumsSubsectionRef
&Checksums
,
772 const StringsAndChecksumsRef
&State
) override
;
773 Error
visitInlineeLines(DebugInlineeLinesSubsectionRef
&Inlinees
,
774 const StringsAndChecksumsRef
&State
) override
;
775 Error
visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef
&Checksums
,
776 const StringsAndChecksumsRef
&State
) override
;
777 Error
visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef
&Inlinees
,
778 const StringsAndChecksumsRef
&State
) override
;
779 Error
visitStringTable(DebugStringTableSubsectionRef
&ST
,
780 const StringsAndChecksumsRef
&State
) override
;
781 Error
visitSymbols(DebugSymbolsSubsectionRef
&Symbols
,
782 const StringsAndChecksumsRef
&State
) override
;
783 Error
visitFrameData(DebugFrameDataSubsectionRef
&Symbols
,
784 const StringsAndChecksumsRef
&State
) override
;
785 Error
visitCOFFSymbolRVAs(DebugSymbolRVASubsectionRef
&Symbols
,
786 const StringsAndChecksumsRef
&State
) override
;
788 YAMLDebugSubsection Subsection
;
791 } // end anonymous namespace
793 Error
SubsectionConversionVisitor::visitUnknown(
794 DebugUnknownSubsectionRef
&Unknown
) {
795 return make_error
<CodeViewError
>(cv_error_code::operation_unsupported
);
798 Error
SubsectionConversionVisitor::visitLines(
799 DebugLinesSubsectionRef
&Lines
, const StringsAndChecksumsRef
&State
) {
800 auto Result
= YAMLLinesSubsection::fromCodeViewSubsection(
801 State
.strings(), State
.checksums(), Lines
);
803 return Result
.takeError();
804 Subsection
.Subsection
= *Result
;
805 return Error::success();
808 Error
SubsectionConversionVisitor::visitFileChecksums(
809 DebugChecksumsSubsectionRef
&Checksums
,
810 const StringsAndChecksumsRef
&State
) {
811 auto Result
= YAMLChecksumsSubsection::fromCodeViewSubsection(State
.strings(),
814 return Result
.takeError();
815 Subsection
.Subsection
= *Result
;
816 return Error::success();
819 Error
SubsectionConversionVisitor::visitInlineeLines(
820 DebugInlineeLinesSubsectionRef
&Inlinees
,
821 const StringsAndChecksumsRef
&State
) {
822 auto Result
= YAMLInlineeLinesSubsection::fromCodeViewSubsection(
823 State
.strings(), State
.checksums(), Inlinees
);
825 return Result
.takeError();
826 Subsection
.Subsection
= *Result
;
827 return Error::success();
830 Error
SubsectionConversionVisitor::visitCrossModuleExports(
831 DebugCrossModuleExportsSubsectionRef
&Exports
,
832 const StringsAndChecksumsRef
&State
) {
834 YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(Exports
);
836 return Result
.takeError();
837 Subsection
.Subsection
= *Result
;
838 return Error::success();
841 Error
SubsectionConversionVisitor::visitCrossModuleImports(
842 DebugCrossModuleImportsSubsectionRef
&Imports
,
843 const StringsAndChecksumsRef
&State
) {
844 auto Result
= YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(
845 State
.strings(), Imports
);
847 return Result
.takeError();
848 Subsection
.Subsection
= *Result
;
849 return Error::success();
852 Error
SubsectionConversionVisitor::visitStringTable(
853 DebugStringTableSubsectionRef
&Strings
,
854 const StringsAndChecksumsRef
&State
) {
855 auto Result
= YAMLStringTableSubsection::fromCodeViewSubsection(Strings
);
857 return Result
.takeError();
858 Subsection
.Subsection
= *Result
;
859 return Error::success();
862 Error
SubsectionConversionVisitor::visitSymbols(
863 DebugSymbolsSubsectionRef
&Symbols
, const StringsAndChecksumsRef
&State
) {
864 auto Result
= YAMLSymbolsSubsection::fromCodeViewSubsection(Symbols
);
866 return Result
.takeError();
867 Subsection
.Subsection
= *Result
;
868 return Error::success();
871 Error
SubsectionConversionVisitor::visitFrameData(
872 DebugFrameDataSubsectionRef
&Frames
, const StringsAndChecksumsRef
&State
) {
874 YAMLFrameDataSubsection::fromCodeViewSubsection(State
.strings(), Frames
);
876 return Result
.takeError();
877 Subsection
.Subsection
= *Result
;
878 return Error::success();
881 Error
SubsectionConversionVisitor::visitCOFFSymbolRVAs(
882 DebugSymbolRVASubsectionRef
&RVAs
, const StringsAndChecksumsRef
&State
) {
883 auto Result
= YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(RVAs
);
885 return Result
.takeError();
886 Subsection
.Subsection
= *Result
;
887 return Error::success();
890 Expected
<YAMLDebugSubsection
>
891 YAMLDebugSubsection::fromCodeViewSubection(const StringsAndChecksumsRef
&SC
,
892 const DebugSubsectionRecord
&SS
) {
893 SubsectionConversionVisitor V
;
894 if (auto EC
= visitDebugSubsection(SS
, V
, SC
))
895 return std::move(EC
);
900 std::vector
<YAMLDebugSubsection
>
901 llvm::CodeViewYAML::fromDebugS(ArrayRef
<uint8_t> Data
,
902 const StringsAndChecksumsRef
&SC
) {
903 BinaryStreamReader
Reader(Data
, support::little
);
906 ExitOnError
Err("Invalid .debug$S section!");
907 Err(Reader
.readInteger(Magic
));
908 assert(Magic
== COFF::DEBUG_SECTION_MAGIC
&& "Invalid .debug$S section!");
910 DebugSubsectionArray Subsections
;
911 Err(Reader
.readArray(Subsections
, Reader
.bytesRemaining()));
913 std::vector
<YAMLDebugSubsection
> Result
;
915 for (const auto &SS
: Subsections
) {
916 auto YamlSS
= Err(YAMLDebugSubsection::fromCodeViewSubection(SC
, SS
));
917 Result
.push_back(YamlSS
);
922 void llvm::CodeViewYAML::initializeStringsAndChecksums(
923 ArrayRef
<YAMLDebugSubsection
> Sections
, codeview::StringsAndChecksums
&SC
) {
924 // String Table and Checksums subsections don't use the allocator.
925 BumpPtrAllocator Allocator
;
927 // It's possible for checksums and strings to even appear in different debug$S
928 // sections, so we have to make this a stateful function that can build up
929 // the strings and checksums field over multiple iterations.
931 // File Checksums require the string table, but may become before it, so we
932 // have to scan for strings first, then scan for checksums again from the
934 if (!SC
.hasStrings()) {
935 for (const auto &SS
: Sections
) {
936 if (SS
.Subsection
->Kind
!= DebugSubsectionKind::StringTable
)
939 auto Result
= SS
.Subsection
->toCodeViewSubsection(Allocator
, SC
);
941 std::static_pointer_cast
<DebugStringTableSubsection
>(Result
));
946 if (SC
.hasStrings() && !SC
.hasChecksums()) {
947 for (const auto &SS
: Sections
) {
948 if (SS
.Subsection
->Kind
!= DebugSubsectionKind::FileChecksums
)
951 auto Result
= SS
.Subsection
->toCodeViewSubsection(Allocator
, SC
);
953 std::static_pointer_cast
<DebugChecksumsSubsection
>(Result
));