]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/ObjectYAML/CodeViewYAMLDebugSections.cpp
Merge llvm, clang, lld, lldb, compiler-rt and libc++ r304659, and update
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / ObjectYAML / CodeViewYAMLDebugSections.cpp
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
15 #include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h"
16
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/ADT/StringSwitch.h"
19 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
20 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
21 #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
22 #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
23 #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
24 #include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"
25 #include "llvm/DebugInfo/CodeView/EnumTables.h"
26 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
27
28 using namespace llvm;
29 using namespace llvm::codeview;
30 using namespace llvm::CodeViewYAML;
31 using namespace llvm::CodeViewYAML::detail;
32 using namespace llvm::yaml;
33
34 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceFileChecksumEntry)
35 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineEntry)
36 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceColumnEntry)
37 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineBlock)
38 LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineInfo)
39 LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeSite)
40 LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeInfo)
41 LLVM_YAML_IS_SEQUENCE_VECTOR(StringRef)
42
43 LLVM_YAML_DECLARE_SCALAR_TRAITS(HexFormattedString, false)
44 LLVM_YAML_DECLARE_ENUM_TRAITS(DebugSubsectionKind)
45 LLVM_YAML_DECLARE_ENUM_TRAITS(FileChecksumKind)
46 LLVM_YAML_DECLARE_BITSET_TRAITS(LineFlags)
47
48 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineEntry)
49 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceColumnEntry)
50 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceFileChecksumEntry)
51 LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineBlock)
52 LLVM_YAML_DECLARE_MAPPING_TRAITS(InlineeSite)
53
54 namespace llvm {
55 namespace CodeViewYAML {
56 namespace detail {
57 struct YAMLSubsectionBase {
58   explicit YAMLSubsectionBase(DebugSubsectionKind Kind) : Kind(Kind) {}
59   DebugSubsectionKind Kind;
60   virtual ~YAMLSubsectionBase() {}
61
62   virtual void map(IO &IO) = 0;
63   virtual std::unique_ptr<DebugSubsection>
64   toCodeViewSubsection(DebugStringTableSubsection *UseStrings,
65                        DebugChecksumsSubsection *UseChecksums) const = 0;
66 };
67 }
68 }
69 }
70
71 namespace {
72 struct YAMLChecksumsSubsection : public YAMLSubsectionBase {
73   YAMLChecksumsSubsection()
74       : YAMLSubsectionBase(DebugSubsectionKind::FileChecksums) {}
75
76   void map(IO &IO) override;
77   std::unique_ptr<DebugSubsection>
78   toCodeViewSubsection(DebugStringTableSubsection *Strings,
79                        DebugChecksumsSubsection *Checksums) const override;
80   static Expected<std::shared_ptr<YAMLChecksumsSubsection>>
81   fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
82                          const DebugChecksumsSubsectionRef &FC);
83
84   std::vector<SourceFileChecksumEntry> Checksums;
85 };
86
87 struct YAMLLinesSubsection : public YAMLSubsectionBase {
88   YAMLLinesSubsection() : YAMLSubsectionBase(DebugSubsectionKind::Lines) {}
89
90   void map(IO &IO) override;
91   std::unique_ptr<DebugSubsection>
92   toCodeViewSubsection(DebugStringTableSubsection *Strings,
93                        DebugChecksumsSubsection *Checksums) const override;
94   static Expected<std::shared_ptr<YAMLLinesSubsection>>
95   fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
96                          const DebugChecksumsSubsectionRef &Checksums,
97                          const DebugLinesSubsectionRef &Lines);
98
99   SourceLineInfo Lines;
100 };
101
102 struct YAMLInlineeLinesSubsection : public YAMLSubsectionBase {
103   YAMLInlineeLinesSubsection()
104       : YAMLSubsectionBase(DebugSubsectionKind::InlineeLines) {}
105
106   void map(IO &IO) override;
107   std::unique_ptr<DebugSubsection>
108   toCodeViewSubsection(DebugStringTableSubsection *Strings,
109                        DebugChecksumsSubsection *Checksums) const override;
110   static Expected<std::shared_ptr<YAMLInlineeLinesSubsection>>
111   fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
112                          const DebugChecksumsSubsectionRef &Checksums,
113                          const DebugInlineeLinesSubsectionRef &Lines);
114
115   InlineeInfo InlineeLines;
116 };
117 }
118
119 void ScalarBitSetTraits<LineFlags>::bitset(IO &io, LineFlags &Flags) {
120   io.bitSetCase(Flags, "HasColumnInfo", LF_HaveColumns);
121   io.enumFallback<Hex16>(Flags);
122 }
123
124 void ScalarEnumerationTraits<FileChecksumKind>::enumeration(
125     IO &io, FileChecksumKind &Kind) {
126   io.enumCase(Kind, "None", FileChecksumKind::None);
127   io.enumCase(Kind, "MD5", FileChecksumKind::MD5);
128   io.enumCase(Kind, "SHA1", FileChecksumKind::SHA1);
129   io.enumCase(Kind, "SHA256", FileChecksumKind::SHA256);
130 }
131
132 void ScalarTraits<HexFormattedString>::output(const HexFormattedString &Value,
133                                               void *ctx, raw_ostream &Out) {
134   StringRef Bytes(reinterpret_cast<const char *>(Value.Bytes.data()),
135                   Value.Bytes.size());
136   Out << toHex(Bytes);
137 }
138
139 StringRef ScalarTraits<HexFormattedString>::input(StringRef Scalar, void *ctxt,
140                                                   HexFormattedString &Value) {
141   std::string H = fromHex(Scalar);
142   Value.Bytes.assign(H.begin(), H.end());
143   return StringRef();
144 }
145
146 void MappingTraits<SourceLineEntry>::mapping(IO &IO, SourceLineEntry &Obj) {
147   IO.mapRequired("Offset", Obj.Offset);
148   IO.mapRequired("LineStart", Obj.LineStart);
149   IO.mapRequired("IsStatement", Obj.IsStatement);
150   IO.mapRequired("EndDelta", Obj.EndDelta);
151 }
152
153 void MappingTraits<SourceColumnEntry>::mapping(IO &IO, SourceColumnEntry &Obj) {
154   IO.mapRequired("StartColumn", Obj.StartColumn);
155   IO.mapRequired("EndColumn", Obj.EndColumn);
156 }
157
158 void MappingTraits<SourceLineBlock>::mapping(IO &IO, SourceLineBlock &Obj) {
159   IO.mapRequired("FileName", Obj.FileName);
160   IO.mapRequired("Lines", Obj.Lines);
161   IO.mapRequired("Columns", Obj.Columns);
162 }
163
164 void MappingTraits<SourceFileChecksumEntry>::mapping(
165     IO &IO, SourceFileChecksumEntry &Obj) {
166   IO.mapRequired("FileName", Obj.FileName);
167   IO.mapRequired("Kind", Obj.Kind);
168   IO.mapRequired("Checksum", Obj.ChecksumBytes);
169 }
170
171 void MappingTraits<InlineeSite>::mapping(IO &IO, InlineeSite &Obj) {
172   IO.mapRequired("FileName", Obj.FileName);
173   IO.mapRequired("LineNum", Obj.SourceLineNum);
174   IO.mapRequired("Inlinee", Obj.Inlinee);
175   IO.mapOptional("ExtraFiles", Obj.ExtraFiles);
176 }
177
178 void YAMLChecksumsSubsection::map(IO &IO) {
179   IO.mapTag("!FileChecksums", true);
180   IO.mapRequired("Checksums", Checksums);
181 }
182
183 void YAMLLinesSubsection::map(IO &IO) {
184   IO.mapTag("!Lines", true);
185   IO.mapRequired("CodeSize", Lines.CodeSize);
186
187   IO.mapRequired("Flags", Lines.Flags);
188   IO.mapRequired("RelocOffset", Lines.RelocOffset);
189   IO.mapRequired("RelocSegment", Lines.RelocSegment);
190   IO.mapRequired("Blocks", Lines.Blocks);
191 }
192
193 void YAMLInlineeLinesSubsection::map(IO &IO) {
194   IO.mapTag("!InlineeLines", true);
195   IO.mapRequired("HasExtraFiles", InlineeLines.HasExtraFiles);
196   IO.mapRequired("Sites", InlineeLines.Sites);
197 }
198
199 void MappingTraits<YAMLDebugSubsection>::mapping(
200     IO &IO, YAMLDebugSubsection &Subsection) {
201   if (!IO.outputting()) {
202     if (IO.mapTag("!FileChecksums")) {
203       auto SS = std::make_shared<YAMLChecksumsSubsection>();
204       Subsection.Subsection = SS;
205     } else if (IO.mapTag("!Lines")) {
206       Subsection.Subsection = std::make_shared<YAMLLinesSubsection>();
207     } else if (IO.mapTag("!InlineeLines")) {
208       Subsection.Subsection = std::make_shared<YAMLInlineeLinesSubsection>();
209     } else {
210       llvm_unreachable("Unexpected subsection tag!");
211     }
212   }
213   Subsection.Subsection->map(IO);
214 }
215
216 static Expected<const YAMLChecksumsSubsection &>
217 findChecksums(ArrayRef<YAMLDebugSubsection> Subsections) {
218   for (const auto &SS : Subsections) {
219     if (SS.Subsection->Kind == DebugSubsectionKind::FileChecksums) {
220       return static_cast<const YAMLChecksumsSubsection &>(*SS.Subsection);
221     }
222   }
223   return make_error<CodeViewError>(cv_error_code::no_records);
224 }
225
226 std::unique_ptr<DebugSubsection> YAMLChecksumsSubsection::toCodeViewSubsection(
227     DebugStringTableSubsection *UseStrings,
228     DebugChecksumsSubsection *UseChecksums) const {
229   assert(UseStrings && !UseChecksums);
230   auto Result = llvm::make_unique<DebugChecksumsSubsection>(*UseStrings);
231   for (const auto &CS : Checksums) {
232     Result->addChecksum(CS.FileName, CS.Kind, CS.ChecksumBytes.Bytes);
233   }
234   return std::move(Result);
235 }
236
237 std::unique_ptr<DebugSubsection> YAMLLinesSubsection::toCodeViewSubsection(
238     DebugStringTableSubsection *UseStrings,
239     DebugChecksumsSubsection *UseChecksums) const {
240   assert(UseStrings && UseChecksums);
241   auto Result =
242       llvm::make_unique<DebugLinesSubsection>(*UseChecksums, *UseStrings);
243   Result->setCodeSize(Lines.CodeSize);
244   Result->setRelocationAddress(Lines.RelocSegment, Lines.RelocOffset);
245   Result->setFlags(Lines.Flags);
246   for (const auto &LC : Lines.Blocks) {
247     Result->createBlock(LC.FileName);
248     if (Result->hasColumnInfo()) {
249       for (const auto &Item : zip(LC.Lines, LC.Columns)) {
250         auto &L = std::get<0>(Item);
251         auto &C = std::get<1>(Item);
252         uint32_t LE = L.LineStart + L.EndDelta;
253         Result->addLineAndColumnInfo(L.Offset,
254                                      LineInfo(L.LineStart, LE, L.IsStatement),
255                                      C.StartColumn, C.EndColumn);
256       }
257     } else {
258       for (const auto &L : LC.Lines) {
259         uint32_t LE = L.LineStart + L.EndDelta;
260         Result->addLineInfo(L.Offset, LineInfo(L.LineStart, LE, L.IsStatement));
261       }
262     }
263   }
264   return llvm::cast<DebugSubsection>(std::move(Result));
265 }
266
267 std::unique_ptr<DebugSubsection>
268 YAMLInlineeLinesSubsection::toCodeViewSubsection(
269     DebugStringTableSubsection *UseStrings,
270     DebugChecksumsSubsection *UseChecksums) const {
271   assert(UseChecksums);
272   auto Result = llvm::make_unique<DebugInlineeLinesSubsection>(
273       *UseChecksums, InlineeLines.HasExtraFiles);
274
275   for (const auto &Site : InlineeLines.Sites) {
276     Result->addInlineSite(TypeIndex(Site.Inlinee), Site.FileName,
277                           Site.SourceLineNum);
278     if (!InlineeLines.HasExtraFiles)
279       continue;
280
281     for (auto EF : Site.ExtraFiles) {
282       Result->addExtraFile(EF);
283     }
284   }
285   return llvm::cast<DebugSubsection>(std::move(Result));
286 }
287
288 static Expected<SourceFileChecksumEntry>
289 convertOneChecksum(const DebugStringTableSubsectionRef &Strings,
290                    const FileChecksumEntry &CS) {
291   auto ExpectedString = Strings.getString(CS.FileNameOffset);
292   if (!ExpectedString)
293     return ExpectedString.takeError();
294
295   SourceFileChecksumEntry Result;
296   Result.ChecksumBytes.Bytes = CS.Checksum;
297   Result.Kind = CS.Kind;
298   Result.FileName = *ExpectedString;
299   return Result;
300 }
301
302 static Expected<StringRef>
303 getFileName(const DebugStringTableSubsectionRef &Strings,
304             const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID) {
305   auto Iter = Checksums.getArray().at(FileID);
306   if (Iter == Checksums.getArray().end())
307     return make_error<CodeViewError>(cv_error_code::no_records);
308   uint32_t Offset = Iter->FileNameOffset;
309   return Strings.getString(Offset);
310 }
311
312 Expected<std::shared_ptr<YAMLChecksumsSubsection>>
313 YAMLChecksumsSubsection::fromCodeViewSubsection(
314     const DebugStringTableSubsectionRef &Strings,
315     const DebugChecksumsSubsectionRef &FC) {
316   auto Result = std::make_shared<YAMLChecksumsSubsection>();
317
318   for (const auto &CS : FC) {
319     auto ConvertedCS = convertOneChecksum(Strings, CS);
320     if (!ConvertedCS)
321       return ConvertedCS.takeError();
322     Result->Checksums.push_back(*ConvertedCS);
323   }
324   return Result;
325 }
326
327 Expected<std::shared_ptr<YAMLLinesSubsection>>
328 YAMLLinesSubsection::fromCodeViewSubsection(
329     const DebugStringTableSubsectionRef &Strings,
330     const DebugChecksumsSubsectionRef &Checksums,
331     const DebugLinesSubsectionRef &Lines) {
332   auto Result = std::make_shared<YAMLLinesSubsection>();
333   Result->Lines.CodeSize = Lines.header()->CodeSize;
334   Result->Lines.RelocOffset = Lines.header()->RelocOffset;
335   Result->Lines.RelocSegment = Lines.header()->RelocSegment;
336   Result->Lines.Flags = static_cast<LineFlags>(uint16_t(Lines.header()->Flags));
337   for (const auto &L : Lines) {
338     SourceLineBlock Block;
339     auto EF = getFileName(Strings, Checksums, L.NameIndex);
340     if (!EF)
341       return EF.takeError();
342     Block.FileName = *EF;
343     if (Lines.hasColumnInfo()) {
344       for (const auto &C : L.Columns) {
345         SourceColumnEntry SCE;
346         SCE.EndColumn = C.EndColumn;
347         SCE.StartColumn = C.StartColumn;
348         Block.Columns.push_back(SCE);
349       }
350     }
351     for (const auto &LN : L.LineNumbers) {
352       SourceLineEntry SLE;
353       LineInfo LI(LN.Flags);
354       SLE.Offset = LN.Offset;
355       SLE.LineStart = LI.getStartLine();
356       SLE.EndDelta = LI.getLineDelta();
357       SLE.IsStatement = LI.isStatement();
358       Block.Lines.push_back(SLE);
359     }
360     Result->Lines.Blocks.push_back(Block);
361   }
362   return Result;
363 }
364
365 Expected<std::shared_ptr<YAMLInlineeLinesSubsection>>
366 YAMLInlineeLinesSubsection::fromCodeViewSubsection(
367     const DebugStringTableSubsectionRef &Strings,
368     const DebugChecksumsSubsectionRef &Checksums,
369     const DebugInlineeLinesSubsectionRef &Lines) {
370   auto Result = std::make_shared<YAMLInlineeLinesSubsection>();
371
372   Result->InlineeLines.HasExtraFiles = Lines.hasExtraFiles();
373   for (const auto &IL : Lines) {
374     InlineeSite Site;
375     auto ExpF = getFileName(Strings, Checksums, IL.Header->FileID);
376     if (!ExpF)
377       return ExpF.takeError();
378     Site.FileName = *ExpF;
379     Site.Inlinee = IL.Header->Inlinee.getIndex();
380     Site.SourceLineNum = IL.Header->SourceLineNum;
381     if (Lines.hasExtraFiles()) {
382       for (const auto EF : IL.ExtraFiles) {
383         auto ExpF2 = getFileName(Strings, Checksums, EF);
384         if (!ExpF2)
385           return ExpF2.takeError();
386         Site.ExtraFiles.push_back(*ExpF2);
387       }
388     }
389     Result->InlineeLines.Sites.push_back(Site);
390   }
391   return Result;
392 }
393
394 Expected<std::vector<std::unique_ptr<DebugSubsection>>>
395 llvm::CodeViewYAML::convertSubsectionList(
396     ArrayRef<YAMLDebugSubsection> Subsections,
397     DebugStringTableSubsection &Strings) {
398   std::vector<std::unique_ptr<DebugSubsection>> Result;
399   if (Subsections.empty())
400     return std::move(Result);
401
402   auto Checksums = findChecksums(Subsections);
403   if (!Checksums)
404     return Checksums.takeError();
405   auto ChecksumsBase = Checksums->toCodeViewSubsection(&Strings, nullptr);
406   DebugChecksumsSubsection &CS =
407       llvm::cast<DebugChecksumsSubsection>(*ChecksumsBase);
408   for (const auto &SS : Subsections) {
409     // We've already converted the checksums subsection, don't do it
410     // twice.
411     std::unique_ptr<DebugSubsection> CVS;
412     if (SS.Subsection->Kind == DebugSubsectionKind::FileChecksums)
413       CVS = std::move(ChecksumsBase);
414     else
415       CVS = SS.Subsection->toCodeViewSubsection(&Strings, &CS);
416     Result.push_back(std::move(CVS));
417   }
418   return std::move(Result);
419 }
420
421 namespace {
422 struct SubsectionConversionVisitor : public DebugSubsectionVisitor {
423   explicit SubsectionConversionVisitor(
424       const DebugStringTableSubsectionRef &Strings,
425       const DebugChecksumsSubsectionRef &Checksums)
426       : Strings(Strings), Checksums(Checksums) {}
427
428   Error visitUnknown(DebugUnknownSubsectionRef &Unknown) override;
429   Error visitLines(DebugLinesSubsectionRef &Lines) override;
430   Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums) override;
431   Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees) override;
432
433   YAMLDebugSubsection Subsection;
434
435 private:
436   const DebugStringTableSubsectionRef &Strings;
437   const DebugChecksumsSubsectionRef &Checksums;
438 };
439
440 Error SubsectionConversionVisitor::visitUnknown(
441     DebugUnknownSubsectionRef &Unknown) {
442   return make_error<CodeViewError>(cv_error_code::operation_unsupported);
443 }
444
445 Error SubsectionConversionVisitor::visitLines(DebugLinesSubsectionRef &Lines) {
446   auto Result =
447       YAMLLinesSubsection::fromCodeViewSubsection(Strings, Checksums, Lines);
448   if (!Result)
449     return Result.takeError();
450   Subsection.Subsection = *Result;
451   return Error::success();
452 }
453
454 Error SubsectionConversionVisitor::visitFileChecksums(
455     DebugChecksumsSubsectionRef &Checksums) {
456   auto Result =
457       YAMLChecksumsSubsection::fromCodeViewSubsection(Strings, Checksums);
458   if (!Result)
459     return Result.takeError();
460   Subsection.Subsection = *Result;
461   return Error::success();
462 }
463
464 Error SubsectionConversionVisitor::visitInlineeLines(
465     DebugInlineeLinesSubsectionRef &Inlinees) {
466   auto Result = YAMLInlineeLinesSubsection::fromCodeViewSubsection(
467       Strings, Checksums, Inlinees);
468   if (!Result)
469     return Result.takeError();
470   Subsection.Subsection = *Result;
471   return Error::success();
472 }
473 }
474
475 Expected<YAMLDebugSubsection> YAMLDebugSubsection::fromCodeViewSubection(
476     const DebugStringTableSubsectionRef &Strings,
477     const DebugChecksumsSubsectionRef &Checksums,
478     const DebugSubsectionRecord &SS) {
479   SubsectionConversionVisitor V(Strings, Checksums);
480   if (auto EC = visitDebugSubsection(SS, V))
481     return std::move(EC);
482
483   return V.Subsection;
484 }