xref: /netbsd-src/external/apache2/llvm/dist/llvm/tools/obj2yaml/dwarf2yaml.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
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 "llvm/BinaryFormat/Dwarf.h"
10 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
11 #include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
12 #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
13 #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
14 #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
15 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
16 #include "llvm/DebugInfo/DWARF/DWARFSection.h"
17 #include "llvm/ObjectYAML/DWARFYAML.h"
18 
19 #include <algorithm>
20 
21 using namespace llvm;
22 
dumpDebugAbbrev(DWARFContext & DCtx,DWARFYAML::Data & Y)23 void dumpDebugAbbrev(DWARFContext &DCtx, DWARFYAML::Data &Y) {
24   auto AbbrevSetPtr = DCtx.getDebugAbbrev();
25   if (AbbrevSetPtr) {
26     uint64_t AbbrevTableID = 0;
27     for (auto AbbrvDeclSet : *AbbrevSetPtr) {
28       Y.DebugAbbrev.emplace_back();
29       Y.DebugAbbrev.back().ID = AbbrevTableID++;
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.DebugAbbrev.back().Table.push_back(Abbrv);
45       }
46     }
47   }
48 }
49 
dumpDebugAddr(DWARFContext & DCtx,DWARFYAML::Data & Y)50 Error dumpDebugAddr(DWARFContext &DCtx, DWARFYAML::Data &Y) {
51   DWARFDebugAddrTable AddrTable;
52   DWARFDataExtractor AddrData(DCtx.getDWARFObj(),
53                               DCtx.getDWARFObj().getAddrSection(),
54                               DCtx.isLittleEndian(), /*AddrSize=*/0);
55   std::vector<DWARFYAML::AddrTableEntry> AddrTables;
56   uint64_t Offset = 0;
57   while (AddrData.isValidOffset(Offset)) {
58     // We ignore any errors that don't prevent parsing the section, since we can
59     // still represent such sections.
60     if (Error Err = AddrTable.extractV5(AddrData, &Offset, /*CUAddrSize=*/0,
61                                         consumeError))
62       return Err;
63     AddrTables.emplace_back();
64     for (uint64_t Addr : AddrTable.getAddressEntries()) {
65       // Currently, the parser doesn't support parsing an address table with non
66       // linear addresses (segment_selector_size != 0). The segment selectors
67       // are specified to be zero.
68       AddrTables.back().SegAddrPairs.push_back(
69           {/*SegmentSelector=*/0, /*Address=*/Addr});
70     }
71 
72     AddrTables.back().Format = AddrTable.getFormat();
73     AddrTables.back().Length = AddrTable.getLength();
74     AddrTables.back().Version = AddrTable.getVersion();
75     AddrTables.back().AddrSize = AddrTable.getAddressSize();
76     AddrTables.back().SegSelectorSize = AddrTable.getSegmentSelectorSize();
77   }
78   Y.DebugAddr = std::move(AddrTables);
79   return Error::success();
80 }
81 
dumpDebugStrings(DWARFContext & DCtx,DWARFYAML::Data & Y)82 Error dumpDebugStrings(DWARFContext &DCtx, DWARFYAML::Data &Y) {
83   DataExtractor StrData = DCtx.getStringExtractor();
84   uint64_t Offset = 0;
85   std::vector<StringRef> DebugStr;
86   Error Err = Error::success();
87   while (StrData.isValidOffset(Offset)) {
88     const char *CStr = StrData.getCStr(&Offset, &Err);
89     if (Err)
90       return Err;
91     DebugStr.push_back(CStr);
92   }
93 
94   Y.DebugStrings = DebugStr;
95   return Err;
96 }
97 
dumpDebugARanges(DWARFContext & DCtx,DWARFYAML::Data & Y)98 Error dumpDebugARanges(DWARFContext &DCtx, DWARFYAML::Data &Y) {
99   DWARFDataExtractor ArangesData(DCtx.getDWARFObj().getArangesSection(),
100                                  DCtx.isLittleEndian(), 0);
101   uint64_t Offset = 0;
102   DWARFDebugArangeSet Set;
103   std::vector<DWARFYAML::ARange> DebugAranges;
104 
105   // We ignore any errors that don't prevent parsing the section, since we can
106   // still represent such sections. These errors are recorded via the
107   // WarningHandler parameter of Set.extract().
108   auto DiscardError = [](Error Err) { consumeError(std::move(Err)); };
109 
110   while (ArangesData.isValidOffset(Offset)) {
111     if (Error E = Set.extract(ArangesData, &Offset, DiscardError))
112       return E;
113     DWARFYAML::ARange Range;
114     Range.Format = Set.getHeader().Format;
115     Range.Length = Set.getHeader().Length;
116     Range.Version = Set.getHeader().Version;
117     Range.CuOffset = Set.getHeader().CuOffset;
118     Range.AddrSize = Set.getHeader().AddrSize;
119     Range.SegSize = Set.getHeader().SegSize;
120     for (auto Descriptor : Set.descriptors()) {
121       DWARFYAML::ARangeDescriptor Desc;
122       Desc.Address = Descriptor.Address;
123       Desc.Length = Descriptor.Length;
124       Range.Descriptors.push_back(Desc);
125     }
126     DebugAranges.push_back(Range);
127   }
128 
129   Y.DebugAranges = DebugAranges;
130   return ErrorSuccess();
131 }
132 
dumpDebugRanges(DWARFContext & DCtx,DWARFYAML::Data & Y)133 Error dumpDebugRanges(DWARFContext &DCtx, DWARFYAML::Data &Y) {
134   // We are assuming all address byte sizes will be consistent across all
135   // compile units.
136   uint8_t AddrSize = 0;
137   for (const auto &CU : DCtx.compile_units()) {
138     const uint8_t CUAddrSize = CU->getAddressByteSize();
139     if (AddrSize == 0)
140       AddrSize = CUAddrSize;
141     else if (CUAddrSize != AddrSize)
142       return createStringError(std::errc::invalid_argument,
143                                "address sizes vary in different compile units");
144   }
145 
146   DWARFDataExtractor Data(DCtx.getDWARFObj().getRangesSection().Data,
147                           DCtx.isLittleEndian(), AddrSize);
148   uint64_t Offset = 0;
149   DWARFDebugRangeList DwarfRanges;
150   std::vector<DWARFYAML::Ranges> DebugRanges;
151 
152   while (Data.isValidOffset(Offset)) {
153     DWARFYAML::Ranges YamlRanges;
154     YamlRanges.Offset = Offset;
155     YamlRanges.AddrSize = AddrSize;
156     if (Error E = DwarfRanges.extract(Data, &Offset))
157       return E;
158     for (const auto &RLE : DwarfRanges.getEntries())
159       YamlRanges.Entries.push_back({RLE.StartAddress, RLE.EndAddress});
160     DebugRanges.push_back(std::move(YamlRanges));
161   }
162 
163   Y.DebugRanges = DebugRanges;
164   return ErrorSuccess();
165 }
166 
167 static Optional<DWARFYAML::PubSection>
dumpPubSection(const DWARFContext & DCtx,const DWARFSection & Section,bool IsGNUStyle)168 dumpPubSection(const DWARFContext &DCtx, const DWARFSection &Section,
169                bool IsGNUStyle) {
170   DWARFYAML::PubSection Y;
171   DWARFDataExtractor PubSectionData(DCtx.getDWARFObj(), Section,
172                                     DCtx.isLittleEndian(), 0);
173   DWARFDebugPubTable Table;
174   // We ignore any errors that don't prevent parsing the section, since we can
175   // still represent such sections.
176   Table.extract(PubSectionData, IsGNUStyle,
177                 [](Error Err) { consumeError(std::move(Err)); });
178   ArrayRef<DWARFDebugPubTable::Set> Sets = Table.getData();
179   if (Sets.empty())
180     return None;
181 
182   // FIXME: Currently, obj2yaml only supports dumping the first pubtable.
183   Y.Format = Sets[0].Format;
184   Y.Length = Sets[0].Length;
185   Y.Version = Sets[0].Version;
186   Y.UnitOffset = Sets[0].Offset;
187   Y.UnitSize = Sets[0].Size;
188 
189   for (const DWARFDebugPubTable::Entry &E : Sets[0].Entries)
190     Y.Entries.push_back(DWARFYAML::PubEntry{(uint32_t)E.SecOffset,
191                                             E.Descriptor.toBits(), E.Name});
192 
193   return Y;
194 }
195 
dumpDebugPubSections(DWARFContext & DCtx,DWARFYAML::Data & Y)196 void dumpDebugPubSections(DWARFContext &DCtx, DWARFYAML::Data &Y) {
197   const DWARFObject &D = DCtx.getDWARFObj();
198 
199   Y.PubNames =
200       dumpPubSection(DCtx, D.getPubnamesSection(), /*IsGNUStyle=*/false);
201   Y.PubTypes =
202       dumpPubSection(DCtx, D.getPubtypesSection(), /*IsGNUStyle=*/false);
203   // TODO: Test dumping .debug_gnu_pubnames section.
204   Y.GNUPubNames =
205       dumpPubSection(DCtx, D.getGnuPubnamesSection(), /*IsGNUStyle=*/true);
206   // TODO: Test dumping .debug_gnu_pubtypes section.
207   Y.GNUPubTypes =
208       dumpPubSection(DCtx, D.getGnuPubtypesSection(), /*IsGNUStyle=*/true);
209 }
210 
dumpDebugInfo(DWARFContext & DCtx,DWARFYAML::Data & Y)211 void dumpDebugInfo(DWARFContext &DCtx, DWARFYAML::Data &Y) {
212   for (const auto &CU : DCtx.compile_units()) {
213     DWARFYAML::Unit NewUnit;
214     NewUnit.Format = CU->getFormat();
215     NewUnit.Length = CU->getLength();
216     NewUnit.Version = CU->getVersion();
217     if (NewUnit.Version >= 5)
218       NewUnit.Type = (dwarf::UnitType)CU->getUnitType();
219     const DWARFDebugAbbrev *DebugAbbrev = DCtx.getDebugAbbrev();
220     NewUnit.AbbrevTableID = std::distance(
221         DebugAbbrev->begin(),
222         llvm::find_if(
223             *DebugAbbrev,
224             [&](const std::pair<uint64_t, DWARFAbbreviationDeclarationSet> &P) {
225               return P.first == CU->getAbbreviations()->getOffset();
226             }));
227     NewUnit.AbbrOffset = CU->getAbbreviations()->getOffset();
228     NewUnit.AddrSize = CU->getAddressByteSize();
229     for (auto DIE : CU->dies()) {
230       DWARFYAML::Entry NewEntry;
231       DataExtractor EntryData = CU->getDebugInfoExtractor();
232       uint64_t offset = DIE.getOffset();
233 
234       assert(EntryData.isValidOffset(offset) && "Invalid DIE Offset");
235       if (!EntryData.isValidOffset(offset))
236         continue;
237 
238       NewEntry.AbbrCode = EntryData.getULEB128(&offset);
239 
240       auto AbbrevDecl = DIE.getAbbreviationDeclarationPtr();
241       if (AbbrevDecl) {
242         for (const auto &AttrSpec : AbbrevDecl->attributes()) {
243           DWARFYAML::FormValue NewValue;
244           NewValue.Value = 0xDEADBEEFDEADBEEF;
245           DWARFDie DIEWrapper(CU.get(), &DIE);
246           auto FormValue = DIEWrapper.find(AttrSpec.Attr);
247           if (!FormValue)
248             return;
249           auto Form = FormValue.getValue().getForm();
250           bool indirect = false;
251           do {
252             indirect = false;
253             switch (Form) {
254             case dwarf::DW_FORM_addr:
255             case dwarf::DW_FORM_GNU_addr_index:
256               if (auto Val = FormValue.getValue().getAsAddress())
257                 NewValue.Value = Val.getValue();
258               break;
259             case dwarf::DW_FORM_ref_addr:
260             case dwarf::DW_FORM_ref1:
261             case dwarf::DW_FORM_ref2:
262             case dwarf::DW_FORM_ref4:
263             case dwarf::DW_FORM_ref8:
264             case dwarf::DW_FORM_ref_udata:
265             case dwarf::DW_FORM_ref_sig8:
266               if (auto Val = FormValue.getValue().getAsReferenceUVal())
267                 NewValue.Value = Val.getValue();
268               break;
269             case dwarf::DW_FORM_exprloc:
270             case dwarf::DW_FORM_block:
271             case dwarf::DW_FORM_block1:
272             case dwarf::DW_FORM_block2:
273             case dwarf::DW_FORM_block4:
274               if (auto Val = FormValue.getValue().getAsBlock()) {
275                 auto BlockData = Val.getValue();
276                 std::copy(BlockData.begin(), BlockData.end(),
277                           std::back_inserter(NewValue.BlockData));
278               }
279               NewValue.Value = NewValue.BlockData.size();
280               break;
281             case dwarf::DW_FORM_data1:
282             case dwarf::DW_FORM_flag:
283             case dwarf::DW_FORM_data2:
284             case dwarf::DW_FORM_data4:
285             case dwarf::DW_FORM_data8:
286             case dwarf::DW_FORM_sdata:
287             case dwarf::DW_FORM_udata:
288             case dwarf::DW_FORM_ref_sup4:
289             case dwarf::DW_FORM_ref_sup8:
290               if (auto Val = FormValue.getValue().getAsUnsignedConstant())
291                 NewValue.Value = Val.getValue();
292               break;
293             case dwarf::DW_FORM_string:
294               if (auto Val = FormValue.getValue().getAsCString())
295                 NewValue.CStr = Val.getValue();
296               break;
297             case dwarf::DW_FORM_indirect:
298               indirect = true;
299               if (auto Val = FormValue.getValue().getAsUnsignedConstant()) {
300                 NewValue.Value = Val.getValue();
301                 NewEntry.Values.push_back(NewValue);
302                 Form = static_cast<dwarf::Form>(Val.getValue());
303               }
304               break;
305             case dwarf::DW_FORM_strp:
306             case dwarf::DW_FORM_sec_offset:
307             case dwarf::DW_FORM_GNU_ref_alt:
308             case dwarf::DW_FORM_GNU_strp_alt:
309             case dwarf::DW_FORM_line_strp:
310             case dwarf::DW_FORM_strp_sup:
311             case dwarf::DW_FORM_GNU_str_index:
312             case dwarf::DW_FORM_strx:
313               if (auto Val = FormValue.getValue().getAsCStringOffset())
314                 NewValue.Value = Val.getValue();
315               break;
316             case dwarf::DW_FORM_flag_present:
317               NewValue.Value = 1;
318               break;
319             default:
320               break;
321             }
322           } while (indirect);
323           NewEntry.Values.push_back(NewValue);
324         }
325       }
326 
327       NewUnit.Entries.push_back(NewEntry);
328     }
329     Y.CompileUnits.push_back(NewUnit);
330   }
331 }
332 
dumpFileEntry(DataExtractor & Data,uint64_t & Offset,DWARFYAML::File & File)333 bool dumpFileEntry(DataExtractor &Data, uint64_t &Offset,
334                    DWARFYAML::File &File) {
335   File.Name = Data.getCStr(&Offset);
336   if (File.Name.empty())
337     return false;
338   File.DirIdx = Data.getULEB128(&Offset);
339   File.ModTime = Data.getULEB128(&Offset);
340   File.Length = Data.getULEB128(&Offset);
341   return true;
342 }
343 
dumpDebugLines(DWARFContext & DCtx,DWARFYAML::Data & Y)344 void dumpDebugLines(DWARFContext &DCtx, DWARFYAML::Data &Y) {
345   for (const auto &CU : DCtx.compile_units()) {
346     auto CUDIE = CU->getUnitDIE();
347     if (!CUDIE)
348       continue;
349     if (auto StmtOffset =
350             dwarf::toSectionOffset(CUDIE.find(dwarf::DW_AT_stmt_list))) {
351       DWARFYAML::LineTable DebugLines;
352       DataExtractor LineData(DCtx.getDWARFObj().getLineSection().Data,
353                              DCtx.isLittleEndian(), CU->getAddressByteSize());
354       uint64_t Offset = *StmtOffset;
355       uint64_t LengthOrDWARF64Prefix = LineData.getU32(&Offset);
356       if (LengthOrDWARF64Prefix == dwarf::DW_LENGTH_DWARF64) {
357         DebugLines.Format = dwarf::DWARF64;
358         DebugLines.Length = LineData.getU64(&Offset);
359       } else {
360         DebugLines.Format = dwarf::DWARF32;
361         DebugLines.Length = LengthOrDWARF64Prefix;
362       }
363       assert(DebugLines.Length);
364       uint64_t LineTableLength = *DebugLines.Length;
365       uint64_t SizeOfPrologueLength =
366           DebugLines.Format == dwarf::DWARF64 ? 8 : 4;
367       DebugLines.Version = LineData.getU16(&Offset);
368       DebugLines.PrologueLength =
369           LineData.getUnsigned(&Offset, SizeOfPrologueLength);
370       assert(DebugLines.PrologueLength);
371       const uint64_t EndPrologue = *DebugLines.PrologueLength + Offset;
372 
373       DebugLines.MinInstLength = LineData.getU8(&Offset);
374       if (DebugLines.Version >= 4)
375         DebugLines.MaxOpsPerInst = LineData.getU8(&Offset);
376       DebugLines.DefaultIsStmt = LineData.getU8(&Offset);
377       DebugLines.LineBase = LineData.getU8(&Offset);
378       DebugLines.LineRange = LineData.getU8(&Offset);
379       DebugLines.OpcodeBase = LineData.getU8(&Offset);
380 
381       DebugLines.StandardOpcodeLengths.emplace();
382       for (uint8_t i = 1; i < DebugLines.OpcodeBase; ++i)
383         DebugLines.StandardOpcodeLengths->push_back(LineData.getU8(&Offset));
384 
385       while (Offset < EndPrologue) {
386         StringRef Dir = LineData.getCStr(&Offset);
387         if (!Dir.empty())
388           DebugLines.IncludeDirs.push_back(Dir);
389         else
390           break;
391       }
392 
393       while (Offset < EndPrologue) {
394         DWARFYAML::File TmpFile;
395         if (dumpFileEntry(LineData, Offset, TmpFile))
396           DebugLines.Files.push_back(TmpFile);
397         else
398           break;
399       }
400 
401       const uint64_t LineEnd =
402           LineTableLength + *StmtOffset + SizeOfPrologueLength;
403       while (Offset < LineEnd) {
404         DWARFYAML::LineTableOpcode NewOp = {};
405         NewOp.Opcode = (dwarf::LineNumberOps)LineData.getU8(&Offset);
406         if (NewOp.Opcode == 0) {
407           auto StartExt = Offset;
408           NewOp.ExtLen = LineData.getULEB128(&Offset);
409           NewOp.SubOpcode =
410               (dwarf::LineNumberExtendedOps)LineData.getU8(&Offset);
411           switch (NewOp.SubOpcode) {
412           case dwarf::DW_LNE_set_address:
413           case dwarf::DW_LNE_set_discriminator:
414             NewOp.Data = LineData.getAddress(&Offset);
415             break;
416           case dwarf::DW_LNE_define_file:
417             dumpFileEntry(LineData, Offset, NewOp.FileEntry);
418             break;
419           case dwarf::DW_LNE_end_sequence:
420             break;
421           default:
422             while (Offset < StartExt + *NewOp.ExtLen)
423               NewOp.UnknownOpcodeData.push_back(LineData.getU8(&Offset));
424           }
425         } else if (NewOp.Opcode < *DebugLines.OpcodeBase) {
426           switch (NewOp.Opcode) {
427           case dwarf::DW_LNS_copy:
428           case dwarf::DW_LNS_negate_stmt:
429           case dwarf::DW_LNS_set_basic_block:
430           case dwarf::DW_LNS_const_add_pc:
431           case dwarf::DW_LNS_set_prologue_end:
432           case dwarf::DW_LNS_set_epilogue_begin:
433             break;
434 
435           case dwarf::DW_LNS_advance_pc:
436           case dwarf::DW_LNS_set_file:
437           case dwarf::DW_LNS_set_column:
438           case dwarf::DW_LNS_set_isa:
439             NewOp.Data = LineData.getULEB128(&Offset);
440             break;
441 
442           case dwarf::DW_LNS_advance_line:
443             NewOp.SData = LineData.getSLEB128(&Offset);
444             break;
445 
446           case dwarf::DW_LNS_fixed_advance_pc:
447             NewOp.Data = LineData.getU16(&Offset);
448             break;
449 
450           default:
451             for (uint8_t i = 0;
452                  i <
453                  DebugLines.StandardOpcodeLengths.getValue()[NewOp.Opcode - 1];
454                  ++i)
455               NewOp.StandardOpcodeData.push_back(LineData.getULEB128(&Offset));
456           }
457         }
458         DebugLines.Opcodes.push_back(NewOp);
459       }
460       Y.DebugLines.push_back(DebugLines);
461     }
462   }
463 }
464