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