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