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 //===----------------------------------------------------------------------===//
8
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"
18
19 #include <algorithm>
20
21 using namespace llvm;
22
dumpDebugAbbrev(DWARFContext & DCtx,DWARFYAML::Data & Y)23 void dumpDebugAbbrev(DWARFContext &DCtx, DWARFYAML::Data &Y) {
24 auto AbbrevSetPtr = DCtx.getDebugAbbrev();
25 if (AbbrevSetPtr) {
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);
43 }
44 Y.DebugAbbrev.back().Table.push_back(Abbrv);
45 }
46 }
47 }
48 }
49
dumpDebugAddr(DWARFContext & DCtx,DWARFYAML::Data & Y)50 Error dumpDebugAddr(DWARFContext &DCtx, DWARFYAML::Data &Y) {
51 DWARFDebugAddrTable AddrTable;
52 DWARFDataExtractor AddrData(DCtx.getDWARFObj(),
53 DCtx.getDWARFObj().getAddrSection(),
54 DCtx.isLittleEndian(), /*AddrSize=*/0);
55 std::vector<DWARFYAML::AddrTableEntry> AddrTables;
56 uint64_t Offset = 0;
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,
61 consumeError))
62 return Err;
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});
70 }
71
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();
77 }
78 Y.DebugAddr = std::move(AddrTables);
79 return Error::success();
80 }
81
dumpDebugStrings(DWARFContext & DCtx,DWARFYAML::Data & Y)82 Error dumpDebugStrings(DWARFContext &DCtx, DWARFYAML::Data &Y) {
83 DataExtractor StrData = DCtx.getStringExtractor();
84 uint64_t Offset = 0;
85 std::vector<StringRef> DebugStr;
86 Error Err = Error::success();
87 while (StrData.isValidOffset(Offset)) {
88 const char *CStr = StrData.getCStr(&Offset, &Err);
89 if (Err)
90 return Err;
91 DebugStr.push_back(CStr);
92 }
93
94 Y.DebugStrings = DebugStr;
95 return Err;
96 }
97
dumpDebugARanges(DWARFContext & DCtx,DWARFYAML::Data & Y)98 Error dumpDebugARanges(DWARFContext &DCtx, DWARFYAML::Data &Y) {
99 DWARFDataExtractor ArangesData(DCtx.getDWARFObj().getArangesSection(),
100 DCtx.isLittleEndian(), 0);
101 uint64_t Offset = 0;
102 DWARFDebugArangeSet Set;
103 std::vector<DWARFYAML::ARange> DebugAranges;
104
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)); };
109
110 while (ArangesData.isValidOffset(Offset)) {
111 if (Error E = Set.extract(ArangesData, &Offset, DiscardError))
112 return E;
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);
125 }
126 DebugAranges.push_back(Range);
127 }
128
129 Y.DebugAranges = DebugAranges;
130 return ErrorSuccess();
131 }
132
dumpDebugRanges(DWARFContext & DCtx,DWARFYAML::Data & Y)133 Error dumpDebugRanges(DWARFContext &DCtx, DWARFYAML::Data &Y) {
134 // We are assuming all address byte sizes will be consistent across all
135 // compile units.
136 uint8_t AddrSize = 0;
137 for (const auto &CU : DCtx.compile_units()) {
138 const uint8_t CUAddrSize = CU->getAddressByteSize();
139 if (AddrSize == 0)
140 AddrSize = CUAddrSize;
141 else if (CUAddrSize != AddrSize)
142 return createStringError(std::errc::invalid_argument,
143 "address sizes vary in different compile units");
144 }
145
146 DWARFDataExtractor Data(DCtx.getDWARFObj().getRangesSection().Data,
147 DCtx.isLittleEndian(), AddrSize);
148 uint64_t Offset = 0;
149 DWARFDebugRangeList DwarfRanges;
150 std::vector<DWARFYAML::Ranges> DebugRanges;
151
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))
157 return E;
158 for (const auto &RLE : DwarfRanges.getEntries())
159 YamlRanges.Entries.push_back({RLE.StartAddress, RLE.EndAddress});
160 DebugRanges.push_back(std::move(YamlRanges));
161 }
162
163 Y.DebugRanges = DebugRanges;
164 return ErrorSuccess();
165 }
166
167 static Optional<DWARFYAML::PubSection>
dumpPubSection(const DWARFContext & DCtx,const DWARFSection & Section,bool IsGNUStyle)168 dumpPubSection(const DWARFContext &DCtx, const DWARFSection &Section,
169 bool IsGNUStyle) {
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();
179 if (Sets.empty())
180 return None;
181
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;
188
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});
192
193 return Y;
194 }
195
dumpDebugPubSections(DWARFContext & DCtx,DWARFYAML::Data & Y)196 void dumpDebugPubSections(DWARFContext &DCtx, DWARFYAML::Data &Y) {
197 const DWARFObject &D = DCtx.getDWARFObj();
198
199 Y.PubNames =
200 dumpPubSection(DCtx, D.getPubnamesSection(), /*IsGNUStyle=*/false);
201 Y.PubTypes =
202 dumpPubSection(DCtx, D.getPubtypesSection(), /*IsGNUStyle=*/false);
203 // TODO: Test dumping .debug_gnu_pubnames section.
204 Y.GNUPubNames =
205 dumpPubSection(DCtx, D.getGnuPubnamesSection(), /*IsGNUStyle=*/true);
206 // TODO: Test dumping .debug_gnu_pubtypes section.
207 Y.GNUPubTypes =
208 dumpPubSection(DCtx, D.getGnuPubtypesSection(), /*IsGNUStyle=*/true);
209 }
210
dumpDebugInfo(DWARFContext & DCtx,DWARFYAML::Data & Y)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(),
222 llvm::find_if(
223 *DebugAbbrev,
224 [&](const std::pair<uint64_t, DWARFAbbreviationDeclarationSet> &P) {
225 return P.first == CU->getAbbreviations()->getOffset();
226 }));
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();
233
234 assert(EntryData.isValidOffset(offset) && "Invalid DIE Offset");
235 if (!EntryData.isValidOffset(offset))
236 continue;
237
238 NewEntry.AbbrCode = EntryData.getULEB128(&offset);
239
240 auto AbbrevDecl = DIE.getAbbreviationDeclarationPtr();
241 if (AbbrevDecl) {
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);
247 if (!FormValue)
248 return;
249 auto Form = FormValue.getValue().getForm();
250 bool indirect = false;
251 do {
252 indirect = false;
253 switch (Form) {
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();
258 break;
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();
268 break;
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));
278 }
279 NewValue.Value = NewValue.BlockData.size();
280 break;
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();
292 break;
293 case dwarf::DW_FORM_string:
294 if (auto Val = FormValue.getValue().getAsCString())
295 NewValue.CStr = Val.getValue();
296 break;
297 case dwarf::DW_FORM_indirect:
298 indirect = true;
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());
303 }
304 break;
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();
315 break;
316 case dwarf::DW_FORM_flag_present:
317 NewValue.Value = 1;
318 break;
319 default:
320 break;
321 }
322 } while (indirect);
323 NewEntry.Values.push_back(NewValue);
324 }
325 }
326
327 NewUnit.Entries.push_back(NewEntry);
328 }
329 Y.CompileUnits.push_back(NewUnit);
330 }
331 }
332
dumpFileEntry(DataExtractor & Data,uint64_t & Offset,DWARFYAML::File & File)333 bool dumpFileEntry(DataExtractor &Data, uint64_t &Offset,
334 DWARFYAML::File &File) {
335 File.Name = Data.getCStr(&Offset);
336 if (File.Name.empty())
337 return false;
338 File.DirIdx = Data.getULEB128(&Offset);
339 File.ModTime = Data.getULEB128(&Offset);
340 File.Length = Data.getULEB128(&Offset);
341 return true;
342 }
343
dumpDebugLines(DWARFContext & DCtx,DWARFYAML::Data & Y)344 void dumpDebugLines(DWARFContext &DCtx, DWARFYAML::Data &Y) {
345 for (const auto &CU : DCtx.compile_units()) {
346 auto CUDIE = CU->getUnitDIE();
347 if (!CUDIE)
348 continue;
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);
359 } else {
360 DebugLines.Format = dwarf::DWARF32;
361 DebugLines.Length = LengthOrDWARF64Prefix;
362 }
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;
372
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);
380
381 DebugLines.StandardOpcodeLengths.emplace();
382 for (uint8_t i = 1; i < DebugLines.OpcodeBase; ++i)
383 DebugLines.StandardOpcodeLengths->push_back(LineData.getU8(&Offset));
384
385 while (Offset < EndPrologue) {
386 StringRef Dir = LineData.getCStr(&Offset);
387 if (!Dir.empty())
388 DebugLines.IncludeDirs.push_back(Dir);
389 else
390 break;
391 }
392
393 while (Offset < EndPrologue) {
394 DWARFYAML::File TmpFile;
395 if (dumpFileEntry(LineData, Offset, TmpFile))
396 DebugLines.Files.push_back(TmpFile);
397 else
398 break;
399 }
400
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);
409 NewOp.SubOpcode =
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);
415 break;
416 case dwarf::DW_LNE_define_file:
417 dumpFileEntry(LineData, Offset, NewOp.FileEntry);
418 break;
419 case dwarf::DW_LNE_end_sequence:
420 break;
421 default:
422 while (Offset < StartExt + *NewOp.ExtLen)
423 NewOp.UnknownOpcodeData.push_back(LineData.getU8(&Offset));
424 }
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:
433 break;
434
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);
440 break;
441
442 case dwarf::DW_LNS_advance_line:
443 NewOp.SData = LineData.getSLEB128(&Offset);
444 break;
445
446 case dwarf::DW_LNS_fixed_advance_pc:
447 NewOp.Data = LineData.getU16(&Offset);
448 break;
449
450 default:
451 for (uint8_t i = 0;
452 i <
453 DebugLines.StandardOpcodeLengths.getValue()[NewOp.Opcode - 1];
454 ++i)
455 NewOp.StandardOpcodeData.push_back(LineData.getULEB128(&Offset));
456 }
457 }
458 DebugLines.Opcodes.push_back(NewOp);
459 }
460 Y.DebugLines.push_back(DebugLines);
461 }
462 }
463 }
464