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(IsGNUStyle); 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.Length.setLength(CU->getLength()); 169 NewUnit.Version = CU->getVersion(); 170 if(NewUnit.Version >= 5) 171 NewUnit.Type = (dwarf::UnitType)CU->getUnitType(); 172 NewUnit.AbbrOffset = CU->getAbbreviations()->getOffset(); 173 NewUnit.AddrSize = CU->getAddressByteSize(); 174 for (auto DIE : CU->dies()) { 175 DWARFYAML::Entry NewEntry; 176 DataExtractor EntryData = CU->getDebugInfoExtractor(); 177 uint64_t offset = DIE.getOffset(); 178 179 assert(EntryData.isValidOffset(offset) && "Invalid DIE Offset"); 180 if (!EntryData.isValidOffset(offset)) 181 continue; 182 183 NewEntry.AbbrCode = EntryData.getULEB128(&offset); 184 185 auto AbbrevDecl = DIE.getAbbreviationDeclarationPtr(); 186 if (AbbrevDecl) { 187 for (const auto &AttrSpec : AbbrevDecl->attributes()) { 188 DWARFYAML::FormValue NewValue; 189 NewValue.Value = 0xDEADBEEFDEADBEEF; 190 DWARFDie DIEWrapper(CU.get(), &DIE); 191 auto FormValue = DIEWrapper.find(AttrSpec.Attr); 192 if (!FormValue) 193 return; 194 auto Form = FormValue.getValue().getForm(); 195 bool indirect = false; 196 do { 197 indirect = false; 198 switch (Form) { 199 case dwarf::DW_FORM_addr: 200 case dwarf::DW_FORM_GNU_addr_index: 201 if (auto Val = FormValue.getValue().getAsAddress()) 202 NewValue.Value = Val.getValue(); 203 break; 204 case dwarf::DW_FORM_ref_addr: 205 case dwarf::DW_FORM_ref1: 206 case dwarf::DW_FORM_ref2: 207 case dwarf::DW_FORM_ref4: 208 case dwarf::DW_FORM_ref8: 209 case dwarf::DW_FORM_ref_udata: 210 case dwarf::DW_FORM_ref_sig8: 211 if (auto Val = FormValue.getValue().getAsReferenceUVal()) 212 NewValue.Value = Val.getValue(); 213 break; 214 case dwarf::DW_FORM_exprloc: 215 case dwarf::DW_FORM_block: 216 case dwarf::DW_FORM_block1: 217 case dwarf::DW_FORM_block2: 218 case dwarf::DW_FORM_block4: 219 if (auto Val = FormValue.getValue().getAsBlock()) { 220 auto BlockData = Val.getValue(); 221 std::copy(BlockData.begin(), BlockData.end(), 222 std::back_inserter(NewValue.BlockData)); 223 } 224 NewValue.Value = NewValue.BlockData.size(); 225 break; 226 case dwarf::DW_FORM_data1: 227 case dwarf::DW_FORM_flag: 228 case dwarf::DW_FORM_data2: 229 case dwarf::DW_FORM_data4: 230 case dwarf::DW_FORM_data8: 231 case dwarf::DW_FORM_sdata: 232 case dwarf::DW_FORM_udata: 233 case dwarf::DW_FORM_ref_sup4: 234 case dwarf::DW_FORM_ref_sup8: 235 if (auto Val = FormValue.getValue().getAsUnsignedConstant()) 236 NewValue.Value = Val.getValue(); 237 break; 238 case dwarf::DW_FORM_string: 239 if (auto Val = FormValue.getValue().getAsCString()) 240 NewValue.CStr = Val.getValue(); 241 break; 242 case dwarf::DW_FORM_indirect: 243 indirect = true; 244 if (auto Val = FormValue.getValue().getAsUnsignedConstant()) { 245 NewValue.Value = Val.getValue(); 246 NewEntry.Values.push_back(NewValue); 247 Form = static_cast<dwarf::Form>(Val.getValue()); 248 } 249 break; 250 case dwarf::DW_FORM_strp: 251 case dwarf::DW_FORM_sec_offset: 252 case dwarf::DW_FORM_GNU_ref_alt: 253 case dwarf::DW_FORM_GNU_strp_alt: 254 case dwarf::DW_FORM_line_strp: 255 case dwarf::DW_FORM_strp_sup: 256 case dwarf::DW_FORM_GNU_str_index: 257 case dwarf::DW_FORM_strx: 258 if (auto Val = FormValue.getValue().getAsCStringOffset()) 259 NewValue.Value = Val.getValue(); 260 break; 261 case dwarf::DW_FORM_flag_present: 262 NewValue.Value = 1; 263 break; 264 default: 265 break; 266 } 267 } while (indirect); 268 NewEntry.Values.push_back(NewValue); 269 } 270 } 271 272 NewUnit.Entries.push_back(NewEntry); 273 } 274 Y.CompileUnits.push_back(NewUnit); 275 } 276 } 277 278 bool dumpFileEntry(DataExtractor &Data, uint64_t &Offset, 279 DWARFYAML::File &File) { 280 File.Name = Data.getCStr(&Offset); 281 if (File.Name.empty()) 282 return false; 283 File.DirIdx = Data.getULEB128(&Offset); 284 File.ModTime = Data.getULEB128(&Offset); 285 File.Length = Data.getULEB128(&Offset); 286 return true; 287 } 288 289 void dumpDebugLines(DWARFContext &DCtx, DWARFYAML::Data &Y) { 290 for (const auto &CU : DCtx.compile_units()) { 291 auto CUDIE = CU->getUnitDIE(); 292 if (!CUDIE) 293 continue; 294 if (auto StmtOffset = 295 dwarf::toSectionOffset(CUDIE.find(dwarf::DW_AT_stmt_list))) { 296 DWARFYAML::LineTable DebugLines; 297 DataExtractor LineData(DCtx.getDWARFObj().getLineSection().Data, 298 DCtx.isLittleEndian(), CU->getAddressByteSize()); 299 uint64_t Offset = *StmtOffset; 300 uint64_t LengthOrDWARF64Prefix = LineData.getU32(&Offset); 301 if (LengthOrDWARF64Prefix == dwarf::DW_LENGTH_DWARF64) { 302 DebugLines.Format = dwarf::DWARF64; 303 DebugLines.Length = LineData.getU64(&Offset); 304 } else { 305 DebugLines.Format = dwarf::DWARF32; 306 DebugLines.Length = LengthOrDWARF64Prefix; 307 } 308 uint64_t LineTableLength = DebugLines.Length; 309 uint64_t SizeOfPrologueLength = 310 DebugLines.Format == dwarf::DWARF64 ? 8 : 4; 311 DebugLines.Version = LineData.getU16(&Offset); 312 DebugLines.PrologueLength = 313 LineData.getUnsigned(&Offset, SizeOfPrologueLength); 314 const uint64_t EndPrologue = DebugLines.PrologueLength + Offset; 315 316 DebugLines.MinInstLength = LineData.getU8(&Offset); 317 if (DebugLines.Version >= 4) 318 DebugLines.MaxOpsPerInst = LineData.getU8(&Offset); 319 DebugLines.DefaultIsStmt = LineData.getU8(&Offset); 320 DebugLines.LineBase = LineData.getU8(&Offset); 321 DebugLines.LineRange = LineData.getU8(&Offset); 322 DebugLines.OpcodeBase = LineData.getU8(&Offset); 323 324 DebugLines.StandardOpcodeLengths.reserve(DebugLines.OpcodeBase - 1); 325 for (uint8_t i = 1; i < DebugLines.OpcodeBase; ++i) 326 DebugLines.StandardOpcodeLengths.push_back(LineData.getU8(&Offset)); 327 328 while (Offset < EndPrologue) { 329 StringRef Dir = LineData.getCStr(&Offset); 330 if (!Dir.empty()) 331 DebugLines.IncludeDirs.push_back(Dir); 332 else 333 break; 334 } 335 336 while (Offset < EndPrologue) { 337 DWARFYAML::File TmpFile; 338 if (dumpFileEntry(LineData, Offset, TmpFile)) 339 DebugLines.Files.push_back(TmpFile); 340 else 341 break; 342 } 343 344 const uint64_t LineEnd = 345 LineTableLength + *StmtOffset + SizeOfPrologueLength; 346 while (Offset < LineEnd) { 347 DWARFYAML::LineTableOpcode NewOp = {}; 348 NewOp.Opcode = (dwarf::LineNumberOps)LineData.getU8(&Offset); 349 if (NewOp.Opcode == 0) { 350 auto StartExt = Offset; 351 NewOp.ExtLen = LineData.getULEB128(&Offset); 352 NewOp.SubOpcode = 353 (dwarf::LineNumberExtendedOps)LineData.getU8(&Offset); 354 switch (NewOp.SubOpcode) { 355 case dwarf::DW_LNE_set_address: 356 case dwarf::DW_LNE_set_discriminator: 357 NewOp.Data = LineData.getAddress(&Offset); 358 break; 359 case dwarf::DW_LNE_define_file: 360 dumpFileEntry(LineData, Offset, NewOp.FileEntry); 361 break; 362 case dwarf::DW_LNE_end_sequence: 363 break; 364 default: 365 while (Offset < StartExt + NewOp.ExtLen) 366 NewOp.UnknownOpcodeData.push_back(LineData.getU8(&Offset)); 367 } 368 } else if (NewOp.Opcode < DebugLines.OpcodeBase) { 369 switch (NewOp.Opcode) { 370 case dwarf::DW_LNS_copy: 371 case dwarf::DW_LNS_negate_stmt: 372 case dwarf::DW_LNS_set_basic_block: 373 case dwarf::DW_LNS_const_add_pc: 374 case dwarf::DW_LNS_set_prologue_end: 375 case dwarf::DW_LNS_set_epilogue_begin: 376 break; 377 378 case dwarf::DW_LNS_advance_pc: 379 case dwarf::DW_LNS_set_file: 380 case dwarf::DW_LNS_set_column: 381 case dwarf::DW_LNS_set_isa: 382 NewOp.Data = LineData.getULEB128(&Offset); 383 break; 384 385 case dwarf::DW_LNS_advance_line: 386 NewOp.SData = LineData.getSLEB128(&Offset); 387 break; 388 389 case dwarf::DW_LNS_fixed_advance_pc: 390 NewOp.Data = LineData.getU16(&Offset); 391 break; 392 393 default: 394 for (uint8_t i = 0; 395 i < DebugLines.StandardOpcodeLengths[NewOp.Opcode - 1]; ++i) 396 NewOp.StandardOpcodeData.push_back(LineData.getULEB128(&Offset)); 397 } 398 } 399 DebugLines.Opcodes.push_back(NewOp); 400 } 401 Y.DebugLines.push_back(DebugLines); 402 } 403 } 404 } 405 406 llvm::Error dwarf2yaml(DWARFContext &DCtx, DWARFYAML::Data &Y) { 407 dumpDebugAbbrev(DCtx, Y); 408 dumpDebugStrings(DCtx, Y); 409 if (Error E = dumpDebugARanges(DCtx, Y)) 410 return E; 411 if (Error E = dumpDebugRanges(DCtx, Y)) 412 return E; 413 dumpDebugPubSections(DCtx, Y); 414 dumpDebugInfo(DCtx, Y); 415 dumpDebugLines(DCtx, Y); 416 return ErrorSuccess(); 417 } 418