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