xref: /freebsd/contrib/llvm-project/llvm/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp (revision 72d849c76142f00c8016fa1ba9d3e6c3eb5481c4)
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 <algorithm>
44  #include <cassert>
45  #include <cstdint>
46  #include <memory>
47  #include <string>
48  #include <tuple>
49  #include <vector>
50  
51  using namespace llvm;
52  using namespace llvm::codeview;
53  using namespace llvm::CodeViewYAML;
54  using namespace llvm::CodeViewYAML::detail;
55  using namespace llvm::yaml;
56  
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)
67  
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)
72  
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)
82  
83  namespace llvm {
84  namespace CodeViewYAML {
85  namespace detail {
86  
87  struct YAMLSubsectionBase {
88    explicit YAMLSubsectionBase(DebugSubsectionKind Kind) : Kind(Kind) {}
89    virtual ~YAMLSubsectionBase() = default;
90  
91    virtual void map(IO &IO) = 0;
92    virtual std::shared_ptr<DebugSubsection>
93    toCodeViewSubsection(BumpPtrAllocator &Allocator,
94                         const codeview::StringsAndChecksums &SC) const = 0;
95  
96    DebugSubsectionKind Kind;
97  };
98  
99  } // end namespace detail
100  } // end namespace CodeViewYAML
101  } // end namespace llvm
102  
103  namespace {
104  
105  struct YAMLChecksumsSubsection : public YAMLSubsectionBase {
106    YAMLChecksumsSubsection()
107        : YAMLSubsectionBase(DebugSubsectionKind::FileChecksums) {}
108  
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);
116  
117    std::vector<SourceFileChecksumEntry> Checksums;
118  };
119  
120  struct YAMLLinesSubsection : public YAMLSubsectionBase {
121    YAMLLinesSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Lines) {}
122  
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);
131  
132    SourceLineInfo Lines;
133  };
134  
135  struct YAMLInlineeLinesSubsection : public YAMLSubsectionBase {
136    YAMLInlineeLinesSubsection()
137        : YAMLSubsectionBase(DebugSubsectionKind::InlineeLines) {}
138  
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);
147  
148    InlineeInfo InlineeLines;
149  };
150  
151  struct YAMLCrossModuleExportsSubsection : public YAMLSubsectionBase {
152    YAMLCrossModuleExportsSubsection()
153        : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeExports) {}
154  
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);
161  
162    std::vector<CrossModuleExport> Exports;
163  };
164  
165  struct YAMLCrossModuleImportsSubsection : public YAMLSubsectionBase {
166    YAMLCrossModuleImportsSubsection()
167        : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeImports) {}
168  
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);
176  
177    std::vector<YAMLCrossModuleImport> Imports;
178  };
179  
180  struct YAMLSymbolsSubsection : public YAMLSubsectionBase {
181    YAMLSymbolsSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Symbols) {}
182  
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);
189  
190    std::vector<CodeViewYAML::SymbolRecord> Symbols;
191  };
192  
193  struct YAMLStringTableSubsection : public YAMLSubsectionBase {
194    YAMLStringTableSubsection()
195        : YAMLSubsectionBase(DebugSubsectionKind::StringTable) {}
196  
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);
203  
204    std::vector<StringRef> Strings;
205  };
206  
207  struct YAMLFrameDataSubsection : public YAMLSubsectionBase {
208    YAMLFrameDataSubsection()
209        : YAMLSubsectionBase(DebugSubsectionKind::FrameData) {}
210  
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);
218  
219    std::vector<YAMLFrameData> Frames;
220  };
221  
222  struct YAMLCoffSymbolRVASubsection : public YAMLSubsectionBase {
223    YAMLCoffSymbolRVASubsection()
224        : YAMLSubsectionBase(DebugSubsectionKind::CoffSymbolRVA) {}
225  
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);
232  
233    std::vector<uint32_t> RVAs;
234  };
235  
236  } // end anonymous namespace
237  
238  void ScalarBitSetTraits<LineFlags>::bitset(IO &io, LineFlags &Flags) {
239    io.bitSetCase(Flags, "HasColumnInfo", LF_HaveColumns);
240    io.enumFallback<Hex16>(Flags);
241  }
242  
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);
249  }
250  
251  void ScalarTraits<HexFormattedString>::output(const HexFormattedString &Value,
252                                                void *ctx, raw_ostream &Out) {
253    StringRef Bytes(reinterpret_cast<const char *>(Value.Bytes.data()),
254                    Value.Bytes.size());
255    Out << toHex(Bytes);
256  }
257  
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());
262    return StringRef();
263  }
264  
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);
270  }
271  
272  void MappingTraits<SourceColumnEntry>::mapping(IO &IO, SourceColumnEntry &Obj) {
273    IO.mapRequired("StartColumn", Obj.StartColumn);
274    IO.mapRequired("EndColumn", Obj.EndColumn);
275  }
276  
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);
281  }
282  
283  void MappingTraits<CrossModuleExport>::mapping(IO &IO, CrossModuleExport &Obj) {
284    IO.mapRequired("LocalId", Obj.Local);
285    IO.mapRequired("GlobalId", Obj.Global);
286  }
287  
288  void MappingTraits<YAMLCrossModuleImport>::mapping(IO &IO,
289                                                     YAMLCrossModuleImport &Obj) {
290    IO.mapRequired("Module", Obj.ModuleName);
291    IO.mapRequired("Imports", Obj.ImportIds);
292  }
293  
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);
299  }
300  
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);
306  }
307  
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);
317  }
318  
319  void YAMLChecksumsSubsection::map(IO &IO) {
320    IO.mapTag("!FileChecksums", true);
321    IO.mapRequired("Checksums", Checksums);
322  }
323  
324  void YAMLLinesSubsection::map(IO &IO) {
325    IO.mapTag("!Lines", true);
326    IO.mapRequired("CodeSize", Lines.CodeSize);
327  
328    IO.mapRequired("Flags", Lines.Flags);
329    IO.mapRequired("RelocOffset", Lines.RelocOffset);
330    IO.mapRequired("RelocSegment", Lines.RelocSegment);
331    IO.mapRequired("Blocks", Lines.Blocks);
332  }
333  
334  void YAMLInlineeLinesSubsection::map(IO &IO) {
335    IO.mapTag("!InlineeLines", true);
336    IO.mapRequired("HasExtraFiles", InlineeLines.HasExtraFiles);
337    IO.mapRequired("Sites", InlineeLines.Sites);
338  }
339  
340  void YAMLCrossModuleExportsSubsection::map(IO &IO) {
341    IO.mapTag("!CrossModuleExports", true);
342    IO.mapOptional("Exports", Exports);
343  }
344  
345  void YAMLCrossModuleImportsSubsection::map(IO &IO) {
346    IO.mapTag("!CrossModuleImports", true);
347    IO.mapOptional("Imports", Imports);
348  }
349  
350  void YAMLSymbolsSubsection::map(IO &IO) {
351    IO.mapTag("!Symbols", true);
352    IO.mapRequired("Records", Symbols);
353  }
354  
355  void YAMLStringTableSubsection::map(IO &IO) {
356    IO.mapTag("!StringTable", true);
357    IO.mapRequired("Strings", Strings);
358  }
359  
360  void YAMLFrameDataSubsection::map(IO &IO) {
361    IO.mapTag("!FrameData", true);
362    IO.mapRequired("Frames", Frames);
363  }
364  
365  void YAMLCoffSymbolRVASubsection::map(IO &IO) {
366    IO.mapTag("!COFFSymbolRVAs", true);
367    IO.mapRequired("RVAs", RVAs);
368  }
369  
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>();
394      } else {
395        llvm_unreachable("Unexpected subsection tag!");
396      }
397    }
398    Subsection.Subsection->map(IO);
399  }
400  
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);
408    }
409    return Result;
410  }
411  
412  std::shared_ptr<DebugSubsection> YAMLLinesSubsection::toCodeViewSubsection(
413      BumpPtrAllocator &Allocator,
414      const codeview::StringsAndChecksums &SC) const {
415    assert(SC.hasStrings() && SC.hasChecksums());
416    auto Result =
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 (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);
431        }
432      } else {
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));
436        }
437      }
438    }
439    return Result;
440  }
441  
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);
449  
450    for (const auto &Site : InlineeLines.Sites) {
451      Result->addInlineSite(TypeIndex(Site.Inlinee), Site.FileName,
452                            Site.SourceLineNum);
453      if (!InlineeLines.HasExtraFiles)
454        continue;
455  
456      for (auto EF : Site.ExtraFiles) {
457        Result->addExtraFile(EF);
458      }
459    }
460    return Result;
461  }
462  
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);
470    return Result;
471  }
472  
473  std::shared_ptr<DebugSubsection>
474  YAMLCrossModuleImportsSubsection::toCodeViewSubsection(
475      BumpPtrAllocator &Allocator,
476      const codeview::StringsAndChecksums &SC) const {
477    assert(SC.hasStrings());
478  
479    auto Result =
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);
484    }
485    return Result;
486  }
487  
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)
493      Result->addSymbol(
494          Sym.toCodeViewSymbol(Allocator, CodeViewContainer::ObjectFile));
495    return Result;
496  }
497  
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)
504      Result->insert(Str);
505    return Result;
506  }
507  
508  std::shared_ptr<DebugSubsection> YAMLFrameDataSubsection::toCodeViewSubsection(
509      BumpPtrAllocator &Allocator,
510      const codeview::StringsAndChecksums &SC) const {
511    assert(SC.hasStrings());
512  
513    auto Result = std::make_shared<DebugFrameDataSubsection>(true);
514    for (const auto &YF : Frames) {
515      codeview::FrameData F;
516      F.CodeSize = YF.CodeSize;
517      F.Flags = YF.Flags;
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);
526    }
527    return Result;
528  }
529  
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)
536      Result->addRVA(RVA);
537    return Result;
538  }
539  
540  static Expected<SourceFileChecksumEntry>
541  convertOneChecksum(const DebugStringTableSubsectionRef &Strings,
542                     const FileChecksumEntry &CS) {
543    auto ExpectedString = Strings.getString(CS.FileNameOffset);
544    if (!ExpectedString)
545      return ExpectedString.takeError();
546  
547    SourceFileChecksumEntry Result;
548    Result.ChecksumBytes.Bytes = CS.Checksum;
549    Result.Kind = CS.Kind;
550    Result.FileName = *ExpectedString;
551    return Result;
552  }
553  
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);
562  }
563  
564  Expected<std::shared_ptr<YAMLChecksumsSubsection>>
565  YAMLChecksumsSubsection::fromCodeViewSubsection(
566      const DebugStringTableSubsectionRef &Strings,
567      const DebugChecksumsSubsectionRef &FC) {
568    auto Result = std::make_shared<YAMLChecksumsSubsection>();
569  
570    for (const auto &CS : FC) {
571      auto ConvertedCS = convertOneChecksum(Strings, CS);
572      if (!ConvertedCS)
573        return ConvertedCS.takeError();
574      Result->Checksums.push_back(*ConvertedCS);
575    }
576    return Result;
577  }
578  
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);
592      if (!EF)
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);
601        }
602      }
603      for (const auto &LN : L.LineNumbers) {
604        SourceLineEntry SLE;
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);
611      }
612      Result->Lines.Blocks.push_back(Block);
613    }
614    return Result;
615  }
616  
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>();
623  
624    Result->InlineeLines.HasExtraFiles = Lines.hasExtraFiles();
625    for (const auto &IL : Lines) {
626      InlineeSite Site;
627      auto ExpF = getFileName(Strings, Checksums, IL.Header->FileID);
628      if (!ExpF)
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);
636          if (!ExpF2)
637            return ExpF2.takeError();
638          Site.ExtraFiles.push_back(*ExpF2);
639        }
640      }
641      Result->InlineeLines.Sites.push_back(Site);
642    }
643    return Result;
644  }
645  
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());
651    return Result;
652  }
653  
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);
662      if (!ExpectedStr)
663        return ExpectedStr.takeError();
664      YCMI.ModuleName = *ExpectedStr;
665      YCMI.ImportIds.assign(CMI.Imports.begin(), CMI.Imports.end());
666      Result->Imports.push_back(YCMI);
667    }
668    return Result;
669  }
670  
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);
677      if (!S)
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!"),
682                          S.takeError());
683  
684      Result->Symbols.push_back(*S);
685    }
686    return Result;
687  }
688  
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());
694    StringRef S;
695    // First item is a single null string, skip it.
696    if (auto EC = Reader.readCString(S))
697      return std::move(EC);
698    assert(S.empty());
699    while (Reader.bytesRemaining() > 0) {
700      if (auto EC = Reader.readCString(S))
701        return std::move(EC);
702      Result->Strings.push_back(S);
703    }
704    return Result;
705  }
706  
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) {
713      YAMLFrameData YF;
714      YF.CodeSize = F.CodeSize;
715      YF.Flags = F.Flags;
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;
722  
723      auto ES = Strings.getString(F.FrameFunc);
724      if (!ES)
725        return joinErrors(
726            make_error<CodeViewError>(
727                cv_error_code::no_records,
728                "Could not find string for string id while mapping FrameData!"),
729            ES.takeError());
730      YF.FrameFunc = *ES;
731      Result->Frames.push_back(YF);
732    }
733    return Result;
734  }
735  
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);
742    }
743    return Result;
744  }
745  
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);
753  
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));
759    }
760    return std::move(Result);
761  }
762  
763  namespace {
764  
765  struct SubsectionConversionVisitor : public DebugSubsectionVisitor {
766    SubsectionConversionVisitor() = default;
767  
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;
787  
788    YAMLDebugSubsection Subsection;
789  };
790  
791  } // end anonymous namespace
792  
793  Error SubsectionConversionVisitor::visitUnknown(
794      DebugUnknownSubsectionRef &Unknown) {
795    return make_error<CodeViewError>(cv_error_code::operation_unsupported);
796  }
797  
798  Error SubsectionConversionVisitor::visitLines(
799      DebugLinesSubsectionRef &Lines, const StringsAndChecksumsRef &State) {
800    auto Result = YAMLLinesSubsection::fromCodeViewSubsection(
801        State.strings(), State.checksums(), Lines);
802    if (!Result)
803      return Result.takeError();
804    Subsection.Subsection = *Result;
805    return Error::success();
806  }
807  
808  Error SubsectionConversionVisitor::visitFileChecksums(
809      DebugChecksumsSubsectionRef &Checksums,
810      const StringsAndChecksumsRef &State) {
811    auto Result = YAMLChecksumsSubsection::fromCodeViewSubsection(State.strings(),
812                                                                  Checksums);
813    if (!Result)
814      return Result.takeError();
815    Subsection.Subsection = *Result;
816    return Error::success();
817  }
818  
819  Error SubsectionConversionVisitor::visitInlineeLines(
820      DebugInlineeLinesSubsectionRef &Inlinees,
821      const StringsAndChecksumsRef &State) {
822    auto Result = YAMLInlineeLinesSubsection::fromCodeViewSubsection(
823        State.strings(), State.checksums(), Inlinees);
824    if (!Result)
825      return Result.takeError();
826    Subsection.Subsection = *Result;
827    return Error::success();
828  }
829  
830  Error SubsectionConversionVisitor::visitCrossModuleExports(
831      DebugCrossModuleExportsSubsectionRef &Exports,
832      const StringsAndChecksumsRef &State) {
833    auto Result =
834        YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(Exports);
835    if (!Result)
836      return Result.takeError();
837    Subsection.Subsection = *Result;
838    return Error::success();
839  }
840  
841  Error SubsectionConversionVisitor::visitCrossModuleImports(
842      DebugCrossModuleImportsSubsectionRef &Imports,
843      const StringsAndChecksumsRef &State) {
844    auto Result = YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(
845        State.strings(), Imports);
846    if (!Result)
847      return Result.takeError();
848    Subsection.Subsection = *Result;
849    return Error::success();
850  }
851  
852  Error SubsectionConversionVisitor::visitStringTable(
853      DebugStringTableSubsectionRef &Strings,
854      const StringsAndChecksumsRef &State) {
855    auto Result = YAMLStringTableSubsection::fromCodeViewSubsection(Strings);
856    if (!Result)
857      return Result.takeError();
858    Subsection.Subsection = *Result;
859    return Error::success();
860  }
861  
862  Error SubsectionConversionVisitor::visitSymbols(
863      DebugSymbolsSubsectionRef &Symbols, const StringsAndChecksumsRef &State) {
864    auto Result = YAMLSymbolsSubsection::fromCodeViewSubsection(Symbols);
865    if (!Result)
866      return Result.takeError();
867    Subsection.Subsection = *Result;
868    return Error::success();
869  }
870  
871  Error SubsectionConversionVisitor::visitFrameData(
872      DebugFrameDataSubsectionRef &Frames, const StringsAndChecksumsRef &State) {
873    auto Result =
874        YAMLFrameDataSubsection::fromCodeViewSubsection(State.strings(), Frames);
875    if (!Result)
876      return Result.takeError();
877    Subsection.Subsection = *Result;
878    return Error::success();
879  }
880  
881  Error SubsectionConversionVisitor::visitCOFFSymbolRVAs(
882      DebugSymbolRVASubsectionRef &RVAs, const StringsAndChecksumsRef &State) {
883    auto Result = YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(RVAs);
884    if (!Result)
885      return Result.takeError();
886    Subsection.Subsection = *Result;
887    return Error::success();
888  }
889  
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);
896  
897    return V.Subsection;
898  }
899  
900  std::vector<YAMLDebugSubsection>
901  llvm::CodeViewYAML::fromDebugS(ArrayRef<uint8_t> Data,
902                                 const StringsAndChecksumsRef &SC) {
903    BinaryStreamReader Reader(Data, support::little);
904    uint32_t Magic;
905  
906    ExitOnError Err("Invalid .debug$S section!");
907    Err(Reader.readInteger(Magic));
908    assert(Magic == COFF::DEBUG_SECTION_MAGIC && "Invalid .debug$S section!");
909  
910    DebugSubsectionArray Subsections;
911    Err(Reader.readArray(Subsections, Reader.bytesRemaining()));
912  
913    std::vector<YAMLDebugSubsection> Result;
914  
915    for (const auto &SS : Subsections) {
916      auto YamlSS = Err(YAMLDebugSubsection::fromCodeViewSubection(SC, SS));
917      Result.push_back(YamlSS);
918    }
919    return Result;
920  }
921  
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;
926  
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.
930  
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
933    // beginning.
934    if (!SC.hasStrings()) {
935      for (const auto &SS : Sections) {
936        if (SS.Subsection->Kind != DebugSubsectionKind::StringTable)
937          continue;
938  
939        auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC);
940        SC.setStrings(
941            std::static_pointer_cast<DebugStringTableSubsection>(Result));
942        break;
943      }
944    }
945  
946    if (SC.hasStrings() && !SC.hasChecksums()) {
947      for (const auto &SS : Sections) {
948        if (SS.Subsection->Kind != DebugSubsectionKind::FileChecksums)
949          continue;
950  
951        auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC);
952        SC.setChecksums(
953            std::static_pointer_cast<DebugChecksumsSubsection>(Result));
954        break;
955      }
956    }
957  }
958