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