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