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