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