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