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