1 //===- DWARFYAML.h - DWARF YAMLIO implementation ----------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file declares classes for handling the YAML representation
11 /// of DWARF Debug Info.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_OBJECTYAML_DWARFYAML_H
16 #define LLVM_OBJECTYAML_DWARFYAML_H
17 
18 #include "llvm/ADT/SetVector.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/BinaryFormat/Dwarf.h"
21 #include "llvm/ObjectYAML/YAML.h"
22 #include "llvm/Support/YAMLTraits.h"
23 #include <cstdint>
24 #include <optional>
25 #include <unordered_map>
26 #include <vector>
27 
28 namespace llvm {
29 namespace DWARFYAML {
30 
31 struct AttributeAbbrev {
32   llvm::dwarf::Attribute Attribute;
33   llvm::dwarf::Form Form;
34   llvm::yaml::Hex64 Value; // Some DWARF5 attributes have values
35 };
36 
37 struct Abbrev {
38   std::optional<yaml::Hex64> Code;
39   llvm::dwarf::Tag Tag;
40   llvm::dwarf::Constants Children;
41   std::vector<AttributeAbbrev> Attributes;
42 };
43 
44 struct AbbrevTable {
45   std::optional<uint64_t> ID;
46   std::vector<Abbrev> Table;
47 };
48 
49 struct ARangeDescriptor {
50   llvm::yaml::Hex64 Address;
51   yaml::Hex64 Length;
52 };
53 
54 struct ARange {
55   dwarf::DwarfFormat Format;
56   std::optional<yaml::Hex64> Length;
57   uint16_t Version;
58   yaml::Hex64 CuOffset;
59   std::optional<yaml::Hex8> AddrSize;
60   yaml::Hex8 SegSize;
61   std::vector<ARangeDescriptor> Descriptors;
62 };
63 
64 /// Class that describes a range list entry, or a base address selection entry
65 /// within a range list in the .debug_ranges section.
66 struct RangeEntry {
67   llvm::yaml::Hex64 LowOffset;
68   llvm::yaml::Hex64 HighOffset;
69 };
70 
71 /// Class that describes a single range list inside the .debug_ranges section.
72 struct Ranges {
73   std::optional<llvm::yaml::Hex64> Offset;
74   std::optional<llvm::yaml::Hex8> AddrSize;
75   std::vector<RangeEntry> Entries;
76 };
77 
78 struct PubEntry {
79   llvm::yaml::Hex32 DieOffset;
80   llvm::yaml::Hex8 Descriptor;
81   StringRef Name;
82 };
83 
84 struct PubSection {
85   dwarf::DwarfFormat Format;
86   yaml::Hex64 Length;
87   uint16_t Version;
88   uint32_t UnitOffset;
89   uint32_t UnitSize;
90   std::vector<PubEntry> Entries;
91 };
92 
93 struct FormValue {
94   llvm::yaml::Hex64 Value;
95   StringRef CStr;
96   std::vector<llvm::yaml::Hex8> BlockData;
97 };
98 
99 struct Entry {
100   llvm::yaml::Hex32 AbbrCode;
101   std::vector<FormValue> Values;
102 };
103 
104 /// Class that contains helpful context information when mapping YAML into DWARF
105 /// data structures.
106 struct DWARFContext {
107   bool IsGNUPubSec = false;
108 };
109 
110 struct Unit {
111   dwarf::DwarfFormat Format;
112   std::optional<yaml::Hex64> Length;
113   uint16_t Version;
114   std::optional<uint8_t> AddrSize;
115   llvm::dwarf::UnitType Type; // Added in DWARF 5
116   std::optional<uint64_t> AbbrevTableID;
117   std::optional<yaml::Hex64> AbbrOffset;
118   std::vector<Entry> Entries;
119 };
120 
121 struct File {
122   StringRef Name;
123   uint64_t DirIdx;
124   uint64_t ModTime;
125   uint64_t Length;
126 };
127 
128 struct LineTableOpcode {
129   dwarf::LineNumberOps Opcode;
130   std::optional<uint64_t> ExtLen;
131   dwarf::LineNumberExtendedOps SubOpcode;
132   uint64_t Data;
133   int64_t SData;
134   File FileEntry;
135   std::vector<llvm::yaml::Hex8> UnknownOpcodeData;
136   std::vector<llvm::yaml::Hex64> StandardOpcodeData;
137 };
138 
139 struct LineTable {
140   dwarf::DwarfFormat Format;
141   std::optional<uint64_t> Length;
142   uint16_t Version;
143   std::optional<uint64_t> PrologueLength;
144   uint8_t MinInstLength;
145   uint8_t MaxOpsPerInst;
146   uint8_t DefaultIsStmt;
147   uint8_t LineBase;
148   uint8_t LineRange;
149   std::optional<uint8_t> OpcodeBase;
150   std::optional<std::vector<uint8_t>> StandardOpcodeLengths;
151   std::vector<StringRef> IncludeDirs;
152   std::vector<File> Files;
153   std::vector<LineTableOpcode> Opcodes;
154 };
155 
156 struct SegAddrPair {
157   yaml::Hex64 Segment;
158   yaml::Hex64 Address;
159 };
160 
161 struct AddrTableEntry {
162   dwarf::DwarfFormat Format;
163   std::optional<yaml::Hex64> Length;
164   yaml::Hex16 Version;
165   std::optional<yaml::Hex8> AddrSize;
166   yaml::Hex8 SegSelectorSize;
167   std::vector<SegAddrPair> SegAddrPairs;
168 };
169 
170 struct StringOffsetsTable {
171   dwarf::DwarfFormat Format;
172   std::optional<yaml::Hex64> Length;
173   yaml::Hex16 Version;
174   yaml::Hex16 Padding;
175   std::vector<yaml::Hex64> Offsets;
176 };
177 
178 struct DWARFOperation {
179   dwarf::LocationAtom Operator;
180   std::vector<yaml::Hex64> Values;
181 };
182 
183 struct RnglistEntry {
184   dwarf::RnglistEntries Operator;
185   std::vector<yaml::Hex64> Values;
186 };
187 
188 struct LoclistEntry {
189   dwarf::LoclistEntries Operator;
190   std::vector<yaml::Hex64> Values;
191   std::optional<yaml::Hex64> DescriptionsLength;
192   std::vector<DWARFOperation> Descriptions;
193 };
194 
195 template <typename EntryType> struct ListEntries {
196   std::optional<std::vector<EntryType>> Entries;
197   std::optional<yaml::BinaryRef> Content;
198 };
199 
200 template <typename EntryType> struct ListTable {
201   dwarf::DwarfFormat Format;
202   std::optional<yaml::Hex64> Length;
203   yaml::Hex16 Version;
204   std::optional<yaml::Hex8> AddrSize;
205   yaml::Hex8 SegSelectorSize;
206   std::optional<uint32_t> OffsetEntryCount;
207   std::optional<std::vector<yaml::Hex64>> Offsets;
208   std::vector<ListEntries<EntryType>> Lists;
209 };
210 
211 struct Data {
212   bool IsLittleEndian;
213   bool Is64BitAddrSize;
214   std::vector<AbbrevTable> DebugAbbrev;
215   std::optional<std::vector<StringRef>> DebugStrings;
216   std::optional<std::vector<StringOffsetsTable>> DebugStrOffsets;
217   std::optional<std::vector<ARange>> DebugAranges;
218   std::optional<std::vector<Ranges>> DebugRanges;
219   std::optional<std::vector<AddrTableEntry>> DebugAddr;
220   std::optional<PubSection> PubNames;
221   std::optional<PubSection> PubTypes;
222 
223   std::optional<PubSection> GNUPubNames;
224   std::optional<PubSection> GNUPubTypes;
225 
226   std::vector<Unit> CompileUnits;
227 
228   std::vector<LineTable> DebugLines;
229   std::optional<std::vector<ListTable<RnglistEntry>>> DebugRnglists;
230   std::optional<std::vector<ListTable<LoclistEntry>>> DebugLoclists;
231 
232   bool isEmpty() const;
233 
234   SetVector<StringRef> getNonEmptySectionNames() const;
235 
236   struct AbbrevTableInfo {
237     uint64_t Index;
238     uint64_t Offset;
239   };
240   Expected<AbbrevTableInfo> getAbbrevTableInfoByID(uint64_t ID) const;
241   StringRef getAbbrevTableContentByIndex(uint64_t Index) const;
242 
243 private:
244   mutable std::unordered_map<uint64_t, AbbrevTableInfo> AbbrevTableInfoMap;
245   mutable std::unordered_map<uint64_t, std::string> AbbrevTableContents;
246 };
247 
248 } // end namespace DWARFYAML
249 } // end namespace llvm
250 
251 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::AttributeAbbrev)
252 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Abbrev)
253 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::AbbrevTable)
254 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::ARangeDescriptor)
255 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::ARange)
256 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::RangeEntry)
257 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Ranges)
258 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::PubEntry)
259 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Unit)
260 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::FormValue)
261 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::Entry)
262 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::File)
263 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::LineTable)
264 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::LineTableOpcode)
265 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::SegAddrPair)
266 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::AddrTableEntry)
267 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::StringOffsetsTable)
268 LLVM_YAML_IS_SEQUENCE_VECTOR(
269     llvm::DWARFYAML::ListTable<DWARFYAML::RnglistEntry>)
270 LLVM_YAML_IS_SEQUENCE_VECTOR(
271     llvm::DWARFYAML::ListEntries<DWARFYAML::RnglistEntry>)
272 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::RnglistEntry)
273 LLVM_YAML_IS_SEQUENCE_VECTOR(
274     llvm::DWARFYAML::ListTable<DWARFYAML::LoclistEntry>)
275 LLVM_YAML_IS_SEQUENCE_VECTOR(
276     llvm::DWARFYAML::ListEntries<DWARFYAML::LoclistEntry>)
277 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::LoclistEntry)
278 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::DWARFOperation)
279 
280 namespace llvm {
281 namespace yaml {
282 
283 template <> struct MappingTraits<DWARFYAML::Data> {
284   static void mapping(IO &IO, DWARFYAML::Data &DWARF);
285 };
286 
287 template <> struct MappingTraits<DWARFYAML::AbbrevTable> {
288   static void mapping(IO &IO, DWARFYAML::AbbrevTable &AbbrevTable);
289 };
290 
291 template <> struct MappingTraits<DWARFYAML::Abbrev> {
292   static void mapping(IO &IO, DWARFYAML::Abbrev &Abbrev);
293 };
294 
295 template <> struct MappingTraits<DWARFYAML::AttributeAbbrev> {
296   static void mapping(IO &IO, DWARFYAML::AttributeAbbrev &AttAbbrev);
297 };
298 
299 template <> struct MappingTraits<DWARFYAML::ARangeDescriptor> {
300   static void mapping(IO &IO, DWARFYAML::ARangeDescriptor &Descriptor);
301 };
302 
303 template <> struct MappingTraits<DWARFYAML::ARange> {
304   static void mapping(IO &IO, DWARFYAML::ARange &ARange);
305 };
306 
307 template <> struct MappingTraits<DWARFYAML::RangeEntry> {
308   static void mapping(IO &IO, DWARFYAML::RangeEntry &Entry);
309 };
310 
311 template <> struct MappingTraits<DWARFYAML::Ranges> {
312   static void mapping(IO &IO, DWARFYAML::Ranges &Ranges);
313 };
314 
315 template <> struct MappingTraits<DWARFYAML::PubEntry> {
316   static void mapping(IO &IO, DWARFYAML::PubEntry &Entry);
317 };
318 
319 template <> struct MappingTraits<DWARFYAML::PubSection> {
320   static void mapping(IO &IO, DWARFYAML::PubSection &Section);
321 };
322 
323 template <> struct MappingTraits<DWARFYAML::Unit> {
324   static void mapping(IO &IO, DWARFYAML::Unit &Unit);
325 };
326 
327 template <> struct MappingTraits<DWARFYAML::Entry> {
328   static void mapping(IO &IO, DWARFYAML::Entry &Entry);
329 };
330 
331 template <> struct MappingTraits<DWARFYAML::FormValue> {
332   static void mapping(IO &IO, DWARFYAML::FormValue &FormValue);
333 };
334 
335 template <> struct MappingTraits<DWARFYAML::File> {
336   static void mapping(IO &IO, DWARFYAML::File &File);
337 };
338 
339 template <> struct MappingTraits<DWARFYAML::LineTableOpcode> {
340   static void mapping(IO &IO, DWARFYAML::LineTableOpcode &LineTableOpcode);
341 };
342 
343 template <> struct MappingTraits<DWARFYAML::LineTable> {
344   static void mapping(IO &IO, DWARFYAML::LineTable &LineTable);
345 };
346 
347 template <> struct MappingTraits<DWARFYAML::SegAddrPair> {
348   static void mapping(IO &IO, DWARFYAML::SegAddrPair &SegAddrPair);
349 };
350 
351 template <> struct MappingTraits<DWARFYAML::DWARFOperation> {
352   static void mapping(IO &IO, DWARFYAML::DWARFOperation &DWARFOperation);
353 };
354 
355 template <typename EntryType>
356 struct MappingTraits<DWARFYAML::ListTable<EntryType>> {
357   static void mapping(IO &IO, DWARFYAML::ListTable<EntryType> &ListTable);
358 };
359 
360 template <typename EntryType>
361 struct MappingTraits<DWARFYAML::ListEntries<EntryType>> {
362   static void mapping(IO &IO, DWARFYAML::ListEntries<EntryType> &ListEntries);
363   static std::string validate(IO &IO,
364                               DWARFYAML::ListEntries<EntryType> &ListEntries);
365 };
366 
367 template <> struct MappingTraits<DWARFYAML::RnglistEntry> {
368   static void mapping(IO &IO, DWARFYAML::RnglistEntry &RnglistEntry);
369 };
370 
371 template <> struct MappingTraits<DWARFYAML::LoclistEntry> {
372   static void mapping(IO &IO, DWARFYAML::LoclistEntry &LoclistEntry);
373 };
374 
375 template <> struct MappingTraits<DWARFYAML::AddrTableEntry> {
376   static void mapping(IO &IO, DWARFYAML::AddrTableEntry &AddrTable);
377 };
378 
379 template <> struct MappingTraits<DWARFYAML::StringOffsetsTable> {
380   static void mapping(IO &IO, DWARFYAML::StringOffsetsTable &StrOffsetsTable);
381 };
382 
383 template <> struct ScalarEnumerationTraits<dwarf::DwarfFormat> {
384   static void enumeration(IO &IO, dwarf::DwarfFormat &Format) {
385     IO.enumCase(Format, "DWARF32", dwarf::DWARF32);
386     IO.enumCase(Format, "DWARF64", dwarf::DWARF64);
387   }
388 };
389 
390 #define HANDLE_DW_TAG(unused, name, unused2, unused3, unused4)                 \
391   io.enumCase(value, "DW_TAG_" #name, dwarf::DW_TAG_##name);
392 
393 template <> struct ScalarEnumerationTraits<dwarf::Tag> {
394   static void enumeration(IO &io, dwarf::Tag &value) {
395 #include "llvm/BinaryFormat/Dwarf.def"
396     io.enumFallback<Hex16>(value);
397   }
398 };
399 
400 #define HANDLE_DW_LNS(unused, name)                                            \
401   io.enumCase(value, "DW_LNS_" #name, dwarf::DW_LNS_##name);
402 
403 template <> struct ScalarEnumerationTraits<dwarf::LineNumberOps> {
404   static void enumeration(IO &io, dwarf::LineNumberOps &value) {
405 #include "llvm/BinaryFormat/Dwarf.def"
406     io.enumFallback<Hex8>(value);
407   }
408 };
409 
410 #define HANDLE_DW_LNE(unused, name)                                            \
411   io.enumCase(value, "DW_LNE_" #name, dwarf::DW_LNE_##name);
412 
413 template <> struct ScalarEnumerationTraits<dwarf::LineNumberExtendedOps> {
414   static void enumeration(IO &io, dwarf::LineNumberExtendedOps &value) {
415 #include "llvm/BinaryFormat/Dwarf.def"
416     io.enumFallback<Hex16>(value);
417   }
418 };
419 
420 #define HANDLE_DW_AT(unused, name, unused2, unused3)                           \
421   io.enumCase(value, "DW_AT_" #name, dwarf::DW_AT_##name);
422 
423 template <> struct ScalarEnumerationTraits<dwarf::Attribute> {
424   static void enumeration(IO &io, dwarf::Attribute &value) {
425 #include "llvm/BinaryFormat/Dwarf.def"
426     io.enumFallback<Hex16>(value);
427   }
428 };
429 
430 #define HANDLE_DW_FORM(unused, name, unused2, unused3)                         \
431   io.enumCase(value, "DW_FORM_" #name, dwarf::DW_FORM_##name);
432 
433 template <> struct ScalarEnumerationTraits<dwarf::Form> {
434   static void enumeration(IO &io, dwarf::Form &value) {
435 #include "llvm/BinaryFormat/Dwarf.def"
436     io.enumFallback<Hex16>(value);
437   }
438 };
439 
440 #define HANDLE_DW_UT(unused, name)                                             \
441   io.enumCase(value, "DW_UT_" #name, dwarf::DW_UT_##name);
442 
443 template <> struct ScalarEnumerationTraits<dwarf::UnitType> {
444   static void enumeration(IO &io, dwarf::UnitType &value) {
445 #include "llvm/BinaryFormat/Dwarf.def"
446     io.enumFallback<Hex8>(value);
447   }
448 };
449 
450 template <> struct ScalarEnumerationTraits<dwarf::Constants> {
451   static void enumeration(IO &io, dwarf::Constants &value) {
452     io.enumCase(value, "DW_CHILDREN_no", dwarf::DW_CHILDREN_no);
453     io.enumCase(value, "DW_CHILDREN_yes", dwarf::DW_CHILDREN_yes);
454     io.enumFallback<Hex16>(value);
455   }
456 };
457 
458 #define HANDLE_DW_RLE(unused, name)                                            \
459   io.enumCase(value, "DW_RLE_" #name, dwarf::DW_RLE_##name);
460 
461 template <> struct ScalarEnumerationTraits<dwarf::RnglistEntries> {
462   static void enumeration(IO &io, dwarf::RnglistEntries &value) {
463 #include "llvm/BinaryFormat/Dwarf.def"
464   }
465 };
466 
467 #define HANDLE_DW_LLE(unused, name)                                            \
468   io.enumCase(value, "DW_LLE_" #name, dwarf::DW_LLE_##name);
469 
470 template <> struct ScalarEnumerationTraits<dwarf::LoclistEntries> {
471   static void enumeration(IO &io, dwarf::LoclistEntries &value) {
472 #include "llvm/BinaryFormat/Dwarf.def"
473   }
474 };
475 
476 #define HANDLE_DW_OP(id, name, version, vendor)                                \
477   io.enumCase(value, "DW_OP_" #name, dwarf::DW_OP_##name);
478 
479 template <> struct ScalarEnumerationTraits<dwarf::LocationAtom> {
480   static void enumeration(IO &io, dwarf::LocationAtom &value) {
481 #include "llvm/BinaryFormat/Dwarf.def"
482     io.enumFallback<yaml::Hex8>(value);
483   }
484 };
485 
486 } // end namespace yaml
487 } // end namespace llvm
488 
489 #endif // LLVM_OBJECTYAML_DWARFYAML_H
490