[sanitizer] Improve FreeBSD ASLR detection
[llvm-project.git] / llvm / tools / obj2yaml / dwarf2yaml.cpp
blob8cae1f3c49077df1952c45a4e969ce749ea90a02
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 //===----------------------------------------------------------------------===//
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"
19 #include <algorithm>
21 using namespace llvm;
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);
44 Y.DebugAbbrev.back().Table.push_back(Abbrv);
50 Error dumpDebugAddr(DWARFContext &DCtx, DWARFYAML::Data &Y) {
51 DWARFDebugAddrTable AddrTable;
52 DWARFDataExtractor AddrData(DCtx.getDWARFObj(),
53 DCtx.getDWARFObj().getAddrSection(),
54 DCtx.isLittleEndian(), /*AddressSize=*/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});
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();
78 Y.DebugAddr = std::move(AddrTables);
79 return Error::success();
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);
94 Y.DebugStrings = DebugStr;
95 return Err;
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;
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)); };
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);
126 DebugAranges.push_back(Range);
129 Y.DebugAranges = DebugAranges;
130 return ErrorSuccess();
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");
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;
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));
163 Y.DebugRanges = DebugRanges;
164 return ErrorSuccess();
167 static Optional<DWARFYAML::PubSection>
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;
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;
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});
193 return Y;
196 void dumpDebugPubSections(DWARFContext &DCtx, DWARFYAML::Data &Y) {
197 const DWARFObject &D = DCtx.getDWARFObj();
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);
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();
234 assert(EntryData.isValidOffset(offset) && "Invalid DIE Offset");
235 if (!EntryData.isValidOffset(offset))
236 continue;
238 NewEntry.AbbrCode = EntryData.getULEB128(&offset);
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));
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 = dwarf::toString(FormValue))
295 NewValue.CStr = *Val;
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());
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;
322 } while (indirect);
323 NewEntry.Values.push_back(NewValue);
327 NewUnit.Entries.push_back(NewEntry);
329 Y.CompileUnits.push_back(NewUnit);
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;
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;
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;
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);
381 DebugLines.StandardOpcodeLengths.emplace();
382 for (uint8_t i = 1; i < DebugLines.OpcodeBase; ++i)
383 DebugLines.StandardOpcodeLengths->push_back(LineData.getU8(&Offset));
385 while (Offset < EndPrologue) {
386 StringRef Dir = LineData.getCStr(&Offset);
387 if (!Dir.empty())
388 DebugLines.IncludeDirs.push_back(Dir);
389 else
390 break;
393 while (Offset < EndPrologue) {
394 DWARFYAML::File TmpFile;
395 if (dumpFileEntry(LineData, Offset, TmpFile))
396 DebugLines.Files.push_back(TmpFile);
397 else
398 break;
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));
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;
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;
442 case dwarf::DW_LNS_advance_line:
443 NewOp.SData = LineData.getSLEB128(&Offset);
444 break;
446 case dwarf::DW_LNS_fixed_advance_pc:
447 NewOp.Data = LineData.getU16(&Offset);
448 break;
450 default:
451 for (uint8_t i = 0;
453 DebugLines.StandardOpcodeLengths.getValue()[NewOp.Opcode - 1];
454 ++i)
455 NewOp.StandardOpcodeData.push_back(LineData.getULEB128(&Offset));
458 DebugLines.Opcodes.push_back(NewOp);
460 Y.DebugLines.push_back(DebugLines);