Line data Source code
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 : #include "llvm/ADT/STLExtras.h"
17 : #include "llvm/ADT/StringExtras.h"
18 : #include "llvm/ADT/StringRef.h"
19 : #include "llvm/BinaryFormat/COFF.h"
20 : #include "llvm/DebugInfo/CodeView/CodeView.h"
21 : #include "llvm/DebugInfo/CodeView/CodeViewError.h"
22 : #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
23 : #include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
24 : #include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
25 : #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
26 : #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
27 : #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
28 : #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
29 : #include "llvm/DebugInfo/CodeView/DebugSubsection.h"
30 : #include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"
31 : #include "llvm/DebugInfo/CodeView/DebugSymbolRVASubsection.h"
32 : #include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
33 : #include "llvm/DebugInfo/CodeView/Line.h"
34 : #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
35 : #include "llvm/DebugInfo/CodeView/TypeIndex.h"
36 : #include "llvm/ObjectYAML/CodeViewYAMLSymbols.h"
37 : #include "llvm/Support/Allocator.h"
38 : #include "llvm/Support/BinaryStreamReader.h"
39 : #include "llvm/Support/Endian.h"
40 : #include "llvm/Support/Error.h"
41 : #include "llvm/Support/ErrorHandling.h"
42 : #include "llvm/Support/YAMLTraits.h"
43 : #include "llvm/Support/raw_ostream.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 :
58 : LLVM_YAML_IS_SEQUENCE_VECTOR(SourceFileChecksumEntry)
59 : LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineEntry)
60 : LLVM_YAML_IS_SEQUENCE_VECTOR(SourceColumnEntry)
61 : LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineBlock)
62 : LLVM_YAML_IS_SEQUENCE_VECTOR(SourceLineInfo)
63 : LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeSite)
64 : LLVM_YAML_IS_SEQUENCE_VECTOR(InlineeInfo)
65 : LLVM_YAML_IS_SEQUENCE_VECTOR(CrossModuleExport)
66 : LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLCrossModuleImport)
67 : LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLFrameData)
68 :
69 0 : LLVM_YAML_DECLARE_SCALAR_TRAITS(HexFormattedString, QuotingType::None)
70 : LLVM_YAML_DECLARE_ENUM_TRAITS(DebugSubsectionKind)
71 : LLVM_YAML_DECLARE_ENUM_TRAITS(FileChecksumKind)
72 : LLVM_YAML_DECLARE_BITSET_TRAITS(LineFlags)
73 :
74 : LLVM_YAML_DECLARE_MAPPING_TRAITS(CrossModuleExport)
75 : LLVM_YAML_DECLARE_MAPPING_TRAITS(YAMLFrameData)
76 : LLVM_YAML_DECLARE_MAPPING_TRAITS(YAMLCrossModuleImport)
77 : LLVM_YAML_DECLARE_MAPPING_TRAITS(CrossModuleImportItem)
78 : LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineEntry)
79 : LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceColumnEntry)
80 : LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceFileChecksumEntry)
81 : LLVM_YAML_DECLARE_MAPPING_TRAITS(SourceLineBlock)
82 : LLVM_YAML_DECLARE_MAPPING_TRAITS(InlineeSite)
83 :
84 : namespace llvm {
85 : namespace CodeViewYAML {
86 : namespace detail {
87 :
88 : struct YAMLSubsectionBase {
89 0 : explicit YAMLSubsectionBase(DebugSubsectionKind Kind) : Kind(Kind) {}
90 0 : 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 :
97 : DebugSubsectionKind Kind;
98 : };
99 :
100 : } // end namespace detail
101 : } // end namespace CodeViewYAML
102 : } // end namespace llvm
103 :
104 : namespace {
105 :
106 60 : struct YAMLChecksumsSubsection : public YAMLSubsectionBase {
107 : YAMLChecksumsSubsection()
108 0 : : YAMLSubsectionBase(DebugSubsectionKind::FileChecksums) {}
109 :
110 : void map(IO &IO) override;
111 : std::shared_ptr<DebugSubsection>
112 : toCodeViewSubsection(BumpPtrAllocator &Allocator,
113 : const codeview::StringsAndChecksums &SC) const override;
114 : static Expected<std::shared_ptr<YAMLChecksumsSubsection>>
115 : fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
116 : const DebugChecksumsSubsectionRef &FC);
117 :
118 : std::vector<SourceFileChecksumEntry> Checksums;
119 : };
120 :
121 74 : struct YAMLLinesSubsection : public YAMLSubsectionBase {
122 0 : 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;
128 : static Expected<std::shared_ptr<YAMLLinesSubsection>>
129 : fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
130 : const DebugChecksumsSubsectionRef &Checksums,
131 : const DebugLinesSubsectionRef &Lines);
132 :
133 : SourceLineInfo Lines;
134 : };
135 :
136 3 : struct YAMLInlineeLinesSubsection : public YAMLSubsectionBase {
137 : YAMLInlineeLinesSubsection()
138 0 : : YAMLSubsectionBase(DebugSubsectionKind::InlineeLines) {}
139 :
140 : void map(IO &IO) override;
141 : std::shared_ptr<DebugSubsection>
142 : toCodeViewSubsection(BumpPtrAllocator &Allocator,
143 : const codeview::StringsAndChecksums &SC) const override;
144 : static Expected<std::shared_ptr<YAMLInlineeLinesSubsection>>
145 : fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
146 : const DebugChecksumsSubsectionRef &Checksums,
147 : const DebugInlineeLinesSubsectionRef &Lines);
148 :
149 : InlineeInfo InlineeLines;
150 : };
151 :
152 4 : struct YAMLCrossModuleExportsSubsection : public YAMLSubsectionBase {
153 : YAMLCrossModuleExportsSubsection()
154 0 : : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeExports) {}
155 :
156 : void map(IO &IO) override;
157 : std::shared_ptr<DebugSubsection>
158 : toCodeViewSubsection(BumpPtrAllocator &Allocator,
159 : const codeview::StringsAndChecksums &SC) const override;
160 : static Expected<std::shared_ptr<YAMLCrossModuleExportsSubsection>>
161 : fromCodeViewSubsection(const DebugCrossModuleExportsSubsectionRef &Exports);
162 :
163 : std::vector<CrossModuleExport> Exports;
164 : };
165 :
166 2 : struct YAMLCrossModuleImportsSubsection : public YAMLSubsectionBase {
167 : YAMLCrossModuleImportsSubsection()
168 0 : : YAMLSubsectionBase(DebugSubsectionKind::CrossScopeImports) {}
169 :
170 : void map(IO &IO) override;
171 : std::shared_ptr<DebugSubsection>
172 : toCodeViewSubsection(BumpPtrAllocator &Allocator,
173 : const codeview::StringsAndChecksums &SC) const override;
174 : static Expected<std::shared_ptr<YAMLCrossModuleImportsSubsection>>
175 : fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
176 : const DebugCrossModuleImportsSubsectionRef &Imports);
177 :
178 : std::vector<YAMLCrossModuleImport> Imports;
179 : };
180 :
181 185 : struct YAMLSymbolsSubsection : public YAMLSubsectionBase {
182 0 : 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;
188 : static Expected<std::shared_ptr<YAMLSymbolsSubsection>>
189 : fromCodeViewSubsection(const DebugSymbolsSubsectionRef &Symbols);
190 :
191 : std::vector<CodeViewYAML::SymbolRecord> Symbols;
192 : };
193 :
194 60 : struct YAMLStringTableSubsection : public YAMLSubsectionBase {
195 : YAMLStringTableSubsection()
196 0 : : YAMLSubsectionBase(DebugSubsectionKind::StringTable) {}
197 :
198 : void map(IO &IO) override;
199 : std::shared_ptr<DebugSubsection>
200 : toCodeViewSubsection(BumpPtrAllocator &Allocator,
201 : const codeview::StringsAndChecksums &SC) const override;
202 : static Expected<std::shared_ptr<YAMLStringTableSubsection>>
203 : fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings);
204 :
205 : std::vector<StringRef> Strings;
206 : };
207 :
208 11 : struct YAMLFrameDataSubsection : public YAMLSubsectionBase {
209 : YAMLFrameDataSubsection()
210 0 : : YAMLSubsectionBase(DebugSubsectionKind::FrameData) {}
211 :
212 : void map(IO &IO) override;
213 : std::shared_ptr<DebugSubsection>
214 : toCodeViewSubsection(BumpPtrAllocator &Allocator,
215 : const codeview::StringsAndChecksums &SC) const override;
216 : static Expected<std::shared_ptr<YAMLFrameDataSubsection>>
217 : fromCodeViewSubsection(const DebugStringTableSubsectionRef &Strings,
218 : const DebugFrameDataSubsectionRef &Frames);
219 :
220 : std::vector<YAMLFrameData> Frames;
221 : };
222 :
223 0 : struct YAMLCoffSymbolRVASubsection : public YAMLSubsectionBase {
224 : YAMLCoffSymbolRVASubsection()
225 0 : : YAMLSubsectionBase(DebugSubsectionKind::CoffSymbolRVA) {}
226 :
227 : void map(IO &IO) override;
228 : std::shared_ptr<DebugSubsection>
229 : toCodeViewSubsection(BumpPtrAllocator &Allocator,
230 : const codeview::StringsAndChecksums &SC) const override;
231 : static Expected<std::shared_ptr<YAMLCoffSymbolRVASubsection>>
232 : fromCodeViewSubsection(const DebugSymbolRVASubsectionRef &RVAs);
233 :
234 : std::vector<uint32_t> RVAs;
235 : };
236 :
237 : } // end anonymous namespace
238 :
239 74 : void ScalarBitSetTraits<LineFlags>::bitset(IO &io, LineFlags &Flags) {
240 74 : io.bitSetCase(Flags, "HasColumnInfo", LF_HaveColumns);
241 74 : io.enumFallback<Hex16>(Flags);
242 74 : }
243 :
244 74 : void ScalarEnumerationTraits<FileChecksumKind>::enumeration(
245 : IO &io, FileChecksumKind &Kind) {
246 74 : io.enumCase(Kind, "None", FileChecksumKind::None);
247 74 : io.enumCase(Kind, "MD5", FileChecksumKind::MD5);
248 74 : io.enumCase(Kind, "SHA1", FileChecksumKind::SHA1);
249 74 : io.enumCase(Kind, "SHA256", FileChecksumKind::SHA256);
250 74 : }
251 :
252 16 : void ScalarTraits<HexFormattedString>::output(const HexFormattedString &Value,
253 : void *ctx, raw_ostream &Out) {
254 : StringRef Bytes(reinterpret_cast<const char *>(Value.Bytes.data()),
255 16 : Value.Bytes.size());
256 16 : Out << toHex(Bytes);
257 16 : }
258 :
259 58 : StringRef ScalarTraits<HexFormattedString>::input(StringRef Scalar, void *ctxt,
260 : HexFormattedString &Value) {
261 58 : std::string H = fromHex(Scalar);
262 58 : Value.Bytes.assign(H.begin(), H.end());
263 58 : return StringRef();
264 : }
265 :
266 158 : void MappingTraits<SourceLineEntry>::mapping(IO &IO, SourceLineEntry &Obj) {
267 158 : IO.mapRequired("Offset", Obj.Offset);
268 158 : IO.mapRequired("LineStart", Obj.LineStart);
269 158 : IO.mapRequired("IsStatement", Obj.IsStatement);
270 158 : IO.mapRequired("EndDelta", Obj.EndDelta);
271 158 : }
272 :
273 1 : void MappingTraits<SourceColumnEntry>::mapping(IO &IO, SourceColumnEntry &Obj) {
274 1 : IO.mapRequired("StartColumn", Obj.StartColumn);
275 1 : IO.mapRequired("EndColumn", Obj.EndColumn);
276 1 : }
277 :
278 74 : void MappingTraits<SourceLineBlock>::mapping(IO &IO, SourceLineBlock &Obj) {
279 74 : IO.mapRequired("FileName", Obj.FileName);
280 74 : IO.mapRequired("Lines", Obj.Lines);
281 74 : IO.mapRequired("Columns", Obj.Columns);
282 74 : }
283 :
284 8 : void MappingTraits<CrossModuleExport>::mapping(IO &IO, CrossModuleExport &Obj) {
285 8 : IO.mapRequired("LocalId", Obj.Local);
286 8 : IO.mapRequired("GlobalId", Obj.Global);
287 8 : }
288 :
289 2 : void MappingTraits<YAMLCrossModuleImport>::mapping(IO &IO,
290 : YAMLCrossModuleImport &Obj) {
291 2 : IO.mapRequired("Module", Obj.ModuleName);
292 2 : IO.mapRequired("Imports", Obj.ImportIds);
293 2 : }
294 :
295 74 : void MappingTraits<SourceFileChecksumEntry>::mapping(
296 : IO &IO, SourceFileChecksumEntry &Obj) {
297 74 : IO.mapRequired("FileName", Obj.FileName);
298 74 : IO.mapRequired("Kind", Obj.Kind);
299 74 : IO.mapRequired("Checksum", Obj.ChecksumBytes);
300 74 : }
301 :
302 3 : void MappingTraits<InlineeSite>::mapping(IO &IO, InlineeSite &Obj) {
303 3 : IO.mapRequired("FileName", Obj.FileName);
304 3 : IO.mapRequired("LineNum", Obj.SourceLineNum);
305 3 : IO.mapRequired("Inlinee", Obj.Inlinee);
306 3 : IO.mapOptional("ExtraFiles", Obj.ExtraFiles);
307 3 : }
308 :
309 28 : void MappingTraits<YAMLFrameData>::mapping(IO &IO, YAMLFrameData &Obj) {
310 28 : IO.mapRequired("CodeSize", Obj.CodeSize);
311 28 : IO.mapRequired("FrameFunc", Obj.FrameFunc);
312 28 : IO.mapRequired("LocalSize", Obj.LocalSize);
313 28 : IO.mapOptional("MaxStackSize", Obj.MaxStackSize);
314 28 : IO.mapOptional("ParamsSize", Obj.ParamsSize);
315 28 : IO.mapOptional("PrologSize", Obj.PrologSize);
316 28 : IO.mapOptional("RvaStart", Obj.RvaStart);
317 28 : IO.mapOptional("SavedRegsSize", Obj.SavedRegsSize);
318 28 : }
319 :
320 60 : void YAMLChecksumsSubsection::map(IO &IO) {
321 120 : IO.mapTag("!FileChecksums", true);
322 60 : IO.mapRequired("Checksums", Checksums);
323 60 : }
324 :
325 74 : void YAMLLinesSubsection::map(IO &IO) {
326 148 : IO.mapTag("!Lines", true);
327 74 : IO.mapRequired("CodeSize", Lines.CodeSize);
328 :
329 74 : IO.mapRequired("Flags", Lines.Flags);
330 74 : IO.mapRequired("RelocOffset", Lines.RelocOffset);
331 74 : IO.mapRequired("RelocSegment", Lines.RelocSegment);
332 74 : IO.mapRequired("Blocks", Lines.Blocks);
333 74 : }
334 :
335 3 : void YAMLInlineeLinesSubsection::map(IO &IO) {
336 6 : IO.mapTag("!InlineeLines", true);
337 3 : IO.mapRequired("HasExtraFiles", InlineeLines.HasExtraFiles);
338 3 : IO.mapRequired("Sites", InlineeLines.Sites);
339 3 : }
340 :
341 4 : void YAMLCrossModuleExportsSubsection::map(IO &IO) {
342 8 : IO.mapTag("!CrossModuleExports", true);
343 4 : IO.mapOptional("Exports", Exports);
344 4 : }
345 :
346 2 : void YAMLCrossModuleImportsSubsection::map(IO &IO) {
347 4 : IO.mapTag("!CrossModuleImports", true);
348 2 : IO.mapOptional("Imports", Imports);
349 2 : }
350 :
351 185 : void YAMLSymbolsSubsection::map(IO &IO) {
352 370 : IO.mapTag("!Symbols", true);
353 185 : IO.mapRequired("Records", Symbols);
354 185 : }
355 :
356 60 : void YAMLStringTableSubsection::map(IO &IO) {
357 120 : IO.mapTag("!StringTable", true);
358 60 : IO.mapRequired("Strings", Strings);
359 60 : }
360 :
361 11 : void YAMLFrameDataSubsection::map(IO &IO) {
362 22 : IO.mapTag("!FrameData", true);
363 11 : IO.mapRequired("Frames", Frames);
364 11 : }
365 :
366 0 : void YAMLCoffSymbolRVASubsection::map(IO &IO) {
367 0 : IO.mapTag("!COFFSymbolRVAs", true);
368 0 : IO.mapRequired("RVAs", RVAs);
369 0 : }
370 :
371 399 : void MappingTraits<YAMLDebugSubsection>::mapping(
372 : IO &IO, YAMLDebugSubsection &Subsection) {
373 399 : if (!IO.outputting()) {
374 688 : if (IO.mapTag("!FileChecksums")) {
375 : auto SS = std::make_shared<YAMLChecksumsSubsection>();
376 : Subsection.Subsection = SS;
377 588 : } else if (IO.mapTag("!Lines")) {
378 60 : Subsection.Subsection = std::make_shared<YAMLLinesSubsection>();
379 468 : } else if (IO.mapTag("!InlineeLines")) {
380 2 : Subsection.Subsection = std::make_shared<YAMLInlineeLinesSubsection>();
381 464 : } else if (IO.mapTag("!CrossModuleExports")) {
382 : Subsection.Subsection =
383 2 : std::make_shared<YAMLCrossModuleExportsSubsection>();
384 460 : } else if (IO.mapTag("!CrossModuleImports")) {
385 : Subsection.Subsection =
386 1 : std::make_shared<YAMLCrossModuleImportsSubsection>();
387 458 : } else if (IO.mapTag("!Symbols")) {
388 167 : Subsection.Subsection = std::make_shared<YAMLSymbolsSubsection>();
389 124 : } else if (IO.mapTag("!StringTable")) {
390 55 : Subsection.Subsection = std::make_shared<YAMLStringTableSubsection>();
391 14 : } else if (IO.mapTag("!FrameData")) {
392 7 : Subsection.Subsection = std::make_shared<YAMLFrameDataSubsection>();
393 0 : } else if (IO.mapTag("!COFFSymbolRVAs")) {
394 0 : Subsection.Subsection = std::make_shared<YAMLCoffSymbolRVASubsection>();
395 : } else {
396 0 : llvm_unreachable("Unexpected subsection tag!");
397 : }
398 : }
399 399 : Subsection.Subsection->map(IO);
400 399 : }
401 :
402 82 : std::shared_ptr<DebugSubsection> YAMLChecksumsSubsection::toCodeViewSubsection(
403 : BumpPtrAllocator &Allocator,
404 : const codeview::StringsAndChecksums &SC) const {
405 : assert(SC.hasStrings());
406 : auto Result = std::make_shared<DebugChecksumsSubsection>(*SC.strings());
407 172 : for (const auto &CS : Checksums) {
408 90 : Result->addChecksum(CS.FileName, CS.Kind, CS.ChecksumBytes.Bytes);
409 : }
410 82 : return Result;
411 : }
412 :
413 51 : 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 51 : Result->setCodeSize(Lines.CodeSize);
420 51 : Result->setRelocationAddress(Lines.RelocSegment, Lines.RelocOffset);
421 51 : Result->setFlags(Lines.Flags);
422 102 : for (const auto &LC : Lines.Blocks) {
423 51 : Result->createBlock(LC.FileName);
424 51 : if (Result->hasColumnInfo()) {
425 2 : for (const auto &Item : zip(LC.Lines, LC.Columns)) {
426 : auto &L = std::get<0>(Item);
427 : auto &C = std::get<1>(Item);
428 1 : uint32_t LE = L.LineStart + L.EndDelta;
429 1 : Result->addLineAndColumnInfo(L.Offset,
430 1 : LineInfo(L.LineStart, LE, L.IsStatement),
431 1 : C.StartColumn, C.EndColumn);
432 : }
433 : } else {
434 151 : for (const auto &L : LC.Lines) {
435 101 : uint32_t LE = L.LineStart + L.EndDelta;
436 101 : Result->addLineInfo(L.Offset, LineInfo(L.LineStart, LE, L.IsStatement));
437 : }
438 : }
439 : }
440 51 : return Result;
441 : }
442 :
443 : std::shared_ptr<DebugSubsection>
444 2 : YAMLInlineeLinesSubsection::toCodeViewSubsection(
445 : BumpPtrAllocator &Allocator,
446 : const codeview::StringsAndChecksums &SC) const {
447 : assert(SC.hasChecksums());
448 : auto Result = std::make_shared<DebugInlineeLinesSubsection>(
449 2 : *SC.checksums(), InlineeLines.HasExtraFiles);
450 :
451 4 : for (const auto &Site : InlineeLines.Sites) {
452 2 : Result->addInlineSite(TypeIndex(Site.Inlinee), Site.FileName,
453 2 : Site.SourceLineNum);
454 2 : if (!InlineeLines.HasExtraFiles)
455 : continue;
456 :
457 0 : for (auto EF : Site.ExtraFiles) {
458 0 : Result->addExtraFile(EF);
459 : }
460 : }
461 2 : return Result;
462 : }
463 :
464 : std::shared_ptr<DebugSubsection>
465 2 : YAMLCrossModuleExportsSubsection::toCodeViewSubsection(
466 : BumpPtrAllocator &Allocator,
467 : const codeview::StringsAndChecksums &SC) const {
468 : auto Result = std::make_shared<DebugCrossModuleExportsSubsection>();
469 6 : for (const auto &M : Exports)
470 4 : Result->addMapping(M.Local, M.Global);
471 2 : return Result;
472 : }
473 :
474 : std::shared_ptr<DebugSubsection>
475 1 : 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 2 : for (const auto &M : Imports) {
483 3 : for (const auto Id : M.ImportIds)
484 2 : Result->addImport(M.ModuleName, Id);
485 : }
486 1 : return Result;
487 : }
488 :
489 141 : std::shared_ptr<DebugSubsection> YAMLSymbolsSubsection::toCodeViewSubsection(
490 : BumpPtrAllocator &Allocator,
491 : const codeview::StringsAndChecksums &SC) const {
492 : auto Result = std::make_shared<DebugSymbolsSubsection>();
493 553 : for (const auto &Sym : Symbols)
494 412 : Result->addSymbol(
495 824 : Sym.toCodeViewSymbol(Allocator, CodeViewContainer::ObjectFile));
496 141 : return Result;
497 : }
498 :
499 : std::shared_ptr<DebugSubsection>
500 91 : YAMLStringTableSubsection::toCodeViewSubsection(
501 : BumpPtrAllocator &Allocator,
502 : const codeview::StringsAndChecksums &SC) const {
503 : auto Result = std::make_shared<DebugStringTableSubsection>();
504 196 : for (const auto &Str : this->Strings)
505 105 : Result->insert(Str);
506 91 : return Result;
507 : }
508 :
509 3 : std::shared_ptr<DebugSubsection> YAMLFrameDataSubsection::toCodeViewSubsection(
510 : BumpPtrAllocator &Allocator,
511 : const codeview::StringsAndChecksums &SC) const {
512 : assert(SC.hasStrings());
513 :
514 3 : auto Result = std::make_shared<DebugFrameDataSubsection>(true);
515 11 : for (const auto &YF : Frames) {
516 : codeview::FrameData F;
517 8 : F.CodeSize = YF.CodeSize;
518 8 : F.Flags = YF.Flags;
519 8 : F.LocalSize = YF.LocalSize;
520 8 : F.MaxStackSize = YF.MaxStackSize;
521 8 : F.ParamsSize = YF.ParamsSize;
522 8 : F.PrologSize = YF.PrologSize;
523 8 : F.RvaStart = YF.RvaStart;
524 8 : F.SavedRegsSize = YF.SavedRegsSize;
525 8 : F.FrameFunc = SC.strings()->insert(YF.FrameFunc);
526 8 : Result->addFrameData(F);
527 : }
528 3 : return Result;
529 : }
530 :
531 : std::shared_ptr<DebugSubsection>
532 0 : YAMLCoffSymbolRVASubsection::toCodeViewSubsection(
533 : BumpPtrAllocator &Allocator,
534 : const codeview::StringsAndChecksums &SC) const {
535 : auto Result = std::make_shared<DebugSymbolRVASubsection>();
536 0 : for (const auto &RVA : RVAs)
537 0 : Result->addRVA(RVA);
538 0 : return Result;
539 : }
540 :
541 : static Expected<SourceFileChecksumEntry>
542 16 : convertOneChecksum(const DebugStringTableSubsectionRef &Strings,
543 : const FileChecksumEntry &CS) {
544 16 : auto ExpectedString = Strings.getString(CS.FileNameOffset);
545 16 : if (!ExpectedString)
546 : return ExpectedString.takeError();
547 :
548 : SourceFileChecksumEntry Result;
549 16 : Result.ChecksumBytes.Bytes = CS.Checksum;
550 16 : Result.Kind = CS.Kind;
551 16 : Result.FileName = *ExpectedString;
552 : return Result;
553 : }
554 :
555 : static Expected<StringRef>
556 15 : getFileName(const DebugStringTableSubsectionRef &Strings,
557 : const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID) {
558 : auto Iter = Checksums.getArray().at(FileID);
559 15 : if (Iter == Checksums.getArray().end())
560 : return make_error<CodeViewError>(cv_error_code::no_records);
561 15 : uint32_t Offset = Iter->FileNameOffset;
562 15 : return Strings.getString(Offset);
563 : }
564 :
565 : Expected<std::shared_ptr<YAMLChecksumsSubsection>>
566 10 : YAMLChecksumsSubsection::fromCodeViewSubsection(
567 : const DebugStringTableSubsectionRef &Strings,
568 : const DebugChecksumsSubsectionRef &FC) {
569 : auto Result = std::make_shared<YAMLChecksumsSubsection>();
570 :
571 26 : for (const auto &CS : FC) {
572 32 : auto ConvertedCS = convertOneChecksum(Strings, CS);
573 16 : if (!ConvertedCS)
574 : return ConvertedCS.takeError();
575 16 : Result->Checksums.push_back(*ConvertedCS);
576 : }
577 : return Result;
578 : }
579 :
580 : Expected<std::shared_ptr<YAMLLinesSubsection>>
581 14 : YAMLLinesSubsection::fromCodeViewSubsection(
582 : const DebugStringTableSubsectionRef &Strings,
583 : const DebugChecksumsSubsectionRef &Checksums,
584 : const DebugLinesSubsectionRef &Lines) {
585 : auto Result = std::make_shared<YAMLLinesSubsection>();
586 28 : Result->Lines.CodeSize = Lines.header()->CodeSize;
587 14 : Result->Lines.RelocOffset = Lines.header()->RelocOffset;
588 14 : Result->Lines.RelocSegment = Lines.header()->RelocSegment;
589 14 : Result->Lines.Flags = static_cast<LineFlags>(uint16_t(Lines.header()->Flags));
590 28 : for (const auto &L : Lines) {
591 14 : SourceLineBlock Block;
592 14 : auto EF = getFileName(Strings, Checksums, L.NameIndex);
593 14 : if (!EF)
594 : return EF.takeError();
595 14 : Block.FileName = *EF;
596 14 : if (Lines.hasColumnInfo()) {
597 0 : for (const auto &C : L.Columns) {
598 : SourceColumnEntry SCE;
599 0 : SCE.EndColumn = C.EndColumn;
600 0 : SCE.StartColumn = C.StartColumn;
601 0 : Block.Columns.push_back(SCE);
602 : }
603 : }
604 49 : for (const auto &LN : L.LineNumbers) {
605 : SourceLineEntry SLE;
606 : LineInfo LI(LN.Flags);
607 35 : SLE.Offset = LN.Offset;
608 35 : SLE.LineStart = LI.getStartLine();
609 35 : SLE.EndDelta = LI.getLineDelta();
610 35 : SLE.IsStatement = LI.isStatement();
611 35 : Block.Lines.push_back(SLE);
612 : }
613 14 : Result->Lines.Blocks.push_back(Block);
614 : }
615 : return Result;
616 : }
617 :
618 : Expected<std::shared_ptr<YAMLInlineeLinesSubsection>>
619 1 : YAMLInlineeLinesSubsection::fromCodeViewSubsection(
620 : const DebugStringTableSubsectionRef &Strings,
621 : const DebugChecksumsSubsectionRef &Checksums,
622 : const DebugInlineeLinesSubsectionRef &Lines) {
623 : auto Result = std::make_shared<YAMLInlineeLinesSubsection>();
624 :
625 1 : Result->InlineeLines.HasExtraFiles = Lines.hasExtraFiles();
626 2 : for (const auto &IL : Lines) {
627 : InlineeSite Site;
628 2 : auto ExpF = getFileName(Strings, Checksums, IL.Header->FileID);
629 1 : if (!ExpF)
630 : return ExpF.takeError();
631 1 : Site.FileName = *ExpF;
632 2 : Site.Inlinee = IL.Header->Inlinee.getIndex();
633 1 : Site.SourceLineNum = IL.Header->SourceLineNum;
634 1 : if (Lines.hasExtraFiles()) {
635 0 : for (const auto EF : IL.ExtraFiles) {
636 0 : auto ExpF2 = getFileName(Strings, Checksums, EF);
637 0 : if (!ExpF2)
638 : return ExpF2.takeError();
639 0 : Site.ExtraFiles.push_back(*ExpF2);
640 : }
641 : }
642 1 : Result->InlineeLines.Sites.push_back(Site);
643 : }
644 : return Result;
645 : }
646 :
647 : Expected<std::shared_ptr<YAMLCrossModuleExportsSubsection>>
648 2 : YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(
649 : const DebugCrossModuleExportsSubsectionRef &Exports) {
650 : auto Result = std::make_shared<YAMLCrossModuleExportsSubsection>();
651 6 : Result->Exports.assign(Exports.begin(), Exports.end());
652 2 : return Result;
653 : }
654 :
655 : Expected<std::shared_ptr<YAMLCrossModuleImportsSubsection>>
656 1 : YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(
657 : const DebugStringTableSubsectionRef &Strings,
658 : const DebugCrossModuleImportsSubsectionRef &Imports) {
659 : auto Result = std::make_shared<YAMLCrossModuleImportsSubsection>();
660 2 : for (const auto &CMI : Imports) {
661 : YAMLCrossModuleImport YCMI;
662 2 : auto ExpectedStr = Strings.getString(CMI.Header->ModuleNameOffset);
663 1 : if (!ExpectedStr)
664 : return ExpectedStr.takeError();
665 1 : YCMI.ModuleName = *ExpectedStr;
666 3 : YCMI.ImportIds.assign(CMI.Imports.begin(), CMI.Imports.end());
667 1 : Result->Imports.push_back(YCMI);
668 : }
669 : return Result;
670 : }
671 :
672 : Expected<std::shared_ptr<YAMLSymbolsSubsection>>
673 18 : YAMLSymbolsSubsection::fromCodeViewSubsection(
674 : const DebugSymbolsSubsectionRef &Symbols) {
675 : auto Result = std::make_shared<YAMLSymbolsSubsection>();
676 225 : for (const auto &Sym : Symbols) {
677 414 : auto S = CodeViewYAML::SymbolRecord::fromCodeViewSymbol(Sym);
678 207 : if (!S)
679 0 : return joinErrors(make_error<CodeViewError>(
680 : cv_error_code::corrupt_record,
681 : "Invalid CodeView Symbol Record in SymbolRecord "
682 : "subsection of .debug$S while converting to YAML!"),
683 0 : S.takeError());
684 :
685 207 : Result->Symbols.push_back(*S);
686 : }
687 : return Result;
688 : }
689 :
690 : Expected<std::shared_ptr<YAMLStringTableSubsection>>
691 5 : YAMLStringTableSubsection::fromCodeViewSubsection(
692 : const DebugStringTableSubsectionRef &Strings) {
693 : auto Result = std::make_shared<YAMLStringTableSubsection>();
694 5 : BinaryStreamReader Reader(Strings.getBuffer());
695 5 : StringRef S;
696 : // First item is a single null string, skip it.
697 10 : if (auto EC = Reader.readCString(S))
698 : return std::move(EC);
699 : assert(S.empty());
700 37 : while (Reader.bytesRemaining() > 0) {
701 32 : if (auto EC = Reader.readCString(S))
702 : return std::move(EC);
703 16 : Result->Strings.push_back(S);
704 : }
705 : return Result;
706 : }
707 :
708 : Expected<std::shared_ptr<YAMLFrameDataSubsection>>
709 4 : YAMLFrameDataSubsection::fromCodeViewSubsection(
710 : const DebugStringTableSubsectionRef &Strings,
711 : const DebugFrameDataSubsectionRef &Frames) {
712 : auto Result = std::make_shared<YAMLFrameDataSubsection>();
713 11 : for (const auto &F : Frames) {
714 : YAMLFrameData YF;
715 7 : YF.CodeSize = F.CodeSize;
716 7 : YF.Flags = F.Flags;
717 7 : YF.LocalSize = F.LocalSize;
718 7 : YF.MaxStackSize = F.MaxStackSize;
719 7 : YF.ParamsSize = F.ParamsSize;
720 7 : YF.PrologSize = F.PrologSize;
721 7 : YF.RvaStart = F.RvaStart;
722 7 : YF.SavedRegsSize = F.SavedRegsSize;
723 :
724 7 : auto ES = Strings.getString(F.FrameFunc);
725 7 : if (!ES)
726 0 : return joinErrors(
727 0 : make_error<CodeViewError>(
728 : cv_error_code::no_records,
729 : "Could not find string for string id while mapping FrameData!"),
730 0 : ES.takeError());
731 7 : YF.FrameFunc = *ES;
732 7 : Result->Frames.push_back(YF);
733 : }
734 : return Result;
735 : }
736 :
737 : Expected<std::shared_ptr<YAMLCoffSymbolRVASubsection>>
738 0 : YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(
739 : const DebugSymbolRVASubsectionRef &Section) {
740 : auto Result = std::make_shared<YAMLCoffSymbolRVASubsection>();
741 0 : for (const auto &RVA : Section) {
742 0 : Result->RVAs.push_back(RVA);
743 : }
744 0 : return Result;
745 : }
746 :
747 : Expected<std::vector<std::shared_ptr<DebugSubsection>>>
748 72 : llvm::CodeViewYAML::toCodeViewSubsectionList(
749 : BumpPtrAllocator &Allocator, ArrayRef<YAMLDebugSubsection> Subsections,
750 : const codeview::StringsAndChecksums &SC) {
751 72 : std::vector<std::shared_ptr<DebugSubsection>> Result;
752 72 : if (Subsections.empty())
753 : return std::move(Result);
754 :
755 349 : for (const auto &SS : Subsections) {
756 287 : std::shared_ptr<DebugSubsection> CVS;
757 574 : 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 55 : 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 0 : Error SubsectionConversionVisitor::visitUnknown(
795 : DebugUnknownSubsectionRef &Unknown) {
796 0 : return make_error<CodeViewError>(cv_error_code::operation_unsupported);
797 : }
798 :
799 14 : Error SubsectionConversionVisitor::visitLines(
800 : DebugLinesSubsectionRef &Lines, const StringsAndChecksumsRef &State) {
801 : auto Result = YAMLLinesSubsection::fromCodeViewSubsection(
802 28 : State.strings(), State.checksums(), Lines);
803 14 : if (!Result)
804 : return Result.takeError();
805 : Subsection.Subsection = *Result;
806 : return Error::success();
807 : }
808 :
809 10 : Error SubsectionConversionVisitor::visitFileChecksums(
810 : DebugChecksumsSubsectionRef &Checksums,
811 : const StringsAndChecksumsRef &State) {
812 : auto Result = YAMLChecksumsSubsection::fromCodeViewSubsection(State.strings(),
813 20 : Checksums);
814 10 : if (!Result)
815 : return Result.takeError();
816 : Subsection.Subsection = *Result;
817 : return Error::success();
818 : }
819 :
820 1 : Error SubsectionConversionVisitor::visitInlineeLines(
821 : DebugInlineeLinesSubsectionRef &Inlinees,
822 : const StringsAndChecksumsRef &State) {
823 : auto Result = YAMLInlineeLinesSubsection::fromCodeViewSubsection(
824 2 : State.strings(), State.checksums(), Inlinees);
825 1 : if (!Result)
826 : return Result.takeError();
827 : Subsection.Subsection = *Result;
828 : return Error::success();
829 : }
830 :
831 2 : Error SubsectionConversionVisitor::visitCrossModuleExports(
832 : DebugCrossModuleExportsSubsectionRef &Exports,
833 : const StringsAndChecksumsRef &State) {
834 : auto Result =
835 4 : YAMLCrossModuleExportsSubsection::fromCodeViewSubsection(Exports);
836 2 : if (!Result)
837 : return Result.takeError();
838 : Subsection.Subsection = *Result;
839 : return Error::success();
840 : }
841 :
842 1 : Error SubsectionConversionVisitor::visitCrossModuleImports(
843 : DebugCrossModuleImportsSubsectionRef &Imports,
844 : const StringsAndChecksumsRef &State) {
845 : auto Result = YAMLCrossModuleImportsSubsection::fromCodeViewSubsection(
846 2 : State.strings(), Imports);
847 1 : if (!Result)
848 : return Result.takeError();
849 : Subsection.Subsection = *Result;
850 : return Error::success();
851 : }
852 :
853 5 : Error SubsectionConversionVisitor::visitStringTable(
854 : DebugStringTableSubsectionRef &Strings,
855 : const StringsAndChecksumsRef &State) {
856 10 : auto Result = YAMLStringTableSubsection::fromCodeViewSubsection(Strings);
857 5 : if (!Result)
858 : return Result.takeError();
859 : Subsection.Subsection = *Result;
860 : return Error::success();
861 : }
862 :
863 18 : Error SubsectionConversionVisitor::visitSymbols(
864 : DebugSymbolsSubsectionRef &Symbols, const StringsAndChecksumsRef &State) {
865 36 : auto Result = YAMLSymbolsSubsection::fromCodeViewSubsection(Symbols);
866 18 : if (!Result)
867 : return Result.takeError();
868 : Subsection.Subsection = *Result;
869 : return Error::success();
870 : }
871 :
872 4 : Error SubsectionConversionVisitor::visitFrameData(
873 : DebugFrameDataSubsectionRef &Frames, const StringsAndChecksumsRef &State) {
874 : auto Result =
875 8 : YAMLFrameDataSubsection::fromCodeViewSubsection(State.strings(), Frames);
876 4 : if (!Result)
877 : return Result.takeError();
878 : Subsection.Subsection = *Result;
879 : return Error::success();
880 : }
881 :
882 0 : Error SubsectionConversionVisitor::visitCOFFSymbolRVAs(
883 : DebugSymbolRVASubsectionRef &RVAs, const StringsAndChecksumsRef &State) {
884 0 : auto Result = YAMLCoffSymbolRVASubsection::fromCodeViewSubsection(RVAs);
885 0 : if (!Result)
886 : return Result.takeError();
887 : Subsection.Subsection = *Result;
888 : return Error::success();
889 : }
890 :
891 : Expected<YAMLDebugSubsection>
892 55 : YAMLDebugSubsection::fromCodeViewSubection(const StringsAndChecksumsRef &SC,
893 : const DebugSubsectionRecord &SS) {
894 55 : SubsectionConversionVisitor V;
895 110 : if (auto EC = visitDebugSubsection(SS, V, SC))
896 : return std::move(EC);
897 :
898 : return V.Subsection;
899 : }
900 :
901 : std::vector<YAMLDebugSubsection>
902 8 : llvm::CodeViewYAML::fromDebugS(ArrayRef<uint8_t> Data,
903 : const StringsAndChecksumsRef &SC) {
904 8 : BinaryStreamReader Reader(Data, support::little);
905 : uint32_t Magic;
906 :
907 16 : ExitOnError Err("Invalid .debug$S section!");
908 16 : Err(Reader.readInteger(Magic));
909 : assert(Magic == COFF::DEBUG_SECTION_MAGIC && "Invalid .debug$S section!");
910 :
911 : DebugSubsectionArray Subsections;
912 16 : Err(Reader.readArray(Subsections, Reader.bytesRemaining()));
913 :
914 : std::vector<YAMLDebugSubsection> Result;
915 :
916 39 : for (const auto &SS : Subsections) {
917 31 : auto YamlSS = Err(YAMLDebugSubsection::fromCodeViewSubection(SC, SS));
918 31 : Result.push_back(YamlSS);
919 : }
920 8 : return Result;
921 : }
922 :
923 59 : void llvm::CodeViewYAML::initializeStringsAndChecksums(
924 : ArrayRef<YAMLDebugSubsection> Sections, codeview::StringsAndChecksums &SC) {
925 : // String Table and Checksums subsections don't use the allocator.
926 59 : BumpPtrAllocator 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 59 : if (!SC.hasStrings()) {
936 226 : for (const auto &SS : Sections) {
937 226 : if (SS.Subsection->Kind != DebugSubsectionKind::StringTable)
938 181 : continue;
939 :
940 45 : auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC);
941 : SC.setStrings(
942 90 : std::static_pointer_cast<DebugStringTableSubsection>(Result));
943 : break;
944 : }
945 : }
946 :
947 59 : if (SC.hasStrings() && !SC.hasChecksums()) {
948 210 : for (const auto &SS : Sections) {
949 192 : if (SS.Subsection->Kind != DebugSubsectionKind::FileChecksums)
950 151 : continue;
951 :
952 41 : auto Result = SS.Subsection->toCodeViewSubsection(Allocator, SC);
953 : SC.setChecksums(
954 82 : std::static_pointer_cast<DebugChecksumsSubsection>(Result));
955 : break;
956 : }
957 : }
958 59 : }
|