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 (!CompileUnits.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.CompileUnits); |
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 | IO.mapOptional(Key: "Entries" , Val&: Unit.Entries); |
220 | } |
221 | |
222 | void MappingTraits<DWARFYAML::Entry>::mapping(IO &IO, DWARFYAML::Entry &Entry) { |
223 | IO.mapRequired(Key: "AbbrCode" , Val&: Entry.AbbrCode); |
224 | IO.mapOptional(Key: "Values" , Val&: Entry.Values); |
225 | } |
226 | |
227 | void MappingTraits<DWARFYAML::FormValue>::mapping( |
228 | IO &IO, DWARFYAML::FormValue &FormValue) { |
229 | IO.mapOptional(Key: "Value" , Val&: FormValue.Value); |
230 | if (!FormValue.CStr.empty() || !IO.outputting()) |
231 | IO.mapOptional(Key: "CStr" , Val&: FormValue.CStr); |
232 | if (!FormValue.BlockData.empty() || !IO.outputting()) |
233 | IO.mapOptional(Key: "BlockData" , Val&: FormValue.BlockData); |
234 | } |
235 | |
236 | void MappingTraits<DWARFYAML::File>::mapping(IO &IO, DWARFYAML::File &File) { |
237 | IO.mapRequired(Key: "Name" , Val&: File.Name); |
238 | IO.mapRequired(Key: "DirIdx" , Val&: File.DirIdx); |
239 | IO.mapRequired(Key: "ModTime" , Val&: File.ModTime); |
240 | IO.mapRequired(Key: "Length" , Val&: File.Length); |
241 | } |
242 | |
243 | void MappingTraits<DWARFYAML::LineTableOpcode>::mapping( |
244 | IO &IO, DWARFYAML::LineTableOpcode &LineTableOpcode) { |
245 | IO.mapRequired(Key: "Opcode" , Val&: LineTableOpcode.Opcode); |
246 | if (LineTableOpcode.Opcode == dwarf::DW_LNS_extended_op) { |
247 | IO.mapOptional(Key: "ExtLen" , Val&: LineTableOpcode.ExtLen); |
248 | IO.mapRequired(Key: "SubOpcode" , Val&: LineTableOpcode.SubOpcode); |
249 | } |
250 | |
251 | if (!LineTableOpcode.UnknownOpcodeData.empty() || !IO.outputting()) |
252 | IO.mapOptional(Key: "UnknownOpcodeData" , Val&: LineTableOpcode.UnknownOpcodeData); |
253 | if (!LineTableOpcode.UnknownOpcodeData.empty() || !IO.outputting()) |
254 | IO.mapOptional(Key: "StandardOpcodeData" , Val&: LineTableOpcode.StandardOpcodeData); |
255 | if (!LineTableOpcode.FileEntry.Name.empty() || !IO.outputting()) |
256 | IO.mapOptional(Key: "FileEntry" , Val&: LineTableOpcode.FileEntry); |
257 | if (LineTableOpcode.Opcode == dwarf::DW_LNS_advance_line || !IO.outputting()) |
258 | IO.mapOptional(Key: "SData" , Val&: LineTableOpcode.SData); |
259 | IO.mapOptional(Key: "Data" , Val&: LineTableOpcode.Data); |
260 | } |
261 | |
262 | void MappingTraits<DWARFYAML::LineTable>::mapping( |
263 | IO &IO, DWARFYAML::LineTable &LineTable) { |
264 | IO.mapOptional(Key: "Format" , Val&: LineTable.Format, Default: dwarf::DWARF32); |
265 | IO.mapOptional(Key: "Length" , Val&: LineTable.Length); |
266 | IO.mapRequired(Key: "Version" , Val&: LineTable.Version); |
267 | IO.mapOptional(Key: "PrologueLength" , Val&: LineTable.PrologueLength); |
268 | IO.mapRequired(Key: "MinInstLength" , Val&: LineTable.MinInstLength); |
269 | if(LineTable.Version >= 4) |
270 | IO.mapRequired(Key: "MaxOpsPerInst" , Val&: LineTable.MaxOpsPerInst); |
271 | IO.mapRequired(Key: "DefaultIsStmt" , Val&: LineTable.DefaultIsStmt); |
272 | IO.mapRequired(Key: "LineBase" , Val&: LineTable.LineBase); |
273 | IO.mapRequired(Key: "LineRange" , Val&: LineTable.LineRange); |
274 | IO.mapOptional(Key: "OpcodeBase" , Val&: LineTable.OpcodeBase); |
275 | IO.mapOptional(Key: "StandardOpcodeLengths" , Val&: LineTable.StandardOpcodeLengths); |
276 | IO.mapOptional(Key: "IncludeDirs" , Val&: LineTable.IncludeDirs); |
277 | IO.mapOptional(Key: "Files" , Val&: LineTable.Files); |
278 | IO.mapOptional(Key: "Opcodes" , Val&: LineTable.Opcodes); |
279 | } |
280 | |
281 | void MappingTraits<DWARFYAML::SegAddrPair>::mapping( |
282 | IO &IO, DWARFYAML::SegAddrPair &SegAddrPair) { |
283 | IO.mapOptional(Key: "Segment" , Val&: SegAddrPair.Segment, Default: 0); |
284 | IO.mapOptional(Key: "Address" , Val&: SegAddrPair.Address, Default: 0); |
285 | } |
286 | |
287 | void MappingTraits<DWARFYAML::AddrTableEntry>::mapping( |
288 | IO &IO, DWARFYAML::AddrTableEntry &AddrTable) { |
289 | IO.mapOptional(Key: "Format" , Val&: AddrTable.Format, Default: dwarf::DWARF32); |
290 | IO.mapOptional(Key: "Length" , Val&: AddrTable.Length); |
291 | IO.mapRequired(Key: "Version" , Val&: AddrTable.Version); |
292 | IO.mapOptional(Key: "AddressSize" , Val&: AddrTable.AddrSize); |
293 | IO.mapOptional(Key: "SegmentSelectorSize" , Val&: AddrTable.SegSelectorSize, Default: 0); |
294 | IO.mapOptional(Key: "Entries" , Val&: AddrTable.SegAddrPairs); |
295 | } |
296 | |
297 | void MappingTraits<DWARFYAML::StringOffsetsTable>::mapping( |
298 | IO &IO, DWARFYAML::StringOffsetsTable &StrOffsetsTable) { |
299 | IO.mapOptional(Key: "Format" , Val&: StrOffsetsTable.Format, Default: dwarf::DWARF32); |
300 | IO.mapOptional(Key: "Length" , Val&: StrOffsetsTable.Length); |
301 | IO.mapOptional(Key: "Version" , Val&: StrOffsetsTable.Version, Default: 5); |
302 | IO.mapOptional(Key: "Padding" , Val&: StrOffsetsTable.Padding, Default: 0); |
303 | IO.mapOptional(Key: "Offsets" , Val&: StrOffsetsTable.Offsets); |
304 | } |
305 | |
306 | void MappingTraits<DWARFYAML::DWARFOperation>::mapping( |
307 | IO &IO, DWARFYAML::DWARFOperation &DWARFOperation) { |
308 | IO.mapRequired(Key: "Operator" , Val&: DWARFOperation.Operator); |
309 | IO.mapOptional(Key: "Values" , Val&: DWARFOperation.Values); |
310 | } |
311 | |
312 | void MappingTraits<DWARFYAML::RnglistEntry>::mapping( |
313 | IO &IO, DWARFYAML::RnglistEntry &RnglistEntry) { |
314 | IO.mapRequired(Key: "Operator" , Val&: RnglistEntry.Operator); |
315 | IO.mapOptional(Key: "Values" , Val&: RnglistEntry.Values); |
316 | } |
317 | |
318 | void MappingTraits<DWARFYAML::LoclistEntry>::mapping( |
319 | IO &IO, DWARFYAML::LoclistEntry &LoclistEntry) { |
320 | IO.mapRequired(Key: "Operator" , Val&: LoclistEntry.Operator); |
321 | IO.mapOptional(Key: "Values" , Val&: LoclistEntry.Values); |
322 | IO.mapOptional(Key: "DescriptionsLength" , Val&: LoclistEntry.DescriptionsLength); |
323 | IO.mapOptional(Key: "Descriptions" , Val&: LoclistEntry.Descriptions); |
324 | } |
325 | |
326 | template <typename EntryType> |
327 | void MappingTraits<DWARFYAML::ListEntries<EntryType>>::mapping( |
328 | IO &IO, DWARFYAML::ListEntries<EntryType> &ListEntries) { |
329 | IO.mapOptional("Entries" , ListEntries.Entries); |
330 | IO.mapOptional("Content" , ListEntries.Content); |
331 | } |
332 | |
333 | template <typename EntryType> |
334 | std::string MappingTraits<DWARFYAML::ListEntries<EntryType>>::validate( |
335 | IO &IO, DWARFYAML::ListEntries<EntryType> &ListEntries) { |
336 | if (ListEntries.Entries && ListEntries.Content) |
337 | return "Entries and Content can't be used together" ; |
338 | return "" ; |
339 | } |
340 | |
341 | template <typename EntryType> |
342 | void MappingTraits<DWARFYAML::ListTable<EntryType>>::mapping( |
343 | IO &IO, DWARFYAML::ListTable<EntryType> &ListTable) { |
344 | IO.mapOptional("Format" , ListTable.Format, dwarf::DWARF32); |
345 | IO.mapOptional("Length" , ListTable.Length); |
346 | IO.mapOptional("Version" , ListTable.Version, 5); |
347 | IO.mapOptional("AddressSize" , ListTable.AddrSize); |
348 | IO.mapOptional("SegmentSelectorSize" , ListTable.SegSelectorSize, 0); |
349 | IO.mapOptional("OffsetEntryCount" , ListTable.OffsetEntryCount); |
350 | IO.mapOptional("Offsets" , ListTable.Offsets); |
351 | IO.mapOptional("Lists" , ListTable.Lists); |
352 | } |
353 | |
354 | } // end namespace yaml |
355 | |
356 | } // end namespace llvm |
357 | |