123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 |
- //===------ dwarf2yaml.cpp - obj2yaml conversion tool -----------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/BinaryFormat/Dwarf.h"
- #include "llvm/DebugInfo/DWARF/DWARFContext.h"
- #include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
- #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
- #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
- #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
- #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
- #include "llvm/DebugInfo/DWARF/DWARFSection.h"
- #include "llvm/ObjectYAML/DWARFYAML.h"
- #include <algorithm>
- using namespace llvm;
- void dumpDebugAbbrev(DWARFContext &DCtx, DWARFYAML::Data &Y) {
- auto AbbrevSetPtr = DCtx.getDebugAbbrev();
- if (AbbrevSetPtr) {
- uint64_t AbbrevTableID = 0;
- for (auto AbbrvDeclSet : *AbbrevSetPtr) {
- Y.DebugAbbrev.emplace_back();
- Y.DebugAbbrev.back().ID = AbbrevTableID++;
- for (auto AbbrvDecl : AbbrvDeclSet.second) {
- DWARFYAML::Abbrev Abbrv;
- Abbrv.Code = AbbrvDecl.getCode();
- Abbrv.Tag = AbbrvDecl.getTag();
- Abbrv.Children = AbbrvDecl.hasChildren() ? dwarf::DW_CHILDREN_yes
- : dwarf::DW_CHILDREN_no;
- for (auto Attribute : AbbrvDecl.attributes()) {
- DWARFYAML::AttributeAbbrev AttAbrv;
- AttAbrv.Attribute = Attribute.Attr;
- AttAbrv.Form = Attribute.Form;
- if (AttAbrv.Form == dwarf::DW_FORM_implicit_const)
- AttAbrv.Value = Attribute.getImplicitConstValue();
- Abbrv.Attributes.push_back(AttAbrv);
- }
- Y.DebugAbbrev.back().Table.push_back(Abbrv);
- }
- }
- }
- }
- Error dumpDebugAddr(DWARFContext &DCtx, DWARFYAML::Data &Y) {
- DWARFDebugAddrTable AddrTable;
- DWARFDataExtractor AddrData(DCtx.getDWARFObj(),
- DCtx.getDWARFObj().getAddrSection(),
- DCtx.isLittleEndian(), /*AddressSize=*/0);
- std::vector<DWARFYAML::AddrTableEntry> AddrTables;
- uint64_t Offset = 0;
- while (AddrData.isValidOffset(Offset)) {
- // We ignore any errors that don't prevent parsing the section, since we can
- // still represent such sections.
- if (Error Err = AddrTable.extractV5(AddrData, &Offset, /*CUAddrSize=*/0,
- consumeError))
- return Err;
- AddrTables.emplace_back();
- for (uint64_t Addr : AddrTable.getAddressEntries()) {
- // Currently, the parser doesn't support parsing an address table with non
- // linear addresses (segment_selector_size != 0). The segment selectors
- // are specified to be zero.
- AddrTables.back().SegAddrPairs.push_back(
- {/*SegmentSelector=*/0, /*Address=*/Addr});
- }
- AddrTables.back().Format = AddrTable.getFormat();
- AddrTables.back().Length = AddrTable.getLength();
- AddrTables.back().Version = AddrTable.getVersion();
- AddrTables.back().AddrSize = AddrTable.getAddressSize();
- AddrTables.back().SegSelectorSize = AddrTable.getSegmentSelectorSize();
- }
- Y.DebugAddr = std::move(AddrTables);
- return Error::success();
- }
- Error dumpDebugStrings(DWARFContext &DCtx, DWARFYAML::Data &Y) {
- DataExtractor StrData = DCtx.getStringExtractor();
- uint64_t Offset = 0;
- std::vector<StringRef> DebugStr;
- Error Err = Error::success();
- while (StrData.isValidOffset(Offset)) {
- const char *CStr = StrData.getCStr(&Offset, &Err);
- if (Err)
- return Err;
- DebugStr.push_back(CStr);
- }
- Y.DebugStrings = DebugStr;
- return Err;
- }
- Error dumpDebugARanges(DWARFContext &DCtx, DWARFYAML::Data &Y) {
- DWARFDataExtractor ArangesData(DCtx.getDWARFObj().getArangesSection(),
- DCtx.isLittleEndian(), 0);
- uint64_t Offset = 0;
- DWARFDebugArangeSet Set;
- std::vector<DWARFYAML::ARange> DebugAranges;
- // We ignore any errors that don't prevent parsing the section, since we can
- // still represent such sections. These errors are recorded via the
- // WarningHandler parameter of Set.extract().
- auto DiscardError = [](Error Err) { consumeError(std::move(Err)); };
- while (ArangesData.isValidOffset(Offset)) {
- if (Error E = Set.extract(ArangesData, &Offset, DiscardError))
- return E;
- DWARFYAML::ARange Range;
- Range.Format = Set.getHeader().Format;
- Range.Length = Set.getHeader().Length;
- Range.Version = Set.getHeader().Version;
- Range.CuOffset = Set.getHeader().CuOffset;
- Range.AddrSize = Set.getHeader().AddrSize;
- Range.SegSize = Set.getHeader().SegSize;
- for (auto Descriptor : Set.descriptors()) {
- DWARFYAML::ARangeDescriptor Desc;
- Desc.Address = Descriptor.Address;
- Desc.Length = Descriptor.Length;
- Range.Descriptors.push_back(Desc);
- }
- DebugAranges.push_back(Range);
- }
- Y.DebugAranges = DebugAranges;
- return ErrorSuccess();
- }
- Error dumpDebugRanges(DWARFContext &DCtx, DWARFYAML::Data &Y) {
- // We are assuming all address byte sizes will be consistent across all
- // compile units.
- uint8_t AddrSize = 0;
- for (const auto &CU : DCtx.compile_units()) {
- const uint8_t CUAddrSize = CU->getAddressByteSize();
- if (AddrSize == 0)
- AddrSize = CUAddrSize;
- else if (CUAddrSize != AddrSize)
- return createStringError(std::errc::invalid_argument,
- "address sizes vary in different compile units");
- }
- DWARFDataExtractor Data(DCtx.getDWARFObj().getRangesSection().Data,
- DCtx.isLittleEndian(), AddrSize);
- uint64_t Offset = 0;
- DWARFDebugRangeList DwarfRanges;
- std::vector<DWARFYAML::Ranges> DebugRanges;
- while (Data.isValidOffset(Offset)) {
- DWARFYAML::Ranges YamlRanges;
- YamlRanges.Offset = Offset;
- YamlRanges.AddrSize = AddrSize;
- if (Error E = DwarfRanges.extract(Data, &Offset))
- return E;
- for (const auto &RLE : DwarfRanges.getEntries())
- YamlRanges.Entries.push_back({RLE.StartAddress, RLE.EndAddress});
- DebugRanges.push_back(std::move(YamlRanges));
- }
- Y.DebugRanges = DebugRanges;
- return ErrorSuccess();
- }
- static Optional<DWARFYAML::PubSection>
- dumpPubSection(const DWARFContext &DCtx, const DWARFSection &Section,
- bool IsGNUStyle) {
- DWARFYAML::PubSection Y;
- DWARFDataExtractor PubSectionData(DCtx.getDWARFObj(), Section,
- DCtx.isLittleEndian(), 0);
- DWARFDebugPubTable Table;
- // We ignore any errors that don't prevent parsing the section, since we can
- // still represent such sections.
- Table.extract(PubSectionData, IsGNUStyle,
- [](Error Err) { consumeError(std::move(Err)); });
- ArrayRef<DWARFDebugPubTable::Set> Sets = Table.getData();
- if (Sets.empty())
- return None;
- // FIXME: Currently, obj2yaml only supports dumping the first pubtable.
- Y.Format = Sets[0].Format;
- Y.Length = Sets[0].Length;
- Y.Version = Sets[0].Version;
- Y.UnitOffset = Sets[0].Offset;
- Y.UnitSize = Sets[0].Size;
- for (const DWARFDebugPubTable::Entry &E : Sets[0].Entries)
- Y.Entries.push_back(DWARFYAML::PubEntry{(uint32_t)E.SecOffset,
- E.Descriptor.toBits(), E.Name});
- return Y;
- }
- void dumpDebugPubSections(DWARFContext &DCtx, DWARFYAML::Data &Y) {
- const DWARFObject &D = DCtx.getDWARFObj();
- Y.PubNames =
- dumpPubSection(DCtx, D.getPubnamesSection(), /*IsGNUStyle=*/false);
- Y.PubTypes =
- dumpPubSection(DCtx, D.getPubtypesSection(), /*IsGNUStyle=*/false);
- // TODO: Test dumping .debug_gnu_pubnames section.
- Y.GNUPubNames =
- dumpPubSection(DCtx, D.getGnuPubnamesSection(), /*IsGNUStyle=*/true);
- // TODO: Test dumping .debug_gnu_pubtypes section.
- Y.GNUPubTypes =
- dumpPubSection(DCtx, D.getGnuPubtypesSection(), /*IsGNUStyle=*/true);
- }
- void dumpDebugInfo(DWARFContext &DCtx, DWARFYAML::Data &Y) {
- for (const auto &CU : DCtx.compile_units()) {
- DWARFYAML::Unit NewUnit;
- NewUnit.Format = CU->getFormat();
- NewUnit.Length = CU->getLength();
- NewUnit.Version = CU->getVersion();
- if (NewUnit.Version >= 5)
- NewUnit.Type = (dwarf::UnitType)CU->getUnitType();
- const DWARFDebugAbbrev *DebugAbbrev = DCtx.getDebugAbbrev();
- NewUnit.AbbrevTableID = std::distance(
- DebugAbbrev->begin(),
- llvm::find_if(
- *DebugAbbrev,
- [&](const std::pair<uint64_t, DWARFAbbreviationDeclarationSet> &P) {
- return P.first == CU->getAbbreviations()->getOffset();
- }));
- NewUnit.AbbrOffset = CU->getAbbreviations()->getOffset();
- NewUnit.AddrSize = CU->getAddressByteSize();
- for (auto DIE : CU->dies()) {
- DWARFYAML::Entry NewEntry;
- DataExtractor EntryData = CU->getDebugInfoExtractor();
- uint64_t offset = DIE.getOffset();
- assert(EntryData.isValidOffset(offset) && "Invalid DIE Offset");
- if (!EntryData.isValidOffset(offset))
- continue;
- NewEntry.AbbrCode = EntryData.getULEB128(&offset);
- auto AbbrevDecl = DIE.getAbbreviationDeclarationPtr();
- if (AbbrevDecl) {
- for (const auto &AttrSpec : AbbrevDecl->attributes()) {
- DWARFYAML::FormValue NewValue;
- NewValue.Value = 0xDEADBEEFDEADBEEF;
- DWARFDie DIEWrapper(CU.get(), &DIE);
- auto FormValue = DIEWrapper.find(AttrSpec.Attr);
- if (!FormValue)
- return;
- auto Form = FormValue.getValue().getForm();
- bool indirect = false;
- do {
- indirect = false;
- switch (Form) {
- case dwarf::DW_FORM_addr:
- case dwarf::DW_FORM_GNU_addr_index:
- if (auto Val = FormValue.getValue().getAsAddress())
- NewValue.Value = Val.getValue();
- break;
- case dwarf::DW_FORM_ref_addr:
- case dwarf::DW_FORM_ref1:
- case dwarf::DW_FORM_ref2:
- case dwarf::DW_FORM_ref4:
- case dwarf::DW_FORM_ref8:
- case dwarf::DW_FORM_ref_udata:
- case dwarf::DW_FORM_ref_sig8:
- if (auto Val = FormValue.getValue().getAsReferenceUVal())
- NewValue.Value = Val.getValue();
- break;
- case dwarf::DW_FORM_exprloc:
- case dwarf::DW_FORM_block:
- case dwarf::DW_FORM_block1:
- case dwarf::DW_FORM_block2:
- case dwarf::DW_FORM_block4:
- if (auto Val = FormValue.getValue().getAsBlock()) {
- auto BlockData = Val.getValue();
- std::copy(BlockData.begin(), BlockData.end(),
- std::back_inserter(NewValue.BlockData));
- }
- NewValue.Value = NewValue.BlockData.size();
- break;
- case dwarf::DW_FORM_data1:
- case dwarf::DW_FORM_flag:
- case dwarf::DW_FORM_data2:
- case dwarf::DW_FORM_data4:
- case dwarf::DW_FORM_data8:
- case dwarf::DW_FORM_sdata:
- case dwarf::DW_FORM_udata:
- case dwarf::DW_FORM_ref_sup4:
- case dwarf::DW_FORM_ref_sup8:
- if (auto Val = FormValue.getValue().getAsUnsignedConstant())
- NewValue.Value = Val.getValue();
- break;
- case dwarf::DW_FORM_string:
- if (auto Val = dwarf::toString(FormValue))
- NewValue.CStr = *Val;
- break;
- case dwarf::DW_FORM_indirect:
- indirect = true;
- if (auto Val = FormValue.getValue().getAsUnsignedConstant()) {
- NewValue.Value = Val.getValue();
- NewEntry.Values.push_back(NewValue);
- Form = static_cast<dwarf::Form>(Val.getValue());
- }
- break;
- case dwarf::DW_FORM_strp:
- case dwarf::DW_FORM_sec_offset:
- case dwarf::DW_FORM_GNU_ref_alt:
- case dwarf::DW_FORM_GNU_strp_alt:
- case dwarf::DW_FORM_line_strp:
- case dwarf::DW_FORM_strp_sup:
- case dwarf::DW_FORM_GNU_str_index:
- case dwarf::DW_FORM_strx:
- if (auto Val = FormValue.getValue().getAsCStringOffset())
- NewValue.Value = Val.getValue();
- break;
- case dwarf::DW_FORM_flag_present:
- NewValue.Value = 1;
- break;
- default:
- break;
- }
- } while (indirect);
- NewEntry.Values.push_back(NewValue);
- }
- }
- NewUnit.Entries.push_back(NewEntry);
- }
- Y.CompileUnits.push_back(NewUnit);
- }
- }
- bool dumpFileEntry(DataExtractor &Data, uint64_t &Offset,
- DWARFYAML::File &File) {
- File.Name = Data.getCStr(&Offset);
- if (File.Name.empty())
- return false;
- File.DirIdx = Data.getULEB128(&Offset);
- File.ModTime = Data.getULEB128(&Offset);
- File.Length = Data.getULEB128(&Offset);
- return true;
- }
- void dumpDebugLines(DWARFContext &DCtx, DWARFYAML::Data &Y) {
- for (const auto &CU : DCtx.compile_units()) {
- auto CUDIE = CU->getUnitDIE();
- if (!CUDIE)
- continue;
- if (auto StmtOffset =
- dwarf::toSectionOffset(CUDIE.find(dwarf::DW_AT_stmt_list))) {
- DWARFYAML::LineTable DebugLines;
- DataExtractor LineData(DCtx.getDWARFObj().getLineSection().Data,
- DCtx.isLittleEndian(), CU->getAddressByteSize());
- uint64_t Offset = *StmtOffset;
- uint64_t LengthOrDWARF64Prefix = LineData.getU32(&Offset);
- if (LengthOrDWARF64Prefix == dwarf::DW_LENGTH_DWARF64) {
- DebugLines.Format = dwarf::DWARF64;
- DebugLines.Length = LineData.getU64(&Offset);
- } else {
- DebugLines.Format = dwarf::DWARF32;
- DebugLines.Length = LengthOrDWARF64Prefix;
- }
- assert(DebugLines.Length);
- uint64_t LineTableLength = *DebugLines.Length;
- uint64_t SizeOfPrologueLength =
- DebugLines.Format == dwarf::DWARF64 ? 8 : 4;
- DebugLines.Version = LineData.getU16(&Offset);
- DebugLines.PrologueLength =
- LineData.getUnsigned(&Offset, SizeOfPrologueLength);
- assert(DebugLines.PrologueLength);
- const uint64_t EndPrologue = *DebugLines.PrologueLength + Offset;
- DebugLines.MinInstLength = LineData.getU8(&Offset);
- if (DebugLines.Version >= 4)
- DebugLines.MaxOpsPerInst = LineData.getU8(&Offset);
- DebugLines.DefaultIsStmt = LineData.getU8(&Offset);
- DebugLines.LineBase = LineData.getU8(&Offset);
- DebugLines.LineRange = LineData.getU8(&Offset);
- DebugLines.OpcodeBase = LineData.getU8(&Offset);
- DebugLines.StandardOpcodeLengths.emplace();
- for (uint8_t i = 1; i < DebugLines.OpcodeBase; ++i)
- DebugLines.StandardOpcodeLengths->push_back(LineData.getU8(&Offset));
- while (Offset < EndPrologue) {
- StringRef Dir = LineData.getCStr(&Offset);
- if (!Dir.empty())
- DebugLines.IncludeDirs.push_back(Dir);
- else
- break;
- }
- while (Offset < EndPrologue) {
- DWARFYAML::File TmpFile;
- if (dumpFileEntry(LineData, Offset, TmpFile))
- DebugLines.Files.push_back(TmpFile);
- else
- break;
- }
- const uint64_t LineEnd =
- LineTableLength + *StmtOffset + SizeOfPrologueLength;
- while (Offset < LineEnd) {
- DWARFYAML::LineTableOpcode NewOp = {};
- NewOp.Opcode = (dwarf::LineNumberOps)LineData.getU8(&Offset);
- if (NewOp.Opcode == 0) {
- auto StartExt = Offset;
- NewOp.ExtLen = LineData.getULEB128(&Offset);
- NewOp.SubOpcode =
- (dwarf::LineNumberExtendedOps)LineData.getU8(&Offset);
- switch (NewOp.SubOpcode) {
- case dwarf::DW_LNE_set_address:
- case dwarf::DW_LNE_set_discriminator:
- NewOp.Data = LineData.getAddress(&Offset);
- break;
- case dwarf::DW_LNE_define_file:
- dumpFileEntry(LineData, Offset, NewOp.FileEntry);
- break;
- case dwarf::DW_LNE_end_sequence:
- break;
- default:
- while (Offset < StartExt + *NewOp.ExtLen)
- NewOp.UnknownOpcodeData.push_back(LineData.getU8(&Offset));
- }
- } else if (NewOp.Opcode < *DebugLines.OpcodeBase) {
- switch (NewOp.Opcode) {
- case dwarf::DW_LNS_copy:
- case dwarf::DW_LNS_negate_stmt:
- case dwarf::DW_LNS_set_basic_block:
- case dwarf::DW_LNS_const_add_pc:
- case dwarf::DW_LNS_set_prologue_end:
- case dwarf::DW_LNS_set_epilogue_begin:
- break;
- case dwarf::DW_LNS_advance_pc:
- case dwarf::DW_LNS_set_file:
- case dwarf::DW_LNS_set_column:
- case dwarf::DW_LNS_set_isa:
- NewOp.Data = LineData.getULEB128(&Offset);
- break;
- case dwarf::DW_LNS_advance_line:
- NewOp.SData = LineData.getSLEB128(&Offset);
- break;
- case dwarf::DW_LNS_fixed_advance_pc:
- NewOp.Data = LineData.getU16(&Offset);
- break;
- default:
- for (uint8_t i = 0;
- i <
- DebugLines.StandardOpcodeLengths.getValue()[NewOp.Opcode - 1];
- ++i)
- NewOp.StandardOpcodeData.push_back(LineData.getULEB128(&Offset));
- }
- }
- DebugLines.Opcodes.push_back(NewOp);
- }
- Y.DebugLines.push_back(DebugLines);
- }
- }
- }
|