121
|
1 //===------ dwarf2yaml.cpp - obj2yaml conversion tool -----------*- C++ -*-===//
|
|
2 //
|
147
|
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
|
121
|
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
|
147
|
19 void dumpInitialLength(DataExtractor &Data, uint64_t &Offset,
|
121
|
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) {
|
147
|
51 StringRef RemainingTable = DCtx.getDWARFObj().getStrSection();
|
121
|
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) {
|
147
|
60 DataExtractor ArangesData(DCtx.getDWARFObj().getArangesSection(),
|
121
|
61 DCtx.isLittleEndian(), 0);
|
147
|
62 uint64_t Offset = 0;
|
121
|
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,
|
147
|
83 DWARFSection Section) {
|
|
84 DWARFDataExtractor PubSectionData(DCtx.getDWARFObj(), Section,
|
|
85 DCtx.isLittleEndian(), 0);
|
|
86 uint64_t Offset = 0;
|
121
|
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;
|
147
|
104 dumpPubSection(DCtx, Y.PubNames, D.getPubnamesSection());
|
121
|
105
|
|
106 Y.PubTypes.IsGNUStyle = false;
|
147
|
107 dumpPubSection(DCtx, Y.PubTypes, D.getPubtypesSection());
|
121
|
108
|
|
109 Y.GNUPubNames.IsGNUStyle = true;
|
147
|
110 dumpPubSection(DCtx, Y.GNUPubNames, D.getGnuPubnamesSection());
|
121
|
111
|
|
112 Y.GNUPubTypes.IsGNUStyle = true;
|
147
|
113 dumpPubSection(DCtx, Y.GNUPubTypes, D.getGnuPubtypesSection());
|
121
|
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();
|
147
|
128 uint64_t offset = DIE.getOffset();
|
121
|
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
|
147
|
229 bool dumpFileEntry(DataExtractor &Data, uint64_t &Offset,
|
121
|
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());
|
147
|
250 uint64_t Offset = *StmtOffset;
|
121
|
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 }
|