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