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