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