LLVM  6.0.0svn
CodeViewYAMLDebugSections.cpp
Go to the documentation of this file.
1 //===- CodeViewYAMLDebugSections.cpp - CodeView YAMLIO debug sections -----===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines classes for handling the YAML representation of CodeView
11 // Debug Info.
12 //
13 //===----------------------------------------------------------------------===//
14 
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/BinaryFormat/COFF.h"
37 #include "llvm/Support/Allocator.h"
39 #include "llvm/Support/Endian.h"
40 #include "llvm/Support/Error.h"
44 #include <algorithm>
45 #include <cassert>
46 #include <cstdint>
47 #include <memory>
48 #include <string>
49 #include <tuple>
50 #include <vector>
51 
52 using namespace llvm;
53 using namespace llvm::codeview;
54 using namespace llvm::CodeViewYAML;
55 using namespace llvm::CodeViewYAML::detail;
56 using namespace llvm::yaml;
57 
68 
73 
83 
84 namespace llvm {
85 namespace CodeViewYAML {
86 namespace detail {
87 
89  explicit YAMLSubsectionBase(DebugSubsectionKind Kind) : Kind(Kind) {}
90  virtual ~YAMLSubsectionBase() = default;
91 
92  virtual void map(IO &IO) = 0;
93  virtual std::shared_ptr<DebugSubsection>
94  toCodeViewSubsection(BumpPtrAllocator &Allocator,
95  const codeview::StringsAndChecksums &SC) const = 0;
96 
98 };
99 
100 } // end namespace detail
101 } // end namespace CodeViewYAML
102 } // end namespace llvm
103 
104 namespace {
105 
106 struct YAMLChecksumsSubsection : public YAMLSubsectionBase {
107  YAMLChecksumsSubsection()
109 
110  void map(IO &IO) override;
111  std::shared_ptr<DebugSubsection>
112  toCodeViewSubsection(BumpPtrAllocator &Allocator,
113  const codeview::StringsAndChecksums &SC) const override;
115  fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
117 
118  std::vector<SourceFileChecksumEntry> Checksums;
119 };
120 
121 struct YAMLLinesSubsection : public YAMLSubsectionBase {
122  YAMLLinesSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Lines) {}
123 
124  void map(IO &IO) override;
125  std::shared_ptr<DebugSubsection>
126  toCodeViewSubsection(BumpPtrAllocator &Allocator,
127  const codeview::StringsAndChecksums &SC) const override;
129  fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
130  const DebugChecksumsSubsectionRef &Checksums,
132 
134 };
135 
136 struct YAMLInlineeLinesSubsection : public YAMLSubsectionBase {
137  YAMLInlineeLinesSubsection()
139 
140  void map(IO &IO) override;
141  std::shared_ptr<DebugSubsection>
142  toCodeViewSubsection(BumpPtrAllocator &Allocator,
143  const codeview::StringsAndChecksums &SC) const override;
145  fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
146  const DebugChecksumsSubsectionRef &Checksums,
148 
150 };
151 
152 struct YAMLCrossModuleExportsSubsection : public YAMLSubsectionBase {
153  YAMLCrossModuleExportsSubsection()
155 
156  void map(IO &IO) override;
157  std::shared_ptr<DebugSubsection>
158  toCodeViewSubsection(BumpPtrAllocator &Allocator,
159  const codeview::StringsAndChecksums &SC) const override;
161  fromCodeViewSubsection(const DebugCrossModuleExportsSubsectionRef &Exports);
162 
163  std::vector<CrossModuleExport> Exports;
164 };
165 
166 struct YAMLCrossModuleImportsSubsection : public YAMLSubsectionBase {
167  YAMLCrossModuleImportsSubsection()
169 
170  void map(IO &IO) override;
171  std::shared_ptr<DebugSubsection>
172  toCodeViewSubsection(BumpPtrAllocator &Allocator,
173  const codeview::StringsAndChecksums &SC) const override;
175  fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
176  const DebugCrossModuleImportsSubsectionRef &Imports);
177 
178  std::vector<YAMLCrossModuleImport> Imports;
179 };
180 
181 struct YAMLSymbolsSubsection : public YAMLSubsectionBase {
182  YAMLSymbolsSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Symbols) {}
183 
184  void map(IO &IO) override;
185  std::shared_ptr<DebugSubsection>
186  toCodeViewSubsection(BumpPtrAllocator &Allocator,
187  const codeview::StringsAndChecksums &SC) const override;
189  fromCodeViewSubsection(const DebugSymbolsSubsectionRef &Symbols);
190 
191  std::vector<CodeViewYAML::SymbolRecord> Symbols;
192 };
193 
194 struct YAMLStringTableSubsection : public YAMLSubsectionBase {
195  YAMLStringTableSubsection()
197 
198  void map(IO &IO) override;
199  std::shared_ptr<DebugSubsection>
200  toCodeViewSubsection(BumpPtrAllocator &Allocator,
201  const codeview::StringsAndChecksums &SC) const override;
203  fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings);
204 
205  std::vector<StringRef> Strings;
206 };
207 
208 struct YAMLFrameDataSubsection : public YAMLSubsectionBase {
209  YAMLFrameDataSubsection()
211 
212  void map(IO &IO) override;
213  std::shared_ptr<DebugSubsection>
214  toCodeViewSubsection(BumpPtrAllocator &Allocator,
215  const codeview::StringsAndChecksums &SC) const override;
217  fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
218  const DebugFrameDataSubsectionRef &Frames);
219 
220  std::vector<YAMLFrameData> Frames;
221 };
222 
223 struct YAMLCoffSymbolRVASubsection : public YAMLSubsectionBase {
224  YAMLCoffSymbolRVASubsection()
226 
227  void map(IO &IO) override;
228  std::shared_ptr<DebugSubsection>
229  toCodeViewSubsection(BumpPtrAllocator &Allocator,
230  const codeview::StringsAndChecksums &SC) const override;
232  fromCodeViewSubsection(const DebugSymbolRVASubsectionRef &RVAs);
233 
234  std::vector<uint32_t> RVAs;
235 };
236 
237 } // end anonymous namespace
238 
240  io.bitSetCase(Flags, "HasColumnInfo", LF_HaveColumns);
241  io.enumFallback<Hex16>(Flags);
242 }
243 
245  IO &io, FileChecksumKind &Kind) {
246  io.enumCase(Kind, "None", FileChecksumKind::None);
247  io.enumCase(Kind, "MD5", FileChecksumKind::MD5);
248  io.enumCase(Kind, "SHA1", FileChecksumKind::SHA1);
249  io.enumCase(Kind, "SHA256", FileChecksumKind::SHA256);
250 }
251 
253  void *ctx, raw_ostream &Out) {
254  StringRef Bytes(reinterpret_cast<const char *>(Value.Bytes.data()),
255  Value.Bytes.size());
256  Out << toHex(Bytes);
257 }
258 
260  HexFormattedString &Value) {
261  std::string H = fromHex(Scalar);
262  Value.Bytes.assign(H.begin(), H.end());
263  return StringRef();
264 }
265 
267  IO.mapRequired("Offset", Obj.Offset);
268  IO.mapRequired("LineStart", Obj.LineStart);
269  IO.mapRequired("IsStatement", Obj.IsStatement);
270  IO.mapRequired("EndDelta", Obj.EndDelta);
271 }
272 
274  IO.mapRequired("StartColumn", Obj.StartColumn);
275  IO.mapRequired("EndColumn", Obj.EndColumn);
276 }
277 
279  IO.mapRequired("FileName", Obj.FileName);
280  IO.mapRequired("Lines", Obj.Lines);
281  IO.mapRequired("Columns", Obj.Columns);
282 }
283 
285  IO.mapRequired("LocalId", Obj.Local);
286  IO.mapRequired("GlobalId", Obj.Global);
287 }
288 
290  YAMLCrossModuleImport &Obj) {
291  IO.mapRequired("Module", Obj.ModuleName);
292  IO.mapRequired("Imports", Obj.ImportIds);
293 }
294 
296  IO &IO, SourceFileChecksumEntry &Obj) {
297  IO.mapRequired("FileName", Obj.FileName);
298  IO.mapRequired("Kind", Obj.Kind);
299  IO.mapRequired("Checksum", Obj.ChecksumBytes);
300 }
301 
303  IO.mapRequired("FileName", Obj.FileName);
304  IO.mapRequired("LineNum", Obj.SourceLineNum);
305  IO.mapRequired("Inlinee", Obj.Inlinee);
306  IO.mapOptional("ExtraFiles", Obj.ExtraFiles);
307 }
308 
310  IO.mapRequired("CodeSize", Obj.CodeSize);
311  IO.mapRequired("FrameFunc", Obj.FrameFunc);
312  IO.mapRequired("LocalSize", Obj.LocalSize);
313  IO.mapOptional("MaxStackSize", Obj.MaxStackSize);
314  IO.mapOptional("ParamsSize", Obj.ParamsSize);
315  IO.mapOptional("PrologSize", Obj.PrologSize);
316  IO.mapOptional("RvaStart", Obj.RvaStart);
317  IO.mapOptional("SavedRegsSize", Obj.SavedRegsSize);
318 }
319 
320 void YAMLChecksumsSubsection::map(IO &IO) {
321  IO.mapTag("!FileChecksums", true);
322  IO.mapRequired("Checksums", Checksums);
323 }
324 
325 void YAMLLinesSubsection::map(IO &IO) {
326  IO.mapTag("!Lines", true);
327  IO.mapRequired("CodeSize", Lines.CodeSize);
328 
329  IO.mapRequired("Flags", Lines.Flags);
330  IO.mapRequired("RelocOffset", Lines.RelocOffset);
331  IO.mapRequired("RelocSegment", Lines.RelocSegment);
332  IO.mapRequired("Blocks", Lines.Blocks);
333 }
334 
335 void YAMLInlineeLinesSubsection::map(IO &IO) {
336  IO.mapTag("!InlineeLines", true);
337  IO.mapRequired("HasExtraFiles", InlineeLines.HasExtraFiles);
338  IO.mapRequired("Sites", InlineeLines.Sites);
339 }
340 
341 void YAMLCrossModuleExportsSubsection::map(IO &IO) {
342  IO.mapTag("!CrossModuleExports", true);
343  IO.mapOptional("Exports", Exports);
344 }
345 
346 void YAMLCrossModuleImportsSubsection::map(IO &IO) {
347  IO.mapTag("!CrossModuleImports", true);
348  IO.mapOptional("Imports", Imports);
349 }
350 
351 void YAMLSymbolsSubsection::map(IO &IO) {
352  IO.mapTag("!Symbols", true);
353  IO.mapRequired("Records", Symbols);
354 }
355 
356 void YAMLStringTableSubsection::map(IO &IO) {
357  IO.mapTag("!StringTable", true);
358  IO.mapRequired("Strings", Strings);
359 }
360 
361 void YAMLFrameDataSubsection::map(IO &IO) {
362  IO.mapTag("!FrameData", true);
363  IO.mapRequired("Frames", Frames);
364 }
365 
366 void YAMLCoffSymbolRVASubsection::map(IO &IO) {
367  IO.mapTag("!COFFSymbolRVAs", true);
368  IO.mapRequired("RVAs", RVAs);
369 }
370 
372  IO &IO, YAMLDebugSubsection &Subsection) {
373  if (!IO.outputting()) {
374  if (IO.mapTag("!FileChecksums")) {
375  auto SS = std::make_shared<YAMLChecksumsSubsection>();
376  Subsection.Subsection = SS;
377  } else if (IO.mapTag("!Lines")) {
378  Subsection.Subsection = std::make_shared<YAMLLinesSubsection>();
379  } else if (IO.mapTag("!InlineeLines")) {
380  Subsection.Subsection = std::make_shared<YAMLInlineeLinesSubsection>();
381  } else if (IO.mapTag("!CrossModuleExports")) {
382  Subsection.Subsection =
383  std::make_shared<YAMLCrossModuleExportsSubsection>();
384  } else if (IO.mapTag("!CrossModuleImports")) {
385  Subsection.Subsection =
386  std::make_shared<YAMLCrossModuleImportsSubsection>();
387  } else if (IO.mapTag("!Symbols")) {
388  Subsection.Subsection = std::make_shared<YAMLSymbolsSubsection>();
389  } else if (IO.mapTag("!StringTable")) {
390  Subsection.Subsection = std::make_shared<YAMLStringTableSubsection>();
391  } else if (IO.mapTag("!FrameData")) {
392  Subsection.Subsection = std::make_shared<YAMLFrameDataSubsection>();
393  } else if (IO.mapTag("!COFFSymbolRVAs")) {
394  Subsection.Subsection = std::make_shared<YAMLCoffSymbolRVASubsection>();
395  } else {
396  llvm_unreachable("Unexpected subsection tag!");
397  }
398  }
399  Subsection.Subsection->map(IO);
400 }
401 
402 std::shared_ptr<DebugSubsection> YAMLChecksumsSubsection::toCodeViewSubsection(
404  const codeview::StringsAndChecksums &SC) const {
405  assert(SC.hasStrings());
406  auto Result = std::make_shared<DebugChecksumsSubsection>(*SC.strings());
407  for (const auto &CS : Checksums) {
408  Result->addChecksum(CS.FileName, CS.Kind, CS.ChecksumBytes.Bytes);
409  }
410  return Result;
411 }
412 
413 std::shared_ptr<DebugSubsection> YAMLLinesSubsection::toCodeViewSubsection(
414  BumpPtrAllocator &Allocator,
415  const codeview::StringsAndChecksums &SC) const {
416  assert(SC.hasStrings() && SC.hasChecksums());
417  auto Result =
418  std::make_shared<DebugLinesSubsection>(*SC.checksums(), *SC.strings());
419  Result->setCodeSize(Lines.CodeSize);
420  Result->setRelocationAddress(Lines.RelocSegment, Lines.RelocOffset);
421  Result->setFlags(Lines.Flags);
422  for (const auto &LC : Lines.Blocks) {
423  Result->createBlock(LC.FileName);
424  if (Result->hasColumnInfo()) {
425  for (const auto &Item : zip(LC.Lines, LC.Columns)) {
426  auto &L = std::get<0>(Item);
427  auto &C = std::get<1>(Item);
428  uint32_t LE = L.LineStart + L.EndDelta;
429  Result->addLineAndColumnInfo(L.Offset,
430  LineInfo(L.LineStart, LE, L.IsStatement),
431  C.StartColumn, C.EndColumn);
432  }
433  } else {
434  for (const auto &L : LC.Lines) {
435  uint32_t LE = L.LineStart + L.EndDelta;
436  Result->addLineInfo(L.Offset, LineInfo(L.LineStart, LE, L.IsStatement));
437  }
438  }
439  }
440  return Result;
441 }
442 
443 std::shared_ptr<DebugSubsection>
444 YAMLInlineeLinesSubsection::toCodeViewSubsection(
445  BumpPtrAllocator &Allocator,
446  const codeview::StringsAndChecksums &SC) const {
447  assert(SC.hasChecksums());
448  auto Result = std::make_shared<DebugInlineeLinesSubsection>(
449  *SC.checksums(), InlineeLines.HasExtraFiles);
450 
451  for (const auto &Site : InlineeLines.Sites) {
452  Result->addInlineSite(TypeIndex(Site.Inlinee), Site.FileName,
453  Site.SourceLineNum);
454  if (!InlineeLines.HasExtraFiles)
455  continue;
456 
457  for (auto EF : Site.ExtraFiles) {
458  Result->addExtraFile(EF);
459  }
460  }
461  return Result;
462 }
463 
464 std::shared_ptr<DebugSubsection>
465 YAMLCrossModuleExportsSubsection::toCodeViewSubsection(
466  BumpPtrAllocator &Allocator,
467  const codeview::StringsAndChecksums &SC) const {
468  auto Result = std::make_shared<DebugCrossModuleExportsSubsection>();
469  for (const auto &M : Exports)
470  Result->addMapping(M.Local, M.Global);
471  return Result;
472 }
473 
474 std::shared_ptr<DebugSubsection>
475 YAMLCrossModuleImportsSubsection::toCodeViewSubsection(
476  BumpPtrAllocator &Allocator,
477  const codeview::StringsAndChecksums &SC) const {
478  assert(SC.hasStrings());
479 
480  auto Result =
481  std::make_shared<DebugCrossModuleImportsSubsection>(*SC.strings());
482  for (const auto &M : Imports) {
483  for (const auto Id : M.ImportIds)
484  Result->addImport(M.ModuleName, Id);
485  }
486  return Result;
487 }
488 
489 std::shared_ptr<DebugSubsection> YAMLSymbolsSubsection::toCodeViewSubsection(
490  BumpPtrAllocator &Allocator,
491  const codeview::StringsAndChecksums &SC) const {
492  auto Result = std::make_shared<DebugSymbolsSubsection>();
493  for (const auto &Sym : Symbols)
494  Result->addSymbol(
495  Sym.toCodeViewSymbol(Allocator, CodeViewContainer::ObjectFile));
496  return Result;
497 }
498 
499 std::shared_ptr<DebugSubsection>
500 YAMLStringTableSubsection::toCodeViewSubsection(
501  BumpPtrAllocator &Allocator,
502  const codeview::StringsAndChecksums &SC) const {
503  auto Result = std::make_shared<DebugStringTableSubsection>();
504  for (const auto &Str : this->Strings)
505  Result->insert(Str);
506  return Result;
507 }
508 
509 std::shared_ptr<DebugSubsection> YAMLFrameDataSubsection::toCodeViewSubsection(
510  BumpPtrAllocator &Allocator,
511  const codeview::StringsAndChecksums &SC) const {
512  assert(SC.hasStrings());
513 
514  auto Result = std::make_shared<DebugFrameDataSubsection>();
515  for (const auto &YF : Frames) {
517  F.CodeSize = YF.CodeSize;
518  F.Flags = YF.Flags;
519  F.LocalSize = YF.LocalSize;
520  F.MaxStackSize = YF.MaxStackSize;
521  F.ParamsSize = YF.ParamsSize;
522  F.PrologSize = YF.PrologSize;
523  F.RvaStart = YF.RvaStart;
524  F.SavedRegsSize = YF.SavedRegsSize;
525  F.FrameFunc = SC.strings()->insert(YF.FrameFunc);
526  Result->addFrameData(F);
527  }
528  return Result;
529 }
530 
531 std::shared_ptr<DebugSubsection>
532 YAMLCoffSymbolRVASubsection::toCodeViewSubsection(
533  BumpPtrAllocator &Allocator,
534  const codeview::StringsAndChecksums &SC) const {
535  auto Result = std::make_shared<DebugSymbolRVASubsection>();
536  for (const auto &RVA : RVAs)
537  Result->addRVA(RVA);
538  return Result;
539 }
540 
543  const FileChecksumEntry &CS) {
544  auto ExpectedString = Strings.getString(CS.FileNameOffset);
545  if (!ExpectedString)
546  return ExpectedString.takeError();
547 
549  Result.ChecksumBytes.Bytes = CS.Checksum;
550  Result.Kind = CS.Kind;
551  Result.FileName = *ExpectedString;
552  return Result;
553 }
554 
555 static Expected<StringRef>
557  const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID) {
558  auto Iter = Checksums.getArray().at(FileID);
559  if (Iter == Checksums.getArray().end())
560  return make_error<CodeViewError>(cv_error_code::no_records);
561  uint32_t Offset = Iter->FileNameOffset;
562  return Strings.getString(Offset);
563 }
564 
566 YAMLChecksumsSubsection::fromCodeViewSubsection(
567  const DebugStringTableSubsectionRef &Strings,
569  auto Result = std::make_shared<YAMLChecksumsSubsection>();
570 
571  for (const auto &CS : FC) {
572  auto ConvertedCS = convertOneChecksum(Strings, CS);
573  if (!ConvertedCS)
574  return ConvertedCS.takeError();
575  Result->Checksums.push_back(*ConvertedCS);
576  }
577  return Result;
578 }
579 
581 YAMLLinesSubsection::fromCodeViewSubsection(
582  const DebugStringTableSubsectionRef &Strings,
583  const DebugChecksumsSubsectionRef &Checksums,
585  auto Result = std::make_shared<YAMLLinesSubsection>();
586  Result->Lines.CodeSize = Lines.header()->CodeSize;
587  Result->Lines.RelocOffset = Lines.header()->RelocOffset;
588  Result->Lines.RelocSegment = Lines.header()->RelocSegment;
589  Result->Lines.Flags = static_cast<LineFlags>(uint16_t(Lines.header()->Flags));
590  for (const auto &L : Lines) {
591  SourceLineBlock Block;
592  auto EF = getFileName(Strings, Checksums, L.NameIndex);
593  if (!EF)
594  return EF.takeError();
595  Block.FileName = *EF;
596  if (Lines.hasColumnInfo()) {
597  for (const auto &C : L.Columns) {
599  SCE.EndColumn = C.EndColumn;
600  SCE.StartColumn = C.StartColumn;
601  Block.Columns.push_back(SCE);
602  }
603  }
604  for (const auto &LN : L.LineNumbers) {
605  SourceLineEntry SLE;
606  LineInfo LI(LN.Flags);
607  SLE.Offset = LN.Offset;
608  SLE.LineStart = LI.getStartLine();
609  SLE.EndDelta = LI.getLineDelta();
610  SLE.IsStatement = LI.isStatement();
611  Block.Lines.push_back(SLE);
612  }
613  Result->Lines.Blocks.push_back(Block);
614  }
615  return Result;
616 }
617 
619 YAMLInlineeLinesSubsection::fromCodeViewSubsection(
620  const DebugStringTableSubsectionRef &Strings,
621  const DebugChecksumsSubsectionRef &Checksums,
622  const DebugInlineeLinesSubsectionRef &Lines) {
623  auto Result = std::make_shared<YAMLInlineeLinesSubsection>();
624 
625  Result->InlineeLines.HasExtraFiles = Lines.hasExtraFiles();
626  for (const auto &IL : Lines) {
627  InlineeSite Site;
628  auto ExpF = getFileName(Strings, Checksums, IL.Header->FileID);
629  if (!ExpF)
630  return ExpF.takeError();
631  Site.FileName = *ExpF;
632  Site.Inlinee = IL.Header->Inlinee.getIndex();
633  Site.SourceLineNum = IL.Header->SourceLineNum;
634  if (Lines.hasExtraFiles()) {
635  for (const auto EF : IL.ExtraFiles) {
636  auto ExpF2 = getFileName(Strings, Checksums, EF);
637  if (!ExpF2)
638  return ExpF2.takeError();
639  Site.ExtraFiles.push_back(*ExpF2);
640  }
641  }
642  Result->InlineeLines.Sites.push_back(Site);
643  }
644  return Result;
645 }
646 
648 YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(
649  const DebugCrossModuleExportsSubsectionRef &Exports) {
650  auto Result = std::make_shared<YAMLCrossModuleExportsSubsection>();
651  Result->Exports.assign(Exports.begin(), Exports.end());
652  return Result;
653 }
654 
656 YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(
657  const DebugStringTableSubsectionRef &Strings,
658  const DebugCrossModuleImportsSubsectionRef &Imports) {
659  auto Result = std::make_shared<YAMLCrossModuleImportsSubsection>();
660  for (const auto &CMI : Imports) {
662  auto ExpectedStr = Strings.getString(CMI.Header->ModuleNameOffset);
663  if (!ExpectedStr)
664  return ExpectedStr.takeError();
665  YCMI.ModuleName = *ExpectedStr;
666  YCMI.ImportIds.assign(CMI.Imports.begin(), CMI.Imports.end());
667  Result->Imports.push_back(YCMI);
668  }
669  return Result;
670 }
671 
673 YAMLSymbolsSubsection::fromCodeViewSubsection(
675  auto Result = std::make_shared<YAMLSymbolsSubsection>();
676  for (const auto &Sym : Symbols) {
678  if (!S)
679  return joinErrors(make_error<CodeViewError>(
681  "Invalid CodeView Symbol Record in SymbolRecord "
682  "subsection of .debug$S while converting to YAML!"),
683  S.takeError());
684 
685  Result->Symbols.push_back(*S);
686  }
687  return Result;
688 }
689 
691 YAMLStringTableSubsection::fromCodeViewSubsection(
692  const DebugStringTableSubsectionRef &Strings) {
693  auto Result = std::make_shared<YAMLStringTableSubsection>();
694  BinaryStreamReader Reader(Strings.getBuffer());
695  StringRef S;
696  // First item is a single null string, skip it.
697  if (auto EC = Reader.readCString(S))
698  return std::move(EC);
699  assert(S.empty());
700  while (Reader.bytesRemaining() > 0) {
701  if (auto EC = Reader.readCString(S))
702  return std::move(EC);
703  Result->Strings.push_back(S);
704  }
705  return Result;
706 }
707 
709 YAMLFrameDataSubsection::fromCodeViewSubsection(
710  const DebugStringTableSubsectionRef &Strings,
711  const DebugFrameDataSubsectionRef &Frames) {
712  auto Result = std::make_shared<YAMLFrameDataSubsection>();
713  for (const auto &F : Frames) {
714  YAMLFrameData YF;
715  YF.CodeSize = F.CodeSize;
716  YF.Flags = F.Flags;
717  YF.LocalSize = F.LocalSize;
718  YF.MaxStackSize = F.MaxStackSize;
719  YF.ParamsSize = F.ParamsSize;
720  YF.PrologSize = F.PrologSize;
721  YF.RvaStart = F.RvaStart;
722  YF.SavedRegsSize = F.SavedRegsSize;
723 
724  auto ES = Strings.getString(F.FrameFunc);
725  if (!ES)
726  return joinErrors(
727  make_error<CodeViewError>(
729  "Could not find string for string id while mapping FrameData!"),
730  ES.takeError());
731  YF.FrameFunc = *ES;
732  Result->Frames.push_back(YF);
733  }
734  return Result;
735 }
736 
738 YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(
740  auto Result = std::make_shared<YAMLCoffSymbolRVASubsection>();
741  for (const auto &RVA : Section) {
742  Result->RVAs.push_back(RVA);
743  }
744  return Result;
745 }
746 
749  BumpPtrAllocator &Allocator, ArrayRef<YAMLDebugSubsection> Subsections,
750  const codeview::StringsAndChecksums &SC) {
751  std::vector<std::shared_ptr<DebugSubsection>> Result;
752  if (Subsections.empty())
753  return std::move(Result);
754 
755  for (const auto &SS : Subsections) {
756  std::shared_ptr<DebugSubsection> CVS;
757  CVS = SS.Subsection->toCodeViewSubsection(Allocator, SC);
758  assert(CVS != nullptr);
759  Result.push_back(std::move(CVS));
760  }
761  return std::move(Result);
762 }
763 
764 namespace {
765 
766 struct SubsectionConversionVisitor : public DebugSubsectionVisitor {
767  SubsectionConversionVisitor() = default;
768 
769  Error visitUnknown(DebugUnknownSubsectionRef &Unknown) override;
770  Error visitLines(DebugLinesSubsectionRef &Lines,
771  const StringsAndChecksumsRef &State) override;
772  Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums,
773  const StringsAndChecksumsRef &State) override;
774  Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees,
775  const StringsAndChecksumsRef &State) override;
776  Error visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef &Checksums,
777  const StringsAndChecksumsRef &State) override;
778  Error visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef &Inlinees,
779  const StringsAndChecksumsRef &State) override;
780  Error visitStringTable(DebugStringTableSubsectionRef &ST,
781  const StringsAndChecksumsRef &State) override;
782  Error visitSymbols(DebugSymbolsSubsectionRef &Symbols,
783  const StringsAndChecksumsRef &State) override;
784  Error visitFrameData(DebugFrameDataSubsectionRef &Symbols,
785  const StringsAndChecksumsRef &State) override;
786  Error visitCOFFSymbolRVAs(DebugSymbolRVASubsectionRef &Symbols,
787  const StringsAndChecksumsRef &State) override;
788 
789  YAMLDebugSubsection Subsection;
790 };
791 
792 } // end anonymous namespace
793 
794 Error SubsectionConversionVisitor::visitUnknown(
796  return make_error<CodeViewError>(cv_error_code::operation_unsupported);
797 }
798 
799 Error SubsectionConversionVisitor::visitLines(
800  DebugLinesSubsectionRef &Lines, const StringsAndChecksumsRef &State) {
801  auto Result = YAMLLinesSubsection::fromCodeViewSubsection(
802  State.strings(), State.checksums(), Lines);
803  if (!Result)
804  return Result.takeError();
805  Subsection.Subsection = *Result;
806  return Error::success();
807 }
808 
809 Error SubsectionConversionVisitor::visitFileChecksums(
810  DebugChecksumsSubsectionRef &Checksums,
811  const StringsAndChecksumsRef &State) {
812  auto Result = YAMLChecksumsSubsection::fromCodeViewSubsection(State.strings(),
813  Checksums);
814  if (!Result)
815  return Result.takeError();
816  Subsection.Subsection = *Result;
817  return Error::success();
818 }
819 
820 Error SubsectionConversionVisitor::visitInlineeLines(
822  const StringsAndChecksumsRef &State) {
823  auto Result = YAMLInlineeLinesSubsection::fromCodeViewSubsection(
824  State.strings(), State.checksums(), Inlinees);
825  if (!Result)
826  return Result.takeError();
827  Subsection.Subsection = *Result;
828  return Error::success();
829 }
830 
831 Error SubsectionConversionVisitor::visitCrossModuleExports(
833  const StringsAndChecksumsRef &State) {
834  auto Result =
835  YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(Exports);
836  if (!Result)
837  return Result.takeError();
838  Subsection.Subsection = *Result;
839  return Error::success();
840 }
841 
842 Error SubsectionConversionVisitor::visitCrossModuleImports(
844  const StringsAndChecksumsRef &State) {
845  auto Result = YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(
846  State.strings(), Imports);
847  if (!Result)
848  return Result.takeError();
849  Subsection.Subsection = *Result;
850  return Error::success();
851 }
852 
853 Error SubsectionConversionVisitor::visitStringTable(
855  const StringsAndChecksumsRef &State) {
856  auto Result = YAMLStringTableSubsection::fromCodeViewSubsection(Strings);
857  if (!Result)
858  return Result.takeError();
859  Subsection.Subsection = *Result;
860  return Error::success();
861 }
862 
863 Error SubsectionConversionVisitor::visitSymbols(
864  DebugSymbolsSubsectionRef &Symbols, const StringsAndChecksumsRef &State) {
865  auto Result = YAMLSymbolsSubsection::fromCodeViewSubsection(Symbols);
866  if (!Result)
867  return Result.takeError();
868  Subsection.Subsection = *Result;
869  return Error::success();
870 }
871 
872 Error SubsectionConversionVisitor::visitFrameData(
873  DebugFrameDataSubsectionRef &Frames, const StringsAndChecksumsRef &State) {
874  auto Result =
875  YAMLFrameDataSubsection::fromCodeViewSubsection(State.strings(), Frames);
876  if (!Result)
877  return Result.takeError();
878  Subsection.Subsection = *Result;
879  return Error::success();
880 }
881 
882 Error SubsectionConversionVisitor::visitCOFFSymbolRVAs(
884  auto Result = YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(RVAs);
885  if (!Result)
886  return Result.takeError();
887  Subsection.Subsection = *Result;
888  return Error::success();
889 }
890 
892 YAMLDebugSubsection::fromCodeViewSubection(const StringsAndChecksumsRef &SC,
893  const DebugSubsectionRecord &SS) {
894  SubsectionConversionVisitor V;
895  if (auto EC = visitDebugSubsection(SS, V, SC))
896  return std::move(EC);
897 
898  return V.Subsection;
899 }
900 
901 std::vector<YAMLDebugSubsection>
903  const StringsAndChecksumsRef &SC) {
904  BinaryStreamReader Reader(Data, support::little);
905  uint32_t Magic;
906 
907  ExitOnError Err("Invalid .debug$S section!");
908  Err(Reader.readInteger(Magic));
909  assert(Magic == COFF::DEBUG_SECTION_MAGIC && "Invalid .debug$S section!");
910 
911  DebugSubsectionArray Subsections;
912  Err(Reader.readArray(Subsections, Reader.bytesRemaining()));
913 
914  std::vector<YAMLDebugSubsection> Result;
915 
916  for (const auto &SS : Subsections) {
917  auto YamlSS = Err(YAMLDebugSubsection::fromCodeViewSubection(SC, SS));
918  Result.push_back(YamlSS);
919  }
920  return Result;
921 }
922 
925  // String Table and Checksums subsections don't use the allocator.
927 
928  // It's possible for checksums and strings to even appear in different debug$S
929  // sections, so we have to make this a stateful function that can build up
930  // the strings and checksums field over multiple iterations.
931 
932  // File Checksums require the string table, but may become before it, so we
933  // have to scan for strings first, then scan for checksums again from the
934  // beginning.
935  if (!SC.hasStrings()) {
936  for (const auto &SS : Sections) {
937  if (SS.Subsection->Kind != DebugSubsectionKind::StringTable)
938  continue;
939 
940  auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC);
941  SC.setStrings(
942  std::static_pointer_cast<DebugStringTableSubsection>(Result));
943  break;
944  }
945  }
946 
947  if (SC.hasStrings() && !SC.hasChecksums()) {
948  for (const auto &SS : Sections) {
949  if (SS.Subsection->Kind != DebugSubsectionKind::FileChecksums)
950  continue;
951 
952  auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC);
953  SC.setChecksums(
954  std::static_pointer_cast<DebugChecksumsSubsection>(Result));
955  break;
956  }
957  }
958 }
std::vector< SourceLineEntry > Lines
void bitSetCase(T &Val, const char *Str, const T ConstVal)
Definition: YAMLTraits.h:616
void mapOptional(const char *Key, T &Val)
Definition: YAMLTraits.h:656
Compute iterated dominance frontiers using a linear time algorithm.
Definition: AllocatorList.h:24
Error readInteger(T &Dest)
Read an integer of the specified endianness into Dest and update the stream&#39;s offset.
Data in the the SUBSEC_FRAMEDATA subection.
Definition: CodeView.h:535
uint32_t getStartLine() const
Definition: Line.h:40
Iterator end() const
support::ulittle32_t RvaStart
Definition: CodeView.h:536
Helper for check-and-exit error handling.
Definition: Error.h:1108
F(f)
std::vector< YAMLDebugSubsection > fromDebugS(ArrayRef< uint8_t > Data, const codeview::StringsAndChecksumsRef &SC)
#define LLVM_YAML_IS_SEQUENCE_VECTOR(type)
Utility for declaring that a std::vector of a particular type should be considered a YAML sequence...
Definition: YAMLTraits.h:1643
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:121
support::ulittle16_t PrologSize
Definition: CodeView.h:542
#define LLVM_YAML_DECLARE_ENUM_TRAITS(Type)
Definition: YAMLTraits.h:1660
support::ulittle32_t CodeSize
Definition: CodeView.h:537
support::ulittle32_t MaxStackSize
Definition: CodeView.h:540
const DebugStringTableSubsectionRef & strings() const
Tagged union holding either a T or a Error.
Definition: CachePruning.h:23
void enumFallback(T &Val)
Definition: YAMLTraits.h:605
This class should be specialized by any type that needs to be converted to/from a YAML mapping...
uint32_t getLineDelta() const
Definition: Line.h:42
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:33
A 32-bit type reference.
Definition: TypeIndex.h:96
static Expected< SourceFileChecksumEntry > convertOneChecksum(const DebugStringTableSubsectionRef &Strings, const FileChecksumEntry &CS)
virtual bool mapTag(StringRef Tag, bool Default=false)=0
static Expected< StringRef > getFileName(const DebugStringTableSubsectionRef &Strings, const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID)
void enumCase(T &Val, const char *Str, const T ConstVal)
Definition: YAMLTraits.h:590
support::ulittle32_t ParamsSize
Definition: CodeView.h:539
bool isStatement() const
Definition: Line.h:48
Allocate memory in an ever growing pool, as if by bump-pointer.
Definition: Allocator.h:138
support::ulittle32_t Flags
Definition: CodeView.h:544
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:479
#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:538
#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:42
const StringsPtr & strings() const
Basic Register Allocator
static ErrorSuccess success()
Create a success value.
Definition: Error.h:313
This class should be specialized by any integral type that converts to/from a YAML scalar where there...
Definition: YAMLTraits.h:98
This class should be specialized by type that requires custom conversion to/from a yaml scalar...
Definition: YAMLTraits.h:137
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.
#define LLVM_YAML_DECLARE_SCALAR_TRAITS(Type, MustQuote)
Definition: YAMLTraits.h:1678
#define LLVM_YAML_DECLARE_BITSET_TRAITS(Type)
Definition: YAMLTraits.h:1669
std::string toHex(StringRef Input)
Convert buffer Input to its hexadecimal representation.
Definition: StringExtras.h:93
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition: Error.h:408
support::ulittle32_t Local
Definition: CodeView.h:560
uint32_t bytesRemaining() const
virtual bool outputting()=0
This class should be specialized by any integer type that is a union of bit values and the YAML repre...
Definition: YAMLTraits.h:115
const unsigned Kind
#define LLVM_YAML_DECLARE_MAPPING_TRAITS(Type)
Definition: YAMLTraits.h:1651
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:156
support::ulittle32_t FrameFunc
Definition: CodeView.h:541
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:44
Provides read only access to a subclass of BinaryStream.
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
void mapRequired(const char *Key, T &Val)
Definition: YAMLTraits.h:646
const LineFragmentHeader * header() const
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:561
bool empty() const
empty - Check if the array is empty.
Definition: ArrayRef.h:144
support::ulittle16_t SavedRegsSize
Definition: CodeView.h:543