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