xref: /llvm-project/llvm/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp (revision 5b7102d1f37eab7a8f17b7bf4124ca76fbdbd66d)
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   for (const auto &RVA : Section) {
739     Result->RVAs.push_back(RVA);
740   }
741   return Result;
742 }
743 
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);
751 
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));
757   }
758   return std::move(Result);
759 }
760 
761 namespace {
762 
763 struct SubsectionConversionVisitor : public DebugSubsectionVisitor {
764   SubsectionConversionVisitor() = default;
765 
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;
785 
786   YAMLDebugSubsection Subsection;
787 };
788 
789 } // end anonymous namespace
790 
791 Error SubsectionConversionVisitor::visitUnknown(
792     DebugUnknownSubsectionRef &Unknown) {
793   return make_error<CodeViewError>(cv_error_code::operation_unsupported);
794 }
795 
796 Error SubsectionConversionVisitor::visitLines(
797     DebugLinesSubsectionRef &Lines, const StringsAndChecksumsRef &State) {
798   auto Result = YAMLLinesSubsection::fromCodeViewSubsection(
799       State.strings(), State.checksums(), Lines);
800   if (!Result)
801     return Result.takeError();
802   Subsection.Subsection = *Result;
803   return Error::success();
804 }
805 
806 Error SubsectionConversionVisitor::visitFileChecksums(
807     DebugChecksumsSubsectionRef &Checksums,
808     const StringsAndChecksumsRef &State) {
809   auto Result = YAMLChecksumsSubsection::fromCodeViewSubsection(State.strings(),
810                                                                 Checksums);
811   if (!Result)
812     return Result.takeError();
813   Subsection.Subsection = *Result;
814   return Error::success();
815 }
816 
817 Error SubsectionConversionVisitor::visitInlineeLines(
818     DebugInlineeLinesSubsectionRef &Inlinees,
819     const StringsAndChecksumsRef &State) {
820   auto Result = YAMLInlineeLinesSubsection::fromCodeViewSubsection(
821       State.strings(), State.checksums(), Inlinees);
822   if (!Result)
823     return Result.takeError();
824   Subsection.Subsection = *Result;
825   return Error::success();
826 }
827 
828 Error SubsectionConversionVisitor::visitCrossModuleExports(
829     DebugCrossModuleExportsSubsectionRef &Exports,
830     const StringsAndChecksumsRef &State) {
831   auto Result =
832       YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(Exports);
833   if (!Result)
834     return Result.takeError();
835   Subsection.Subsection = *Result;
836   return Error::success();
837 }
838 
839 Error SubsectionConversionVisitor::visitCrossModuleImports(
840     DebugCrossModuleImportsSubsectionRef &Imports,
841     const StringsAndChecksumsRef &State) {
842   auto Result = YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(
843       State.strings(), Imports);
844   if (!Result)
845     return Result.takeError();
846   Subsection.Subsection = *Result;
847   return Error::success();
848 }
849 
850 Error SubsectionConversionVisitor::visitStringTable(
851     DebugStringTableSubsectionRef &Strings,
852     const StringsAndChecksumsRef &State) {
853   auto Result = YAMLStringTableSubsection::fromCodeViewSubsection(Strings);
854   if (!Result)
855     return Result.takeError();
856   Subsection.Subsection = *Result;
857   return Error::success();
858 }
859 
860 Error SubsectionConversionVisitor::visitSymbols(
861     DebugSymbolsSubsectionRef &Symbols, const StringsAndChecksumsRef &State) {
862   auto Result = YAMLSymbolsSubsection::fromCodeViewSubsection(Symbols);
863   if (!Result)
864     return Result.takeError();
865   Subsection.Subsection = *Result;
866   return Error::success();
867 }
868 
869 Error SubsectionConversionVisitor::visitFrameData(
870     DebugFrameDataSubsectionRef &Frames, const StringsAndChecksumsRef &State) {
871   auto Result =
872       YAMLFrameDataSubsection::fromCodeViewSubsection(State.strings(), Frames);
873   if (!Result)
874     return Result.takeError();
875   Subsection.Subsection = *Result;
876   return Error::success();
877 }
878 
879 Error SubsectionConversionVisitor::visitCOFFSymbolRVAs(
880     DebugSymbolRVASubsectionRef &RVAs, const StringsAndChecksumsRef &State) {
881   auto Result = YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(RVAs);
882   if (!Result)
883     return Result.takeError();
884   Subsection.Subsection = *Result;
885   return Error::success();
886 }
887 
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);
894 
895   return V.Subsection;
896 }
897 
898 std::vector<YAMLDebugSubsection>
899 llvm::CodeViewYAML::fromDebugS(ArrayRef<uint8_t> Data,
900                                const StringsAndChecksumsRef &SC) {
901   BinaryStreamReader Reader(Data, llvm::endianness::little);
902   uint32_t Magic;
903 
904   ExitOnError Err("Invalid .debug$S section!");
905   Err(Reader.readInteger(Magic));
906   assert(Magic == COFF::DEBUG_SECTION_MAGIC && "Invalid .debug$S section!");
907 
908   DebugSubsectionArray Subsections;
909   Err(Reader.readArray(Subsections, Reader.bytesRemaining()));
910 
911   std::vector<YAMLDebugSubsection> Result;
912 
913   for (const auto &SS : Subsections) {
914     auto YamlSS = Err(YAMLDebugSubsection::fromCodeViewSubection(SC, SS));
915     Result.push_back(YamlSS);
916   }
917   return Result;
918 }
919 
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;
924 
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.
928 
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
931   // beginning.
932   if (!SC.hasStrings()) {
933     for (const auto &SS : Sections) {
934       if (SS.Subsection->Kind != DebugSubsectionKind::StringTable)
935         continue;
936 
937       auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC);
938       SC.setStrings(
939           std::static_pointer_cast<DebugStringTableSubsection>(Result));
940       break;
941     }
942   }
943 
944   if (SC.hasStrings() && !SC.hasChecksums()) {
945     for (const auto &SS : Sections) {
946       if (SS.Subsection->Kind != DebugSubsectionKind::FileChecksums)
947         continue;
948 
949       auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC);
950       SC.setChecksums(
951           std::static_pointer_cast<DebugChecksumsSubsection>(Result));
952       break;
953     }
954   }
955 }
956