OSDN Git Service

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