1 //===------ dwarf2yaml.cpp - obj2yaml conversion tool -----------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/BinaryFormat/Dwarf.h"
10 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
11 #include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
12 #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
13 #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
14 #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
15 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
16 #include "llvm/DebugInfo/DWARF/DWARFSection.h"
17 #include "llvm/ObjectYAML/DWARFYAML.h"
23 void dumpDebugAbbrev(DWARFContext
&DCtx
, DWARFYAML::Data
&Y
) {
24 auto AbbrevSetPtr
= DCtx
.getDebugAbbrev();
26 uint64_t AbbrevTableID
= 0;
27 for (auto AbbrvDeclSet
: *AbbrevSetPtr
) {
28 Y
.DebugAbbrev
.emplace_back();
29 Y
.DebugAbbrev
.back().ID
= AbbrevTableID
++;
30 for (auto AbbrvDecl
: AbbrvDeclSet
.second
) {
31 DWARFYAML::Abbrev Abbrv
;
32 Abbrv
.Code
= AbbrvDecl
.getCode();
33 Abbrv
.Tag
= AbbrvDecl
.getTag();
34 Abbrv
.Children
= AbbrvDecl
.hasChildren() ? dwarf::DW_CHILDREN_yes
35 : dwarf::DW_CHILDREN_no
;
36 for (auto Attribute
: AbbrvDecl
.attributes()) {
37 DWARFYAML::AttributeAbbrev AttAbrv
;
38 AttAbrv
.Attribute
= Attribute
.Attr
;
39 AttAbrv
.Form
= Attribute
.Form
;
40 if (AttAbrv
.Form
== dwarf::DW_FORM_implicit_const
)
41 AttAbrv
.Value
= Attribute
.getImplicitConstValue();
42 Abbrv
.Attributes
.push_back(AttAbrv
);
44 Y
.DebugAbbrev
.back().Table
.push_back(Abbrv
);
50 Error
dumpDebugAddr(DWARFContext
&DCtx
, DWARFYAML::Data
&Y
) {
51 DWARFDebugAddrTable AddrTable
;
52 DWARFDataExtractor
AddrData(DCtx
.getDWARFObj(),
53 DCtx
.getDWARFObj().getAddrSection(),
54 DCtx
.isLittleEndian(), /*AddressSize=*/0);
55 std::vector
<DWARFYAML::AddrTableEntry
> AddrTables
;
57 while (AddrData
.isValidOffset(Offset
)) {
58 // We ignore any errors that don't prevent parsing the section, since we can
59 // still represent such sections.
60 if (Error Err
= AddrTable
.extractV5(AddrData
, &Offset
, /*CUAddrSize=*/0,
63 AddrTables
.emplace_back();
64 for (uint64_t Addr
: AddrTable
.getAddressEntries()) {
65 // Currently, the parser doesn't support parsing an address table with non
66 // linear addresses (segment_selector_size != 0). The segment selectors
67 // are specified to be zero.
68 AddrTables
.back().SegAddrPairs
.push_back(
69 {/*SegmentSelector=*/0, /*Address=*/Addr
});
72 AddrTables
.back().Format
= AddrTable
.getFormat();
73 AddrTables
.back().Length
= AddrTable
.getLength();
74 AddrTables
.back().Version
= AddrTable
.getVersion();
75 AddrTables
.back().AddrSize
= AddrTable
.getAddressSize();
76 AddrTables
.back().SegSelectorSize
= AddrTable
.getSegmentSelectorSize();
78 Y
.DebugAddr
= std::move(AddrTables
);
79 return Error::success();
82 Error
dumpDebugStrings(DWARFContext
&DCtx
, DWARFYAML::Data
&Y
) {
83 DataExtractor StrData
= DCtx
.getStringExtractor();
85 std::vector
<StringRef
> DebugStr
;
86 Error Err
= Error::success();
87 while (StrData
.isValidOffset(Offset
)) {
88 const char *CStr
= StrData
.getCStr(&Offset
, &Err
);
91 DebugStr
.push_back(CStr
);
94 Y
.DebugStrings
= DebugStr
;
98 Error
dumpDebugARanges(DWARFContext
&DCtx
, DWARFYAML::Data
&Y
) {
99 DWARFDataExtractor
ArangesData(DCtx
.getDWARFObj().getArangesSection(),
100 DCtx
.isLittleEndian(), 0);
102 DWARFDebugArangeSet Set
;
103 std::vector
<DWARFYAML::ARange
> DebugAranges
;
105 // We ignore any errors that don't prevent parsing the section, since we can
106 // still represent such sections. These errors are recorded via the
107 // WarningHandler parameter of Set.extract().
108 auto DiscardError
= [](Error Err
) { consumeError(std::move(Err
)); };
110 while (ArangesData
.isValidOffset(Offset
)) {
111 if (Error E
= Set
.extract(ArangesData
, &Offset
, DiscardError
))
113 DWARFYAML::ARange Range
;
114 Range
.Format
= Set
.getHeader().Format
;
115 Range
.Length
= Set
.getHeader().Length
;
116 Range
.Version
= Set
.getHeader().Version
;
117 Range
.CuOffset
= Set
.getHeader().CuOffset
;
118 Range
.AddrSize
= Set
.getHeader().AddrSize
;
119 Range
.SegSize
= Set
.getHeader().SegSize
;
120 for (auto Descriptor
: Set
.descriptors()) {
121 DWARFYAML::ARangeDescriptor Desc
;
122 Desc
.Address
= Descriptor
.Address
;
123 Desc
.Length
= Descriptor
.Length
;
124 Range
.Descriptors
.push_back(Desc
);
126 DebugAranges
.push_back(Range
);
129 Y
.DebugAranges
= DebugAranges
;
130 return ErrorSuccess();
133 Error
dumpDebugRanges(DWARFContext
&DCtx
, DWARFYAML::Data
&Y
) {
134 // We are assuming all address byte sizes will be consistent across all
136 uint8_t AddrSize
= 0;
137 for (const auto &CU
: DCtx
.compile_units()) {
138 const uint8_t CUAddrSize
= CU
->getAddressByteSize();
140 AddrSize
= CUAddrSize
;
141 else if (CUAddrSize
!= AddrSize
)
142 return createStringError(std::errc::invalid_argument
,
143 "address sizes vary in different compile units");
146 DWARFDataExtractor
Data(DCtx
.getDWARFObj().getRangesSection().Data
,
147 DCtx
.isLittleEndian(), AddrSize
);
149 DWARFDebugRangeList DwarfRanges
;
150 std::vector
<DWARFYAML::Ranges
> DebugRanges
;
152 while (Data
.isValidOffset(Offset
)) {
153 DWARFYAML::Ranges YamlRanges
;
154 YamlRanges
.Offset
= Offset
;
155 YamlRanges
.AddrSize
= AddrSize
;
156 if (Error E
= DwarfRanges
.extract(Data
, &Offset
))
158 for (const auto &RLE
: DwarfRanges
.getEntries())
159 YamlRanges
.Entries
.push_back({RLE
.StartAddress
, RLE
.EndAddress
});
160 DebugRanges
.push_back(std::move(YamlRanges
));
163 Y
.DebugRanges
= DebugRanges
;
164 return ErrorSuccess();
167 static Optional
<DWARFYAML::PubSection
>
168 dumpPubSection(const DWARFContext
&DCtx
, const DWARFSection
&Section
,
170 DWARFYAML::PubSection Y
;
171 DWARFDataExtractor
PubSectionData(DCtx
.getDWARFObj(), Section
,
172 DCtx
.isLittleEndian(), 0);
173 DWARFDebugPubTable Table
;
174 // We ignore any errors that don't prevent parsing the section, since we can
175 // still represent such sections.
176 Table
.extract(PubSectionData
, IsGNUStyle
,
177 [](Error Err
) { consumeError(std::move(Err
)); });
178 ArrayRef
<DWARFDebugPubTable::Set
> Sets
= Table
.getData();
182 // FIXME: Currently, obj2yaml only supports dumping the first pubtable.
183 Y
.Format
= Sets
[0].Format
;
184 Y
.Length
= Sets
[0].Length
;
185 Y
.Version
= Sets
[0].Version
;
186 Y
.UnitOffset
= Sets
[0].Offset
;
187 Y
.UnitSize
= Sets
[0].Size
;
189 for (const DWARFDebugPubTable::Entry
&E
: Sets
[0].Entries
)
190 Y
.Entries
.push_back(DWARFYAML::PubEntry
{(uint32_t)E
.SecOffset
,
191 E
.Descriptor
.toBits(), E
.Name
});
196 void dumpDebugPubSections(DWARFContext
&DCtx
, DWARFYAML::Data
&Y
) {
197 const DWARFObject
&D
= DCtx
.getDWARFObj();
200 dumpPubSection(DCtx
, D
.getPubnamesSection(), /*IsGNUStyle=*/false);
202 dumpPubSection(DCtx
, D
.getPubtypesSection(), /*IsGNUStyle=*/false);
203 // TODO: Test dumping .debug_gnu_pubnames section.
205 dumpPubSection(DCtx
, D
.getGnuPubnamesSection(), /*IsGNUStyle=*/true);
206 // TODO: Test dumping .debug_gnu_pubtypes section.
208 dumpPubSection(DCtx
, D
.getGnuPubtypesSection(), /*IsGNUStyle=*/true);
211 void dumpDebugInfo(DWARFContext
&DCtx
, DWARFYAML::Data
&Y
) {
212 for (const auto &CU
: DCtx
.compile_units()) {
213 DWARFYAML::Unit NewUnit
;
214 NewUnit
.Format
= CU
->getFormat();
215 NewUnit
.Length
= CU
->getLength();
216 NewUnit
.Version
= CU
->getVersion();
217 if (NewUnit
.Version
>= 5)
218 NewUnit
.Type
= (dwarf::UnitType
)CU
->getUnitType();
219 const DWARFDebugAbbrev
*DebugAbbrev
= DCtx
.getDebugAbbrev();
220 NewUnit
.AbbrevTableID
= std::distance(
221 DebugAbbrev
->begin(),
224 [&](const std::pair
<uint64_t, DWARFAbbreviationDeclarationSet
> &P
) {
225 return P
.first
== CU
->getAbbreviations()->getOffset();
227 NewUnit
.AbbrOffset
= CU
->getAbbreviations()->getOffset();
228 NewUnit
.AddrSize
= CU
->getAddressByteSize();
229 for (auto DIE
: CU
->dies()) {
230 DWARFYAML::Entry NewEntry
;
231 DataExtractor EntryData
= CU
->getDebugInfoExtractor();
232 uint64_t offset
= DIE
.getOffset();
234 assert(EntryData
.isValidOffset(offset
) && "Invalid DIE Offset");
235 if (!EntryData
.isValidOffset(offset
))
238 NewEntry
.AbbrCode
= EntryData
.getULEB128(&offset
);
240 auto AbbrevDecl
= DIE
.getAbbreviationDeclarationPtr();
242 for (const auto &AttrSpec
: AbbrevDecl
->attributes()) {
243 DWARFYAML::FormValue NewValue
;
244 NewValue
.Value
= 0xDEADBEEFDEADBEEF;
245 DWARFDie
DIEWrapper(CU
.get(), &DIE
);
246 auto FormValue
= DIEWrapper
.find(AttrSpec
.Attr
);
249 auto Form
= FormValue
.getValue().getForm();
250 bool indirect
= false;
254 case dwarf::DW_FORM_addr
:
255 case dwarf::DW_FORM_GNU_addr_index
:
256 if (auto Val
= FormValue
.getValue().getAsAddress())
257 NewValue
.Value
= Val
.getValue();
259 case dwarf::DW_FORM_ref_addr
:
260 case dwarf::DW_FORM_ref1
:
261 case dwarf::DW_FORM_ref2
:
262 case dwarf::DW_FORM_ref4
:
263 case dwarf::DW_FORM_ref8
:
264 case dwarf::DW_FORM_ref_udata
:
265 case dwarf::DW_FORM_ref_sig8
:
266 if (auto Val
= FormValue
.getValue().getAsReferenceUVal())
267 NewValue
.Value
= Val
.getValue();
269 case dwarf::DW_FORM_exprloc
:
270 case dwarf::DW_FORM_block
:
271 case dwarf::DW_FORM_block1
:
272 case dwarf::DW_FORM_block2
:
273 case dwarf::DW_FORM_block4
:
274 if (auto Val
= FormValue
.getValue().getAsBlock()) {
275 auto BlockData
= Val
.getValue();
276 std::copy(BlockData
.begin(), BlockData
.end(),
277 std::back_inserter(NewValue
.BlockData
));
279 NewValue
.Value
= NewValue
.BlockData
.size();
281 case dwarf::DW_FORM_data1
:
282 case dwarf::DW_FORM_flag
:
283 case dwarf::DW_FORM_data2
:
284 case dwarf::DW_FORM_data4
:
285 case dwarf::DW_FORM_data8
:
286 case dwarf::DW_FORM_sdata
:
287 case dwarf::DW_FORM_udata
:
288 case dwarf::DW_FORM_ref_sup4
:
289 case dwarf::DW_FORM_ref_sup8
:
290 if (auto Val
= FormValue
.getValue().getAsUnsignedConstant())
291 NewValue
.Value
= Val
.getValue();
293 case dwarf::DW_FORM_string
:
294 if (auto Val
= dwarf::toString(FormValue
))
295 NewValue
.CStr
= *Val
;
297 case dwarf::DW_FORM_indirect
:
299 if (auto Val
= FormValue
.getValue().getAsUnsignedConstant()) {
300 NewValue
.Value
= Val
.getValue();
301 NewEntry
.Values
.push_back(NewValue
);
302 Form
= static_cast<dwarf::Form
>(Val
.getValue());
305 case dwarf::DW_FORM_strp
:
306 case dwarf::DW_FORM_sec_offset
:
307 case dwarf::DW_FORM_GNU_ref_alt
:
308 case dwarf::DW_FORM_GNU_strp_alt
:
309 case dwarf::DW_FORM_line_strp
:
310 case dwarf::DW_FORM_strp_sup
:
311 case dwarf::DW_FORM_GNU_str_index
:
312 case dwarf::DW_FORM_strx
:
313 if (auto Val
= FormValue
.getValue().getAsCStringOffset())
314 NewValue
.Value
= Val
.getValue();
316 case dwarf::DW_FORM_flag_present
:
323 NewEntry
.Values
.push_back(NewValue
);
327 NewUnit
.Entries
.push_back(NewEntry
);
329 Y
.CompileUnits
.push_back(NewUnit
);
333 bool dumpFileEntry(DataExtractor
&Data
, uint64_t &Offset
,
334 DWARFYAML::File
&File
) {
335 File
.Name
= Data
.getCStr(&Offset
);
336 if (File
.Name
.empty())
338 File
.DirIdx
= Data
.getULEB128(&Offset
);
339 File
.ModTime
= Data
.getULEB128(&Offset
);
340 File
.Length
= Data
.getULEB128(&Offset
);
344 void dumpDebugLines(DWARFContext
&DCtx
, DWARFYAML::Data
&Y
) {
345 for (const auto &CU
: DCtx
.compile_units()) {
346 auto CUDIE
= CU
->getUnitDIE();
349 if (auto StmtOffset
=
350 dwarf::toSectionOffset(CUDIE
.find(dwarf::DW_AT_stmt_list
))) {
351 DWARFYAML::LineTable DebugLines
;
352 DataExtractor
LineData(DCtx
.getDWARFObj().getLineSection().Data
,
353 DCtx
.isLittleEndian(), CU
->getAddressByteSize());
354 uint64_t Offset
= *StmtOffset
;
355 uint64_t LengthOrDWARF64Prefix
= LineData
.getU32(&Offset
);
356 if (LengthOrDWARF64Prefix
== dwarf::DW_LENGTH_DWARF64
) {
357 DebugLines
.Format
= dwarf::DWARF64
;
358 DebugLines
.Length
= LineData
.getU64(&Offset
);
360 DebugLines
.Format
= dwarf::DWARF32
;
361 DebugLines
.Length
= LengthOrDWARF64Prefix
;
363 assert(DebugLines
.Length
);
364 uint64_t LineTableLength
= *DebugLines
.Length
;
365 uint64_t SizeOfPrologueLength
=
366 DebugLines
.Format
== dwarf::DWARF64
? 8 : 4;
367 DebugLines
.Version
= LineData
.getU16(&Offset
);
368 DebugLines
.PrologueLength
=
369 LineData
.getUnsigned(&Offset
, SizeOfPrologueLength
);
370 assert(DebugLines
.PrologueLength
);
371 const uint64_t EndPrologue
= *DebugLines
.PrologueLength
+ Offset
;
373 DebugLines
.MinInstLength
= LineData
.getU8(&Offset
);
374 if (DebugLines
.Version
>= 4)
375 DebugLines
.MaxOpsPerInst
= LineData
.getU8(&Offset
);
376 DebugLines
.DefaultIsStmt
= LineData
.getU8(&Offset
);
377 DebugLines
.LineBase
= LineData
.getU8(&Offset
);
378 DebugLines
.LineRange
= LineData
.getU8(&Offset
);
379 DebugLines
.OpcodeBase
= LineData
.getU8(&Offset
);
381 DebugLines
.StandardOpcodeLengths
.emplace();
382 for (uint8_t i
= 1; i
< DebugLines
.OpcodeBase
; ++i
)
383 DebugLines
.StandardOpcodeLengths
->push_back(LineData
.getU8(&Offset
));
385 while (Offset
< EndPrologue
) {
386 StringRef Dir
= LineData
.getCStr(&Offset
);
388 DebugLines
.IncludeDirs
.push_back(Dir
);
393 while (Offset
< EndPrologue
) {
394 DWARFYAML::File TmpFile
;
395 if (dumpFileEntry(LineData
, Offset
, TmpFile
))
396 DebugLines
.Files
.push_back(TmpFile
);
401 const uint64_t LineEnd
=
402 LineTableLength
+ *StmtOffset
+ SizeOfPrologueLength
;
403 while (Offset
< LineEnd
) {
404 DWARFYAML::LineTableOpcode NewOp
= {};
405 NewOp
.Opcode
= (dwarf::LineNumberOps
)LineData
.getU8(&Offset
);
406 if (NewOp
.Opcode
== 0) {
407 auto StartExt
= Offset
;
408 NewOp
.ExtLen
= LineData
.getULEB128(&Offset
);
410 (dwarf::LineNumberExtendedOps
)LineData
.getU8(&Offset
);
411 switch (NewOp
.SubOpcode
) {
412 case dwarf::DW_LNE_set_address
:
413 case dwarf::DW_LNE_set_discriminator
:
414 NewOp
.Data
= LineData
.getAddress(&Offset
);
416 case dwarf::DW_LNE_define_file
:
417 dumpFileEntry(LineData
, Offset
, NewOp
.FileEntry
);
419 case dwarf::DW_LNE_end_sequence
:
422 while (Offset
< StartExt
+ *NewOp
.ExtLen
)
423 NewOp
.UnknownOpcodeData
.push_back(LineData
.getU8(&Offset
));
425 } else if (NewOp
.Opcode
< *DebugLines
.OpcodeBase
) {
426 switch (NewOp
.Opcode
) {
427 case dwarf::DW_LNS_copy
:
428 case dwarf::DW_LNS_negate_stmt
:
429 case dwarf::DW_LNS_set_basic_block
:
430 case dwarf::DW_LNS_const_add_pc
:
431 case dwarf::DW_LNS_set_prologue_end
:
432 case dwarf::DW_LNS_set_epilogue_begin
:
435 case dwarf::DW_LNS_advance_pc
:
436 case dwarf::DW_LNS_set_file
:
437 case dwarf::DW_LNS_set_column
:
438 case dwarf::DW_LNS_set_isa
:
439 NewOp
.Data
= LineData
.getULEB128(&Offset
);
442 case dwarf::DW_LNS_advance_line
:
443 NewOp
.SData
= LineData
.getSLEB128(&Offset
);
446 case dwarf::DW_LNS_fixed_advance_pc
:
447 NewOp
.Data
= LineData
.getU16(&Offset
);
453 DebugLines
.StandardOpcodeLengths
.getValue()[NewOp
.Opcode
- 1];
455 NewOp
.StandardOpcodeData
.push_back(LineData
.getULEB128(&Offset
));
458 DebugLines
.Opcodes
.push_back(NewOp
);
460 Y
.DebugLines
.push_back(DebugLines
);