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