LLVM  10.0.0svn
CodeViewYAMLDebugSections.cpp
Go to the documentation of this file.
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 
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/StringExtras.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/BinaryFormat/COFF.h"
36 #include "llvm/Support/Allocator.h"
38 #include "llvm/Support/Endian.h"
39 #include "llvm/Support/Error.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 
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 
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()
108 
109  void map(IO &IO) override;
110  std::shared_ptr<DebugSubsection>
111  toCodeViewSubsection(BumpPtrAllocator &Allocator,
112  const codeview::StringsAndChecksums &SC) const override;
114  fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
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;
128  fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
129  const DebugChecksumsSubsectionRef &Checksums,
131 
133 };
134 
135 struct YAMLInlineeLinesSubsection : public YAMLSubsectionBase {
136  YAMLInlineeLinesSubsection()
138 
139  void map(IO &IO) override;
140  std::shared_ptr<DebugSubsection>
141  toCodeViewSubsection(BumpPtrAllocator &Allocator,
142  const codeview::StringsAndChecksums &SC) const override;
144  fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
145  const DebugChecksumsSubsectionRef &Checksums,
147 
149 };
150 
151 struct YAMLCrossModuleExportsSubsection : public YAMLSubsectionBase {
152  YAMLCrossModuleExportsSubsection()
154 
155  void map(IO &IO) override;
156  std::shared_ptr<DebugSubsection>
157  toCodeViewSubsection(BumpPtrAllocator &Allocator,
158  const codeview::StringsAndChecksums &SC) const override;
160  fromCodeViewSubsection(const DebugCrossModuleExportsSubsectionRef &Exports);
161 
162  std::vector<CrossModuleExport> Exports;
163 };
164 
165 struct YAMLCrossModuleImportsSubsection : public YAMLSubsectionBase {
166  YAMLCrossModuleImportsSubsection()
168 
169  void map(IO &IO) override;
170  std::shared_ptr<DebugSubsection>
171  toCodeViewSubsection(BumpPtrAllocator &Allocator,
172  const codeview::StringsAndChecksums &SC) const override;
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;
188  fromCodeViewSubsection(const DebugSymbolsSubsectionRef &Symbols);
189 
190  std::vector<CodeViewYAML::SymbolRecord> Symbols;
191 };
192 
193 struct YAMLStringTableSubsection : public YAMLSubsectionBase {
194  YAMLStringTableSubsection()
196 
197  void map(IO &IO) override;
198  std::shared_ptr<DebugSubsection>
199  toCodeViewSubsection(BumpPtrAllocator &Allocator,
200  const codeview::StringsAndChecksums &SC) const override;
202  fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings);
203 
204  std::vector<StringRef> Strings;
205 };
206 
207 struct YAMLFrameDataSubsection : public YAMLSubsectionBase {
208  YAMLFrameDataSubsection()
210 
211  void map(IO &IO) override;
212  std::shared_ptr<DebugSubsection>
213  toCodeViewSubsection(BumpPtrAllocator &Allocator,
214  const codeview::StringsAndChecksums &SC) const override;
216  fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
217  const DebugFrameDataSubsectionRef &Frames);
218 
219  std::vector<YAMLFrameData> Frames;
220 };
221 
222 struct YAMLCoffSymbolRVASubsection : public YAMLSubsectionBase {
223  YAMLCoffSymbolRVASubsection()
225 
226  void map(IO &IO) override;
227  std::shared_ptr<DebugSubsection>
228  toCodeViewSubsection(BumpPtrAllocator &Allocator,
229  const codeview::StringsAndChecksums &SC) const override;
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 
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 
273  IO.mapRequired("StartColumn", Obj.StartColumn);
274  IO.mapRequired("EndColumn", Obj.EndColumn);
275 }
276 
278  IO.mapRequired("FileName", Obj.FileName);
279  IO.mapRequired("Lines", Obj.Lines);
280  IO.mapRequired("Columns", Obj.Columns);
281 }
282 
284  IO.mapRequired("LocalId", Obj.Local);
285  IO.mapRequired("GlobalId", Obj.Global);
286 }
287 
289  YAMLCrossModuleImport &Obj) {
290  IO.mapRequired("Module", Obj.ModuleName);
291  IO.mapRequired("Imports", Obj.ImportIds);
292 }
293 
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 
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 
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 
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(
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 (const auto &Item : zip(LC.Lines, LC.Columns)) {
425  auto &L = std::get<0>(Item);
426  auto &C = std::get<1>(Item);
427  uint32_t LE = L.LineStart + L.EndDelta;
428  Result->addLineAndColumnInfo(L.Offset,
429  LineInfo(L.LineStart, LE, L.IsStatement),
430  C.StartColumn, C.EndColumn);
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) {
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 
542  const FileChecksumEntry &CS) {
543  auto ExpectedString = Strings.getString(CS.FileNameOffset);
544  if (!ExpectedString)
545  return ExpectedString.takeError();
546 
548  Result.ChecksumBytes.Bytes = CS.Checksum;
549  Result.Kind = CS.Kind;
550  Result.FileName = *ExpectedString;
551  return Result;
552 }
553 
554 static Expected<StringRef>
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 
565 YAMLChecksumsSubsection::fromCodeViewSubsection(
566  const DebugStringTableSubsectionRef &Strings,
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 
580 YAMLLinesSubsection::fromCodeViewSubsection(
581  const DebugStringTableSubsectionRef &Strings,
582  const DebugChecksumsSubsectionRef &Checksums,
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) {
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 
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 
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 
655 YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(
656  const DebugStringTableSubsectionRef &Strings,
657  const DebugCrossModuleImportsSubsectionRef &Imports) {
658  auto Result = std::make_shared<YAMLCrossModuleImportsSubsection>();
659  for (const auto &CMI : Imports) {
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 
672 YAMLSymbolsSubsection::fromCodeViewSubsection(
674  auto Result = std::make_shared<YAMLSymbolsSubsection>();
675  for (const auto &Sym : Symbols) {
677  if (!S)
678  return joinErrors(make_error<CodeViewError>(
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 
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 
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>(
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 
737 YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(
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 
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(
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(
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(
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(
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(
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(
883  auto Result = YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(RVAs);
884  if (!Result)
885  return Result.takeError();
886  Subsection.Subsection = *Result;
887  return Error::success();
888 }
889 
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>
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 
924  // String Table and Checksums subsections don't use the 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 }
std::vector< SourceLineEntry > Lines
This class represents lattice values for constants.
Definition: AllocatorList.h:23
Error readInteger(T &Dest)
Read an integer of the specified endianness into Dest and update the stream&#39;s offset.
Data in the SUBSEC_FRAMEDATA subection.
Definition: CodeView.h:569
uint32_t getStartLine() const
Definition: Line.h:39
Iterator end() const
support::ulittle32_t RvaStart
Definition: CodeView.h:570
Helper for check-and-exit error handling.
Definition: Error.h:1273
F(f)
std::vector< YAMLDebugSubsection > fromDebugS(ArrayRef< uint8_t > Data, const codeview::StringsAndChecksumsRef &SC)
Expected< StringRef > getString(uint32_t Offset) const
This file defines the MallocAllocator and BumpPtrAllocator interfaces.
std::string fromHex(StringRef Input)
Convert hexadecimal string Input to its binary representation.
Definition: StringExtras.h:170
support::ulittle16_t PrologSize
Definition: CodeView.h:576
support::ulittle32_t CodeSize
Definition: CodeView.h:571
support::ulittle32_t MaxStackSize
Definition: CodeView.h:574
const DebugStringTableSubsectionRef & strings() const
Tagged union holding either a T or a Error.
Definition: yaml2obj.h:21
uint32_t getLineDelta() const
Definition: Line.h:41
void initializeStringsAndChecksums(ArrayRef< YAMLDebugSubsection > Sections, codeview::StringsAndChecksums &SC)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
Definition: APInt.h:32
A 32-bit type reference.
Definition: TypeIndex.h:95
static Expected< SourceFileChecksumEntry > convertOneChecksum(const DebugStringTableSubsectionRef &Strings, const FileChecksumEntry &CS)
static Expected< StringRef > getFileName(const DebugStringTableSubsectionRef &Strings, const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID)
support::ulittle32_t ParamsSize
Definition: CodeView.h:573
bool isStatement() const
Definition: Line.h:47
Allocate memory in an ever growing pool, as if by bump-pointer.
Definition: Allocator.h:140
support::ulittle32_t Flags
Definition: CodeView.h:578
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&... args)
zip iterator for two or more iteratable types.
Definition: STLExtras.h:655
#define H(x, y, z)
Definition: MD5.cpp:57
static Expected< SymbolRecord > fromCodeViewSymbol(codeview::CVSymbol Symbol)
std::vector< SourceColumnEntry > Columns
support::ulittle32_t LocalSize
Definition: CodeView.h:572
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void setChecksums(const ChecksumsPtr &CP)
const ChecksumsPtr & checksums() const
void setStrings(const StringsPtr &SP)
static const char *const Magic
Definition: Archive.cpp:41
const StringsPtr & strings() const
Basic Register Allocator
static ErrorSuccess success()
Create a success value.
Definition: Error.h:326
CHAIN = SC CHAIN, Imm128 - System call.
std::shared_ptr< detail::YAMLSubsectionBase > Subsection
Error visitDebugSubsection(const DebugSubsectionRecord &R, DebugSubsectionVisitor &V, const StringsAndChecksumsRef &State)
Represents a read-only view of a CodeView string table.
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition: Error.h:423
support::ulittle32_t Local
Definition: CodeView.h:594
uint32_t bytesRemaining() const
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Iterator at(uint32_t Offset) const
given an offset into the array&#39;s underlying stream, return an iterator to the record at that offset...
LLVM Value Representation.
Definition: Value.h:73
const DebugChecksumsSubsectionRef & checksums() const
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
support::ulittle32_t FrameFunc
Definition: CodeView.h:575
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:45
Provides read only access to a subclass of BinaryStream.
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
const LineFragmentHeader * header() const
std::string toHex(StringRef Input, bool LowerCase=false)
Convert buffer Input to its hexadecimal representation.
Definition: StringExtras.h:141
Expected< std::vector< std::shared_ptr< codeview::DebugSubsection > > > toCodeViewSubsectionList(BumpPtrAllocator &Allocator, ArrayRef< YAMLDebugSubsection > Subsections, const codeview::StringsAndChecksums &SC)
Error readArray(ArrayRef< T > &Array, uint32_t NumElements)
Get a reference to a NumElements element array of objects of type T from the underlying stream as if ...
support::ulittle32_t Global
Definition: CodeView.h:595
bool empty() const
empty - Check if the array is empty.
Definition: ArrayRef.h:143
support::ulittle16_t SavedRegsSize
Definition: CodeView.h:577