| 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 "llvm/BinaryFormat/Dwarf.h" |
| 10 | #include "llvm/DebugInfo/DWARF/DWARFContext.h" |
| 11 | #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" |
| 12 | #include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h" |
| 13 | #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" |
| 14 | #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" |
| 15 | #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" |
| 16 | #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" |
| 17 | #include "llvm/DebugInfo/DWARF/DWARFSection.h" |
| 18 | #include "llvm/ObjectYAML/DWARFYAML.h" |
| 19 | |
| 20 | #include <algorithm> |
| 21 | #include <optional> |
| 22 | |
| 23 | using namespace llvm; |
| 24 | |
| 25 | Error dumpDebugAbbrev(DWARFContext &DCtx, DWARFYAML::Data &Y) { |
| 26 | auto AbbrevSetPtr = DCtx.getDebugAbbrev(); |
| 27 | if (AbbrevSetPtr) { |
| 28 | uint64_t AbbrevTableID = 0; |
| 29 | if (Error Err = AbbrevSetPtr->parse()) |
| 30 | return Err; |
| 31 | for (const auto &AbbrvDeclSet : *AbbrevSetPtr) { |
| 32 | Y.DebugAbbrev.emplace_back(); |
| 33 | Y.DebugAbbrev.back().ID = AbbrevTableID++; |
| 34 | for (const DWARFAbbreviationDeclaration &AbbrvDecl : |
| 35 | AbbrvDeclSet.second) { |
| 36 | DWARFYAML::Abbrev Abbrv; |
| 37 | Abbrv.Code = AbbrvDecl.getCode(); |
| 38 | Abbrv.Tag = AbbrvDecl.getTag(); |
| 39 | Abbrv.Children = AbbrvDecl.hasChildren() ? dwarf::DW_CHILDREN_yes |
| 40 | : dwarf::DW_CHILDREN_no; |
| 41 | for (auto Attribute : AbbrvDecl.attributes()) { |
| 42 | DWARFYAML::AttributeAbbrev AttAbrv; |
| 43 | AttAbrv.Attribute = Attribute.Attr; |
| 44 | AttAbrv.Form = Attribute.Form; |
| 45 | if (AttAbrv.Form == dwarf::DW_FORM_implicit_const) |
| 46 | AttAbrv.Value = Attribute.getImplicitConstValue(); |
| 47 | Abbrv.Attributes.push_back(x: AttAbrv); |
| 48 | } |
| 49 | Y.DebugAbbrev.back().Table.push_back(x: Abbrv); |
| 50 | } |
| 51 | } |
| 52 | } |
| 53 | return Error::success(); |
| 54 | } |
| 55 | |
| 56 | Error dumpDebugAddr(DWARFContext &DCtx, DWARFYAML::Data &Y) { |
| 57 | DWARFDebugAddrTable AddrTable; |
| 58 | DWARFDataExtractor AddrData(DCtx.getDWARFObj(), |
| 59 | DCtx.getDWARFObj().getAddrSection(), |
| 60 | DCtx.isLittleEndian(), /*AddressSize=*/0); |
| 61 | std::vector<DWARFYAML::AddrTableEntry> AddrTables; |
| 62 | uint64_t Offset = 0; |
| 63 | while (AddrData.isValidOffset(offset: Offset)) { |
| 64 | // We ignore any errors that don't prevent parsing the section, since we can |
| 65 | // still represent such sections. |
| 66 | if (Error Err = AddrTable.extractV5(Data: AddrData, OffsetPtr: &Offset, /*CUAddrSize=*/0, |
| 67 | WarnCallback: consumeError)) |
| 68 | return Err; |
| 69 | AddrTables.emplace_back(); |
| 70 | for (uint64_t Addr : AddrTable.getAddressEntries()) { |
| 71 | // Currently, the parser doesn't support parsing an address table with non |
| 72 | // linear addresses (segment_selector_size != 0). The segment selectors |
| 73 | // are specified to be zero. |
| 74 | AddrTables.back().SegAddrPairs.push_back( |
| 75 | x: {/*SegmentSelector=*/.Segment: 0, /*Address=*/Addr}); |
| 76 | } |
| 77 | |
| 78 | AddrTables.back().Format = AddrTable.getFormat(); |
| 79 | AddrTables.back().Length = AddrTable.getLength(); |
| 80 | AddrTables.back().Version = AddrTable.getVersion(); |
| 81 | AddrTables.back().AddrSize = AddrTable.getAddressSize(); |
| 82 | AddrTables.back().SegSelectorSize = AddrTable.getSegmentSelectorSize(); |
| 83 | } |
| 84 | Y.DebugAddr = std::move(AddrTables); |
| 85 | return Error::success(); |
| 86 | } |
| 87 | |
| 88 | Error dumpDebugStrings(DWARFContext &DCtx, DWARFYAML::Data &Y) { |
| 89 | DataExtractor StrData = DCtx.getStringExtractor(); |
| 90 | uint64_t Offset = 0; |
| 91 | std::vector<StringRef> DebugStr; |
| 92 | Error Err = Error::success(); |
| 93 | while (StrData.isValidOffset(offset: Offset)) { |
| 94 | const char *CStr = StrData.getCStr(OffsetPtr: &Offset, Err: &Err); |
| 95 | if (Err) |
| 96 | return Err; |
| 97 | DebugStr.push_back(x: CStr); |
| 98 | } |
| 99 | |
| 100 | Y.DebugStrings = DebugStr; |
| 101 | return Err; |
| 102 | } |
| 103 | |
| 104 | Error dumpDebugARanges(DWARFContext &DCtx, DWARFYAML::Data &Y) { |
| 105 | DWARFDataExtractor ArangesData(DCtx.getDWARFObj().getArangesSection(), |
| 106 | DCtx.isLittleEndian(), 0); |
| 107 | uint64_t Offset = 0; |
| 108 | DWARFDebugArangeSet Set; |
| 109 | std::vector<DWARFYAML::ARange> DebugAranges; |
| 110 | |
| 111 | // We ignore any errors that don't prevent parsing the section, since we can |
| 112 | // still represent such sections. These errors are recorded via the |
| 113 | // WarningHandler parameter of Set.extract(). |
| 114 | auto DiscardError = [](Error Err) { consumeError(Err: std::move(Err)); }; |
| 115 | |
| 116 | while (ArangesData.isValidOffset(offset: Offset)) { |
| 117 | if (Error E = Set.extract(data: ArangesData, offset_ptr: &Offset, WarningHandler: DiscardError)) |
| 118 | return E; |
| 119 | DWARFYAML::ARange Range; |
| 120 | Range.Format = Set.getHeader().Format; |
| 121 | Range.Length = Set.getHeader().Length; |
| 122 | Range.Version = Set.getHeader().Version; |
| 123 | Range.CuOffset = Set.getHeader().CuOffset; |
| 124 | Range.AddrSize = Set.getHeader().AddrSize; |
| 125 | Range.SegSize = Set.getHeader().SegSize; |
| 126 | for (auto Descriptor : Set.descriptors()) { |
| 127 | DWARFYAML::ARangeDescriptor Desc; |
| 128 | Desc.Address = Descriptor.Address; |
| 129 | Desc.Length = Descriptor.Length; |
| 130 | Range.Descriptors.push_back(x: Desc); |
| 131 | } |
| 132 | DebugAranges.push_back(x: Range); |
| 133 | } |
| 134 | |
| 135 | Y.DebugAranges = DebugAranges; |
| 136 | return ErrorSuccess(); |
| 137 | } |
| 138 | |
| 139 | Error dumpDebugRanges(DWARFContext &DCtx, DWARFYAML::Data &Y) { |
| 140 | // We are assuming all address byte sizes will be consistent across all |
| 141 | // compile units. |
| 142 | uint8_t AddrSize = 0; |
| 143 | for (const auto &CU : DCtx.compile_units()) { |
| 144 | const uint8_t CUAddrSize = CU->getAddressByteSize(); |
| 145 | if (AddrSize == 0) |
| 146 | AddrSize = CUAddrSize; |
| 147 | else if (CUAddrSize != AddrSize) |
| 148 | return createStringError(EC: std::errc::invalid_argument, |
| 149 | Fmt: "address sizes vary in different compile units" ); |
| 150 | } |
| 151 | |
| 152 | DWARFDataExtractor Data(DCtx.getDWARFObj().getRangesSection().Data, |
| 153 | DCtx.isLittleEndian(), AddrSize); |
| 154 | uint64_t Offset = 0; |
| 155 | DWARFDebugRangeList DwarfRanges; |
| 156 | std::vector<DWARFYAML::Ranges> DebugRanges; |
| 157 | |
| 158 | while (Data.isValidOffset(offset: Offset)) { |
| 159 | DWARFYAML::Ranges YamlRanges; |
| 160 | YamlRanges.Offset = Offset; |
| 161 | YamlRanges.AddrSize = AddrSize; |
| 162 | if (Error E = DwarfRanges.extract(data: Data, offset_ptr: &Offset)) |
| 163 | return E; |
| 164 | for (const auto &RLE : DwarfRanges.getEntries()) |
| 165 | YamlRanges.Entries.push_back(x: {.LowOffset: RLE.StartAddress, .HighOffset: RLE.EndAddress}); |
| 166 | DebugRanges.push_back(x: std::move(YamlRanges)); |
| 167 | } |
| 168 | |
| 169 | Y.DebugRanges = DebugRanges; |
| 170 | return ErrorSuccess(); |
| 171 | } |
| 172 | |
| 173 | static std::optional<DWARFYAML::PubSection> |
| 174 | dumpPubSection(const DWARFContext &DCtx, const DWARFSection &Section, |
| 175 | bool IsGNUStyle) { |
| 176 | DWARFYAML::PubSection Y; |
| 177 | DWARFDataExtractor PubSectionData(DCtx.getDWARFObj(), Section, |
| 178 | DCtx.isLittleEndian(), 0); |
| 179 | DWARFDebugPubTable Table; |
| 180 | // We ignore any errors that don't prevent parsing the section, since we can |
| 181 | // still represent such sections. |
| 182 | Table.extract(Data: PubSectionData, GnuStyle: IsGNUStyle, |
| 183 | RecoverableErrorHandler: [](Error Err) { consumeError(Err: std::move(Err)); }); |
| 184 | ArrayRef<DWARFDebugPubTable::Set> Sets = Table.getData(); |
| 185 | if (Sets.empty()) |
| 186 | return std::nullopt; |
| 187 | |
| 188 | // FIXME: Currently, obj2yaml only supports dumping the first pubtable. |
| 189 | Y.Format = Sets[0].Format; |
| 190 | Y.Length = Sets[0].Length; |
| 191 | Y.Version = Sets[0].Version; |
| 192 | Y.UnitOffset = Sets[0].Offset; |
| 193 | Y.UnitSize = Sets[0].Size; |
| 194 | |
| 195 | for (const DWARFDebugPubTable::Entry &E : Sets[0].Entries) |
| 196 | Y.Entries.push_back(x: DWARFYAML::PubEntry{.DieOffset: (uint32_t)E.SecOffset, |
| 197 | .Descriptor: E.Descriptor.toBits(), .Name: E.Name}); |
| 198 | |
| 199 | return Y; |
| 200 | } |
| 201 | |
| 202 | void dumpDebugPubSections(DWARFContext &DCtx, DWARFYAML::Data &Y) { |
| 203 | const DWARFObject &D = DCtx.getDWARFObj(); |
| 204 | |
| 205 | Y.PubNames = |
| 206 | dumpPubSection(DCtx, Section: D.getPubnamesSection(), /*IsGNUStyle=*/false); |
| 207 | Y.PubTypes = |
| 208 | dumpPubSection(DCtx, Section: D.getPubtypesSection(), /*IsGNUStyle=*/false); |
| 209 | // TODO: Test dumping .debug_gnu_pubnames section. |
| 210 | Y.GNUPubNames = |
| 211 | dumpPubSection(DCtx, Section: D.getGnuPubnamesSection(), /*IsGNUStyle=*/true); |
| 212 | // TODO: Test dumping .debug_gnu_pubtypes section. |
| 213 | Y.GNUPubTypes = |
| 214 | dumpPubSection(DCtx, Section: D.getGnuPubtypesSection(), /*IsGNUStyle=*/true); |
| 215 | } |
| 216 | |
| 217 | void dumpDebugInfo(DWARFContext &DCtx, DWARFYAML::Data &Y) { |
| 218 | for (const auto &CU : DCtx.compile_units()) { |
| 219 | DWARFYAML::Unit NewUnit; |
| 220 | NewUnit.Format = CU->getFormat(); |
| 221 | NewUnit.Length = CU->getLength(); |
| 222 | NewUnit.Version = CU->getVersion(); |
| 223 | if (NewUnit.Version >= 5) |
| 224 | NewUnit.Type = (dwarf::UnitType)CU->getUnitType(); |
| 225 | const DWARFDebugAbbrev *DebugAbbrev = DCtx.getDebugAbbrev(); |
| 226 | // FIXME: Ideally we would propagate this error upwards, but that would |
| 227 | // prevent us from displaying any debug info at all. For now we just consume |
| 228 | // the error and display everything that was parsed successfully. |
| 229 | if (Error Err = DebugAbbrev->parse()) |
| 230 | llvm::consumeError(Err: std::move(Err)); |
| 231 | |
| 232 | NewUnit.AbbrevTableID = std::distance( |
| 233 | first: DebugAbbrev->begin(), |
| 234 | last: llvm::find_if( |
| 235 | Range: *DebugAbbrev, |
| 236 | P: [&](const std::pair<uint64_t, DWARFAbbreviationDeclarationSet> &P) { |
| 237 | return P.first == CU->getAbbreviations()->getOffset(); |
| 238 | })); |
| 239 | NewUnit.AbbrOffset = CU->getAbbreviations()->getOffset(); |
| 240 | NewUnit.AddrSize = CU->getAddressByteSize(); |
| 241 | for (auto DIE : CU->dies()) { |
| 242 | DWARFYAML::Entry NewEntry; |
| 243 | DataExtractor EntryData = CU->getDebugInfoExtractor(); |
| 244 | uint64_t offset = DIE.getOffset(); |
| 245 | |
| 246 | assert(EntryData.isValidOffset(offset) && "Invalid DIE Offset" ); |
| 247 | if (!EntryData.isValidOffset(offset)) |
| 248 | continue; |
| 249 | |
| 250 | NewEntry.AbbrCode = EntryData.getULEB128(offset_ptr: &offset); |
| 251 | |
| 252 | auto AbbrevDecl = DIE.getAbbreviationDeclarationPtr(); |
| 253 | if (AbbrevDecl) { |
| 254 | for (const auto &AttrSpec : AbbrevDecl->attributes()) { |
| 255 | DWARFYAML::FormValue NewValue; |
| 256 | NewValue.Value = 0xDEADBEEFDEADBEEF; |
| 257 | DWARFDie DIEWrapper(CU.get(), &DIE); |
| 258 | auto FormValue = DIEWrapper.find(Attr: AttrSpec.Attr); |
| 259 | if (!FormValue) |
| 260 | return; |
| 261 | auto Form = FormValue->getForm(); |
| 262 | bool indirect = false; |
| 263 | do { |
| 264 | indirect = false; |
| 265 | switch (Form) { |
| 266 | case dwarf::DW_FORM_addr: |
| 267 | case dwarf::DW_FORM_GNU_addr_index: |
| 268 | if (auto Val = FormValue->getAsAddress()) |
| 269 | NewValue.Value = *Val; |
| 270 | break; |
| 271 | case dwarf::DW_FORM_ref_addr: |
| 272 | case dwarf::DW_FORM_ref1: |
| 273 | case dwarf::DW_FORM_ref2: |
| 274 | case dwarf::DW_FORM_ref4: |
| 275 | case dwarf::DW_FORM_ref8: |
| 276 | case dwarf::DW_FORM_ref_udata: |
| 277 | case dwarf::DW_FORM_ref_sig8: |
| 278 | if (auto Val = FormValue->getAsReferenceUVal()) |
| 279 | NewValue.Value = *Val; |
| 280 | break; |
| 281 | case dwarf::DW_FORM_exprloc: |
| 282 | case dwarf::DW_FORM_block: |
| 283 | case dwarf::DW_FORM_block1: |
| 284 | case dwarf::DW_FORM_block2: |
| 285 | case dwarf::DW_FORM_block4: |
| 286 | if (auto Val = FormValue->getAsBlock()) { |
| 287 | auto BlockData = *Val; |
| 288 | std::copy(first: BlockData.begin(), last: BlockData.end(), |
| 289 | result: std::back_inserter(x&: NewValue.BlockData)); |
| 290 | } |
| 291 | NewValue.Value = NewValue.BlockData.size(); |
| 292 | break; |
| 293 | case dwarf::DW_FORM_data1: |
| 294 | case dwarf::DW_FORM_flag: |
| 295 | case dwarf::DW_FORM_data2: |
| 296 | case dwarf::DW_FORM_data4: |
| 297 | case dwarf::DW_FORM_data8: |
| 298 | case dwarf::DW_FORM_sdata: |
| 299 | case dwarf::DW_FORM_udata: |
| 300 | case dwarf::DW_FORM_ref_sup4: |
| 301 | case dwarf::DW_FORM_ref_sup8: |
| 302 | if (auto Val = FormValue->getAsUnsignedConstant()) |
| 303 | NewValue.Value = *Val; |
| 304 | break; |
| 305 | case dwarf::DW_FORM_string: |
| 306 | if (auto Val = dwarf::toString(V: FormValue)) |
| 307 | NewValue.CStr = *Val; |
| 308 | break; |
| 309 | case dwarf::DW_FORM_indirect: |
| 310 | indirect = true; |
| 311 | if (auto Val = FormValue->getAsUnsignedConstant()) { |
| 312 | NewValue.Value = *Val; |
| 313 | NewEntry.Values.push_back(x: NewValue); |
| 314 | Form = static_cast<dwarf::Form>(*Val); |
| 315 | } |
| 316 | break; |
| 317 | case dwarf::DW_FORM_strp: |
| 318 | case dwarf::DW_FORM_sec_offset: |
| 319 | case dwarf::DW_FORM_GNU_ref_alt: |
| 320 | case dwarf::DW_FORM_GNU_strp_alt: |
| 321 | case dwarf::DW_FORM_line_strp: |
| 322 | case dwarf::DW_FORM_strp_sup: |
| 323 | case dwarf::DW_FORM_GNU_str_index: |
| 324 | case dwarf::DW_FORM_strx: |
| 325 | if (auto Val = FormValue->getAsCStringOffset()) |
| 326 | NewValue.Value = *Val; |
| 327 | break; |
| 328 | case dwarf::DW_FORM_flag_present: |
| 329 | NewValue.Value = 1; |
| 330 | break; |
| 331 | default: |
| 332 | break; |
| 333 | } |
| 334 | } while (indirect); |
| 335 | NewEntry.Values.push_back(x: NewValue); |
| 336 | } |
| 337 | } |
| 338 | |
| 339 | NewUnit.Entries.push_back(x: NewEntry); |
| 340 | } |
| 341 | Y.Units.push_back(x: NewUnit); |
| 342 | } |
| 343 | } |
| 344 | |
| 345 | bool (DataExtractor &Data, uint64_t &Offset, |
| 346 | DWARFYAML::File &File) { |
| 347 | File.Name = Data.getCStr(OffsetPtr: &Offset); |
| 348 | if (File.Name.empty()) |
| 349 | return false; |
| 350 | File.DirIdx = Data.getULEB128(offset_ptr: &Offset); |
| 351 | File.ModTime = Data.getULEB128(offset_ptr: &Offset); |
| 352 | File.Length = Data.getULEB128(offset_ptr: &Offset); |
| 353 | return true; |
| 354 | } |
| 355 | |
| 356 | void dumpDebugLines(DWARFContext &DCtx, DWARFYAML::Data &Y) { |
| 357 | for (const auto &CU : DCtx.compile_units()) { |
| 358 | auto CUDIE = CU->getUnitDIE(); |
| 359 | if (!CUDIE) |
| 360 | continue; |
| 361 | if (auto StmtOffset = |
| 362 | dwarf::toSectionOffset(V: CUDIE.find(Attr: dwarf::DW_AT_stmt_list))) { |
| 363 | DWARFYAML::LineTable DebugLines; |
| 364 | DataExtractor LineData(DCtx.getDWARFObj().getLineSection().Data, |
| 365 | DCtx.isLittleEndian(), CU->getAddressByteSize()); |
| 366 | uint64_t Offset = *StmtOffset; |
| 367 | uint64_t LengthOrDWARF64Prefix = LineData.getU32(offset_ptr: &Offset); |
| 368 | if (LengthOrDWARF64Prefix == dwarf::DW_LENGTH_DWARF64) { |
| 369 | DebugLines.Format = dwarf::DWARF64; |
| 370 | DebugLines.Length = LineData.getU64(offset_ptr: &Offset); |
| 371 | } else { |
| 372 | DebugLines.Format = dwarf::DWARF32; |
| 373 | DebugLines.Length = LengthOrDWARF64Prefix; |
| 374 | } |
| 375 | assert(DebugLines.Length); |
| 376 | uint64_t LineTableLength = *DebugLines.Length; |
| 377 | uint64_t SizeOfPrologueLength = |
| 378 | DebugLines.Format == dwarf::DWARF64 ? 8 : 4; |
| 379 | DebugLines.Version = LineData.getU16(offset_ptr: &Offset); |
| 380 | DebugLines.PrologueLength = |
| 381 | LineData.getUnsigned(offset_ptr: &Offset, byte_size: SizeOfPrologueLength); |
| 382 | assert(DebugLines.PrologueLength); |
| 383 | const uint64_t EndPrologue = *DebugLines.PrologueLength + Offset; |
| 384 | |
| 385 | DebugLines.MinInstLength = LineData.getU8(offset_ptr: &Offset); |
| 386 | if (DebugLines.Version >= 4) |
| 387 | DebugLines.MaxOpsPerInst = LineData.getU8(offset_ptr: &Offset); |
| 388 | DebugLines.DefaultIsStmt = LineData.getU8(offset_ptr: &Offset); |
| 389 | DebugLines.LineBase = LineData.getU8(offset_ptr: &Offset); |
| 390 | DebugLines.LineRange = LineData.getU8(offset_ptr: &Offset); |
| 391 | DebugLines.OpcodeBase = LineData.getU8(offset_ptr: &Offset); |
| 392 | |
| 393 | DebugLines.StandardOpcodeLengths.emplace(); |
| 394 | for (uint8_t i = 1; i < DebugLines.OpcodeBase; ++i) |
| 395 | DebugLines.StandardOpcodeLengths->push_back(x: LineData.getU8(offset_ptr: &Offset)); |
| 396 | |
| 397 | while (Offset < EndPrologue) { |
| 398 | StringRef Dir = LineData.getCStr(OffsetPtr: &Offset); |
| 399 | if (!Dir.empty()) |
| 400 | DebugLines.IncludeDirs.push_back(x: Dir); |
| 401 | else |
| 402 | break; |
| 403 | } |
| 404 | |
| 405 | while (Offset < EndPrologue) { |
| 406 | DWARFYAML::File TmpFile; |
| 407 | if (dumpFileEntry(Data&: LineData, Offset, File&: TmpFile)) |
| 408 | DebugLines.Files.push_back(x: TmpFile); |
| 409 | else |
| 410 | break; |
| 411 | } |
| 412 | |
| 413 | const uint64_t LineEnd = |
| 414 | LineTableLength + *StmtOffset + SizeOfPrologueLength; |
| 415 | while (Offset < LineEnd) { |
| 416 | DWARFYAML::LineTableOpcode NewOp = {}; |
| 417 | NewOp.Opcode = (dwarf::LineNumberOps)LineData.getU8(offset_ptr: &Offset); |
| 418 | if (NewOp.Opcode == 0) { |
| 419 | auto StartExt = Offset; |
| 420 | NewOp.ExtLen = LineData.getULEB128(offset_ptr: &Offset); |
| 421 | NewOp.SubOpcode = |
| 422 | (dwarf::LineNumberExtendedOps)LineData.getU8(offset_ptr: &Offset); |
| 423 | switch (NewOp.SubOpcode) { |
| 424 | case dwarf::DW_LNE_set_address: |
| 425 | case dwarf::DW_LNE_set_discriminator: |
| 426 | NewOp.Data = LineData.getAddress(offset_ptr: &Offset); |
| 427 | break; |
| 428 | case dwarf::DW_LNE_define_file: |
| 429 | dumpFileEntry(Data&: LineData, Offset, File&: NewOp.FileEntry); |
| 430 | break; |
| 431 | case dwarf::DW_LNE_end_sequence: |
| 432 | break; |
| 433 | default: |
| 434 | while (Offset < StartExt + *NewOp.ExtLen) |
| 435 | NewOp.UnknownOpcodeData.push_back(x: LineData.getU8(offset_ptr: &Offset)); |
| 436 | } |
| 437 | } else if (NewOp.Opcode < *DebugLines.OpcodeBase) { |
| 438 | switch (NewOp.Opcode) { |
| 439 | case dwarf::DW_LNS_copy: |
| 440 | case dwarf::DW_LNS_negate_stmt: |
| 441 | case dwarf::DW_LNS_set_basic_block: |
| 442 | case dwarf::DW_LNS_const_add_pc: |
| 443 | case dwarf::DW_LNS_set_prologue_end: |
| 444 | case dwarf::DW_LNS_set_epilogue_begin: |
| 445 | break; |
| 446 | |
| 447 | case dwarf::DW_LNS_advance_pc: |
| 448 | case dwarf::DW_LNS_set_file: |
| 449 | case dwarf::DW_LNS_set_column: |
| 450 | case dwarf::DW_LNS_set_isa: |
| 451 | NewOp.Data = LineData.getULEB128(offset_ptr: &Offset); |
| 452 | break; |
| 453 | |
| 454 | case dwarf::DW_LNS_advance_line: |
| 455 | NewOp.SData = LineData.getSLEB128(OffsetPtr: &Offset); |
| 456 | break; |
| 457 | |
| 458 | case dwarf::DW_LNS_fixed_advance_pc: |
| 459 | NewOp.Data = LineData.getU16(offset_ptr: &Offset); |
| 460 | break; |
| 461 | |
| 462 | default: |
| 463 | for (uint8_t i = 0; |
| 464 | i < (*DebugLines.StandardOpcodeLengths)[NewOp.Opcode - 1]; ++i) |
| 465 | NewOp.StandardOpcodeData.push_back(x: LineData.getULEB128(offset_ptr: &Offset)); |
| 466 | } |
| 467 | } |
| 468 | DebugLines.Opcodes.push_back(x: NewOp); |
| 469 | } |
| 470 | Y.DebugLines.push_back(x: DebugLines); |
| 471 | } |
| 472 | } |
| 473 | } |
| 474 | |