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 //===----------------------------------------------------------------------===//
10 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
11 #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
12 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
13 #include "llvm/ObjectYAML/DWARFYAML.h"
19 void dumpInitialLength(DataExtractor
&Data
, uint64_t &Offset
,
20 DWARFYAML::InitialLength
&InitialLength
) {
21 InitialLength
.TotalLength
= Data
.getU32(&Offset
);
22 if (InitialLength
.isDWARF64())
23 InitialLength
.TotalLength64
= Data
.getU64(&Offset
);
26 void dumpDebugAbbrev(DWARFContext
&DCtx
, DWARFYAML::Data
&Y
) {
27 auto AbbrevSetPtr
= DCtx
.getDebugAbbrev();
29 for (auto AbbrvDeclSet
: *AbbrevSetPtr
) {
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
.AbbrevDecls
.push_back(Abbrv
);
50 void dumpDebugStrings(DWARFContext
&DCtx
, DWARFYAML::Data
&Y
) {
51 StringRef RemainingTable
= DCtx
.getDWARFObj().getStrSection();
52 while (RemainingTable
.size() > 0) {
53 auto SymbolPair
= RemainingTable
.split('\0');
54 RemainingTable
= SymbolPair
.second
;
55 Y
.DebugStrings
.push_back(SymbolPair
.first
);
59 void dumpDebugARanges(DWARFContext
&DCtx
, DWARFYAML::Data
&Y
) {
60 DataExtractor
ArangesData(DCtx
.getDWARFObj().getArangesSection(),
61 DCtx
.isLittleEndian(), 0);
63 DWARFDebugArangeSet Set
;
65 while (Set
.extract(ArangesData
, &Offset
)) {
66 DWARFYAML::ARange Range
;
67 Range
.Length
.setLength(Set
.getHeader().Length
);
68 Range
.Version
= Set
.getHeader().Version
;
69 Range
.CuOffset
= Set
.getHeader().CuOffset
;
70 Range
.AddrSize
= Set
.getHeader().AddrSize
;
71 Range
.SegSize
= Set
.getHeader().SegSize
;
72 for (auto Descriptor
: Set
.descriptors()) {
73 DWARFYAML::ARangeDescriptor Desc
;
74 Desc
.Address
= Descriptor
.Address
;
75 Desc
.Length
= Descriptor
.Length
;
76 Range
.Descriptors
.push_back(Desc
);
78 Y
.ARanges
.push_back(Range
);
82 void dumpPubSection(DWARFContext
&DCtx
, DWARFYAML::PubSection
&Y
,
83 DWARFSection Section
) {
84 DWARFDataExtractor
PubSectionData(DCtx
.getDWARFObj(), Section
,
85 DCtx
.isLittleEndian(), 0);
87 dumpInitialLength(PubSectionData
, Offset
, Y
.Length
);
88 Y
.Version
= PubSectionData
.getU16(&Offset
);
89 Y
.UnitOffset
= PubSectionData
.getU32(&Offset
);
90 Y
.UnitSize
= PubSectionData
.getU32(&Offset
);
91 while (Offset
< Y
.Length
.getLength()) {
92 DWARFYAML::PubEntry NewEntry
;
93 NewEntry
.DieOffset
= PubSectionData
.getU32(&Offset
);
95 NewEntry
.Descriptor
= PubSectionData
.getU8(&Offset
);
96 NewEntry
.Name
= PubSectionData
.getCStr(&Offset
);
97 Y
.Entries
.push_back(NewEntry
);
101 void dumpDebugPubSections(DWARFContext
&DCtx
, DWARFYAML::Data
&Y
) {
102 const DWARFObject
&D
= DCtx
.getDWARFObj();
103 Y
.PubNames
.IsGNUStyle
= false;
104 dumpPubSection(DCtx
, Y
.PubNames
, D
.getPubnamesSection());
106 Y
.PubTypes
.IsGNUStyle
= false;
107 dumpPubSection(DCtx
, Y
.PubTypes
, D
.getPubtypesSection());
109 Y
.GNUPubNames
.IsGNUStyle
= true;
110 dumpPubSection(DCtx
, Y
.GNUPubNames
, D
.getGnuPubnamesSection());
112 Y
.GNUPubTypes
.IsGNUStyle
= true;
113 dumpPubSection(DCtx
, Y
.GNUPubTypes
, D
.getGnuPubtypesSection());
116 void dumpDebugInfo(DWARFContext
&DCtx
, DWARFYAML::Data
&Y
) {
117 for (const auto &CU
: DCtx
.compile_units()) {
118 DWARFYAML::Unit NewUnit
;
119 NewUnit
.Length
.setLength(CU
->getLength());
120 NewUnit
.Version
= CU
->getVersion();
121 if(NewUnit
.Version
>= 5)
122 NewUnit
.Type
= (dwarf::UnitType
)CU
->getUnitType();
123 NewUnit
.AbbrOffset
= CU
->getAbbreviations()->getOffset();
124 NewUnit
.AddrSize
= CU
->getAddressByteSize();
125 for (auto DIE
: CU
->dies()) {
126 DWARFYAML::Entry NewEntry
;
127 DataExtractor EntryData
= CU
->getDebugInfoExtractor();
128 uint64_t offset
= DIE
.getOffset();
130 assert(EntryData
.isValidOffset(offset
) && "Invalid DIE Offset");
131 if (!EntryData
.isValidOffset(offset
))
134 NewEntry
.AbbrCode
= EntryData
.getULEB128(&offset
);
136 auto AbbrevDecl
= DIE
.getAbbreviationDeclarationPtr();
138 for (const auto &AttrSpec
: AbbrevDecl
->attributes()) {
139 DWARFYAML::FormValue NewValue
;
140 NewValue
.Value
= 0xDEADBEEFDEADBEEF;
141 DWARFDie
DIEWrapper(CU
.get(), &DIE
);
142 auto FormValue
= DIEWrapper
.find(AttrSpec
.Attr
);
145 auto Form
= FormValue
.getValue().getForm();
146 bool indirect
= false;
150 case dwarf::DW_FORM_addr
:
151 case dwarf::DW_FORM_GNU_addr_index
:
152 if (auto Val
= FormValue
.getValue().getAsAddress())
153 NewValue
.Value
= Val
.getValue();
155 case dwarf::DW_FORM_ref_addr
:
156 case dwarf::DW_FORM_ref1
:
157 case dwarf::DW_FORM_ref2
:
158 case dwarf::DW_FORM_ref4
:
159 case dwarf::DW_FORM_ref8
:
160 case dwarf::DW_FORM_ref_udata
:
161 case dwarf::DW_FORM_ref_sig8
:
162 if (auto Val
= FormValue
.getValue().getAsReferenceUVal())
163 NewValue
.Value
= Val
.getValue();
165 case dwarf::DW_FORM_exprloc
:
166 case dwarf::DW_FORM_block
:
167 case dwarf::DW_FORM_block1
:
168 case dwarf::DW_FORM_block2
:
169 case dwarf::DW_FORM_block4
:
170 if (auto Val
= FormValue
.getValue().getAsBlock()) {
171 auto BlockData
= Val
.getValue();
172 std::copy(BlockData
.begin(), BlockData
.end(),
173 std::back_inserter(NewValue
.BlockData
));
175 NewValue
.Value
= NewValue
.BlockData
.size();
177 case dwarf::DW_FORM_data1
:
178 case dwarf::DW_FORM_flag
:
179 case dwarf::DW_FORM_data2
:
180 case dwarf::DW_FORM_data4
:
181 case dwarf::DW_FORM_data8
:
182 case dwarf::DW_FORM_sdata
:
183 case dwarf::DW_FORM_udata
:
184 case dwarf::DW_FORM_ref_sup4
:
185 case dwarf::DW_FORM_ref_sup8
:
186 if (auto Val
= FormValue
.getValue().getAsUnsignedConstant())
187 NewValue
.Value
= Val
.getValue();
189 case dwarf::DW_FORM_string
:
190 if (auto Val
= FormValue
.getValue().getAsCString())
191 NewValue
.CStr
= Val
.getValue();
193 case dwarf::DW_FORM_indirect
:
195 if (auto Val
= FormValue
.getValue().getAsUnsignedConstant()) {
196 NewValue
.Value
= Val
.getValue();
197 NewEntry
.Values
.push_back(NewValue
);
198 Form
= static_cast<dwarf::Form
>(Val
.getValue());
201 case dwarf::DW_FORM_strp
:
202 case dwarf::DW_FORM_sec_offset
:
203 case dwarf::DW_FORM_GNU_ref_alt
:
204 case dwarf::DW_FORM_GNU_strp_alt
:
205 case dwarf::DW_FORM_line_strp
:
206 case dwarf::DW_FORM_strp_sup
:
207 case dwarf::DW_FORM_GNU_str_index
:
208 case dwarf::DW_FORM_strx
:
209 if (auto Val
= FormValue
.getValue().getAsCStringOffset())
210 NewValue
.Value
= Val
.getValue();
212 case dwarf::DW_FORM_flag_present
:
219 NewEntry
.Values
.push_back(NewValue
);
223 NewUnit
.Entries
.push_back(NewEntry
);
225 Y
.CompileUnits
.push_back(NewUnit
);
229 bool dumpFileEntry(DataExtractor
&Data
, uint64_t &Offset
,
230 DWARFYAML::File
&File
) {
231 File
.Name
= Data
.getCStr(&Offset
);
232 if (File
.Name
.empty())
234 File
.DirIdx
= Data
.getULEB128(&Offset
);
235 File
.ModTime
= Data
.getULEB128(&Offset
);
236 File
.Length
= Data
.getULEB128(&Offset
);
240 void dumpDebugLines(DWARFContext
&DCtx
, DWARFYAML::Data
&Y
) {
241 for (const auto &CU
: DCtx
.compile_units()) {
242 auto CUDIE
= CU
->getUnitDIE();
245 if (auto StmtOffset
=
246 dwarf::toSectionOffset(CUDIE
.find(dwarf::DW_AT_stmt_list
))) {
247 DWARFYAML::LineTable DebugLines
;
248 DataExtractor
LineData(DCtx
.getDWARFObj().getLineSection().Data
,
249 DCtx
.isLittleEndian(), CU
->getAddressByteSize());
250 uint64_t Offset
= *StmtOffset
;
251 dumpInitialLength(LineData
, Offset
, DebugLines
.Length
);
252 uint64_t LineTableLength
= DebugLines
.Length
.getLength();
253 uint64_t SizeOfPrologueLength
= DebugLines
.Length
.isDWARF64() ? 8 : 4;
254 DebugLines
.Version
= LineData
.getU16(&Offset
);
255 DebugLines
.PrologueLength
=
256 LineData
.getUnsigned(&Offset
, SizeOfPrologueLength
);
257 const uint64_t EndPrologue
= DebugLines
.PrologueLength
+ Offset
;
259 DebugLines
.MinInstLength
= LineData
.getU8(&Offset
);
260 if (DebugLines
.Version
>= 4)
261 DebugLines
.MaxOpsPerInst
= LineData
.getU8(&Offset
);
262 DebugLines
.DefaultIsStmt
= LineData
.getU8(&Offset
);
263 DebugLines
.LineBase
= LineData
.getU8(&Offset
);
264 DebugLines
.LineRange
= LineData
.getU8(&Offset
);
265 DebugLines
.OpcodeBase
= LineData
.getU8(&Offset
);
267 DebugLines
.StandardOpcodeLengths
.reserve(DebugLines
.OpcodeBase
- 1);
268 for (uint8_t i
= 1; i
< DebugLines
.OpcodeBase
; ++i
)
269 DebugLines
.StandardOpcodeLengths
.push_back(LineData
.getU8(&Offset
));
271 while (Offset
< EndPrologue
) {
272 StringRef Dir
= LineData
.getCStr(&Offset
);
274 DebugLines
.IncludeDirs
.push_back(Dir
);
279 while (Offset
< EndPrologue
) {
280 DWARFYAML::File TmpFile
;
281 if (dumpFileEntry(LineData
, Offset
, TmpFile
))
282 DebugLines
.Files
.push_back(TmpFile
);
287 const uint64_t LineEnd
=
288 LineTableLength
+ *StmtOffset
+ SizeOfPrologueLength
;
289 while (Offset
< LineEnd
) {
290 DWARFYAML::LineTableOpcode NewOp
;
291 NewOp
.Opcode
= (dwarf::LineNumberOps
)LineData
.getU8(&Offset
);
292 if (NewOp
.Opcode
== 0) {
293 auto StartExt
= Offset
;
294 NewOp
.ExtLen
= LineData
.getULEB128(&Offset
);
296 (dwarf::LineNumberExtendedOps
)LineData
.getU8(&Offset
);
297 switch (NewOp
.SubOpcode
) {
298 case dwarf::DW_LNE_set_address
:
299 case dwarf::DW_LNE_set_discriminator
:
300 NewOp
.Data
= LineData
.getAddress(&Offset
);
302 case dwarf::DW_LNE_define_file
:
303 dumpFileEntry(LineData
, Offset
, NewOp
.FileEntry
);
305 case dwarf::DW_LNE_end_sequence
:
308 while (Offset
< StartExt
+ NewOp
.ExtLen
)
309 NewOp
.UnknownOpcodeData
.push_back(LineData
.getU8(&Offset
));
311 } else if (NewOp
.Opcode
< DebugLines
.OpcodeBase
) {
312 switch (NewOp
.Opcode
) {
313 case dwarf::DW_LNS_copy
:
314 case dwarf::DW_LNS_negate_stmt
:
315 case dwarf::DW_LNS_set_basic_block
:
316 case dwarf::DW_LNS_const_add_pc
:
317 case dwarf::DW_LNS_set_prologue_end
:
318 case dwarf::DW_LNS_set_epilogue_begin
:
321 case dwarf::DW_LNS_advance_pc
:
322 case dwarf::DW_LNS_set_file
:
323 case dwarf::DW_LNS_set_column
:
324 case dwarf::DW_LNS_set_isa
:
325 NewOp
.Data
= LineData
.getULEB128(&Offset
);
328 case dwarf::DW_LNS_advance_line
:
329 NewOp
.SData
= LineData
.getSLEB128(&Offset
);
332 case dwarf::DW_LNS_fixed_advance_pc
:
333 NewOp
.Data
= LineData
.getU16(&Offset
);
338 i
< DebugLines
.StandardOpcodeLengths
[NewOp
.Opcode
- 1]; ++i
)
339 NewOp
.StandardOpcodeData
.push_back(LineData
.getULEB128(&Offset
));
342 DebugLines
.Opcodes
.push_back(NewOp
);
344 Y
.DebugLines
.push_back(DebugLines
);
349 std::error_code
dwarf2yaml(DWARFContext
&DCtx
, DWARFYAML::Data
&Y
) {
350 dumpDebugAbbrev(DCtx
, Y
);
351 dumpDebugStrings(DCtx
, Y
);
352 dumpDebugARanges(DCtx
, Y
);
353 dumpDebugPubSections(DCtx
, Y
);
354 dumpDebugInfo(DCtx
, Y
);
355 dumpDebugLines(DCtx
, Y
);
356 return obj2yaml_error::success
;