Fix test failures introduced by PR #113697 (#116941)
[llvm-project.git] / llvm / tools / obj2yaml / dwarf2yaml.cpp
blobf19004bdcde389b5578c88bfe1ec52dfc409315c
1 //===------ dwarf2yaml.cpp - obj2yaml conversion tool -----------*- 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 //===----------------------------------------------------------------------===//
9 #include "llvm/BinaryFormat/Dwarf.h"
10 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
11 #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
12 #include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
13 #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
14 #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
15 #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
16 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
17 #include "llvm/DebugInfo/DWARF/DWARFSection.h"
18 #include "llvm/ObjectYAML/DWARFYAML.h"
20 #include <algorithm>
21 #include <optional>
23 using namespace llvm;
25 Error dumpDebugAbbrev(DWARFContext &DCtx, DWARFYAML::Data &Y) {
26 auto AbbrevSetPtr = DCtx.getDebugAbbrev();
27 if (AbbrevSetPtr) {
28 uint64_t AbbrevTableID = 0;
29 if (Error Err = AbbrevSetPtr->parse())
30 return Err;
31 for (const auto &AbbrvDeclSet : *AbbrevSetPtr) {
32 Y.DebugAbbrev.emplace_back();
33 Y.DebugAbbrev.back().ID = AbbrevTableID++;
34 for (const DWARFAbbreviationDeclaration &AbbrvDecl :
35 AbbrvDeclSet.second) {
36 DWARFYAML::Abbrev Abbrv;
37 Abbrv.Code = AbbrvDecl.getCode();
38 Abbrv.Tag = AbbrvDecl.getTag();
39 Abbrv.Children = AbbrvDecl.hasChildren() ? dwarf::DW_CHILDREN_yes
40 : dwarf::DW_CHILDREN_no;
41 for (auto Attribute : AbbrvDecl.attributes()) {
42 DWARFYAML::AttributeAbbrev AttAbrv;
43 AttAbrv.Attribute = Attribute.Attr;
44 AttAbrv.Form = Attribute.Form;
45 if (AttAbrv.Form == dwarf::DW_FORM_implicit_const)
46 AttAbrv.Value = Attribute.getImplicitConstValue();
47 Abbrv.Attributes.push_back(AttAbrv);
49 Y.DebugAbbrev.back().Table.push_back(Abbrv);
53 return Error::success();
56 Error dumpDebugAddr(DWARFContext &DCtx, DWARFYAML::Data &Y) {
57 DWARFDebugAddrTable AddrTable;
58 DWARFDataExtractor AddrData(DCtx.getDWARFObj(),
59 DCtx.getDWARFObj().getAddrSection(),
60 DCtx.isLittleEndian(), /*AddressSize=*/0);
61 std::vector<DWARFYAML::AddrTableEntry> AddrTables;
62 uint64_t Offset = 0;
63 while (AddrData.isValidOffset(Offset)) {
64 // We ignore any errors that don't prevent parsing the section, since we can
65 // still represent such sections.
66 if (Error Err = AddrTable.extractV5(AddrData, &Offset, /*CUAddrSize=*/0,
67 consumeError))
68 return Err;
69 AddrTables.emplace_back();
70 for (uint64_t Addr : AddrTable.getAddressEntries()) {
71 // Currently, the parser doesn't support parsing an address table with non
72 // linear addresses (segment_selector_size != 0). The segment selectors
73 // are specified to be zero.
74 AddrTables.back().SegAddrPairs.push_back(
75 {/*SegmentSelector=*/0, /*Address=*/Addr});
78 AddrTables.back().Format = AddrTable.getFormat();
79 AddrTables.back().Length = AddrTable.getLength();
80 AddrTables.back().Version = AddrTable.getVersion();
81 AddrTables.back().AddrSize = AddrTable.getAddressSize();
82 AddrTables.back().SegSelectorSize = AddrTable.getSegmentSelectorSize();
84 Y.DebugAddr = std::move(AddrTables);
85 return Error::success();
88 Error dumpDebugStrings(DWARFContext &DCtx, DWARFYAML::Data &Y) {
89 DataExtractor StrData = DCtx.getStringExtractor();
90 uint64_t Offset = 0;
91 std::vector<StringRef> DebugStr;
92 Error Err = Error::success();
93 while (StrData.isValidOffset(Offset)) {
94 const char *CStr = StrData.getCStr(&Offset, &Err);
95 if (Err)
96 return Err;
97 DebugStr.push_back(CStr);
100 Y.DebugStrings = DebugStr;
101 return Err;
104 Error dumpDebugARanges(DWARFContext &DCtx, DWARFYAML::Data &Y) {
105 DWARFDataExtractor ArangesData(DCtx.getDWARFObj().getArangesSection(),
106 DCtx.isLittleEndian(), 0);
107 uint64_t Offset = 0;
108 DWARFDebugArangeSet Set;
109 std::vector<DWARFYAML::ARange> DebugAranges;
111 // We ignore any errors that don't prevent parsing the section, since we can
112 // still represent such sections. These errors are recorded via the
113 // WarningHandler parameter of Set.extract().
114 auto DiscardError = [](Error Err) { consumeError(std::move(Err)); };
116 while (ArangesData.isValidOffset(Offset)) {
117 if (Error E = Set.extract(ArangesData, &Offset, DiscardError))
118 return E;
119 DWARFYAML::ARange Range;
120 Range.Format = Set.getHeader().Format;
121 Range.Length = Set.getHeader().Length;
122 Range.Version = Set.getHeader().Version;
123 Range.CuOffset = Set.getHeader().CuOffset;
124 Range.AddrSize = Set.getHeader().AddrSize;
125 Range.SegSize = Set.getHeader().SegSize;
126 for (auto Descriptor : Set.descriptors()) {
127 DWARFYAML::ARangeDescriptor Desc;
128 Desc.Address = Descriptor.Address;
129 Desc.Length = Descriptor.Length;
130 Range.Descriptors.push_back(Desc);
132 DebugAranges.push_back(Range);
135 Y.DebugAranges = DebugAranges;
136 return ErrorSuccess();
139 Error dumpDebugRanges(DWARFContext &DCtx, DWARFYAML::Data &Y) {
140 // We are assuming all address byte sizes will be consistent across all
141 // compile units.
142 uint8_t AddrSize = 0;
143 for (const auto &CU : DCtx.compile_units()) {
144 const uint8_t CUAddrSize = CU->getAddressByteSize();
145 if (AddrSize == 0)
146 AddrSize = CUAddrSize;
147 else if (CUAddrSize != AddrSize)
148 return createStringError(std::errc::invalid_argument,
149 "address sizes vary in different compile units");
152 DWARFDataExtractor Data(DCtx.getDWARFObj().getRangesSection().Data,
153 DCtx.isLittleEndian(), AddrSize);
154 uint64_t Offset = 0;
155 DWARFDebugRangeList DwarfRanges;
156 std::vector<DWARFYAML::Ranges> DebugRanges;
158 while (Data.isValidOffset(Offset)) {
159 DWARFYAML::Ranges YamlRanges;
160 YamlRanges.Offset = Offset;
161 YamlRanges.AddrSize = AddrSize;
162 if (Error E = DwarfRanges.extract(Data, &Offset))
163 return E;
164 for (const auto &RLE : DwarfRanges.getEntries())
165 YamlRanges.Entries.push_back({RLE.StartAddress, RLE.EndAddress});
166 DebugRanges.push_back(std::move(YamlRanges));
169 Y.DebugRanges = DebugRanges;
170 return ErrorSuccess();
173 static std::optional<DWARFYAML::PubSection>
174 dumpPubSection(const DWARFContext &DCtx, const DWARFSection &Section,
175 bool IsGNUStyle) {
176 DWARFYAML::PubSection Y;
177 DWARFDataExtractor PubSectionData(DCtx.getDWARFObj(), Section,
178 DCtx.isLittleEndian(), 0);
179 DWARFDebugPubTable Table;
180 // We ignore any errors that don't prevent parsing the section, since we can
181 // still represent such sections.
182 Table.extract(PubSectionData, IsGNUStyle,
183 [](Error Err) { consumeError(std::move(Err)); });
184 ArrayRef<DWARFDebugPubTable::Set> Sets = Table.getData();
185 if (Sets.empty())
186 return std::nullopt;
188 // FIXME: Currently, obj2yaml only supports dumping the first pubtable.
189 Y.Format = Sets[0].Format;
190 Y.Length = Sets[0].Length;
191 Y.Version = Sets[0].Version;
192 Y.UnitOffset = Sets[0].Offset;
193 Y.UnitSize = Sets[0].Size;
195 for (const DWARFDebugPubTable::Entry &E : Sets[0].Entries)
196 Y.Entries.push_back(DWARFYAML::PubEntry{(uint32_t)E.SecOffset,
197 E.Descriptor.toBits(), E.Name});
199 return Y;
202 void dumpDebugPubSections(DWARFContext &DCtx, DWARFYAML::Data &Y) {
203 const DWARFObject &D = DCtx.getDWARFObj();
205 Y.PubNames =
206 dumpPubSection(DCtx, D.getPubnamesSection(), /*IsGNUStyle=*/false);
207 Y.PubTypes =
208 dumpPubSection(DCtx, D.getPubtypesSection(), /*IsGNUStyle=*/false);
209 // TODO: Test dumping .debug_gnu_pubnames section.
210 Y.GNUPubNames =
211 dumpPubSection(DCtx, D.getGnuPubnamesSection(), /*IsGNUStyle=*/true);
212 // TODO: Test dumping .debug_gnu_pubtypes section.
213 Y.GNUPubTypes =
214 dumpPubSection(DCtx, D.getGnuPubtypesSection(), /*IsGNUStyle=*/true);
217 void dumpDebugInfo(DWARFContext &DCtx, DWARFYAML::Data &Y) {
218 for (const auto &CU : DCtx.compile_units()) {
219 DWARFYAML::Unit NewUnit;
220 NewUnit.Format = CU->getFormat();
221 NewUnit.Length = CU->getLength();
222 NewUnit.Version = CU->getVersion();
223 if (NewUnit.Version >= 5)
224 NewUnit.Type = (dwarf::UnitType)CU->getUnitType();
225 const DWARFDebugAbbrev *DebugAbbrev = DCtx.getDebugAbbrev();
226 // FIXME: Ideally we would propagate this error upwards, but that would
227 // prevent us from displaying any debug info at all. For now we just consume
228 // the error and display everything that was parsed successfully.
229 if (Error Err = DebugAbbrev->parse())
230 llvm::consumeError(std::move(Err));
232 NewUnit.AbbrevTableID = std::distance(
233 DebugAbbrev->begin(),
234 llvm::find_if(
235 *DebugAbbrev,
236 [&](const std::pair<uint64_t, DWARFAbbreviationDeclarationSet> &P) {
237 return P.first == CU->getAbbreviations()->getOffset();
238 }));
239 NewUnit.AbbrOffset = CU->getAbbreviations()->getOffset();
240 NewUnit.AddrSize = CU->getAddressByteSize();
241 for (auto DIE : CU->dies()) {
242 DWARFYAML::Entry NewEntry;
243 DataExtractor EntryData = CU->getDebugInfoExtractor();
244 uint64_t offset = DIE.getOffset();
246 assert(EntryData.isValidOffset(offset) && "Invalid DIE Offset");
247 if (!EntryData.isValidOffset(offset))
248 continue;
250 NewEntry.AbbrCode = EntryData.getULEB128(&offset);
252 auto AbbrevDecl = DIE.getAbbreviationDeclarationPtr();
253 if (AbbrevDecl) {
254 for (const auto &AttrSpec : AbbrevDecl->attributes()) {
255 DWARFYAML::FormValue NewValue;
256 NewValue.Value = 0xDEADBEEFDEADBEEF;
257 DWARFDie DIEWrapper(CU.get(), &DIE);
258 auto FormValue = DIEWrapper.find(AttrSpec.Attr);
259 if (!FormValue)
260 return;
261 auto Form = FormValue->getForm();
262 bool indirect = false;
263 do {
264 indirect = false;
265 switch (Form) {
266 case dwarf::DW_FORM_addr:
267 case dwarf::DW_FORM_GNU_addr_index:
268 if (auto Val = FormValue->getAsAddress())
269 NewValue.Value = *Val;
270 break;
271 case dwarf::DW_FORM_ref_addr:
272 case dwarf::DW_FORM_ref1:
273 case dwarf::DW_FORM_ref2:
274 case dwarf::DW_FORM_ref4:
275 case dwarf::DW_FORM_ref8:
276 case dwarf::DW_FORM_ref_udata:
277 case dwarf::DW_FORM_ref_sig8:
278 if (auto Val = FormValue->getAsReferenceUVal())
279 NewValue.Value = *Val;
280 break;
281 case dwarf::DW_FORM_exprloc:
282 case dwarf::DW_FORM_block:
283 case dwarf::DW_FORM_block1:
284 case dwarf::DW_FORM_block2:
285 case dwarf::DW_FORM_block4:
286 if (auto Val = FormValue->getAsBlock()) {
287 auto BlockData = *Val;
288 std::copy(BlockData.begin(), BlockData.end(),
289 std::back_inserter(NewValue.BlockData));
291 NewValue.Value = NewValue.BlockData.size();
292 break;
293 case dwarf::DW_FORM_data1:
294 case dwarf::DW_FORM_flag:
295 case dwarf::DW_FORM_data2:
296 case dwarf::DW_FORM_data4:
297 case dwarf::DW_FORM_data8:
298 case dwarf::DW_FORM_sdata:
299 case dwarf::DW_FORM_udata:
300 case dwarf::DW_FORM_ref_sup4:
301 case dwarf::DW_FORM_ref_sup8:
302 if (auto Val = FormValue->getAsUnsignedConstant())
303 NewValue.Value = *Val;
304 break;
305 case dwarf::DW_FORM_string:
306 if (auto Val = dwarf::toString(FormValue))
307 NewValue.CStr = *Val;
308 break;
309 case dwarf::DW_FORM_indirect:
310 indirect = true;
311 if (auto Val = FormValue->getAsUnsignedConstant()) {
312 NewValue.Value = *Val;
313 NewEntry.Values.push_back(NewValue);
314 Form = static_cast<dwarf::Form>(*Val);
316 break;
317 case dwarf::DW_FORM_strp:
318 case dwarf::DW_FORM_sec_offset:
319 case dwarf::DW_FORM_GNU_ref_alt:
320 case dwarf::DW_FORM_GNU_strp_alt:
321 case dwarf::DW_FORM_line_strp:
322 case dwarf::DW_FORM_strp_sup:
323 case dwarf::DW_FORM_GNU_str_index:
324 case dwarf::DW_FORM_strx:
325 if (auto Val = FormValue->getAsCStringOffset())
326 NewValue.Value = *Val;
327 break;
328 case dwarf::DW_FORM_flag_present:
329 NewValue.Value = 1;
330 break;
331 default:
332 break;
334 } while (indirect);
335 NewEntry.Values.push_back(NewValue);
339 NewUnit.Entries.push_back(NewEntry);
341 Y.Units.push_back(NewUnit);
345 bool dumpFileEntry(DataExtractor &Data, uint64_t &Offset,
346 DWARFYAML::File &File) {
347 File.Name = Data.getCStr(&Offset);
348 if (File.Name.empty())
349 return false;
350 File.DirIdx = Data.getULEB128(&Offset);
351 File.ModTime = Data.getULEB128(&Offset);
352 File.Length = Data.getULEB128(&Offset);
353 return true;
356 void dumpDebugLines(DWARFContext &DCtx, DWARFYAML::Data &Y) {
357 for (const auto &CU : DCtx.compile_units()) {
358 auto CUDIE = CU->getUnitDIE();
359 if (!CUDIE)
360 continue;
361 if (auto StmtOffset =
362 dwarf::toSectionOffset(CUDIE.find(dwarf::DW_AT_stmt_list))) {
363 DWARFYAML::LineTable DebugLines;
364 DataExtractor LineData(DCtx.getDWARFObj().getLineSection().Data,
365 DCtx.isLittleEndian(), CU->getAddressByteSize());
366 uint64_t Offset = *StmtOffset;
367 uint64_t LengthOrDWARF64Prefix = LineData.getU32(&Offset);
368 if (LengthOrDWARF64Prefix == dwarf::DW_LENGTH_DWARF64) {
369 DebugLines.Format = dwarf::DWARF64;
370 DebugLines.Length = LineData.getU64(&Offset);
371 } else {
372 DebugLines.Format = dwarf::DWARF32;
373 DebugLines.Length = LengthOrDWARF64Prefix;
375 assert(DebugLines.Length);
376 uint64_t LineTableLength = *DebugLines.Length;
377 uint64_t SizeOfPrologueLength =
378 DebugLines.Format == dwarf::DWARF64 ? 8 : 4;
379 DebugLines.Version = LineData.getU16(&Offset);
380 DebugLines.PrologueLength =
381 LineData.getUnsigned(&Offset, SizeOfPrologueLength);
382 assert(DebugLines.PrologueLength);
383 const uint64_t EndPrologue = *DebugLines.PrologueLength + Offset;
385 DebugLines.MinInstLength = LineData.getU8(&Offset);
386 if (DebugLines.Version >= 4)
387 DebugLines.MaxOpsPerInst = LineData.getU8(&Offset);
388 DebugLines.DefaultIsStmt = LineData.getU8(&Offset);
389 DebugLines.LineBase = LineData.getU8(&Offset);
390 DebugLines.LineRange = LineData.getU8(&Offset);
391 DebugLines.OpcodeBase = LineData.getU8(&Offset);
393 DebugLines.StandardOpcodeLengths.emplace();
394 for (uint8_t i = 1; i < DebugLines.OpcodeBase; ++i)
395 DebugLines.StandardOpcodeLengths->push_back(LineData.getU8(&Offset));
397 while (Offset < EndPrologue) {
398 StringRef Dir = LineData.getCStr(&Offset);
399 if (!Dir.empty())
400 DebugLines.IncludeDirs.push_back(Dir);
401 else
402 break;
405 while (Offset < EndPrologue) {
406 DWARFYAML::File TmpFile;
407 if (dumpFileEntry(LineData, Offset, TmpFile))
408 DebugLines.Files.push_back(TmpFile);
409 else
410 break;
413 const uint64_t LineEnd =
414 LineTableLength + *StmtOffset + SizeOfPrologueLength;
415 while (Offset < LineEnd) {
416 DWARFYAML::LineTableOpcode NewOp = {};
417 NewOp.Opcode = (dwarf::LineNumberOps)LineData.getU8(&Offset);
418 if (NewOp.Opcode == 0) {
419 auto StartExt = Offset;
420 NewOp.ExtLen = LineData.getULEB128(&Offset);
421 NewOp.SubOpcode =
422 (dwarf::LineNumberExtendedOps)LineData.getU8(&Offset);
423 switch (NewOp.SubOpcode) {
424 case dwarf::DW_LNE_set_address:
425 case dwarf::DW_LNE_set_discriminator:
426 NewOp.Data = LineData.getAddress(&Offset);
427 break;
428 case dwarf::DW_LNE_define_file:
429 dumpFileEntry(LineData, Offset, NewOp.FileEntry);
430 break;
431 case dwarf::DW_LNE_end_sequence:
432 break;
433 default:
434 while (Offset < StartExt + *NewOp.ExtLen)
435 NewOp.UnknownOpcodeData.push_back(LineData.getU8(&Offset));
437 } else if (NewOp.Opcode < *DebugLines.OpcodeBase) {
438 switch (NewOp.Opcode) {
439 case dwarf::DW_LNS_copy:
440 case dwarf::DW_LNS_negate_stmt:
441 case dwarf::DW_LNS_set_basic_block:
442 case dwarf::DW_LNS_const_add_pc:
443 case dwarf::DW_LNS_set_prologue_end:
444 case dwarf::DW_LNS_set_epilogue_begin:
445 break;
447 case dwarf::DW_LNS_advance_pc:
448 case dwarf::DW_LNS_set_file:
449 case dwarf::DW_LNS_set_column:
450 case dwarf::DW_LNS_set_isa:
451 NewOp.Data = LineData.getULEB128(&Offset);
452 break;
454 case dwarf::DW_LNS_advance_line:
455 NewOp.SData = LineData.getSLEB128(&Offset);
456 break;
458 case dwarf::DW_LNS_fixed_advance_pc:
459 NewOp.Data = LineData.getU16(&Offset);
460 break;
462 default:
463 for (uint8_t i = 0;
464 i < (*DebugLines.StandardOpcodeLengths)[NewOp.Opcode - 1]; ++i)
465 NewOp.StandardOpcodeData.push_back(LineData.getULEB128(&Offset));
468 DebugLines.Opcodes.push_back(NewOp);
470 Y.DebugLines.push_back(DebugLines);