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