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