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