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 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 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 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 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 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> 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 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 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 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 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