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