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
51using namespace llvm;
52using namespace llvm::codeview;
53using namespace llvm::CodeViewYAML;
54using namespace llvm::CodeViewYAML::detail;
55using namespace llvm::yaml;
56
57LLVM_YAML_IS_SEQUENCE_VECTOR(SourceFileChecksumEntry)
58LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineEntry)
59LLVM_YAML_IS_SEQUENCE_VECTOR(SourceColumnEntry)
60LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineBlock)
61LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineInfo)
62LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeSite)
63LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeInfo)
64LLVM_YAML_IS_SEQUENCE_VECTOR(CrossModuleExport)
65LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLCrossModuleImport)
66LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLFrameData)
67
68LLVM_YAML_DECLARE_SCALAR_TRAITS(HexFormattedString, QuotingType::None)
69LLVM_YAML_DECLARE_ENUM_TRAITS(DebugSubsectionKind)
70LLVM_YAML_DECLARE_ENUM_TRAITS(FileChecksumKind)
71LLVM_YAML_DECLARE_BITSET_TRAITS(LineFlags)
72
73LLVM_YAML_DECLARE_MAPPING_TRAITS(CrossModuleExport)
74LLVM_YAML_DECLARE_MAPPING_TRAITS(YAMLFrameData)
75LLVM_YAML_DECLARE_MAPPING_TRAITS(YAMLCrossModuleImport)
76LLVM_YAML_DECLARE_MAPPING_TRAITS(CrossModuleImportItem)
77LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineEntry)
78LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceColumnEntry)
79LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceFileChecksumEntry)
80LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineBlock)
81LLVM_YAML_DECLARE_MAPPING_TRAITS(InlineeSite)
82
83namespace llvm {
84namespace CodeViewYAML {
85namespace detail {
86
87struct 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
103namespace {
104
105struct 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
120struct 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
135struct 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
151struct 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
165struct 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
180struct 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
193struct 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
207struct 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
222struct 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
238void ScalarBitSetTraits<LineFlags>::bitset(IO &io, LineFlags &Flags) {
239  io.bitSetCase(Flags, "HasColumnInfo", LF_HaveColumns);
240  io.enumFallback<Hex16>(Flags);
241}
242
243void 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
251void 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
258StringRef 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
265void 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
272void MappingTraits<SourceColumnEntry>::mapping(IO &IO, SourceColumnEntry &Obj) {
273  IO.mapRequired("StartColumn", Obj.StartColumn);
274  IO.mapRequired("EndColumn", Obj.EndColumn);
275}
276
277void 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
283void MappingTraits<CrossModuleExport>::mapping(IO &IO, CrossModuleExport &Obj) {
284  IO.mapRequired("LocalId", Obj.Local);
285  IO.mapRequired("GlobalId", Obj.Global);
286}
287
288void MappingTraits<YAMLCrossModuleImport>::mapping(IO &IO,
289                                                   YAMLCrossModuleImport &Obj) {
290  IO.mapRequired("Module", Obj.ModuleName);
291  IO.mapRequired("Imports", Obj.ImportIds);
292}
293
294void 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
301void 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
308void 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
319void YAMLChecksumsSubsection::map(IO &IO) {
320  IO.mapTag("!FileChecksums", true);
321  IO.mapRequired("Checksums", Checksums);
322}
323
324void 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
334void YAMLInlineeLinesSubsection::map(IO &IO) {
335  IO.mapTag("!InlineeLines", true);
336  IO.mapRequired("HasExtraFiles", InlineeLines.HasExtraFiles);
337  IO.mapRequired("Sites", InlineeLines.Sites);
338}
339
340void YAMLCrossModuleExportsSubsection::map(IO &IO) {
341  IO.mapTag("!CrossModuleExports", true);
342  IO.mapOptional("Exports", Exports);
343}
344
345void YAMLCrossModuleImportsSubsection::map(IO &IO) {
346  IO.mapTag("!CrossModuleImports", true);
347  IO.mapOptional("Imports", Imports);
348}
349
350void YAMLSymbolsSubsection::map(IO &IO) {
351  IO.mapTag("!Symbols", true);
352  IO.mapRequired("Records", Symbols);
353}
354
355void YAMLStringTableSubsection::map(IO &IO) {
356  IO.mapTag("!StringTable", true);
357  IO.mapRequired("Strings", Strings);
358}
359
360void YAMLFrameDataSubsection::map(IO &IO) {
361  IO.mapTag("!FrameData", true);
362  IO.mapRequired("Frames", Frames);
363}
364
365void YAMLCoffSymbolRVASubsection::map(IO &IO) {
366  IO.mapTag("!COFFSymbolRVAs", true);
367  IO.mapRequired("RVAs", RVAs);
368}
369
370void 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
401std::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
412std::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
442std::shared_ptr<DebugSubsection>
443YAMLInlineeLinesSubsection::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
463std::shared_ptr<DebugSubsection>
464YAMLCrossModuleExportsSubsection::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
473std::shared_ptr<DebugSubsection>
474YAMLCrossModuleImportsSubsection::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
488std::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
498std::shared_ptr<DebugSubsection>
499YAMLStringTableSubsection::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
508std::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
530std::shared_ptr<DebugSubsection>
531YAMLCoffSymbolRVASubsection::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
540static Expected<SourceFileChecksumEntry>
541convertOneChecksum(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
554static Expected<StringRef>
555getFileName(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
564Expected<std::shared_ptr<YAMLChecksumsSubsection>>
565YAMLChecksumsSubsection::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
579Expected<std::shared_ptr<YAMLLinesSubsection>>
580YAMLLinesSubsection::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
617Expected<std::shared_ptr<YAMLInlineeLinesSubsection>>
618YAMLInlineeLinesSubsection::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
646Expected<std::shared_ptr<YAMLCrossModuleExportsSubsection>>
647YAMLCrossModuleExportsSubsection::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
654Expected<std::shared_ptr<YAMLCrossModuleImportsSubsection>>
655YAMLCrossModuleImportsSubsection::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
671Expected<std::shared_ptr<YAMLSymbolsSubsection>>
672YAMLSymbolsSubsection::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
689Expected<std::shared_ptr<YAMLStringTableSubsection>>
690YAMLStringTableSubsection::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
707Expected<std::shared_ptr<YAMLFrameDataSubsection>>
708YAMLFrameDataSubsection::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
736Expected<std::shared_ptr<YAMLCoffSymbolRVASubsection>>
737YAMLCoffSymbolRVASubsection::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
746Expected<std::vector<std::shared_ptr<DebugSubsection>>>
747llvm::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
763namespace {
764
765struct 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
793Error SubsectionConversionVisitor::visitUnknown(
794    DebugUnknownSubsectionRef &Unknown) {
795  return make_error<CodeViewError>(cv_error_code::operation_unsupported);
796}
797
798Error 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
808Error 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
819Error 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
830Error 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
841Error 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
852Error 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
862Error 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
871Error 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
881Error 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
890Expected<YAMLDebugSubsection>
891YAMLDebugSubsection::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
900std::vector<YAMLDebugSubsection>
901llvm::CodeViewYAML::fromDebugS(ArrayRef<uint8_t> Data,
902                               const StringsAndChecksumsRef &SC) {
903  BinaryStreamReader Reader(Data, llvm::endianness::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
922void 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