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