1 | //===- DWARFYAML.cpp - DWARF YAMLIO implementation ------------------------===// |
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 | // This file defines classes for handling the YAML representation of DWARF Debug |
10 | // Info. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "llvm/ObjectYAML/DWARFYAML.h" |
15 | #include "llvm/BinaryFormat/Dwarf.h" |
16 | #include "llvm/Support/Errc.h" |
17 | #include "llvm/Support/Error.h" |
18 | |
19 | namespace llvm { |
20 | |
21 | bool DWARFYAML::Data::isEmpty() const { |
22 | return getNonEmptySectionNames().empty(); |
23 | } |
24 | |
25 | SetVector<StringRef> DWARFYAML::Data::getNonEmptySectionNames() const { |
26 | SetVector<StringRef> SecNames; |
27 | if (DebugStrings) |
28 | SecNames.insert(X: "debug_str" ); |
29 | if (DebugAranges) |
30 | SecNames.insert(X: "debug_aranges" ); |
31 | if (DebugRanges) |
32 | SecNames.insert(X: "debug_ranges" ); |
33 | if (!DebugLines.empty()) |
34 | SecNames.insert(X: "debug_line" ); |
35 | if (DebugAddr) |
36 | SecNames.insert(X: "debug_addr" ); |
37 | if (!DebugAbbrev.empty()) |
38 | SecNames.insert(X: "debug_abbrev" ); |
39 | if (!Units.empty()) |
40 | SecNames.insert(X: "debug_info" ); |
41 | if (PubNames) |
42 | SecNames.insert(X: "debug_pubnames" ); |
43 | if (PubTypes) |
44 | SecNames.insert(X: "debug_pubtypes" ); |
45 | if (GNUPubNames) |
46 | SecNames.insert(X: "debug_gnu_pubnames" ); |
47 | if (GNUPubTypes) |
48 | SecNames.insert(X: "debug_gnu_pubtypes" ); |
49 | if (DebugStrOffsets) |
50 | SecNames.insert(X: "debug_str_offsets" ); |
51 | if (DebugRnglists) |
52 | SecNames.insert(X: "debug_rnglists" ); |
53 | if (DebugLoclists) |
54 | SecNames.insert(X: "debug_loclists" ); |
55 | if (DebugNames) |
56 | SecNames.insert(X: "debug_names" ); |
57 | return SecNames; |
58 | } |
59 | |
60 | Expected<DWARFYAML::Data::AbbrevTableInfo> |
61 | DWARFYAML::Data::getAbbrevTableInfoByID(uint64_t ID) const { |
62 | if (AbbrevTableInfoMap.empty()) { |
63 | uint64_t AbbrevTableOffset = 0; |
64 | for (const auto &[Index, AbbrevTable] : enumerate(First: DebugAbbrev)) { |
65 | // If the abbrev table's ID isn't specified, we use the index as its ID. |
66 | uint64_t AbbrevTableID = AbbrevTable.ID.value_or(u&: Index); |
67 | auto It = AbbrevTableInfoMap.insert( |
68 | x: {AbbrevTableID, AbbrevTableInfo{/*Index=*/Index, |
69 | /*Offset=*/AbbrevTableOffset}}); |
70 | if (!It.second) |
71 | return createStringError( |
72 | EC: errc::invalid_argument, |
73 | Fmt: "the ID (%" PRIu64 ") of abbrev table with index %zu has been used " |
74 | "by abbrev table with index %" PRIu64, |
75 | Vals: AbbrevTableID, Vals: Index, Vals: It.first->second.Index); |
76 | |
77 | AbbrevTableOffset += getAbbrevTableContentByIndex(Index).size(); |
78 | } |
79 | } |
80 | |
81 | auto It = AbbrevTableInfoMap.find(x: ID); |
82 | if (It == AbbrevTableInfoMap.end()) |
83 | return createStringError(EC: errc::invalid_argument, |
84 | Fmt: "cannot find abbrev table whose ID is %" PRIu64, |
85 | Vals: ID); |
86 | return It->second; |
87 | } |
88 | |
89 | namespace yaml { |
90 | |
91 | void MappingTraits<DWARFYAML::Data>::mapping(IO &IO, DWARFYAML::Data &DWARF) { |
92 | void *OldContext = IO.getContext(); |
93 | DWARFYAML::DWARFContext DWARFCtx; |
94 | IO.setContext(&DWARFCtx); |
95 | IO.mapOptional(Key: "debug_str" , Val&: DWARF.DebugStrings); |
96 | IO.mapOptional(Key: "debug_abbrev" , Val&: DWARF.DebugAbbrev); |
97 | IO.mapOptional(Key: "debug_aranges" , Val&: DWARF.DebugAranges); |
98 | IO.mapOptional(Key: "debug_ranges" , Val&: DWARF.DebugRanges); |
99 | IO.mapOptional(Key: "debug_pubnames" , Val&: DWARF.PubNames); |
100 | IO.mapOptional(Key: "debug_pubtypes" , Val&: DWARF.PubTypes); |
101 | DWARFCtx.IsGNUPubSec = true; |
102 | IO.mapOptional(Key: "debug_gnu_pubnames" , Val&: DWARF.GNUPubNames); |
103 | IO.mapOptional(Key: "debug_gnu_pubtypes" , Val&: DWARF.GNUPubTypes); |
104 | IO.mapOptional(Key: "debug_info" , Val&: DWARF.Units); |
105 | IO.mapOptional(Key: "debug_line" , Val&: DWARF.DebugLines); |
106 | IO.mapOptional(Key: "debug_addr" , Val&: DWARF.DebugAddr); |
107 | IO.mapOptional(Key: "debug_str_offsets" , Val&: DWARF.DebugStrOffsets); |
108 | IO.mapOptional(Key: "debug_rnglists" , Val&: DWARF.DebugRnglists); |
109 | IO.mapOptional(Key: "debug_loclists" , Val&: DWARF.DebugLoclists); |
110 | IO.mapOptional(Key: "debug_names" , Val&: DWARF.DebugNames); |
111 | IO.setContext(OldContext); |
112 | } |
113 | |
114 | void MappingTraits<DWARFYAML::AbbrevTable>::mapping( |
115 | IO &IO, DWARFYAML::AbbrevTable &AbbrevTable) { |
116 | IO.mapOptional(Key: "ID" , Val&: AbbrevTable.ID); |
117 | IO.mapOptional(Key: "Table" , Val&: AbbrevTable.Table); |
118 | } |
119 | |
120 | void MappingTraits<DWARFYAML::Abbrev>::mapping(IO &IO, |
121 | DWARFYAML::Abbrev &Abbrev) { |
122 | IO.mapOptional(Key: "Code" , Val&: Abbrev.Code); |
123 | IO.mapRequired(Key: "Tag" , Val&: Abbrev.Tag); |
124 | IO.mapRequired(Key: "Children" , Val&: Abbrev.Children); |
125 | IO.mapOptional(Key: "Attributes" , Val&: Abbrev.Attributes); |
126 | } |
127 | |
128 | void MappingTraits<DWARFYAML::IdxForm>::mapping(IO &IO, |
129 | DWARFYAML::IdxForm &IdxForm) { |
130 | IO.mapRequired(Key: "Idx" , Val&: IdxForm.Idx); |
131 | IO.mapRequired(Key: "Form" , Val&: IdxForm.Form); |
132 | } |
133 | |
134 | void MappingTraits<DWARFYAML::DebugNameAbbreviation>::mapping( |
135 | IO &IO, DWARFYAML::DebugNameAbbreviation &DebugNameAbbreviation) { |
136 | IO.mapRequired(Key: "Code" , Val&: DebugNameAbbreviation.Code); |
137 | IO.mapRequired(Key: "Tag" , Val&: DebugNameAbbreviation.Tag); |
138 | IO.mapRequired(Key: "Indices" , Val&: DebugNameAbbreviation.Indices); |
139 | } |
140 | |
141 | void MappingTraits<DWARFYAML::DebugNameEntry>::mapping( |
142 | IO &IO, DWARFYAML::DebugNameEntry &DebugNameEntry) { |
143 | IO.mapRequired(Key: "Name" , Val&: DebugNameEntry.NameStrp); |
144 | IO.mapRequired(Key: "Code" , Val&: DebugNameEntry.Code); |
145 | IO.mapOptional(Key: "Values" , Val&: DebugNameEntry.Values); |
146 | } |
147 | |
148 | void MappingTraits<DWARFYAML::DebugNamesSection>::mapping( |
149 | IO &IO, DWARFYAML::DebugNamesSection &DebugNames) { |
150 | IO.mapRequired(Key: "Abbreviations" , Val&: DebugNames.Abbrevs); |
151 | IO.mapRequired(Key: "Entries" , Val&: DebugNames.Entries); |
152 | } |
153 | |
154 | void MappingTraits<DWARFYAML::AttributeAbbrev>::mapping( |
155 | IO &IO, DWARFYAML::AttributeAbbrev &AttAbbrev) { |
156 | IO.mapRequired(Key: "Attribute" , Val&: AttAbbrev.Attribute); |
157 | IO.mapRequired(Key: "Form" , Val&: AttAbbrev.Form); |
158 | if(AttAbbrev.Form == dwarf::DW_FORM_implicit_const) |
159 | IO.mapRequired(Key: "Value" , Val&: AttAbbrev.Value); |
160 | } |
161 | |
162 | void MappingTraits<DWARFYAML::ARangeDescriptor>::mapping( |
163 | IO &IO, DWARFYAML::ARangeDescriptor &Descriptor) { |
164 | IO.mapRequired(Key: "Address" , Val&: Descriptor.Address); |
165 | IO.mapRequired(Key: "Length" , Val&: Descriptor.Length); |
166 | } |
167 | |
168 | void MappingTraits<DWARFYAML::ARange>::mapping(IO &IO, |
169 | DWARFYAML::ARange &ARange) { |
170 | IO.mapOptional(Key: "Format" , Val&: ARange.Format, Default: dwarf::DWARF32); |
171 | IO.mapOptional(Key: "Length" , Val&: ARange.Length); |
172 | IO.mapRequired(Key: "Version" , Val&: ARange.Version); |
173 | IO.mapRequired(Key: "CuOffset" , Val&: ARange.CuOffset); |
174 | IO.mapOptional(Key: "AddressSize" , Val&: ARange.AddrSize); |
175 | IO.mapOptional(Key: "SegmentSelectorSize" , Val&: ARange.SegSize, Default: 0); |
176 | IO.mapOptional(Key: "Descriptors" , Val&: ARange.Descriptors); |
177 | } |
178 | |
179 | void MappingTraits<DWARFYAML::RangeEntry>::mapping( |
180 | IO &IO, DWARFYAML::RangeEntry &Descriptor) { |
181 | IO.mapRequired(Key: "LowOffset" , Val&: Descriptor.LowOffset); |
182 | IO.mapRequired(Key: "HighOffset" , Val&: Descriptor.HighOffset); |
183 | } |
184 | |
185 | void MappingTraits<DWARFYAML::Ranges>::mapping(IO &IO, |
186 | DWARFYAML::Ranges &DebugRanges) { |
187 | IO.mapOptional(Key: "Offset" , Val&: DebugRanges.Offset); |
188 | IO.mapOptional(Key: "AddrSize" , Val&: DebugRanges.AddrSize); |
189 | IO.mapRequired(Key: "Entries" , Val&: DebugRanges.Entries); |
190 | } |
191 | |
192 | void MappingTraits<DWARFYAML::PubEntry>::mapping(IO &IO, |
193 | DWARFYAML::PubEntry &Entry) { |
194 | IO.mapRequired(Key: "DieOffset" , Val&: Entry.DieOffset); |
195 | if (static_cast<DWARFYAML::DWARFContext *>(IO.getContext())->IsGNUPubSec) |
196 | IO.mapRequired(Key: "Descriptor" , Val&: Entry.Descriptor); |
197 | IO.mapRequired(Key: "Name" , Val&: Entry.Name); |
198 | } |
199 | |
200 | void MappingTraits<DWARFYAML::PubSection>::mapping( |
201 | IO &IO, DWARFYAML::PubSection &Section) { |
202 | IO.mapOptional(Key: "Format" , Val&: Section.Format, Default: dwarf::DWARF32); |
203 | IO.mapRequired(Key: "Length" , Val&: Section.Length); |
204 | IO.mapRequired(Key: "Version" , Val&: Section.Version); |
205 | IO.mapRequired(Key: "UnitOffset" , Val&: Section.UnitOffset); |
206 | IO.mapRequired(Key: "UnitSize" , Val&: Section.UnitSize); |
207 | IO.mapRequired(Key: "Entries" , Val&: Section.Entries); |
208 | } |
209 | |
210 | void MappingTraits<DWARFYAML::Unit>::mapping(IO &IO, DWARFYAML::Unit &Unit) { |
211 | IO.mapOptional(Key: "Format" , Val&: Unit.Format, Default: dwarf::DWARF32); |
212 | IO.mapOptional(Key: "Length" , Val&: Unit.Length); |
213 | IO.mapRequired(Key: "Version" , Val&: Unit.Version); |
214 | if (Unit.Version >= 5) |
215 | IO.mapRequired(Key: "UnitType" , Val&: Unit.Type); |
216 | IO.mapOptional(Key: "AbbrevTableID" , Val&: Unit.AbbrevTableID); |
217 | IO.mapOptional(Key: "AbbrOffset" , Val&: Unit.AbbrOffset); |
218 | IO.mapOptional(Key: "AddrSize" , Val&: Unit.AddrSize); |
219 | if (Unit.Version >= 5) { |
220 | switch (Unit.Type) { |
221 | case dwarf::DW_UT_compile: |
222 | case dwarf::DW_UT_partial: |
223 | default: |
224 | break; |
225 | case dwarf::DW_UT_type: |
226 | case dwarf::DW_UT_split_type: |
227 | IO.mapRequired(Key: "TypeSignature" , Val&: Unit.TypeSignatureOrDwoID); |
228 | IO.mapRequired(Key: "TypeOffset" , Val&: Unit.TypeOffset); |
229 | break; |
230 | case dwarf::DW_UT_skeleton: |
231 | case dwarf::DW_UT_split_compile: |
232 | IO.mapRequired(Key: "DwoID" , Val&: Unit.TypeSignatureOrDwoID); |
233 | } |
234 | } |
235 | IO.mapOptional(Key: "Entries" , Val&: Unit.Entries); |
236 | } |
237 | |
238 | void MappingTraits<DWARFYAML::Entry>::mapping(IO &IO, DWARFYAML::Entry &Entry) { |
239 | IO.mapRequired(Key: "AbbrCode" , Val&: Entry.AbbrCode); |
240 | IO.mapOptional(Key: "Values" , Val&: Entry.Values); |
241 | } |
242 | |
243 | void MappingTraits<DWARFYAML::FormValue>::mapping( |
244 | IO &IO, DWARFYAML::FormValue &FormValue) { |
245 | IO.mapOptional(Key: "Value" , Val&: FormValue.Value); |
246 | if (!FormValue.CStr.empty() || !IO.outputting()) |
247 | IO.mapOptional(Key: "CStr" , Val&: FormValue.CStr); |
248 | if (!FormValue.BlockData.empty() || !IO.outputting()) |
249 | IO.mapOptional(Key: "BlockData" , Val&: FormValue.BlockData); |
250 | } |
251 | |
252 | void MappingTraits<DWARFYAML::File>::mapping(IO &IO, DWARFYAML::File &File) { |
253 | IO.mapRequired(Key: "Name" , Val&: File.Name); |
254 | IO.mapRequired(Key: "DirIdx" , Val&: File.DirIdx); |
255 | IO.mapRequired(Key: "ModTime" , Val&: File.ModTime); |
256 | IO.mapRequired(Key: "Length" , Val&: File.Length); |
257 | } |
258 | |
259 | void MappingTraits<DWARFYAML::LineTableOpcode>::mapping( |
260 | IO &IO, DWARFYAML::LineTableOpcode &LineTableOpcode) { |
261 | IO.mapRequired(Key: "Opcode" , Val&: LineTableOpcode.Opcode); |
262 | if (LineTableOpcode.Opcode == dwarf::DW_LNS_extended_op) { |
263 | IO.mapOptional(Key: "ExtLen" , Val&: LineTableOpcode.ExtLen); |
264 | IO.mapRequired(Key: "SubOpcode" , Val&: LineTableOpcode.SubOpcode); |
265 | } |
266 | |
267 | if (!LineTableOpcode.UnknownOpcodeData.empty() || !IO.outputting()) |
268 | IO.mapOptional(Key: "UnknownOpcodeData" , Val&: LineTableOpcode.UnknownOpcodeData); |
269 | if (!LineTableOpcode.UnknownOpcodeData.empty() || !IO.outputting()) |
270 | IO.mapOptional(Key: "StandardOpcodeData" , Val&: LineTableOpcode.StandardOpcodeData); |
271 | if (!LineTableOpcode.FileEntry.Name.empty() || !IO.outputting()) |
272 | IO.mapOptional(Key: "FileEntry" , Val&: LineTableOpcode.FileEntry); |
273 | if (LineTableOpcode.Opcode == dwarf::DW_LNS_advance_line || !IO.outputting()) |
274 | IO.mapOptional(Key: "SData" , Val&: LineTableOpcode.SData); |
275 | IO.mapOptional(Key: "Data" , Val&: LineTableOpcode.Data); |
276 | } |
277 | |
278 | void MappingTraits<DWARFYAML::LineTable>::mapping( |
279 | IO &IO, DWARFYAML::LineTable &LineTable) { |
280 | IO.mapOptional(Key: "Format" , Val&: LineTable.Format, Default: dwarf::DWARF32); |
281 | IO.mapOptional(Key: "Length" , Val&: LineTable.Length); |
282 | IO.mapRequired(Key: "Version" , Val&: LineTable.Version); |
283 | IO.mapOptional(Key: "PrologueLength" , Val&: LineTable.PrologueLength); |
284 | IO.mapRequired(Key: "MinInstLength" , Val&: LineTable.MinInstLength); |
285 | if(LineTable.Version >= 4) |
286 | IO.mapRequired(Key: "MaxOpsPerInst" , Val&: LineTable.MaxOpsPerInst); |
287 | IO.mapRequired(Key: "DefaultIsStmt" , Val&: LineTable.DefaultIsStmt); |
288 | IO.mapRequired(Key: "LineBase" , Val&: LineTable.LineBase); |
289 | IO.mapRequired(Key: "LineRange" , Val&: LineTable.LineRange); |
290 | IO.mapOptional(Key: "OpcodeBase" , Val&: LineTable.OpcodeBase); |
291 | IO.mapOptional(Key: "StandardOpcodeLengths" , Val&: LineTable.StandardOpcodeLengths); |
292 | IO.mapOptional(Key: "IncludeDirs" , Val&: LineTable.IncludeDirs); |
293 | IO.mapOptional(Key: "Files" , Val&: LineTable.Files); |
294 | IO.mapOptional(Key: "Opcodes" , Val&: LineTable.Opcodes); |
295 | } |
296 | |
297 | void MappingTraits<DWARFYAML::SegAddrPair>::mapping( |
298 | IO &IO, DWARFYAML::SegAddrPair &SegAddrPair) { |
299 | IO.mapOptional(Key: "Segment" , Val&: SegAddrPair.Segment, Default: 0); |
300 | IO.mapOptional(Key: "Address" , Val&: SegAddrPair.Address, Default: 0); |
301 | } |
302 | |
303 | void MappingTraits<DWARFYAML::AddrTableEntry>::mapping( |
304 | IO &IO, DWARFYAML::AddrTableEntry &AddrTable) { |
305 | IO.mapOptional(Key: "Format" , Val&: AddrTable.Format, Default: dwarf::DWARF32); |
306 | IO.mapOptional(Key: "Length" , Val&: AddrTable.Length); |
307 | IO.mapRequired(Key: "Version" , Val&: AddrTable.Version); |
308 | IO.mapOptional(Key: "AddressSize" , Val&: AddrTable.AddrSize); |
309 | IO.mapOptional(Key: "SegmentSelectorSize" , Val&: AddrTable.SegSelectorSize, Default: 0); |
310 | IO.mapOptional(Key: "Entries" , Val&: AddrTable.SegAddrPairs); |
311 | } |
312 | |
313 | void MappingTraits<DWARFYAML::StringOffsetsTable>::mapping( |
314 | IO &IO, DWARFYAML::StringOffsetsTable &StrOffsetsTable) { |
315 | IO.mapOptional(Key: "Format" , Val&: StrOffsetsTable.Format, Default: dwarf::DWARF32); |
316 | IO.mapOptional(Key: "Length" , Val&: StrOffsetsTable.Length); |
317 | IO.mapOptional(Key: "Version" , Val&: StrOffsetsTable.Version, Default: 5); |
318 | IO.mapOptional(Key: "Padding" , Val&: StrOffsetsTable.Padding, Default: 0); |
319 | IO.mapOptional(Key: "Offsets" , Val&: StrOffsetsTable.Offsets); |
320 | } |
321 | |
322 | void MappingTraits<DWARFYAML::DWARFOperation>::mapping( |
323 | IO &IO, DWARFYAML::DWARFOperation &DWARFOperation) { |
324 | IO.mapRequired(Key: "Operator" , Val&: DWARFOperation.Operator); |
325 | IO.mapOptional(Key: "Values" , Val&: DWARFOperation.Values); |
326 | } |
327 | |
328 | void MappingTraits<DWARFYAML::RnglistEntry>::mapping( |
329 | IO &IO, DWARFYAML::RnglistEntry &RnglistEntry) { |
330 | IO.mapRequired(Key: "Operator" , Val&: RnglistEntry.Operator); |
331 | IO.mapOptional(Key: "Values" , Val&: RnglistEntry.Values); |
332 | } |
333 | |
334 | void MappingTraits<DWARFYAML::LoclistEntry>::mapping( |
335 | IO &IO, DWARFYAML::LoclistEntry &LoclistEntry) { |
336 | IO.mapRequired(Key: "Operator" , Val&: LoclistEntry.Operator); |
337 | IO.mapOptional(Key: "Values" , Val&: LoclistEntry.Values); |
338 | IO.mapOptional(Key: "DescriptionsLength" , Val&: LoclistEntry.DescriptionsLength); |
339 | IO.mapOptional(Key: "Descriptions" , Val&: LoclistEntry.Descriptions); |
340 | } |
341 | |
342 | template <typename EntryType> |
343 | void MappingTraits<DWARFYAML::ListEntries<EntryType>>::mapping( |
344 | IO &IO, DWARFYAML::ListEntries<EntryType> &ListEntries) { |
345 | IO.mapOptional("Entries" , ListEntries.Entries); |
346 | IO.mapOptional("Content" , ListEntries.Content); |
347 | } |
348 | |
349 | template <typename EntryType> |
350 | std::string MappingTraits<DWARFYAML::ListEntries<EntryType>>::validate( |
351 | IO &IO, DWARFYAML::ListEntries<EntryType> &ListEntries) { |
352 | if (ListEntries.Entries && ListEntries.Content) |
353 | return "Entries and Content can't be used together" ; |
354 | return "" ; |
355 | } |
356 | |
357 | template <typename EntryType> |
358 | void MappingTraits<DWARFYAML::ListTable<EntryType>>::mapping( |
359 | IO &IO, DWARFYAML::ListTable<EntryType> &ListTable) { |
360 | IO.mapOptional("Format" , ListTable.Format, dwarf::DWARF32); |
361 | IO.mapOptional("Length" , ListTable.Length); |
362 | IO.mapOptional("Version" , ListTable.Version, 5); |
363 | IO.mapOptional("AddressSize" , ListTable.AddrSize); |
364 | IO.mapOptional("SegmentSelectorSize" , ListTable.SegSelectorSize, 0); |
365 | IO.mapOptional("OffsetEntryCount" , ListTable.OffsetEntryCount); |
366 | IO.mapOptional("Offsets" , ListTable.Offsets); |
367 | IO.mapOptional("Lists" , ListTable.Lists); |
368 | } |
369 | |
370 | } // end namespace yaml |
371 | |
372 | } // end namespace llvm |
373 | |