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