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