blob: a85dcf97cd4bc69fc2adffa29ef7b9d54a186800 [file] [log] [blame]
Zachary Turner1b88f4f2017-05-31 04:17:13 +00001//===- 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"
Zachary Turner92dcdda2017-06-02 19:49:14 +000020#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"
Zachary Turner1b88f4f2017-05-31 04:17:13 +000025#include "llvm/DebugInfo/CodeView/EnumTables.h"
26#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
27
28using namespace llvm;
29using namespace llvm::codeview;
30using namespace llvm::CodeViewYAML;
31using namespace llvm::CodeViewYAML::detail;
32using namespace llvm::yaml;
33
34LLVM_YAML_IS_SEQUENCE_VECTOR(SourceFileChecksumEntry)
35LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineEntry)
36LLVM_YAML_IS_SEQUENCE_VECTOR(SourceColumnEntry)
37LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineBlock)
38LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineInfo)
39LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeSite)
40LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeInfo)
41LLVM_YAML_IS_SEQUENCE_VECTOR(StringRef)
42
43LLVM_YAML_DECLARE_SCALAR_TRAITS(HexFormattedString, false)
Zachary Turner92dcdda2017-06-02 19:49:14 +000044LLVM_YAML_DECLARE_ENUM_TRAITS(DebugSubsectionKind)
Zachary Turner1b88f4f2017-05-31 04:17:13 +000045LLVM_YAML_DECLARE_ENUM_TRAITS(FileChecksumKind)
46LLVM_YAML_DECLARE_BITSET_TRAITS(LineFlags)
47
Zachary Turner92dcdda2017-06-02 19:49:14 +000048LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineEntry)
49LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceColumnEntry)
50LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceFileChecksumEntry)
51LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineBlock)
52LLVM_YAML_DECLARE_MAPPING_TRAITS(InlineeSite)
53
54namespace llvm {
55namespace CodeViewYAML {
56namespace detail {
57struct 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
71namespace {
72struct 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
87struct 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
102struct 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}
Zachary Turner1b88f4f2017-05-31 04:17:13 +0000118
119void ScalarBitSetTraits<LineFlags>::bitset(IO &io, LineFlags &Flags) {
120 io.bitSetCase(Flags, "HasColumnInfo", LF_HaveColumns);
121 io.enumFallback<Hex16>(Flags);
122}
123
124void 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
132void 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
139StringRef 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
146void 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
153void MappingTraits<SourceColumnEntry>::mapping(IO &IO, SourceColumnEntry &Obj) {
154 IO.mapRequired("StartColumn", Obj.StartColumn);
155 IO.mapRequired("EndColumn", Obj.EndColumn);
156}
157
158void 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
164void 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
Zachary Turner1b88f4f2017-05-31 04:17:13 +0000171void 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
Zachary Turner92dcdda2017-06-02 19:49:14 +0000178void YAMLChecksumsSubsection::map(IO &IO) {
179 IO.mapTag("!FileChecksums", true);
180 IO.mapRequired("Checksums", Checksums);
181}
182
183void 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
193void YAMLInlineeLinesSubsection::map(IO &IO) {
194 IO.mapTag("!InlineeLines", true);
195 IO.mapRequired("HasExtraFiles", InlineeLines.HasExtraFiles);
196 IO.mapRequired("Sites", InlineeLines.Sites);
197}
198
199void 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
216static Expected<const YAMLChecksumsSubsection &>
217findChecksums(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
226std::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
237std::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 }
Zachary Turner4bedb5f2017-06-02 20:00:10 +0000264 return llvm::cast<DebugSubsection>(std::move(Result));
Zachary Turner92dcdda2017-06-02 19:49:14 +0000265}
266
267std::unique_ptr<DebugSubsection>
268YAMLInlineeLinesSubsection::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 }
Zachary Turner4bedb5f2017-06-02 20:00:10 +0000285 return llvm::cast<DebugSubsection>(std::move(Result));
Zachary Turner92dcdda2017-06-02 19:49:14 +0000286}
287
288static Expected<SourceFileChecksumEntry>
289convertOneChecksum(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
302static Expected<StringRef>
303getFileName(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
312Expected<std::shared_ptr<YAMLChecksumsSubsection>>
313YAMLChecksumsSubsection::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
327Expected<std::shared_ptr<YAMLLinesSubsection>>
328YAMLLinesSubsection::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
365Expected<std::shared_ptr<YAMLInlineeLinesSubsection>>
366YAMLInlineeLinesSubsection::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
394Expected<std::vector<std::unique_ptr<DebugSubsection>>>
395llvm::CodeViewYAML::convertSubsectionList(
396 ArrayRef<YAMLDebugSubsection> Subsections,
397 DebugStringTableSubsection &Strings) {
398 std::vector<std::unique_ptr<DebugSubsection>> Result;
399 if (Subsections.empty())
400 return 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
421namespace {
422struct 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
435private:
436 const DebugStringTableSubsectionRef &Strings;
437 const DebugChecksumsSubsectionRef &Checksums;
438};
439
440Error SubsectionConversionVisitor::visitUnknown(
441 DebugUnknownSubsectionRef &Unknown) {
442 return make_error<CodeViewError>(cv_error_code::operation_unsupported);
443}
444
445Error 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
454Error 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
464Error 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
475Expected<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;
Zachary Turner1b88f4f2017-05-31 04:17:13 +0000484}