xref: /freebsd/contrib/llvm-project/llvm/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
1 //===- CodeViewYAMLDebugSections.cpp - CodeView YAMLIO debug sections -----===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines classes for handling the YAML representation of CodeView
10 // Debug Info.
11 //
12 //===----------------------------------------------------------------------===//
13 
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"
43 #include <cassert>
44 #include <cstdint>
45 #include <memory>
46 #include <string>
47 #include <vector>
48 
49 using namespace llvm;
50 using namespace llvm::codeview;
51 using namespace llvm::CodeViewYAML;
52 using namespace llvm::CodeViewYAML::detail;
53 using namespace llvm::yaml;
54 
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)
65 
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)
70 
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)
80 
81 namespace llvm {
82 namespace CodeViewYAML {
83 namespace detail {
84 
85 struct YAMLSubsectionBase {
86   explicit YAMLSubsectionBase(DebugSubsectionKind Kind) : Kind(Kind) {}
87   virtual ~YAMLSubsectionBase() = default;
88 
89   virtual void map(IO &IO) = 0;
90   virtual std::shared_ptr<DebugSubsection>
91   toCodeViewSubsection(BumpPtrAllocator &Allocator,
92                        const codeview::StringsAndChecksums &SC) const = 0;
93 
94   DebugSubsectionKind Kind;
95 };
96 
97 } // end namespace detail
98 } // end namespace CodeViewYAML
99 } // end namespace llvm
100 
101 namespace {
102 
103 struct YAMLChecksumsSubsection : public YAMLSubsectionBase {
104   YAMLChecksumsSubsection()
105       : YAMLSubsectionBase(DebugSubsectionKind::FileChecksums) {}
106 
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);
114 
115   std::vector<SourceFileChecksumEntry> Checksums;
116 };
117 
118 struct YAMLLinesSubsection : public YAMLSubsectionBase {
119   YAMLLinesSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Lines) {}
120 
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);
129 
130   SourceLineInfo Lines;
131 };
132 
133 struct YAMLInlineeLinesSubsection : public YAMLSubsectionBase {
134   YAMLInlineeLinesSubsection()
135       : YAMLSubsectionBase(DebugSubsectionKind::InlineeLines) {}
136 
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);
145 
146   InlineeInfo InlineeLines;
147 };
148 
149 struct YAMLCrossModuleExportsSubsection : public YAMLSubsectionBase {
150   YAMLCrossModuleExportsSubsection()
151       : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeExports) {}
152 
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);
159 
160   std::vector<CrossModuleExport> Exports;
161 };
162 
163 struct YAMLCrossModuleImportsSubsection : public YAMLSubsectionBase {
164   YAMLCrossModuleImportsSubsection()
165       : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeImports) {}
166 
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);
174 
175   std::vector<YAMLCrossModuleImport> Imports;
176 };
177 
178 struct YAMLSymbolsSubsection : public YAMLSubsectionBase {
179   YAMLSymbolsSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Symbols) {}
180 
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);
187 
188   std::vector<CodeViewYAML::SymbolRecord> Symbols;
189 };
190 
191 struct YAMLStringTableSubsection : public YAMLSubsectionBase {
192   YAMLStringTableSubsection()
193       : YAMLSubsectionBase(DebugSubsectionKind::StringTable) {}
194 
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);
201 
202   std::vector<StringRef> Strings;
203 };
204 
205 struct YAMLFrameDataSubsection : public YAMLSubsectionBase {
206   YAMLFrameDataSubsection()
207       : YAMLSubsectionBase(DebugSubsectionKind::FrameData) {}
208 
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);
216 
217   std::vector<YAMLFrameData> Frames;
218 };
219 
220 struct YAMLCoffSymbolRVASubsection : public YAMLSubsectionBase {
221   YAMLCoffSymbolRVASubsection()
222       : YAMLSubsectionBase(DebugSubsectionKind::CoffSymbolRVA) {}
223 
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);
230 
231   std::vector<uint32_t> RVAs;
232 };
233 
234 } // end anonymous namespace
235 
236 void ScalarBitSetTraits<LineFlags>::bitset(IO &io, LineFlags &Flags) {
237   io.bitSetCase(Flags, "HasColumnInfo", LF_HaveColumns);
238   io.enumFallback<Hex16>(Flags);
239 }
240 
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);
247 }
248 
249 void ScalarTraits<HexFormattedString>::output(const HexFormattedString &Value,
250                                               void *ctx, raw_ostream &Out) {
251   StringRef Bytes(reinterpret_cast<const char *>(Value.Bytes.data()),
252                   Value.Bytes.size());
253   Out << toHex(Bytes);
254 }
255 
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());
260   return StringRef();
261 }
262 
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);
268 }
269 
270 void MappingTraits<SourceColumnEntry>::mapping(IO &IO, SourceColumnEntry &Obj) {
271   IO.mapRequired("StartColumn", Obj.StartColumn);
272   IO.mapRequired("EndColumn", Obj.EndColumn);
273 }
274 
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);
279 }
280 
281 void MappingTraits<CrossModuleExport>::mapping(IO &IO, CrossModuleExport &Obj) {
282   IO.mapRequired("LocalId", Obj.Local);
283   IO.mapRequired("GlobalId", Obj.Global);
284 }
285 
286 void MappingTraits<YAMLCrossModuleImport>::mapping(IO &IO,
287                                                    YAMLCrossModuleImport &Obj) {
288   IO.mapRequired("Module", Obj.ModuleName);
289   IO.mapRequired("Imports", Obj.ImportIds);
290 }
291 
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);
297 }
298 
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);
304 }
305 
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);
315 }
316 
317 void YAMLChecksumsSubsection::map(IO &IO) {
318   IO.mapTag("!FileChecksums", true);
319   IO.mapRequired("Checksums", Checksums);
320 }
321 
322 void YAMLLinesSubsection::map(IO &IO) {
323   IO.mapTag("!Lines", true);
324   IO.mapRequired("CodeSize", Lines.CodeSize);
325 
326   IO.mapRequired("Flags", Lines.Flags);
327   IO.mapRequired("RelocOffset", Lines.RelocOffset);
328   IO.mapRequired("RelocSegment", Lines.RelocSegment);
329   IO.mapRequired("Blocks", Lines.Blocks);
330 }
331 
332 void YAMLInlineeLinesSubsection::map(IO &IO) {
333   IO.mapTag("!InlineeLines", true);
334   IO.mapRequired("HasExtraFiles", InlineeLines.HasExtraFiles);
335   IO.mapRequired("Sites", InlineeLines.Sites);
336 }
337 
338 void YAMLCrossModuleExportsSubsection::map(IO &IO) {
339   IO.mapTag("!CrossModuleExports", true);
340   IO.mapOptional("Exports", Exports);
341 }
342 
343 void YAMLCrossModuleImportsSubsection::map(IO &IO) {
344   IO.mapTag("!CrossModuleImports", true);
345   IO.mapOptional("Imports", Imports);
346 }
347 
348 void YAMLSymbolsSubsection::map(IO &IO) {
349   IO.mapTag("!Symbols", true);
350   IO.mapRequired("Records", Symbols);
351 }
352 
353 void YAMLStringTableSubsection::map(IO &IO) {
354   IO.mapTag("!StringTable", true);
355   IO.mapRequired("Strings", Strings);
356 }
357 
358 void YAMLFrameDataSubsection::map(IO &IO) {
359   IO.mapTag("!FrameData", true);
360   IO.mapRequired("Frames", Frames);
361 }
362 
363 void YAMLCoffSymbolRVASubsection::map(IO &IO) {
364   IO.mapTag("!COFFSymbolRVAs", true);
365   IO.mapRequired("RVAs", RVAs);
366 }
367 
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>();
392     } else {
393       llvm_unreachable("Unexpected subsection tag!");
394     }
395   }
396   Subsection.Subsection->map(IO);
397 }
398 
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);
406   }
407   return Result;
408 }
409 
410 std::shared_ptr<DebugSubsection> YAMLLinesSubsection::toCodeViewSubsection(
411     BumpPtrAllocator &Allocator,
412     const codeview::StringsAndChecksums &SC) const {
413   assert(SC.hasStrings() && SC.hasChecksums());
414   auto Result =
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);
429       }
430     } else {
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));
434       }
435     }
436   }
437   return Result;
438 }
439 
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);
447 
448   for (const auto &Site : InlineeLines.Sites) {
449     Result->addInlineSite(TypeIndex(Site.Inlinee), Site.FileName,
450                           Site.SourceLineNum);
451     if (!InlineeLines.HasExtraFiles)
452       continue;
453 
454     for (auto EF : Site.ExtraFiles) {
455       Result->addExtraFile(EF);
456     }
457   }
458   return Result;
459 }
460 
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);
468   return Result;
469 }
470 
471 std::shared_ptr<DebugSubsection>
472 YAMLCrossModuleImportsSubsection::toCodeViewSubsection(
473     BumpPtrAllocator &Allocator,
474     const codeview::StringsAndChecksums &SC) const {
475   assert(SC.hasStrings());
476 
477   auto Result =
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);
482   }
483   return Result;
484 }
485 
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)
491     Result->addSymbol(
492         Sym.toCodeViewSymbol(Allocator, CodeViewContainer::ObjectFile));
493   return Result;
494 }
495 
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)
502     Result->insert(Str);
503   return Result;
504 }
505 
506 std::shared_ptr<DebugSubsection> YAMLFrameDataSubsection::toCodeViewSubsection(
507     BumpPtrAllocator &Allocator,
508     const codeview::StringsAndChecksums &SC) const {
509   assert(SC.hasStrings());
510 
511   auto Result = std::make_shared<DebugFrameDataSubsection>(true);
512   for (const auto &YF : Frames) {
513     codeview::FrameData F;
514     F.CodeSize = YF.CodeSize;
515     F.Flags = YF.Flags;
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);
524   }
525   return Result;
526 }
527 
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)
534     Result->addRVA(RVA);
535   return Result;
536 }
537 
538 static Expected<SourceFileChecksumEntry>
539 convertOneChecksum(const DebugStringTableSubsectionRef &Strings,
540                    const FileChecksumEntry &CS) {
541   auto ExpectedString = Strings.getString(CS.FileNameOffset);
542   if (!ExpectedString)
543     return ExpectedString.takeError();
544 
545   SourceFileChecksumEntry Result;
546   Result.ChecksumBytes.Bytes = CS.Checksum;
547   Result.Kind = CS.Kind;
548   Result.FileName = *ExpectedString;
549   return Result;
550 }
551 
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);
560 }
561 
562 Expected<std::shared_ptr<YAMLChecksumsSubsection>>
563 YAMLChecksumsSubsection::fromCodeViewSubsection(
564     const DebugStringTableSubsectionRef &Strings,
565     const DebugChecksumsSubsectionRef &FC) {
566   auto Result = std::make_shared<YAMLChecksumsSubsection>();
567 
568   for (const auto &CS : FC) {
569     auto ConvertedCS = convertOneChecksum(Strings, CS);
570     if (!ConvertedCS)
571       return ConvertedCS.takeError();
572     Result->Checksums.push_back(*ConvertedCS);
573   }
574   return Result;
575 }
576 
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);
590     if (!EF)
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);
599       }
600     }
601     for (const auto &LN : L.LineNumbers) {
602       SourceLineEntry SLE;
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);
609     }
610     Result->Lines.Blocks.push_back(Block);
611   }
612   return Result;
613 }
614 
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>();
621 
622   Result->InlineeLines.HasExtraFiles = Lines.hasExtraFiles();
623   for (const auto &IL : Lines) {
624     InlineeSite Site;
625     auto ExpF = getFileName(Strings, Checksums, IL.Header->FileID);
626     if (!ExpF)
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);
634         if (!ExpF2)
635           return ExpF2.takeError();
636         Site.ExtraFiles.push_back(*ExpF2);
637       }
638     }
639     Result->InlineeLines.Sites.push_back(Site);
640   }
641   return Result;
642 }
643 
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());
649   return Result;
650 }
651 
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);
660     if (!ExpectedStr)
661       return ExpectedStr.takeError();
662     YCMI.ModuleName = *ExpectedStr;
663     YCMI.ImportIds.assign(CMI.Imports.begin(), CMI.Imports.end());
664     Result->Imports.push_back(YCMI);
665   }
666   return Result;
667 }
668 
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);
675     if (!S)
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!"),
680                         S.takeError());
681 
682     Result->Symbols.push_back(*S);
683   }
684   return Result;
685 }
686 
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());
692   StringRef S;
693   // First item is a single null string, skip it.
694   if (auto EC = Reader.readCString(S))
695     return std::move(EC);
696   assert(S.empty());
697   while (Reader.bytesRemaining() > 0) {
698     if (auto EC = Reader.readCString(S))
699       return std::move(EC);
700     Result->Strings.push_back(S);
701   }
702   return Result;
703 }
704 
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) {
711     YAMLFrameData YF;
712     YF.CodeSize = F.CodeSize;
713     YF.Flags = F.Flags;
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;
720 
721     auto ES = Strings.getString(F.FrameFunc);
722     if (!ES)
723       return joinErrors(
724           make_error<CodeViewError>(
725               cv_error_code::no_records,
726               "Could not find string for string id while mapping FrameData!"),
727           ES.takeError());
728     YF.FrameFunc = *ES;
729     Result->Frames.push_back(YF);
730   }
731   return Result;
732 }
733 
734 Expected<std::shared_ptr<YAMLCoffSymbolRVASubsection>>
735 YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(
736     const DebugSymbolRVASubsectionRef &Section) {
737   auto Result = std::make_shared<YAMLCoffSymbolRVASubsection>();
738   llvm::append_range(Result->RVAs, Section);
739   return Result;
740 }
741 
742 Expected<std::vector<std::shared_ptr<DebugSubsection>>>
743 llvm::CodeViewYAML::toCodeViewSubsectionList(
744     BumpPtrAllocator &Allocator, ArrayRef<YAMLDebugSubsection> Subsections,
745     const codeview::StringsAndChecksums &SC) {
746   std::vector<std::shared_ptr<DebugSubsection>> Result;
747   if (Subsections.empty())
748     return std::move(Result);
749 
750   for (const auto &SS : Subsections) {
751     std::shared_ptr<DebugSubsection> CVS;
752     CVS = SS.Subsection->toCodeViewSubsection(Allocator, SC);
753     assert(CVS != nullptr);
754     Result.push_back(std::move(CVS));
755   }
756   return std::move(Result);
757 }
758 
759 namespace {
760 
761 struct SubsectionConversionVisitor : public DebugSubsectionVisitor {
762   SubsectionConversionVisitor() = default;
763 
764   Error visitUnknown(DebugUnknownSubsectionRef &Unknown) override;
765   Error visitLines(DebugLinesSubsectionRef &Lines,
766                    const StringsAndChecksumsRef &State) override;
767   Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums,
768                            const StringsAndChecksumsRef &State) override;
769   Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees,
770                           const StringsAndChecksumsRef &State) override;
771   Error visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef &Checksums,
772                                 const StringsAndChecksumsRef &State) override;
773   Error visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef &Inlinees,
774                                 const StringsAndChecksumsRef &State) override;
775   Error visitStringTable(DebugStringTableSubsectionRef &ST,
776                          const StringsAndChecksumsRef &State) override;
777   Error visitSymbols(DebugSymbolsSubsectionRef &Symbols,
778                      const StringsAndChecksumsRef &State) override;
779   Error visitFrameData(DebugFrameDataSubsectionRef &Symbols,
780                        const StringsAndChecksumsRef &State) override;
781   Error visitCOFFSymbolRVAs(DebugSymbolRVASubsectionRef &Symbols,
782                             const StringsAndChecksumsRef &State) override;
783 
784   YAMLDebugSubsection Subsection;
785 };
786 
787 } // end anonymous namespace
788 
789 Error SubsectionConversionVisitor::visitUnknown(
790     DebugUnknownSubsectionRef &Unknown) {
791   return make_error<CodeViewError>(cv_error_code::operation_unsupported);
792 }
793 
794 Error SubsectionConversionVisitor::visitLines(
795     DebugLinesSubsectionRef &Lines, const StringsAndChecksumsRef &State) {
796   auto Result = YAMLLinesSubsection::fromCodeViewSubsection(
797       State.strings(), State.checksums(), Lines);
798   if (!Result)
799     return Result.takeError();
800   Subsection.Subsection = *Result;
801   return Error::success();
802 }
803 
804 Error SubsectionConversionVisitor::visitFileChecksums(
805     DebugChecksumsSubsectionRef &Checksums,
806     const StringsAndChecksumsRef &State) {
807   auto Result = YAMLChecksumsSubsection::fromCodeViewSubsection(State.strings(),
808                                                                 Checksums);
809   if (!Result)
810     return Result.takeError();
811   Subsection.Subsection = *Result;
812   return Error::success();
813 }
814 
815 Error SubsectionConversionVisitor::visitInlineeLines(
816     DebugInlineeLinesSubsectionRef &Inlinees,
817     const StringsAndChecksumsRef &State) {
818   auto Result = YAMLInlineeLinesSubsection::fromCodeViewSubsection(
819       State.strings(), State.checksums(), Inlinees);
820   if (!Result)
821     return Result.takeError();
822   Subsection.Subsection = *Result;
823   return Error::success();
824 }
825 
826 Error SubsectionConversionVisitor::visitCrossModuleExports(
827     DebugCrossModuleExportsSubsectionRef &Exports,
828     const StringsAndChecksumsRef &State) {
829   auto Result =
830       YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(Exports);
831   if (!Result)
832     return Result.takeError();
833   Subsection.Subsection = *Result;
834   return Error::success();
835 }
836 
837 Error SubsectionConversionVisitor::visitCrossModuleImports(
838     DebugCrossModuleImportsSubsectionRef &Imports,
839     const StringsAndChecksumsRef &State) {
840   auto Result = YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(
841       State.strings(), Imports);
842   if (!Result)
843     return Result.takeError();
844   Subsection.Subsection = *Result;
845   return Error::success();
846 }
847 
848 Error SubsectionConversionVisitor::visitStringTable(
849     DebugStringTableSubsectionRef &Strings,
850     const StringsAndChecksumsRef &State) {
851   auto Result = YAMLStringTableSubsection::fromCodeViewSubsection(Strings);
852   if (!Result)
853     return Result.takeError();
854   Subsection.Subsection = *Result;
855   return Error::success();
856 }
857 
858 Error SubsectionConversionVisitor::visitSymbols(
859     DebugSymbolsSubsectionRef &Symbols, const StringsAndChecksumsRef &State) {
860   auto Result = YAMLSymbolsSubsection::fromCodeViewSubsection(Symbols);
861   if (!Result)
862     return Result.takeError();
863   Subsection.Subsection = *Result;
864   return Error::success();
865 }
866 
867 Error SubsectionConversionVisitor::visitFrameData(
868     DebugFrameDataSubsectionRef &Frames, const StringsAndChecksumsRef &State) {
869   auto Result =
870       YAMLFrameDataSubsection::fromCodeViewSubsection(State.strings(), Frames);
871   if (!Result)
872     return Result.takeError();
873   Subsection.Subsection = *Result;
874   return Error::success();
875 }
876 
877 Error SubsectionConversionVisitor::visitCOFFSymbolRVAs(
878     DebugSymbolRVASubsectionRef &RVAs, const StringsAndChecksumsRef &State) {
879   auto Result = YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(RVAs);
880   if (!Result)
881     return Result.takeError();
882   Subsection.Subsection = *Result;
883   return Error::success();
884 }
885 
886 Expected<YAMLDebugSubsection>
887 YAMLDebugSubsection::fromCodeViewSubection(const StringsAndChecksumsRef &SC,
888                                            const DebugSubsectionRecord &SS) {
889   SubsectionConversionVisitor V;
890   if (auto EC = visitDebugSubsection(SS, V, SC))
891     return std::move(EC);
892 
893   return V.Subsection;
894 }
895 
896 std::vector<YAMLDebugSubsection>
897 llvm::CodeViewYAML::fromDebugS(ArrayRef<uint8_t> Data,
898                                const StringsAndChecksumsRef &SC) {
899   BinaryStreamReader Reader(Data, llvm::endianness::little);
900   uint32_t Magic;
901 
902   ExitOnError Err("Invalid .debug$S section!");
903   Err(Reader.readInteger(Magic));
904   assert(Magic == COFF::DEBUG_SECTION_MAGIC && "Invalid .debug$S section!");
905 
906   DebugSubsectionArray Subsections;
907   Err(Reader.readArray(Subsections, Reader.bytesRemaining()));
908 
909   std::vector<YAMLDebugSubsection> Result;
910 
911   for (const auto &SS : Subsections) {
912     auto YamlSS = Err(YAMLDebugSubsection::fromCodeViewSubection(SC, SS));
913     Result.push_back(YamlSS);
914   }
915   return Result;
916 }
917 
918 void llvm::CodeViewYAML::initializeStringsAndChecksums(
919     ArrayRef<YAMLDebugSubsection> Sections, codeview::StringsAndChecksums &SC) {
920   // String Table and Checksums subsections don't use the allocator.
921   BumpPtrAllocator Allocator;
922 
923   // It's possible for checksums and strings to even appear in different debug$S
924   // sections, so we have to make this a stateful function that can build up
925   // the strings and checksums field over multiple iterations.
926 
927   // File Checksums require the string table, but may become before it, so we
928   // have to scan for strings first, then scan for checksums again from the
929   // beginning.
930   if (!SC.hasStrings()) {
931     for (const auto &SS : Sections) {
932       if (SS.Subsection->Kind != DebugSubsectionKind::StringTable)
933         continue;
934 
935       auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC);
936       SC.setStrings(
937           std::static_pointer_cast<DebugStringTableSubsection>(Result));
938       break;
939     }
940   }
941 
942   if (SC.hasStrings() && !SC.hasChecksums()) {
943     for (const auto &SS : Sections) {
944       if (SS.Subsection->Kind != DebugSubsectionKind::FileChecksums)
945         continue;
946 
947       auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC);
948       SC.setChecksums(
949           std::static_pointer_cast<DebugChecksumsSubsection>(Result));
950       break;
951     }
952   }
953 }
954