diff options
Diffstat (limited to 'lib/DebugInfo/DWARF')
23 files changed, 2351 insertions, 819 deletions
diff --git a/lib/DebugInfo/DWARF/CMakeLists.txt b/lib/DebugInfo/DWARF/CMakeLists.txt index 11f94509e8fa..620016d76fb6 100644 --- a/lib/DebugInfo/DWARF/CMakeLists.txt +++ b/lib/DebugInfo/DWARF/CMakeLists.txt @@ -15,6 +15,7 @@ add_llvm_library(LLVMDebugInfoDWARF DWARFDebugPubTable.cpp DWARFDebugRangeList.cpp DWARFDie.cpp + DWARFExpression.cpp DWARFFormValue.cpp DWARFGdbIndex.cpp DWARFTypeUnit.cpp diff --git a/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp b/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp index bb475a669efb..f593953c62ff 100644 --- a/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp +++ b/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp @@ -63,13 +63,13 @@ DWARFAbbreviationDeclaration::extract(DataExtractor Data, auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr)); auto F = static_cast<Form>(Data.getULEB128(OffsetPtr)); if (A && F) { - Optional<int64_t> V; bool IsImplicitConst = (F == DW_FORM_implicit_const); if (IsImplicitConst) { - V = Data.getSLEB128(OffsetPtr); + int64_t V = Data.getSLEB128(OffsetPtr); AttributeSpecs.push_back(AttributeSpec(A, F, V)); continue; } + Optional<uint8_t> ByteSize; // If this abbrevation still has a fixed byte size, then update the // FixedAttributeSize as needed. switch (F) { @@ -96,11 +96,10 @@ DWARFAbbreviationDeclaration::extract(DataExtractor Data, default: // The form has a byte size that doesn't depend on Params. // If it's a fixed size, keep track of it. - if (auto Size = - DWARFFormValue::getFixedByteSize(F, DWARFFormParams())) { - V = *Size; + if ((ByteSize = + DWARFFormValue::getFixedByteSize(F, DWARFFormParams()))) { if (FixedAttributeSize) - FixedAttributeSize->NumBytes += *V; + FixedAttributeSize->NumBytes += *ByteSize; break; } // Indicate we no longer have a fixed byte size for this @@ -110,7 +109,7 @@ DWARFAbbreviationDeclaration::extract(DataExtractor Data, break; } // Record this attribute and its fixed size if it has one. - AttributeSpecs.push_back(AttributeSpec(A, F, V)); + AttributeSpecs.push_back(AttributeSpec(A, F, ByteSize)); } else if (A == 0 && F == 0) { // We successfully reached the end of this abbreviation declaration // since both attribute and form are zero. @@ -149,7 +148,7 @@ void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const { else OS << format("DW_FORM_Unknown_%x", Spec.Form); if (Spec.isImplicitConst()) - OS << '\t' << *Spec.ByteSizeOrValue; + OS << '\t' << Spec.getImplicitConstValue(); OS << '\n'; } OS << '\n'; @@ -182,10 +181,10 @@ Optional<DWARFFormValue> DWARFAbbreviationDeclaration::getAttributeValue( // We have arrived at the attribute to extract, extract if from Offset. DWARFFormValue FormValue(Spec.Form); if (Spec.isImplicitConst()) { - FormValue.setSValue(*Spec.ByteSizeOrValue); + FormValue.setSValue(Spec.getImplicitConstValue()); return FormValue; } - if (FormValue.extractValue(DebugInfoData, &Offset, &U)) + if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U)) return FormValue; } // March Offset along until we get to the attribute we want. @@ -215,8 +214,8 @@ Optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize( const DWARFUnit &U) const { if (isImplicitConst()) return 0; - if (ByteSizeOrValue) - return ByteSizeOrValue; + if (ByteSize.HasByteSize) + return ByteSize.ByteSize; Optional<int64_t> S; auto FixedByteSize = DWARFFormValue::getFixedByteSize(Form, U.getFormParams()); diff --git a/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp index 9ae7c9a07f76..17f29737bf93 100644 --- a/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -11,8 +11,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Format.h" @@ -23,12 +21,13 @@ using namespace llvm; -bool DWARFAcceleratorTable::extract() { +llvm::Error DWARFAcceleratorTable::extract() { uint32_t Offset = 0; // Check that we can at least read the header. if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength)+4)) - return false; + return make_error<StringError>("Section too small: cannot read header.", + inconvertibleErrorCode()); Hdr.Magic = AccelSection.getU32(&Offset); Hdr.Version = AccelSection.getU16(&Offset); @@ -39,9 +38,13 @@ bool DWARFAcceleratorTable::extract() { // Check that we can read all the hashes and offsets from the // section (see SourceLevelDebugging.rst for the structure of the index). + // We need to substract one because we're checking for an *offset* which is + // equal to the size for an empty table and hence pointer after the section. if (!AccelSection.isValidOffset(sizeof(Hdr) + Hdr.HeaderDataLength + - Hdr.NumBuckets*4 + Hdr.NumHashes*8)) - return false; + Hdr.NumBuckets * 4 + Hdr.NumHashes * 8 - 1)) + return make_error<StringError>( + "Section too small: cannot read buckets and hashes.", + inconvertibleErrorCode()); HdrData.DIEOffsetBase = AccelSection.getU32(&Offset); uint32_t NumAtoms = AccelSection.getU32(&Offset); @@ -52,7 +55,8 @@ bool DWARFAcceleratorTable::extract() { HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm)); } - return true; + IsValid = true; + return Error::success(); } uint32_t DWARFAcceleratorTable::getNumBuckets() { return Hdr.NumBuckets; } @@ -73,6 +77,8 @@ bool DWARFAcceleratorTable::validateForms() { DWARFFormValue FormValue(Atom.second); switch (Atom.first) { case dwarf::DW_ATOM_die_offset: + case dwarf::DW_ATOM_die_tag: + case dwarf::DW_ATOM_type_flags: if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) && !FormValue.isFormClass(DWARFFormValue::FC_Flag)) || FormValue.getForm() == dwarf::DW_FORM_sdata) @@ -84,24 +90,33 @@ bool DWARFAcceleratorTable::validateForms() { return true; } -uint32_t DWARFAcceleratorTable::readAtoms(uint32_t &HashDataOffset) { +std::pair<uint32_t, dwarf::Tag> +DWARFAcceleratorTable::readAtoms(uint32_t &HashDataOffset) { uint32_t DieOffset = dwarf::DW_INVALID_OFFSET; + dwarf::Tag DieTag = dwarf::DW_TAG_null; + DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32}; for (auto Atom : getAtomsDesc()) { DWARFFormValue FormValue(Atom.second); - FormValue.extractValue(AccelSection, &HashDataOffset, NULL); + FormValue.extractValue(AccelSection, &HashDataOffset, FormParams); switch (Atom.first) { case dwarf::DW_ATOM_die_offset: DieOffset = *FormValue.getAsUnsignedConstant(); break; + case dwarf::DW_ATOM_die_tag: + DieTag = (dwarf::Tag)*FormValue.getAsUnsignedConstant(); + break; default: break; } } - return DieOffset; + return {DieOffset, DieTag}; } LLVM_DUMP_METHOD void DWARFAcceleratorTable::dump(raw_ostream &OS) const { + if (!IsValid) + return; + // Dump the header. OS << "Magic = " << format("0x%08x", Hdr.Magic) << '\n' << "Version = " << format("0x%04x", Hdr.Version) << '\n' @@ -135,6 +150,7 @@ LLVM_DUMP_METHOD void DWARFAcceleratorTable::dump(raw_ostream &OS) const { uint32_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength; unsigned HashesBase = Offset + Hdr.NumBuckets * 4; unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4; + DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32}; for (unsigned Bucket = 0; Bucket < Hdr.NumBuckets; ++Bucket) { unsigned Index = AccelSection.getU32(&Offset); @@ -171,7 +187,7 @@ LLVM_DUMP_METHOD void DWARFAcceleratorTable::dump(raw_ostream &OS) const { unsigned i = 0; for (auto &Atom : AtomForms) { OS << format("{Atom[%d]: ", i++); - if (Atom.extractValue(AccelSection, &DataOffset, nullptr)) + if (Atom.extractValue(AccelSection, &DataOffset, FormParams)) Atom.dump(OS); else OS << "Error extracting the value"; @@ -183,3 +199,69 @@ LLVM_DUMP_METHOD void DWARFAcceleratorTable::dump(raw_ostream &OS) const { } } } + +DWARFAcceleratorTable::ValueIterator::ValueIterator( + const DWARFAcceleratorTable &AccelTable, unsigned Offset) + : AccelTable(&AccelTable), DataOffset(Offset) { + if (!AccelTable.AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) + return; + + for (const auto &Atom : AccelTable.HdrData.Atoms) + AtomForms.push_back(DWARFFormValue(Atom.second)); + + // Read the first entry. + NumData = AccelTable.AccelSection.getU32(&DataOffset); + Next(); +} + +void DWARFAcceleratorTable::ValueIterator::Next() { + assert(NumData > 0 && "attempted to increment iterator past the end"); + auto &AccelSection = AccelTable->AccelSection; + if (Data >= NumData || + !AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) { + NumData = 0; + return; + } + DWARFFormParams FormParams = {AccelTable->Hdr.Version, 0, + dwarf::DwarfFormat::DWARF32}; + for (auto &Atom : AtomForms) + Atom.extractValue(AccelSection, &DataOffset, FormParams); + ++Data; +} + +iterator_range<DWARFAcceleratorTable::ValueIterator> +DWARFAcceleratorTable::equal_range(StringRef Key) const { + if (!IsValid) + return make_range(ValueIterator(), ValueIterator()); + + // Find the bucket. + unsigned HashValue = dwarf::djbHash(Key); + unsigned Bucket = HashValue % Hdr.NumBuckets; + unsigned BucketBase = sizeof(Hdr) + Hdr.HeaderDataLength; + unsigned HashesBase = BucketBase + Hdr.NumBuckets * 4; + unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4; + + unsigned BucketOffset = BucketBase + Bucket * 4; + unsigned Index = AccelSection.getU32(&BucketOffset); + + // Search through all hashes in the bucket. + for (unsigned HashIdx = Index; HashIdx < Hdr.NumHashes; ++HashIdx) { + unsigned HashOffset = HashesBase + HashIdx * 4; + unsigned OffsetsOffset = OffsetsBase + HashIdx * 4; + uint32_t Hash = AccelSection.getU32(&HashOffset); + + if (Hash % Hdr.NumBuckets != Bucket) + // We are already in the next bucket. + break; + + unsigned DataOffset = AccelSection.getU32(&OffsetsOffset); + unsigned StringOffset = AccelSection.getRelocatedValue(4, &DataOffset); + if (!StringOffset) + break; + + // Finally, compare the key. + if (Key == StringSection.getCStr(&StringOffset)) + return make_range({*this, DataOffset}, ValueIterator()); + } + return make_range(ValueIterator(), ValueIterator()); +} diff --git a/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp b/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp index 358e9bf43d00..43b235621d18 100644 --- a/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp +++ b/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp @@ -27,7 +27,7 @@ void DWARFCompileUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) { << ")\n"; if (DWARFDie CUDie = getUnitDIE(false)) - CUDie.dump(OS, -1U, 0, DumpOpts); + CUDie.dump(OS, 0, DumpOpts); else OS << "<compile unit can't be parsed!>\n\n"; } diff --git a/lib/DebugInfo/DWARF/DWARFContext.cpp b/lib/DebugInfo/DWARF/DWARFContext.cpp index dd3235244e24..a5defa90eb35 100644 --- a/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -31,6 +31,7 @@ #include "llvm/DebugInfo/DWARF/DWARFSection.h" #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" #include "llvm/DebugInfo/DWARF/DWARFVerifier.h" +#include "llvm/MC/MCRegisterInfo.h" #include "llvm/Object/Decompressor.h" #include "llvm/Object/MachO.h" #include "llvm/Object/ObjectFile.h" @@ -40,12 +41,13 @@ #include "llvm/Support/Error.h" #include "llvm/Support/Format.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cstdint> #include <map> #include <string> -#include <tuple> #include <utility> #include <vector> @@ -59,23 +61,39 @@ using DWARFLineTable = DWARFDebugLine::LineTable; using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind; using FunctionNameKind = DILineInfoSpecifier::FunctionNameKind; -static void dumpAccelSection(raw_ostream &OS, StringRef Name, - const DWARFSection& Section, StringRef StringSection, - bool LittleEndian) { - DWARFDataExtractor AccelSection(Section, LittleEndian, 0); - DataExtractor StrData(StringSection, LittleEndian, 0); - OS << "\n." << Name << " contents:\n"; - DWARFAcceleratorTable Accel(AccelSection, StrData); - if (!Accel.extract()) +DWARFContext::DWARFContext(std::unique_ptr<const DWARFObject> DObj, + std::string DWPName) + : DIContext(CK_DWARF), DWPName(std::move(DWPName)), DObj(std::move(DObj)) {} + +DWARFContext::~DWARFContext() = default; + +/// Dump the UUID load command. +static void dumpUUID(raw_ostream &OS, const ObjectFile &Obj) { + auto *MachO = dyn_cast<MachOObjectFile>(&Obj); + if (!MachO) return; - Accel.dump(OS); + for (auto LC : MachO->load_commands()) { + raw_ostream::uuid_t UUID; + if (LC.C.cmd == MachO::LC_UUID) { + if (LC.C.cmdsize < sizeof(UUID) + sizeof(LC.C)) { + OS << "error: UUID load command is too short.\n"; + return; + } + OS << "UUID: "; + memcpy(&UUID, LC.Ptr+sizeof(LC.C), sizeof(UUID)); + OS.write_uuid(UUID); + OS << ' ' << MachO->getFileFormatName(); + OS << ' ' << MachO->getFileName() << '\n'; + } + } } static void dumpDWARFv5StringOffsetsSection(raw_ostream &OS, StringRef SectionName, + const DWARFObject &Obj, const DWARFSection &StringOffsetsSection, StringRef StringSection, bool LittleEndian) { - DWARFDataExtractor StrOffsetExt(StringOffsetsSection, LittleEndian, 0); + DWARFDataExtractor StrOffsetExt(Obj, StringOffsetsSection, LittleEndian, 0); uint32_t Offset = 0; uint64_t SectionSize = StringOffsetsSection.Data.size(); @@ -153,17 +171,15 @@ dumpDWARFv5StringOffsetsSection(raw_ostream &OS, StringRef SectionName, // monolithic series of string offsets, as generated by the pre-DWARF v5 // implementation of split DWARF. static void dumpStringOffsetsSection(raw_ostream &OS, StringRef SectionName, + const DWARFObject &Obj, const DWARFSection &StringOffsetsSection, StringRef StringSection, bool LittleEndian, unsigned MaxVersion) { - if (StringOffsetsSection.Data.empty()) - return; - OS << "\n." << SectionName << " contents:\n"; // If we have at least one (compile or type) unit with DWARF v5 or greater, // we assume that the section is formatted like a DWARF v5 string offsets // section. if (MaxVersion >= 5) - dumpDWARFv5StringOffsetsSection(OS, SectionName, StringOffsetsSection, + dumpDWARFv5StringOffsetsSection(OS, SectionName, Obj, StringOffsetsSection, StringSection, LittleEndian); else { DataExtractor strOffsetExt(StringOffsetsSection.Data, LittleEndian, 0); @@ -188,140 +204,217 @@ static void dumpStringOffsetsSection(raw_ostream &OS, StringRef SectionName, } } -void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) { - DIDumpType DumpType = DumpOpts.DumpType; - bool DumpEH = DumpOpts.DumpEH; - bool SummarizeTypes = DumpOpts.SummarizeTypes; +// We want to supply the Unit associated with a .debug_line[.dwo] table when +// we dump it, if possible, but still dump the table even if there isn't a Unit. +// Therefore, collect up handles on all the Units that point into the +// line-table section. +typedef std::map<uint64_t, DWARFUnit *> LineToUnitMap; - if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) { - OS << ".debug_abbrev contents:\n"; - getDebugAbbrev()->dump(OS); - } +static LineToUnitMap +buildLineToUnitMap(DWARFContext::cu_iterator_range CUs, + DWARFContext::tu_section_iterator_range TUSections) { + LineToUnitMap LineToUnit; + for (const auto &CU : CUs) + if (auto CUDIE = CU->getUnitDIE()) + if (auto StmtOffset = toSectionOffset(CUDIE.find(DW_AT_stmt_list))) + LineToUnit.insert(std::make_pair(*StmtOffset, &*CU)); + for (const auto &TUS : TUSections) + for (const auto &TU : TUS) + if (auto TUDIE = TU->getUnitDIE()) + if (auto StmtOffset = toSectionOffset(TUDIE.find(DW_AT_stmt_list))) + LineToUnit.insert(std::make_pair(*StmtOffset, &*TU)); + return LineToUnit; +} - if (DumpType == DIDT_All || DumpType == DIDT_AbbrevDwo) - if (const DWARFDebugAbbrev *D = getDebugAbbrevDWO()) { - OS << "\n.debug_abbrev.dwo contents:\n"; - D->dump(OS); - } +void DWARFContext::dump( + raw_ostream &OS, DIDumpOptions DumpOpts, + std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets) { - if (DumpType == DIDT_All || DumpType == DIDT_Info) { - OS << "\n.debug_info contents:\n"; - for (const auto &CU : compile_units()) - CU->dump(OS, DumpOpts); - } + Optional<uint64_t> DumpOffset; + uint64_t DumpType = DumpOpts.DumpType; - if ((DumpType == DIDT_All || DumpType == DIDT_InfoDwo) && - getNumDWOCompileUnits()) { - OS << "\n.debug_info.dwo contents:\n"; - for (const auto &DWOCU : dwo_compile_units()) - DWOCU->dump(OS, DumpOpts); - } + StringRef Extension = sys::path::extension(DObj->getFileName()); + bool IsDWO = (Extension == ".dwo") || (Extension == ".dwp"); + + // Print UUID header. + const auto *ObjFile = DObj->getFile(); + if (DumpType & DIDT_UUID) + dumpUUID(OS, *ObjFile); + + // Print a header for each explicitly-requested section. + // Otherwise just print one for non-empty sections. + // Only print empty .dwo section headers when dumping a .dwo file. + bool Explicit = DumpType != DIDT_All && !IsDWO; + bool ExplicitDWO = Explicit && IsDWO; + auto shouldDump = [&](bool Explicit, const char *Name, unsigned ID, + StringRef Section) { + DumpOffset = DumpOffsets[ID]; + unsigned Mask = 1U << ID; + bool Should = (DumpType & Mask) && (Explicit || !Section.empty()); + if (Should) + OS << "\n" << Name << " contents:\n"; + return Should; + }; + + // Dump individual sections. + if (shouldDump(Explicit, ".debug_abbrev", DIDT_ID_DebugAbbrev, + DObj->getAbbrevSection())) + getDebugAbbrev()->dump(OS); + if (shouldDump(ExplicitDWO, ".debug_abbrev.dwo", DIDT_ID_DebugAbbrev, + DObj->getAbbrevDWOSection())) + getDebugAbbrevDWO()->dump(OS); + + auto dumpDebugInfo = [&](bool IsExplicit, const char *Name, + DWARFSection Section, cu_iterator_range CUs) { + if (shouldDump(IsExplicit, Name, DIDT_ID_DebugInfo, Section.Data)) { + if (DumpOffset) + getDIEForOffset(DumpOffset.getValue()) + .dump(OS, 0, DumpOpts.noImplicitRecursion()); + else + for (const auto &CU : CUs) + CU->dump(OS, DumpOpts); + } + }; + dumpDebugInfo(Explicit, ".debug_info", DObj->getInfoSection(), + compile_units()); + dumpDebugInfo(ExplicitDWO, ".debug_info.dwo", DObj->getInfoDWOSection(), + dwo_compile_units()); - if ((DumpType == DIDT_All || DumpType == DIDT_Types) && getNumTypeUnits()) { - OS << "\n.debug_types contents:\n"; - for (const auto &TUS : type_unit_sections()) + auto dumpDebugType = [&](const char *Name, + tu_section_iterator_range TUSections) { + OS << '\n' << Name << " contents:\n"; + DumpOffset = DumpOffsets[DIDT_ID_DebugTypes]; + for (const auto &TUS : TUSections) for (const auto &TU : TUS) - TU->dump(OS, SummarizeTypes); + if (DumpOffset) + TU->getDIEForOffset(*DumpOffset) + .dump(OS, 0, DumpOpts.noImplicitRecursion()); + else + TU->dump(OS, DumpOpts); + }; + if ((DumpType & DIDT_DebugTypes)) { + if (Explicit || getNumTypeUnits()) + dumpDebugType(".debug_types", type_unit_sections()); + if (ExplicitDWO || getNumDWOTypeUnits()) + dumpDebugType(".debug_types.dwo", dwo_type_unit_sections()); } - if ((DumpType == DIDT_All || DumpType == DIDT_TypesDwo) && - getNumDWOTypeUnits()) { - OS << "\n.debug_types.dwo contents:\n"; - for (const auto &DWOTUS : dwo_type_unit_sections()) - for (const auto &DWOTU : DWOTUS) - DWOTU->dump(OS, SummarizeTypes); + if (shouldDump(Explicit, ".debug_loc", DIDT_ID_DebugLoc, + DObj->getLocSection().Data)) { + getDebugLoc()->dump(OS, getRegisterInfo(), DumpOffset); } - - if (DumpType == DIDT_All || DumpType == DIDT_Loc) { - OS << "\n.debug_loc contents:\n"; - getDebugLoc()->dump(OS); + if (shouldDump(ExplicitDWO, ".debug_loc.dwo", DIDT_ID_DebugLoc, + DObj->getLocDWOSection().Data)) { + getDebugLocDWO()->dump(OS, getRegisterInfo(), DumpOffset); } - if (DumpType == DIDT_All || DumpType == DIDT_LocDwo) { - OS << "\n.debug_loc.dwo contents:\n"; - getDebugLocDWO()->dump(OS); - } + if (shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrame, + DObj->getDebugFrameSection())) + getDebugFrame()->dump(OS, DumpOffset); - if (DumpType == DIDT_All || DumpType == DIDT_Frames) { - OS << "\n.debug_frame contents:\n"; - getDebugFrame()->dump(OS); - if (DumpEH) { - OS << "\n.eh_frame contents:\n"; - getEHFrame()->dump(OS); - } - } + if (shouldDump(Explicit, ".eh_frame", DIDT_ID_DebugFrame, + DObj->getEHFrameSection())) + getEHFrame()->dump(OS, DumpOffset); - if (DumpType == DIDT_All || DumpType == DIDT_Macro) { - OS << "\n.debug_macinfo contents:\n"; - getDebugMacro()->dump(OS); + if (DumpType & DIDT_DebugMacro) { + if (Explicit || !getDebugMacro()->empty()) { + OS << "\n.debug_macinfo contents:\n"; + getDebugMacro()->dump(OS); + } } - uint32_t offset = 0; - if (DumpType == DIDT_All || DumpType == DIDT_Aranges) { - OS << "\n.debug_aranges contents:\n"; - DataExtractor arangesData(getARangeSection(), isLittleEndian(), 0); + if (shouldDump(Explicit, ".debug_aranges", DIDT_ID_DebugAranges, + DObj->getARangeSection())) { + uint32_t offset = 0; + DataExtractor arangesData(DObj->getARangeSection(), isLittleEndian(), 0); DWARFDebugArangeSet set; while (set.extract(arangesData, &offset)) set.dump(OS); } - uint8_t savedAddressByteSize = 0; - if (DumpType == DIDT_All || DumpType == DIDT_Line) { - OS << "\n.debug_line contents:\n"; - for (const auto &CU : compile_units()) { - savedAddressByteSize = CU->getAddressByteSize(); - auto CUDIE = CU->getUnitDIE(); - if (!CUDIE) + if (shouldDump(Explicit, ".debug_line", DIDT_ID_DebugLine, + DObj->getLineSection().Data)) { + LineToUnitMap LineToUnit = + buildLineToUnitMap(compile_units(), type_unit_sections()); + unsigned Offset = 0; + DWARFDataExtractor LineData(*DObj, DObj->getLineSection(), isLittleEndian(), + 0); + while (Offset < LineData.getData().size()) { + DWARFUnit *U = nullptr; + auto It = LineToUnit.find(Offset); + if (It != LineToUnit.end()) + U = It->second; + LineData.setAddressSize(U ? U->getAddressByteSize() : 0); + DWARFDebugLine::LineTable LineTable; + if (DumpOffset && Offset != *DumpOffset) { + // Find the size of this part of the line table section and skip it. + unsigned OldOffset = Offset; + LineTable.Prologue.parse(LineData, &Offset, U); + Offset = OldOffset + LineTable.Prologue.TotalLength + + LineTable.Prologue.sizeofTotalLength(); continue; - if (auto StmtOffset = toSectionOffset(CUDIE.find(DW_AT_stmt_list))) { - DWARFDataExtractor lineData(getLineSection(), isLittleEndian(), - savedAddressByteSize); - DWARFDebugLine::LineTable LineTable; - uint32_t Offset = *StmtOffset; - LineTable.parse(lineData, &Offset); + } + // Verbose dumping is done during parsing and not on the intermediate + // representation. + OS << "debug_line[" << format("0x%8.8x", Offset) << "]\n"; + unsigned OldOffset = Offset; + if (DumpOpts.Verbose) { + LineTable.parse(LineData, &Offset, U, &OS); + } else { + LineTable.parse(LineData, &Offset, U); LineTable.dump(OS); } + // Check for unparseable prologue, to avoid infinite loops. + if (OldOffset == Offset) + break; } } - if (DumpType == DIDT_All || DumpType == DIDT_CUIndex) { - OS << "\n.debug_cu_index contents:\n"; - getCUIndex().dump(OS); + if (shouldDump(ExplicitDWO, ".debug_line.dwo", DIDT_ID_DebugLine, + DObj->getLineDWOSection().Data)) { + LineToUnitMap LineToUnit = + buildLineToUnitMap(dwo_compile_units(), dwo_type_unit_sections()); + unsigned Offset = 0; + DWARFDataExtractor LineData(*DObj, DObj->getLineDWOSection(), + isLittleEndian(), 0); + while (Offset < LineData.getData().size()) { + DWARFUnit *U = nullptr; + auto It = LineToUnit.find(Offset); + if (It != LineToUnit.end()) + U = It->second; + DWARFDebugLine::LineTable LineTable; + unsigned OldOffset = Offset; + if (!LineTable.Prologue.parse(LineData, &Offset, U)) + break; + if (!DumpOffset || OldOffset == *DumpOffset) + LineTable.dump(OS); + } } - if (DumpType == DIDT_All || DumpType == DIDT_TUIndex) { - OS << "\n.debug_tu_index contents:\n"; - getTUIndex().dump(OS); + if (shouldDump(Explicit, ".debug_cu_index", DIDT_ID_DebugCUIndex, + DObj->getCUIndexSection())) { + getCUIndex().dump(OS); } - if (DumpType == DIDT_All || DumpType == DIDT_LineDwo) { - OS << "\n.debug_line.dwo contents:\n"; - unsigned stmtOffset = 0; - DWARFDataExtractor lineData(getLineDWOSection(), isLittleEndian(), - savedAddressByteSize); - DWARFDebugLine::LineTable LineTable; - while (LineTable.Prologue.parse(lineData, &stmtOffset)) { - LineTable.dump(OS); - LineTable.clear(); - } + if (shouldDump(Explicit, ".debug_tu_index", DIDT_ID_DebugTUIndex, + DObj->getTUIndexSection())) { + getTUIndex().dump(OS); } - if (DumpType == DIDT_All || DumpType == DIDT_Str) { - OS << "\n.debug_str contents:\n"; - DataExtractor strData(getStringSection(), isLittleEndian(), 0); - offset = 0; + if (shouldDump(Explicit, ".debug_str", DIDT_ID_DebugStr, + DObj->getStringSection())) { + DataExtractor strData(DObj->getStringSection(), isLittleEndian(), 0); + uint32_t offset = 0; uint32_t strOffset = 0; while (const char *s = strData.getCStr(&offset)) { OS << format("0x%8.8x: \"%s\"\n", strOffset, s); strOffset = offset; } } - - if ((DumpType == DIDT_All || DumpType == DIDT_StrDwo) && - !getStringDWOSection().empty()) { - OS << "\n.debug_str.dwo contents:\n"; - DataExtractor strDWOData(getStringDWOSection(), isLittleEndian(), 0); - offset = 0; + if (shouldDump(ExplicitDWO, ".debug_str.dwo", DIDT_ID_DebugStr, + DObj->getStringDWOSection())) { + DataExtractor strDWOData(DObj->getStringDWOSection(), isLittleEndian(), 0); + uint32_t offset = 0; uint32_t strDWOOffset = 0; while (const char *s = strDWOData.getCStr(&offset)) { OS << format("0x%8.8x: \"%s\"\n", strDWOOffset, s); @@ -329,75 +422,94 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) { } } - if (DumpType == DIDT_All || DumpType == DIDT_Ranges) { - OS << "\n.debug_ranges contents:\n"; + if (shouldDump(Explicit, ".debug_ranges", DIDT_ID_DebugRanges, + DObj->getRangeSection().Data)) { // In fact, different compile units may have different address byte - // sizes, but for simplicity we just use the address byte size of the last - // compile unit (there is no easy and fast way to associate address range - // list and the compile unit it describes). - DWARFDataExtractor rangesData(getRangeSection(), isLittleEndian(), - savedAddressByteSize); - offset = 0; + // sizes, but for simplicity we just use the address byte size of the + // last compile unit (there is no easy and fast way to associate address + // range list and the compile unit it describes). + // FIXME: savedAddressByteSize seems sketchy. + uint8_t savedAddressByteSize = 0; + for (const auto &CU : compile_units()) { + savedAddressByteSize = CU->getAddressByteSize(); + break; + } + DWARFDataExtractor rangesData(*DObj, DObj->getRangeSection(), + isLittleEndian(), savedAddressByteSize); + uint32_t offset = 0; DWARFDebugRangeList rangeList; while (rangeList.extract(rangesData, &offset)) rangeList.dump(OS); } - if (DumpType == DIDT_All || DumpType == DIDT_Pubnames) - DWARFDebugPubTable(getPubNamesSection(), isLittleEndian(), false) - .dump("debug_pubnames", OS); + if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames, + DObj->getPubNamesSection())) + DWARFDebugPubTable(DObj->getPubNamesSection(), isLittleEndian(), false) + .dump(OS); - if (DumpType == DIDT_All || DumpType == DIDT_Pubtypes) - DWARFDebugPubTable(getPubTypesSection(), isLittleEndian(), false) - .dump("debug_pubtypes", OS); + if (shouldDump(Explicit, ".debug_pubtypes", DIDT_ID_DebugPubtypes, + DObj->getPubTypesSection())) + DWARFDebugPubTable(DObj->getPubTypesSection(), isLittleEndian(), false) + .dump(OS); - if (DumpType == DIDT_All || DumpType == DIDT_GnuPubnames) - DWARFDebugPubTable(getGnuPubNamesSection(), isLittleEndian(), + if (shouldDump(Explicit, ".debug_gnu_pubnames", DIDT_ID_DebugGnuPubnames, + DObj->getGnuPubNamesSection())) + DWARFDebugPubTable(DObj->getGnuPubNamesSection(), isLittleEndian(), true /* GnuStyle */) - .dump("debug_gnu_pubnames", OS); + .dump(OS); - if (DumpType == DIDT_All || DumpType == DIDT_GnuPubtypes) - DWARFDebugPubTable(getGnuPubTypesSection(), isLittleEndian(), + if (shouldDump(Explicit, ".debug_gnu_pubtypes", DIDT_ID_DebugGnuPubtypes, + DObj->getGnuPubTypesSection())) + DWARFDebugPubTable(DObj->getGnuPubTypesSection(), isLittleEndian(), true /* GnuStyle */) - .dump("debug_gnu_pubtypes", OS); - - if (DumpType == DIDT_All || DumpType == DIDT_StrOffsets) - dumpStringOffsetsSection(OS, "debug_str_offsets", getStringOffsetSection(), - getStringSection(), isLittleEndian(), - getMaxVersion()); + .dump(OS); - if (DumpType == DIDT_All || DumpType == DIDT_StrOffsetsDwo) { - dumpStringOffsetsSection(OS, "debug_str_offsets.dwo", - getStringOffsetDWOSection(), getStringDWOSection(), - isLittleEndian(), getMaxVersion()); - } + if (shouldDump(Explicit, ".debug_str_offsets", DIDT_ID_DebugStrOffsets, + DObj->getStringOffsetSection().Data)) + dumpStringOffsetsSection( + OS, "debug_str_offsets", *DObj, DObj->getStringOffsetSection(), + DObj->getStringSection(), isLittleEndian(), getMaxVersion()); + if (shouldDump(ExplicitDWO, ".debug_str_offsets.dwo", DIDT_ID_DebugStrOffsets, + DObj->getStringOffsetDWOSection().Data)) + dumpStringOffsetsSection( + OS, "debug_str_offsets.dwo", *DObj, DObj->getStringOffsetDWOSection(), + DObj->getStringDWOSection(), isLittleEndian(), getMaxVersion()); - if ((DumpType == DIDT_All || DumpType == DIDT_GdbIndex) && - !getGdbIndexSection().empty()) { - OS << "\n.gnu_index contents:\n"; + if (shouldDump(Explicit, ".gnu_index", DIDT_ID_GdbIndex, + DObj->getGdbIndexSection())) { getGdbIndex().dump(OS); } - if (DumpType == DIDT_All || DumpType == DIDT_AppleNames) - dumpAccelSection(OS, "apple_names", getAppleNamesSection(), - getStringSection(), isLittleEndian()); + if (shouldDump(Explicit, ".apple_names", DIDT_ID_AppleNames, + DObj->getAppleNamesSection().Data)) + getAppleNames().dump(OS); - if (DumpType == DIDT_All || DumpType == DIDT_AppleTypes) - dumpAccelSection(OS, "apple_types", getAppleTypesSection(), - getStringSection(), isLittleEndian()); + if (shouldDump(Explicit, ".apple_types", DIDT_ID_AppleTypes, + DObj->getAppleTypesSection().Data)) + getAppleTypes().dump(OS); - if (DumpType == DIDT_All || DumpType == DIDT_AppleNamespaces) - dumpAccelSection(OS, "apple_namespaces", getAppleNamespacesSection(), - getStringSection(), isLittleEndian()); + if (shouldDump(Explicit, ".apple_namespaces", DIDT_ID_AppleNamespaces, + DObj->getAppleNamespacesSection().Data)) + getAppleNamespaces().dump(OS); - if (DumpType == DIDT_All || DumpType == DIDT_AppleObjC) - dumpAccelSection(OS, "apple_objc", getAppleObjCSection(), - getStringSection(), isLittleEndian()); + if (shouldDump(Explicit, ".apple_objc", DIDT_ID_AppleObjC, + DObj->getAppleObjCSection().Data)) + getAppleObjC().dump(OS); } DWARFCompileUnit *DWARFContext::getDWOCompileUnitForHash(uint64_t Hash) { - // FIXME: Improve this for the case where this DWO file is really a DWP file - // with an index - use the index for lookup instead of a linear search. + DWOCUs.parseDWO(*this, DObj->getInfoDWOSection(), true); + + if (const auto &CUI = getCUIndex()) { + if (const auto *R = CUI.getFromHash(Hash)) + return DWOCUs.getUnitForIndexEntry(*R); + return nullptr; + } + + // If there's no index, just search through the CUs in the DWO - there's + // probably only one unless this is something like LTO - though an in-process + // built/cached lookup table could be used in that case to improve repeated + // lookups of different CUs in the DWO. for (const auto &DWOCU : dwo_compile_units()) if (DWOCU->getDWOId() == Hash) return DWOCU.get(); @@ -411,21 +523,16 @@ DWARFDie DWARFContext::getDIEForOffset(uint32_t Offset) { return DWARFDie(); } -bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) { +bool DWARFContext::verify(raw_ostream &OS, DIDumpOptions DumpOpts) { bool Success = true; - DWARFVerifier verifier(OS, *this); - if (DumpType == DIDT_All || DumpType == DIDT_Info) { - if (!verifier.handleDebugInfo()) - Success = false; - } - if (DumpType == DIDT_All || DumpType == DIDT_Line) { - if (!verifier.handleDebugLine()) - Success = false; - } - if (DumpType == DIDT_All || DumpType == DIDT_AppleNames) { - if (!verifier.handleAppleNames()) - Success = false; - } + DWARFVerifier verifier(OS, *this, DumpOpts); + + Success &= verifier.handleDebugAbbrev(); + if (DumpOpts.DumpType & DIDT_DebugInfo) + Success &= verifier.handleDebugInfo(); + if (DumpOpts.DumpType & DIDT_DebugLine) + Success &= verifier.handleDebugLine(); + Success &= verifier.handleAccelTables(); return Success; } @@ -433,7 +540,7 @@ const DWARFUnitIndex &DWARFContext::getCUIndex() { if (CUIndex) return *CUIndex; - DataExtractor CUIndexData(getCUIndexSection(), isLittleEndian(), 0); + DataExtractor CUIndexData(DObj->getCUIndexSection(), isLittleEndian(), 0); CUIndex = llvm::make_unique<DWARFUnitIndex>(DW_SECT_INFO); CUIndex->parse(CUIndexData); @@ -444,7 +551,7 @@ const DWARFUnitIndex &DWARFContext::getTUIndex() { if (TUIndex) return *TUIndex; - DataExtractor TUIndexData(getTUIndexSection(), isLittleEndian(), 0); + DataExtractor TUIndexData(DObj->getTUIndexSection(), isLittleEndian(), 0); TUIndex = llvm::make_unique<DWARFUnitIndex>(DW_SECT_TYPES); TUIndex->parse(TUIndexData); @@ -455,7 +562,7 @@ DWARFGdbIndex &DWARFContext::getGdbIndex() { if (GdbIndex) return *GdbIndex; - DataExtractor GdbIndexData(getGdbIndexSection(), true /*LE*/, 0); + DataExtractor GdbIndexData(DObj->getGdbIndexSection(), true /*LE*/, 0); GdbIndex = llvm::make_unique<DWARFGdbIndex>(); GdbIndex->parse(GdbIndexData); return *GdbIndex; @@ -465,7 +572,7 @@ const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() { if (Abbrev) return Abbrev.get(); - DataExtractor abbrData(getAbbrevSection(), isLittleEndian(), 0); + DataExtractor abbrData(DObj->getAbbrevSection(), isLittleEndian(), 0); Abbrev.reset(new DWARFDebugAbbrev()); Abbrev->extract(abbrData); @@ -476,7 +583,7 @@ const DWARFDebugAbbrev *DWARFContext::getDebugAbbrevDWO() { if (AbbrevDWO) return AbbrevDWO.get(); - DataExtractor abbrData(getAbbrevDWOSection(), isLittleEndian(), 0); + DataExtractor abbrData(DObj->getAbbrevDWOSection(), isLittleEndian(), 0); AbbrevDWO.reset(new DWARFDebugAbbrev()); AbbrevDWO->extract(abbrData); return AbbrevDWO.get(); @@ -489,7 +596,7 @@ const DWARFDebugLoc *DWARFContext::getDebugLoc() { Loc.reset(new DWARFDebugLoc); // assume all compile units have the same address byte size if (getNumCompileUnits()) { - DWARFDataExtractor LocData(getLocSection(), isLittleEndian(), + DWARFDataExtractor LocData(*DObj, DObj->getLocSection(), isLittleEndian(), getCompileUnitAtIndex(0)->getAddressByteSize()); Loc->parse(LocData); } @@ -500,7 +607,7 @@ const DWARFDebugLocDWO *DWARFContext::getDebugLocDWO() { if (LocDWO) return LocDWO.get(); - DataExtractor LocData(getLocDWOSection().Data, isLittleEndian(), 0); + DataExtractor LocData(DObj->getLocDWOSection().Data, isLittleEndian(), 0); LocDWO.reset(new DWARFDebugLocDWO()); LocDWO->parse(LocData); return LocDWO.get(); @@ -528,8 +635,8 @@ const DWARFDebugFrame *DWARFContext::getDebugFrame() { // provides this information). This problem is fixed in DWARFv4 // See this dwarf-discuss discussion for more details: // http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html - DataExtractor debugFrameData(getDebugFrameSection(), isLittleEndian(), - getAddressSize()); + DataExtractor debugFrameData(DObj->getDebugFrameSection(), isLittleEndian(), + DObj->getAddressSize()); DebugFrame.reset(new DWARFDebugFrame(false /* IsEH */)); DebugFrame->parse(debugFrameData); return DebugFrame.get(); @@ -539,8 +646,8 @@ const DWARFDebugFrame *DWARFContext::getEHFrame() { if (EHFrame) return EHFrame.get(); - DataExtractor debugFrameData(getEHFrameSection(), isLittleEndian(), - getAddressSize()); + DataExtractor debugFrameData(DObj->getEHFrameSection(), isLittleEndian(), + DObj->getAddressSize()); DebugFrame.reset(new DWARFDebugFrame(true /* IsEH */)); DebugFrame->parse(debugFrameData); return DebugFrame.get(); @@ -550,12 +657,47 @@ const DWARFDebugMacro *DWARFContext::getDebugMacro() { if (Macro) return Macro.get(); - DataExtractor MacinfoData(getMacinfoSection(), isLittleEndian(), 0); + DataExtractor MacinfoData(DObj->getMacinfoSection(), isLittleEndian(), 0); Macro.reset(new DWARFDebugMacro()); Macro->parse(MacinfoData); return Macro.get(); } +static DWARFAcceleratorTable & +getAccelTable(std::unique_ptr<DWARFAcceleratorTable> &Cache, + const DWARFObject &Obj, const DWARFSection &Section, + StringRef StringSection, bool IsLittleEndian) { + if (Cache) + return *Cache; + DWARFDataExtractor AccelSection(Obj, Section, IsLittleEndian, 0); + DataExtractor StrData(StringSection, IsLittleEndian, 0); + Cache.reset(new DWARFAcceleratorTable(AccelSection, StrData)); + if (Error E = Cache->extract()) + llvm::consumeError(std::move(E)); + return *Cache; +} + +const DWARFAcceleratorTable &DWARFContext::getAppleNames() { + return getAccelTable(AppleNames, *DObj, DObj->getAppleNamesSection(), + DObj->getStringSection(), isLittleEndian()); +} + +const DWARFAcceleratorTable &DWARFContext::getAppleTypes() { + return getAccelTable(AppleTypes, *DObj, DObj->getAppleTypesSection(), + DObj->getStringSection(), isLittleEndian()); +} + +const DWARFAcceleratorTable &DWARFContext::getAppleNamespaces() { + return getAccelTable(AppleNamespaces, *DObj, + DObj->getAppleNamespacesSection(), + DObj->getStringSection(), isLittleEndian()); +} + +const DWARFAcceleratorTable &DWARFContext::getAppleObjC() { + return getAccelTable(AppleObjC, *DObj, DObj->getAppleObjCSection(), + DObj->getStringSection(), isLittleEndian()); +} + const DWARFLineTable * DWARFContext::getLineTableForUnit(DWARFUnit *U) { if (!Line) @@ -576,35 +718,35 @@ DWARFContext::getLineTableForUnit(DWARFUnit *U) { // Make sure the offset is good before we try to parse. if (stmtOffset >= U->getLineSection().Data.size()) - return nullptr; + return nullptr; // We have to parse it first. - DWARFDataExtractor lineData(U->getLineSection(), isLittleEndian(), + DWARFDataExtractor lineData(*DObj, U->getLineSection(), isLittleEndian(), U->getAddressByteSize()); - return Line->getOrParseLineTable(lineData, stmtOffset); + return Line->getOrParseLineTable(lineData, stmtOffset, U); } void DWARFContext::parseCompileUnits() { - CUs.parse(*this, getInfoSection()); + CUs.parse(*this, DObj->getInfoSection()); } void DWARFContext::parseTypeUnits() { if (!TUs.empty()) return; - forEachTypesSections([&](const DWARFSection &S) { + DObj->forEachTypesSections([&](const DWARFSection &S) { TUs.emplace_back(); TUs.back().parse(*this, S); }); } void DWARFContext::parseDWOCompileUnits() { - DWOCUs.parseDWO(*this, getInfoDWOSection()); + DWOCUs.parseDWO(*this, DObj->getInfoDWOSection()); } void DWARFContext::parseDWOTypeUnits() { if (!DWOTUs.empty()) return; - forEachTypesDWOSections([&](const DWARFSection &S) { + DObj->forEachTypesDWOSections([&](const DWARFSection &S) { DWOTUs.emplace_back(); DWOTUs.back().parseDWO(*this, S); }); @@ -622,6 +764,35 @@ DWARFCompileUnit *DWARFContext::getCompileUnitForAddress(uint64_t Address) { return getCompileUnitForOffset(CUOffset); } +DWARFContext::DIEsForAddress DWARFContext::getDIEsForAddress(uint64_t Address) { + DIEsForAddress Result; + + DWARFCompileUnit *CU = getCompileUnitForAddress(Address); + if (!CU) + return Result; + + Result.CompileUnit = CU; + Result.FunctionDIE = CU->getSubroutineForAddress(Address); + + std::vector<DWARFDie> Worklist; + Worklist.push_back(Result.FunctionDIE); + while (!Worklist.empty()) { + DWARFDie DIE = Worklist.back(); + Worklist.pop_back(); + + if (DIE.getTag() == DW_TAG_lexical_block && + DIE.addressRangeContainsAddress(Address)) { + Result.BlockDIE = DIE; + break; + } + + for (auto Child : DIE) + Worklist.push_back(Child); + } + + return Result; +} + static bool getFunctionNameAndStartLineForAddress(DWARFCompileUnit *CU, uint64_t Address, FunctionNameKind Kind, @@ -793,11 +964,13 @@ DWARFContext::getDWOContext(StringRef AbsolutePath) { return std::shared_ptr<DWARFContext>(std::move(S), Ctxt); } - SmallString<128> DWPName; Expected<OwningBinary<ObjectFile>> Obj = [&] { if (!CheckedForDWP) { - (getFileName() + ".dwp").toVector(DWPName); - auto Obj = object::ObjectFile::createObjectFile(DWPName); + SmallString<128> DWPName; + auto Obj = object::ObjectFile::createObjectFile( + this->DWPName.empty() + ? (DObj->getFileName() + ".dwp").toStringRef(DWPName) + : StringRef(this->DWPName)); if (Obj) { Entry = &DWP; return Obj; @@ -820,7 +993,7 @@ DWARFContext::getDWOContext(StringRef AbsolutePath) { auto S = std::make_shared<DWOFile>(); S->File = std::move(Obj.get()); - S->Context = llvm::make_unique<DWARFContextInMemory>(*S->File.getBinary()); + S->Context = DWARFContext::create(*S->File.getBinary()); *Entry = S; auto *Ctxt = S->Context.get(); return std::shared_ptr<DWARFContext>(std::move(S), Ctxt); @@ -906,208 +1079,400 @@ static bool isRelocScattered(const object::ObjectFile &Obj, return MachObj->isRelocationScattered(RelocInfo); } -Error DWARFContextInMemory::maybeDecompress(const SectionRef &Sec, - StringRef Name, StringRef &Data) { - if (!Decompressor::isCompressed(Sec)) - return Error::success(); +ErrorPolicy DWARFContext::defaultErrorHandler(Error E) { + errs() << "error: " + toString(std::move(E)) << '\n'; + return ErrorPolicy::Continue; +} - Expected<Decompressor> Decompressor = - Decompressor::create(Name, Data, IsLittleEndian, AddressSize == 8); - if (!Decompressor) - return Decompressor.takeError(); +namespace { +struct DWARFSectionMap final : public DWARFSection { + RelocAddrMap Relocs; +}; - SmallString<32> Out; - if (auto Err = Decompressor->resizeAndDecompress(Out)) - return Err; +class DWARFObjInMemory final : public DWARFObject { + bool IsLittleEndian; + uint8_t AddressSize; + StringRef FileName; + const object::ObjectFile *Obj = nullptr; + std::vector<SectionName> SectionNames; - UncompressedSections.emplace_back(std::move(Out)); - Data = UncompressedSections.back(); + using TypeSectionMap = MapVector<object::SectionRef, DWARFSectionMap, + std::map<object::SectionRef, unsigned>>; - return Error::success(); -} + TypeSectionMap TypesSections; + TypeSectionMap TypesDWOSections; -ErrorPolicy DWARFContextInMemory::defaultErrorHandler(Error E) { - errs() << "error: " + toString(std::move(E)) << '\n'; - return ErrorPolicy::Continue; -} + DWARFSectionMap InfoSection; + DWARFSectionMap LocSection; + DWARFSectionMap LineSection; + DWARFSectionMap RangeSection; + DWARFSectionMap StringOffsetSection; + DWARFSectionMap InfoDWOSection; + DWARFSectionMap LineDWOSection; + DWARFSectionMap LocDWOSection; + DWARFSectionMap StringOffsetDWOSection; + DWARFSectionMap RangeDWOSection; + DWARFSectionMap AddrSection; + DWARFSectionMap AppleNamesSection; + DWARFSectionMap AppleTypesSection; + DWARFSectionMap AppleNamespacesSection; + DWARFSectionMap AppleObjCSection; -DWARFContextInMemory::DWARFContextInMemory( - const object::ObjectFile &Obj, const LoadedObjectInfo *L, - function_ref<ErrorPolicy(Error)> HandleError) - : FileName(Obj.getFileName()), IsLittleEndian(Obj.isLittleEndian()), - AddressSize(Obj.getBytesInAddress()) { - for (const SectionRef &Section : Obj.sections()) { - StringRef Name; - Section.getName(Name); - // Skip BSS and Virtual sections, they aren't interesting. - if (Section.isBSS() || Section.isVirtual()) - continue; + DWARFSectionMap *mapNameToDWARFSection(StringRef Name) { + return StringSwitch<DWARFSectionMap *>(Name) + .Case("debug_info", &InfoSection) + .Case("debug_loc", &LocSection) + .Case("debug_line", &LineSection) + .Case("debug_str_offsets", &StringOffsetSection) + .Case("debug_ranges", &RangeSection) + .Case("debug_info.dwo", &InfoDWOSection) + .Case("debug_loc.dwo", &LocDWOSection) + .Case("debug_line.dwo", &LineDWOSection) + .Case("debug_str_offsets.dwo", &StringOffsetDWOSection) + .Case("debug_addr", &AddrSection) + .Case("apple_names", &AppleNamesSection) + .Case("apple_types", &AppleTypesSection) + .Case("apple_namespaces", &AppleNamespacesSection) + .Case("apple_namespac", &AppleNamespacesSection) + .Case("apple_objc", &AppleObjCSection) + .Default(nullptr); + } - StringRef Data; - section_iterator RelocatedSection = Section.getRelocatedSection(); - // Try to obtain an already relocated version of this section. - // Else use the unrelocated section from the object file. We'll have to - // apply relocations ourselves later. - if (!L || !L->getLoadedSectionContents(*RelocatedSection, Data)) - Section.getContents(Data); + StringRef AbbrevSection; + StringRef ARangeSection; + StringRef DebugFrameSection; + StringRef EHFrameSection; + StringRef StringSection; + StringRef MacinfoSection; + StringRef PubNamesSection; + StringRef PubTypesSection; + StringRef GnuPubNamesSection; + StringRef AbbrevDWOSection; + StringRef StringDWOSection; + StringRef GnuPubTypesSection; + StringRef CUIndexSection; + StringRef GdbIndexSection; + StringRef TUIndexSection; - if (auto Err = maybeDecompress(Section, Name, Data)) { - ErrorPolicy EP = HandleError( - createError("failed to decompress '" + Name + "', ", std::move(Err))); - if (EP == ErrorPolicy::Halt) - return; - continue; - } + SmallVector<SmallString<32>, 4> UncompressedSections; - // Compressed sections names in GNU style starts from ".z", - // at this point section is decompressed and we drop compression prefix. - Name = Name.substr( - Name.find_first_not_of("._z")); // Skip ".", "z" and "_" prefixes. + StringRef *mapSectionToMember(StringRef Name) { + if (DWARFSection *Sec = mapNameToDWARFSection(Name)) + return &Sec->Data; + return StringSwitch<StringRef *>(Name) + .Case("debug_abbrev", &AbbrevSection) + .Case("debug_aranges", &ARangeSection) + .Case("debug_frame", &DebugFrameSection) + .Case("eh_frame", &EHFrameSection) + .Case("debug_str", &StringSection) + .Case("debug_macinfo", &MacinfoSection) + .Case("debug_pubnames", &PubNamesSection) + .Case("debug_pubtypes", &PubTypesSection) + .Case("debug_gnu_pubnames", &GnuPubNamesSection) + .Case("debug_gnu_pubtypes", &GnuPubTypesSection) + .Case("debug_abbrev.dwo", &AbbrevDWOSection) + .Case("debug_str.dwo", &StringDWOSection) + .Case("debug_cu_index", &CUIndexSection) + .Case("debug_tu_index", &TUIndexSection) + .Case("gdb_index", &GdbIndexSection) + // Any more debug info sections go here. + .Default(nullptr); + } - // Map platform specific debug section names to DWARF standard section - // names. - Name = Obj.mapDebugSectionName(Name); + /// If Sec is compressed section, decompresses and updates its contents + /// provided by Data. Otherwise leaves it unchanged. + Error maybeDecompress(const object::SectionRef &Sec, StringRef Name, + StringRef &Data) { + if (!Decompressor::isCompressed(Sec)) + return Error::success(); - if (StringRef *SectionData = mapSectionToMember(Name)) { - *SectionData = Data; - if (Name == "debug_ranges") { - // FIXME: Use the other dwo range section when we emit it. - RangeDWOSection.Data = Data; - } - } else if (Name == "debug_types") { - // Find debug_types data by section rather than name as there are - // multiple, comdat grouped, debug_types sections. - TypesSections[Section].Data = Data; - } else if (Name == "debug_types.dwo") { - TypesDWOSections[Section].Data = Data; + Expected<Decompressor> Decompressor = + Decompressor::create(Name, Data, IsLittleEndian, AddressSize == 8); + if (!Decompressor) + return Decompressor.takeError(); + + SmallString<32> Out; + if (auto Err = Decompressor->resizeAndDecompress(Out)) + return Err; + + UncompressedSections.emplace_back(std::move(Out)); + Data = UncompressedSections.back(); + + return Error::success(); + } + +public: + DWARFObjInMemory(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, + uint8_t AddrSize, bool IsLittleEndian) + : IsLittleEndian(IsLittleEndian) { + for (const auto &SecIt : Sections) { + if (StringRef *SectionData = mapSectionToMember(SecIt.first())) + *SectionData = SecIt.second->getBuffer(); } + } + DWARFObjInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L, + function_ref<ErrorPolicy(Error)> HandleError) + : IsLittleEndian(Obj.isLittleEndian()), + AddressSize(Obj.getBytesInAddress()), FileName(Obj.getFileName()), + Obj(&Obj) { + + StringMap<unsigned> SectionAmountMap; + for (const SectionRef &Section : Obj.sections()) { + StringRef Name; + Section.getName(Name); + ++SectionAmountMap[Name]; + SectionNames.push_back({ Name, true }); + + // Skip BSS and Virtual sections, they aren't interesting. + if (Section.isBSS() || Section.isVirtual()) + continue; - if (RelocatedSection == Obj.section_end()) - continue; + // Skip sections stripped by dsymutil. + if (Section.isStripped()) + continue; - StringRef RelSecName; - StringRef RelSecData; - RelocatedSection->getName(RelSecName); + StringRef Data; + section_iterator RelocatedSection = Section.getRelocatedSection(); + // Try to obtain an already relocated version of this section. + // Else use the unrelocated section from the object file. We'll have to + // apply relocations ourselves later. + if (!L || !L->getLoadedSectionContents(*RelocatedSection, Data)) + Section.getContents(Data); - // If the section we're relocating was relocated already by the JIT, - // then we used the relocated version above, so we do not need to process - // relocations for it now. - if (L && L->getLoadedSectionContents(*RelocatedSection, RelSecData)) - continue; + if (auto Err = maybeDecompress(Section, Name, Data)) { + ErrorPolicy EP = HandleError(createError( + "failed to decompress '" + Name + "', ", std::move(Err))); + if (EP == ErrorPolicy::Halt) + return; + continue; + } - // In Mach-o files, the relocations do not need to be applied if - // there is no load offset to apply. The value read at the - // relocation point already factors in the section address - // (actually applying the relocations will produce wrong results - // as the section address will be added twice). - if (!L && isa<MachOObjectFile>(&Obj)) - continue; + // Compressed sections names in GNU style starts from ".z", + // at this point section is decompressed and we drop compression prefix. + Name = Name.substr( + Name.find_first_not_of("._z")); // Skip ".", "z" and "_" prefixes. - RelSecName = RelSecName.substr( - RelSecName.find_first_not_of("._z")); // Skip . and _ prefixes. + // Map platform specific debug section names to DWARF standard section + // names. + Name = Obj.mapDebugSectionName(Name); - // TODO: Add support for relocations in other sections as needed. - // Record relocations for the debug_info and debug_line sections. - DWARFSection *Sec = mapNameToDWARFSection(RelSecName); - RelocAddrMap *Map = Sec ? &Sec->Relocs : nullptr; - if (!Map) { - // Find debug_types relocs by section rather than name as there are - // multiple, comdat grouped, debug_types sections. - if (RelSecName == "debug_types") - Map = &TypesSections[*RelocatedSection].Relocs; - else if (RelSecName == "debug_types.dwo") - Map = &TypesDWOSections[*RelocatedSection].Relocs; - else + if (StringRef *SectionData = mapSectionToMember(Name)) { + *SectionData = Data; + if (Name == "debug_ranges") { + // FIXME: Use the other dwo range section when we emit it. + RangeDWOSection.Data = Data; + } + } else if (Name == "debug_types") { + // Find debug_types data by section rather than name as there are + // multiple, comdat grouped, debug_types sections. + TypesSections[Section].Data = Data; + } else if (Name == "debug_types.dwo") { + TypesDWOSections[Section].Data = Data; + } + + if (RelocatedSection == Obj.section_end()) continue; - } - if (Section.relocation_begin() == Section.relocation_end()) - continue; + StringRef RelSecName; + StringRef RelSecData; + RelocatedSection->getName(RelSecName); - // Symbol to [address, section index] cache mapping. - std::map<SymbolRef, SymInfo> AddrCache; - for (const RelocationRef &Reloc : Section.relocations()) { - // FIXME: it's not clear how to correctly handle scattered - // relocations. - if (isRelocScattered(Obj, Reloc)) + // If the section we're relocating was relocated already by the JIT, + // then we used the relocated version above, so we do not need to process + // relocations for it now. + if (L && L->getLoadedSectionContents(*RelocatedSection, RelSecData)) continue; - Expected<SymInfo> SymInfoOrErr = getSymbolInfo(Obj, Reloc, L, AddrCache); - if (!SymInfoOrErr) { - if (HandleError(SymInfoOrErr.takeError()) == ErrorPolicy::Halt) - return; + // In Mach-o files, the relocations do not need to be applied if + // there is no load offset to apply. The value read at the + // relocation point already factors in the section address + // (actually applying the relocations will produce wrong results + // as the section address will be added twice). + if (!L && isa<MachOObjectFile>(&Obj)) continue; + + RelSecName = RelSecName.substr( + RelSecName.find_first_not_of("._z")); // Skip . and _ prefixes. + + // TODO: Add support for relocations in other sections as needed. + // Record relocations for the debug_info and debug_line sections. + DWARFSectionMap *Sec = mapNameToDWARFSection(RelSecName); + RelocAddrMap *Map = Sec ? &Sec->Relocs : nullptr; + if (!Map) { + // Find debug_types relocs by section rather than name as there are + // multiple, comdat grouped, debug_types sections. + if (RelSecName == "debug_types") + Map = + &static_cast<DWARFSectionMap &>(TypesSections[*RelocatedSection]) + .Relocs; + else if (RelSecName == "debug_types.dwo") + Map = &static_cast<DWARFSectionMap &>( + TypesDWOSections[*RelocatedSection]) + .Relocs; + else + continue; } - object::RelocVisitor V(Obj); - uint64_t Val = V.visit(Reloc.getType(), Reloc, SymInfoOrErr->Address); - if (V.error()) { - SmallString<32> Type; - Reloc.getTypeName(Type); - ErrorPolicy EP = HandleError( - createError("failed to compute relocation: " + Type + ", ", - errorCodeToError(object_error::parse_failed))); - if (EP == ErrorPolicy::Halt) - return; + if (Section.relocation_begin() == Section.relocation_end()) continue; + + // Symbol to [address, section index] cache mapping. + std::map<SymbolRef, SymInfo> AddrCache; + for (const RelocationRef &Reloc : Section.relocations()) { + // FIXME: it's not clear how to correctly handle scattered + // relocations. + if (isRelocScattered(Obj, Reloc)) + continue; + + Expected<SymInfo> SymInfoOrErr = + getSymbolInfo(Obj, Reloc, L, AddrCache); + if (!SymInfoOrErr) { + if (HandleError(SymInfoOrErr.takeError()) == ErrorPolicy::Halt) + return; + continue; + } + + object::RelocVisitor V(Obj); + uint64_t Val = V.visit(Reloc.getType(), Reloc, SymInfoOrErr->Address); + if (V.error()) { + SmallString<32> Type; + Reloc.getTypeName(Type); + ErrorPolicy EP = HandleError( + createError("failed to compute relocation: " + Type + ", ", + errorCodeToError(object_error::parse_failed))); + if (EP == ErrorPolicy::Halt) + return; + continue; + } + RelocAddrEntry Rel = {SymInfoOrErr->SectionIndex, Val}; + Map->insert({Reloc.getOffset(), Rel}); } - RelocAddrEntry Rel = {SymInfoOrErr->SectionIndex, Val}; - Map->insert({Reloc.getOffset(), Rel}); } + + for (SectionName &S : SectionNames) + if (SectionAmountMap[S.Name] > 1) + S.IsNameUnique = false; } -} -DWARFContextInMemory::DWARFContextInMemory( - const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, uint8_t AddrSize, - bool isLittleEndian) - : IsLittleEndian(isLittleEndian), AddressSize(AddrSize) { - for (const auto &SecIt : Sections) { - if (StringRef *SectionData = mapSectionToMember(SecIt.first())) - *SectionData = SecIt.second->getBuffer(); + Optional<RelocAddrEntry> find(const DWARFSection &S, + uint64_t Pos) const override { + auto &Sec = static_cast<const DWARFSectionMap &>(S); + RelocAddrMap::const_iterator AI = Sec.Relocs.find(Pos); + if (AI == Sec.Relocs.end()) + return None; + return AI->second; + } + + const object::ObjectFile *getFile() const override { return Obj; } + + ArrayRef<SectionName> getSectionNames() const override { + return SectionNames; } -} -DWARFSection *DWARFContextInMemory::mapNameToDWARFSection(StringRef Name) { - return StringSwitch<DWARFSection *>(Name) - .Case("debug_info", &InfoSection) - .Case("debug_loc", &LocSection) - .Case("debug_line", &LineSection) - .Case("debug_str_offsets", &StringOffsetSection) - .Case("debug_ranges", &RangeSection) - .Case("debug_info.dwo", &InfoDWOSection) - .Case("debug_loc.dwo", &LocDWOSection) - .Case("debug_line.dwo", &LineDWOSection) - .Case("debug_str_offsets.dwo", &StringOffsetDWOSection) - .Case("debug_addr", &AddrSection) - .Case("apple_names", &AppleNamesSection) - .Case("apple_types", &AppleTypesSection) - .Case("apple_namespaces", &AppleNamespacesSection) - .Case("apple_namespac", &AppleNamespacesSection) - .Case("apple_objc", &AppleObjCSection) - .Default(nullptr); + bool isLittleEndian() const override { return IsLittleEndian; } + StringRef getAbbrevDWOSection() const override { return AbbrevDWOSection; } + const DWARFSection &getLineDWOSection() const override { + return LineDWOSection; + } + const DWARFSection &getLocDWOSection() const override { + return LocDWOSection; + } + StringRef getStringDWOSection() const override { return StringDWOSection; } + const DWARFSection &getStringOffsetDWOSection() const override { + return StringOffsetDWOSection; + } + const DWARFSection &getRangeDWOSection() const override { + return RangeDWOSection; + } + const DWARFSection &getAddrSection() const override { return AddrSection; } + StringRef getCUIndexSection() const override { return CUIndexSection; } + StringRef getGdbIndexSection() const override { return GdbIndexSection; } + StringRef getTUIndexSection() const override { return TUIndexSection; } + + // DWARF v5 + const DWARFSection &getStringOffsetSection() const override { + return StringOffsetSection; + } + + // Sections for DWARF5 split dwarf proposal. + const DWARFSection &getInfoDWOSection() const override { + return InfoDWOSection; + } + void forEachTypesDWOSections( + function_ref<void(const DWARFSection &)> F) const override { + for (auto &P : TypesDWOSections) + F(P.second); + } + + StringRef getAbbrevSection() const override { return AbbrevSection; } + const DWARFSection &getLocSection() const override { return LocSection; } + StringRef getARangeSection() const override { return ARangeSection; } + StringRef getDebugFrameSection() const override { return DebugFrameSection; } + StringRef getEHFrameSection() const override { return EHFrameSection; } + const DWARFSection &getLineSection() const override { return LineSection; } + StringRef getStringSection() const override { return StringSection; } + const DWARFSection &getRangeSection() const override { return RangeSection; } + StringRef getMacinfoSection() const override { return MacinfoSection; } + StringRef getPubNamesSection() const override { return PubNamesSection; } + StringRef getPubTypesSection() const override { return PubTypesSection; } + StringRef getGnuPubNamesSection() const override { + return GnuPubNamesSection; + } + StringRef getGnuPubTypesSection() const override { + return GnuPubTypesSection; + } + const DWARFSection &getAppleNamesSection() const override { + return AppleNamesSection; + } + const DWARFSection &getAppleTypesSection() const override { + return AppleTypesSection; + } + const DWARFSection &getAppleNamespacesSection() const override { + return AppleNamespacesSection; + } + const DWARFSection &getAppleObjCSection() const override { + return AppleObjCSection; + } + + StringRef getFileName() const override { return FileName; } + uint8_t getAddressSize() const override { return AddressSize; } + const DWARFSection &getInfoSection() const override { return InfoSection; } + void forEachTypesSections( + function_ref<void(const DWARFSection &)> F) const override { + for (auto &P : TypesSections) + F(P.second); + } +}; +} // namespace + +std::unique_ptr<DWARFContext> +DWARFContext::create(const object::ObjectFile &Obj, const LoadedObjectInfo *L, + function_ref<ErrorPolicy(Error)> HandleError, + std::string DWPName) { + auto DObj = llvm::make_unique<DWARFObjInMemory>(Obj, L, HandleError); + return llvm::make_unique<DWARFContext>(std::move(DObj), std::move(DWPName)); } -StringRef *DWARFContextInMemory::mapSectionToMember(StringRef Name) { - if (DWARFSection *Sec = mapNameToDWARFSection(Name)) - return &Sec->Data; - return StringSwitch<StringRef *>(Name) - .Case("debug_abbrev", &AbbrevSection) - .Case("debug_aranges", &ARangeSection) - .Case("debug_frame", &DebugFrameSection) - .Case("eh_frame", &EHFrameSection) - .Case("debug_str", &StringSection) - .Case("debug_macinfo", &MacinfoSection) - .Case("debug_pubnames", &PubNamesSection) - .Case("debug_pubtypes", &PubTypesSection) - .Case("debug_gnu_pubnames", &GnuPubNamesSection) - .Case("debug_gnu_pubtypes", &GnuPubTypesSection) - .Case("debug_abbrev.dwo", &AbbrevDWOSection) - .Case("debug_str.dwo", &StringDWOSection) - .Case("debug_cu_index", &CUIndexSection) - .Case("debug_tu_index", &TUIndexSection) - .Case("gdb_index", &GdbIndexSection) - // Any more debug info sections go here. - .Default(nullptr); +std::unique_ptr<DWARFContext> +DWARFContext::create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, + uint8_t AddrSize, bool isLittleEndian) { + auto DObj = + llvm::make_unique<DWARFObjInMemory>(Sections, AddrSize, isLittleEndian); + return llvm::make_unique<DWARFContext>(std::move(DObj), ""); } -void DWARFContextInMemory::anchor() {} +Error DWARFContext::loadRegisterInfo(const object::ObjectFile &Obj) { + // Detect the architecture from the object file. We usually don't need OS + // info to lookup a target and create register info. + Triple TT; + TT.setArch(Triple::ArchType(Obj.getArch())); + TT.setVendor(Triple::UnknownVendor); + TT.setOS(Triple::UnknownOS); + std::string TargetLookupError; + const Target *TheTarget = + TargetRegistry::lookupTarget(TT.str(), TargetLookupError); + if (!TargetLookupError.empty()) + return make_error<StringError>(TargetLookupError, inconvertibleErrorCode()); + RegInfo.reset(TheTarget->createMCRegInfo(TT.str())); + return Error::success(); +} diff --git a/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp b/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp index 001097e56c71..861dd313fb09 100644 --- a/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp +++ b/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp @@ -8,17 +8,20 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" using namespace llvm; uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint32_t *Off, uint64_t *SecNdx) const { - if (!RelocMap) + if (SecNdx) + *SecNdx = -1ULL; + if (!Section) return getUnsigned(Off, Size); - RelocAddrMap::const_iterator AI = RelocMap->find(*Off); - if (AI == RelocMap->end()) + Optional<RelocAddrEntry> Rel = Obj->find(*Section, *Off); + if (!Rel) return getUnsigned(Off, Size); if (SecNdx) - *SecNdx = AI->second.SectionIndex; - return getUnsigned(Off, Size) + AI->second.Value; + *SecNdx = Rel->SectionIndex; + return getUnsigned(Off, Size) + Rel->Value; } diff --git a/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp b/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp index 76dd2e4c21bc..4830c36a8ee7 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp @@ -68,9 +68,7 @@ DWARFAbbreviationDeclarationSet::getAbbreviationDeclaration( return &Decls[AbbrCode - FirstAbbrCode]; } -DWARFDebugAbbrev::DWARFDebugAbbrev() { - clear(); -} +DWARFDebugAbbrev::DWARFDebugAbbrev() { clear(); } void DWARFDebugAbbrev::clear() { AbbrDeclSets.clear(); @@ -79,18 +77,29 @@ void DWARFDebugAbbrev::clear() { void DWARFDebugAbbrev::extract(DataExtractor Data) { clear(); + this->Data = Data; +} +void DWARFDebugAbbrev::parse() const { + if (!Data) + return; uint32_t Offset = 0; DWARFAbbreviationDeclarationSet AbbrDecls; - while (Data.isValidOffset(Offset)) { + auto I = AbbrDeclSets.begin(); + while (Data->isValidOffset(Offset)) { + while (I != AbbrDeclSets.end() && I->first < Offset) + ++I; uint32_t CUAbbrOffset = Offset; - if (!AbbrDecls.extract(Data, &Offset)) + if (!AbbrDecls.extract(*Data, &Offset)) break; - AbbrDeclSets[CUAbbrOffset] = std::move(AbbrDecls); + AbbrDeclSets.insert(I, std::make_pair(CUAbbrOffset, std::move(AbbrDecls))); } + Data = None; } void DWARFDebugAbbrev::dump(raw_ostream &OS) const { + parse(); + if (AbbrDeclSets.empty()) { OS << "< EMPTY >\n"; return; @@ -115,5 +124,16 @@ DWARFDebugAbbrev::getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const { return &(Pos->second); } + if (Data && CUAbbrOffset < Data->getData().size()) { + uint32_t Offset = CUAbbrOffset; + DWARFAbbreviationDeclarationSet AbbrDecls; + if (!AbbrDecls.extract(*Data, &Offset)) + return nullptr; + PrevAbbrOffsetPos = + AbbrDeclSets.insert(std::make_pair(CUAbbrOffset, std::move(AbbrDecls))) + .first; + return &PrevAbbrOffsetPos->second; + } + return nullptr; } diff --git a/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp b/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp index 6601393d7459..a3ecb15e3661 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp @@ -43,7 +43,8 @@ void DWARFDebugAranges::generate(DWARFContext *CTX) { return; // Extract aranges from .debug_aranges section. - DataExtractor ArangesData(CTX->getARangeSection(), CTX->isLittleEndian(), 0); + DataExtractor ArangesData(CTX->getDWARFObj().getARangeSection(), + CTX->isLittleEndian(), 0); extract(ArangesData); // Generate aranges from DIEs: even if .debug_aranges section is present, @@ -106,8 +107,8 @@ void DWARFDebugAranges::construct() { assert(ValidCUs.empty()); // Endpoints are not needed now. - std::vector<RangeEndpoint> EmptyEndpoints; - EmptyEndpoints.swap(Endpoints); + Endpoints.clear(); + Endpoints.shrink_to_fit(); } uint32_t DWARFDebugAranges::findAddress(uint64_t Address) const { diff --git a/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp index 475cf25b781b..3312da67804b 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp @@ -11,7 +11,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" @@ -46,19 +45,26 @@ public: FrameKind getKind() const { return Kind; } virtual uint64_t getOffset() const { return Offset; } - /// \brief Parse and store a sequence of CFI instructions from Data, + /// Parse and store a sequence of CFI instructions from Data, /// starting at *Offset and ending at EndOffset. If everything /// goes well, *Offset should be equal to EndOffset when this method /// returns. Otherwise, an error occurred. virtual void parseInstructions(DataExtractor Data, uint32_t *Offset, uint32_t EndOffset); - /// \brief Dump the entry header to the given output stream. + /// Dump the entry header to the given output stream. virtual void dumpHeader(raw_ostream &OS) const = 0; - /// \brief Dump the entry's instructions to the given output stream. + /// Dump the entry's instructions to the given output stream. virtual void dumpInstructions(raw_ostream &OS) const; + /// Dump the entire entry to the given output stream. + void dump(raw_ostream &OS) const { + dumpHeader(OS); + dumpInstructions(OS); + OS << "\n"; + } + protected: const FrameKind Kind; @@ -157,6 +163,7 @@ void FrameEntry::parseInstructions(DataExtractor Data, uint32_t *Offset, case DW_CFA_same_value: case DW_CFA_def_cfa_register: case DW_CFA_def_cfa_offset: + case DW_CFA_GNU_args_size: // Operands: ULEB128 addInstruction(Opcode, Data.getULEB128(Offset)); break; @@ -188,10 +195,16 @@ void FrameEntry::parseInstructions(DataExtractor Data, uint32_t *Offset, break; } case DW_CFA_def_cfa_expression: + // FIXME: Parse the actual instruction. + *Offset += Data.getULEB128(Offset); + break; case DW_CFA_expression: - case DW_CFA_val_expression: - // TODO: implement this - report_fatal_error("Values with expressions not implemented yet!"); + case DW_CFA_val_expression: { + // FIXME: Parse the actual instruction. + Data.getULEB128(Offset); + *Offset += Data.getULEB128(Offset); + break; + } } } } @@ -686,11 +699,24 @@ void DWARFDebugFrame::parse(DataExtractor Data) { } } -void DWARFDebugFrame::dump(raw_ostream &OS) const { - OS << "\n"; - for (const auto &Entry : Entries) { - Entry->dumpHeader(OS); - Entry->dumpInstructions(OS); - OS << "\n"; +FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const { + auto It = + std::lower_bound(Entries.begin(), Entries.end(), Offset, + [](const std::unique_ptr<FrameEntry> &E, + uint64_t Offset) { return E->getOffset() < Offset; }); + if (It != Entries.end() && (*It)->getOffset() == Offset) + return It->get(); + return nullptr; +} + +void DWARFDebugFrame::dump(raw_ostream &OS, Optional<uint64_t> Offset) const { + if (Offset) { + if (auto *Entry = getEntryAtOffset(*Offset)) + Entry->dump(OS); + return; } + + OS << "\n"; + for (const auto &Entry : Entries) + Entry->dump(OS); } diff --git a/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/lib/DebugInfo/DWARF/DWARFDebugLine.cpp index 7d180564e9f7..e5ef4eaceebe 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -12,7 +12,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/Support/Format.h" @@ -49,6 +48,7 @@ void DWARFDebugLine::Prologue::clear() { MinInstLength = MaxOpsPerInst = DefaultIsStmt = LineBase = LineRange = 0; OpcodeBase = 0; FormParams = DWARFFormParams({0, 0, DWARF32}); + HasMD5 = false; StandardOpcodeLengths.clear(); IncludeDirectories.clear(); FileNames.clear(); @@ -79,15 +79,23 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const { << IncludeDirectories[I] << "'\n"; if (!FileNames.empty()) { - OS << " Dir Mod Time File Len File Name\n" - << " ---- ---------- ---------- -----------" - "----------------\n"; + if (HasMD5) + OS << " Dir MD5 Checksum File Name\n" + << " ---- -------------------------------- -----------" + "---------------\n"; + else + OS << " Dir Mod Time File Len File Name\n" + << " ---- ---------- ---------- -----------" + "----------------\n"; for (uint32_t I = 0; I != FileNames.size(); ++I) { const FileNameEntry &FileEntry = FileNames[I]; - OS << format("file_names[%3u] %4" PRIu64 " ", I + 1, FileEntry.DirIdx) - << format("0x%8.8" PRIx64 " 0x%8.8" PRIx64 " ", FileEntry.ModTime, - FileEntry.Length) - << FileEntry.Name << '\n'; + OS << format("file_names[%3u] %4" PRIu64 " ", I + 1, FileEntry.DirIdx); + if (HasMD5) + OS << FileEntry.Checksum.digest(); + else + OS << format("0x%8.8" PRIx64 " 0x%8.8" PRIx64, FileEntry.ModTime, + FileEntry.Length); + OS << ' ' << FileEntry.Name << '\n'; } } } @@ -123,7 +131,7 @@ parseV2DirFileTables(const DWARFDataExtractor &DebugLineData, // ran off the end of the prologue. static ContentDescriptors parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, - uint64_t EndPrologueOffset) { + uint64_t EndPrologueOffset, bool *HasMD5) { ContentDescriptors Descriptors; int FormatCount = DebugLineData.getU8(OffsetPtr); bool HasPath = false; @@ -136,6 +144,8 @@ parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, Descriptor.Form = dwarf::Form(DebugLineData.getULEB128(OffsetPtr)); if (Descriptor.Type == dwarf::DW_LNCT_path) HasPath = true; + else if (Descriptor.Type == dwarf::DW_LNCT_MD5 && HasMD5) + *HasMD5 = true; Descriptors.push_back(Descriptor); } return HasPath ? Descriptors : ContentDescriptors(); @@ -144,12 +154,12 @@ parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, static bool parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, uint64_t EndPrologueOffset, - const DWARFFormParams &FormParams, - std::vector<StringRef> &IncludeDirectories, + const DWARFFormParams &FormParams, const DWARFUnit *U, + bool &HasMD5, std::vector<StringRef> &IncludeDirectories, std::vector<DWARFDebugLine::FileNameEntry> &FileNames) { // Get the directory entry description. ContentDescriptors DirDescriptors = - parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset); + parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset, nullptr); if (DirDescriptors.empty()) return false; @@ -162,7 +172,7 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, DWARFFormValue Value(Descriptor.Form); switch (Descriptor.Type) { case DW_LNCT_path: - if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr)) + if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, U)) return false; IncludeDirectories.push_back(Value.getAsCString().getValue()); break; @@ -175,7 +185,7 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, // Get the file entry description. ContentDescriptors FileDescriptors = - parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset); + parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset, &HasMD5); if (FileDescriptors.empty()) return false; @@ -187,7 +197,7 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, DWARFDebugLine::FileNameEntry FileEntry; for (auto Descriptor : FileDescriptors) { DWARFFormValue Value(Descriptor.Form); - if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr)) + if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, U)) return false; switch (Descriptor.Type) { case DW_LNCT_path: @@ -202,7 +212,11 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, case DW_LNCT_size: FileEntry.Length = Value.getAsUnsignedConstant().getValue(); break; - // FIXME: Add MD5 + case DW_LNCT_MD5: + assert(Value.getAsBlock().getValue().size() == 16); + std::uninitialized_copy_n(Value.getAsBlock().getValue().begin(), 16, + FileEntry.Checksum.Bytes.begin()); + break; default: break; } @@ -213,7 +227,7 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, } bool DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData, - uint32_t *OffsetPtr) { + uint32_t *OffsetPtr, const DWARFUnit *U) { const uint64_t PrologueOffset = *OffsetPtr; clear(); @@ -230,7 +244,8 @@ bool DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData, if (getVersion() >= 5) { FormParams.AddrSize = DebugLineData.getU8(OffsetPtr); - assert(getAddressSize() == DebugLineData.getAddressSize() && + assert((DebugLineData.getAddressSize() == 0 || + DebugLineData.getAddressSize() == getAddressSize()) && "Line table header and data extractor disagree"); SegSelectorSize = DebugLineData.getU8(OffsetPtr); } @@ -253,7 +268,8 @@ bool DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData, if (getVersion() >= 5) { if (!parseV5DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset, - getFormParams(), IncludeDirectories, FileNames)) { + getFormParams(), U, HasMD5, IncludeDirectories, + FileNames)) { fprintf(stderr, "warning: parsing line table prologue at 0x%8.8" PRIx64 " found an invalid directory or file table description at" @@ -381,46 +397,71 @@ DWARFDebugLine::getLineTable(uint32_t Offset) const { } const DWARFDebugLine::LineTable * -DWARFDebugLine::getOrParseLineTable(const DWARFDataExtractor &DebugLineData, - uint32_t Offset) { +DWARFDebugLine::getOrParseLineTable(DWARFDataExtractor &DebugLineData, + uint32_t Offset, const DWARFUnit *U) { std::pair<LineTableIter, bool> Pos = LineTableMap.insert(LineTableMapTy::value_type(Offset, LineTable())); LineTable *LT = &Pos.first->second; if (Pos.second) { - if (!LT->parse(DebugLineData, &Offset)) + if (!LT->parse(DebugLineData, &Offset, U)) return nullptr; } return LT; } -bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, - uint32_t *OffsetPtr) { +bool DWARFDebugLine::LineTable::parse(DWARFDataExtractor &DebugLineData, + uint32_t *OffsetPtr, const DWARFUnit *U, + raw_ostream *OS) { const uint32_t DebugLineOffset = *OffsetPtr; clear(); - if (!Prologue.parse(DebugLineData, OffsetPtr)) { + if (!Prologue.parse(DebugLineData, OffsetPtr, U)) { // Restore our offset and return false to indicate failure! *OffsetPtr = DebugLineOffset; return false; } + if (OS) + Prologue.dump(*OS); + const uint32_t EndOffset = DebugLineOffset + Prologue.TotalLength + Prologue.sizeofTotalLength(); + // See if we should tell the data extractor the address size. + if (DebugLineData.getAddressSize() == 0) + DebugLineData.setAddressSize(Prologue.getAddressSize()); + else + assert(Prologue.getAddressSize() == 0 || + Prologue.getAddressSize() == DebugLineData.getAddressSize()); + ParsingState State(this); while (*OffsetPtr < EndOffset) { + if (OS) + *OS << format("0x%08.08" PRIx32 ": ", *OffsetPtr); + uint8_t Opcode = DebugLineData.getU8(OffsetPtr); + if (OS) + *OS << format("%02.02" PRIx8 " ", Opcode); + if (Opcode == 0) { // Extended Opcodes always start with a zero opcode followed by // a uleb128 length so you can skip ones you don't know about - uint32_t ExtOffset = *OffsetPtr; uint64_t Len = DebugLineData.getULEB128(OffsetPtr); - uint32_t ArgSize = Len - (*OffsetPtr - ExtOffset); + uint32_t ExtOffset = *OffsetPtr; + + // Tolerate zero-length; assume length is correct and soldier on. + if (Len == 0) { + if (OS) + *OS << "Badly formed extended line op (length 0)\n"; + continue; + } uint8_t SubOpcode = DebugLineData.getU8(OffsetPtr); + if (OS) + *OS << LNExtendedString(SubOpcode); switch (SubOpcode) { case DW_LNE_end_sequence: // Set the end_sequence register of the state machine to true and @@ -432,6 +473,11 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, // of the sequence. State.Row.EndSequence = true; State.appendRowToMatrix(*OffsetPtr); + if (OS) { + *OS << "\n"; + OS->indent(12); + State.Row.dump(*OS); + } State.resetRowAndSequence(); break; @@ -442,7 +488,16 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, // relocatable address. All of the other statement program opcodes // that affect the address register add a delta to it. This instruction // stores a relocatable value into it instead. + // + // Make sure the extractor knows the address size. If not, infer it + // from the size of the operand. + if (DebugLineData.getAddressSize() == 0) + DebugLineData.setAddressSize(Len - 1); + else + assert(DebugLineData.getAddressSize() == Len - 1); State.Row.Address = DebugLineData.getRelocatedAddress(OffsetPtr); + if (OS) + *OS << format(" (0x%16.16" PRIx64 ")", State.Row.Address); break; case DW_LNE_define_file: @@ -473,20 +528,42 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr); FileEntry.Length = DebugLineData.getULEB128(OffsetPtr); Prologue.FileNames.push_back(FileEntry); + if (OS) + *OS << " (" << FileEntry.Name.str() + << ", dir=" << FileEntry.DirIdx << ", mod_time=" + << format("(0x%16.16" PRIx64 ")", FileEntry.ModTime) + << ", length=" << FileEntry.Length << ")"; } break; case DW_LNE_set_discriminator: State.Row.Discriminator = DebugLineData.getULEB128(OffsetPtr); + if (OS) + *OS << " (" << State.Row.Discriminator << ")"; break; default: - // Length doesn't include the zero opcode byte or the length itself, but - // it does include the sub_opcode, so we have to adjust for that below - (*OffsetPtr) += ArgSize; + if (OS) + *OS << format("Unrecognized extended op 0x%02.02" PRIx8, SubOpcode) + << format(" length %" PRIx64, Len); + // Len doesn't include the zero opcode byte or the length itself, but + // it does include the sub_opcode, so we have to adjust for that. + (*OffsetPtr) += Len - 1; break; } + // Make sure the stated and parsed lengths are the same. + // Otherwise we have an unparseable line-number program. + if (*OffsetPtr - ExtOffset != Len) { + fprintf(stderr, "Unexpected line op length at offset 0x%8.8" PRIx32 + " expected 0x%2.2" PRIx64 " found 0x%2.2" PRIx32 "\n", + ExtOffset, Len, *OffsetPtr - ExtOffset); + // Skip the rest of the line-number program. + *OffsetPtr = EndOffset; + return false; + } } else if (Opcode < Prologue.OpcodeBase) { + if (OS) + *OS << LNStandardString(Opcode); switch (Opcode) { // Standard Opcodes case DW_LNS_copy: @@ -494,32 +571,49 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, // current values of the state-machine registers. Then set // the basic_block register to false. State.appendRowToMatrix(*OffsetPtr); + if (OS) { + *OS << "\n"; + OS->indent(12); + State.Row.dump(*OS); + *OS << "\n"; + } break; case DW_LNS_advance_pc: // Takes a single unsigned LEB128 operand, multiplies it by the // min_inst_length field of the prologue, and adds the // result to the address register of the state machine. - State.Row.Address += - DebugLineData.getULEB128(OffsetPtr) * Prologue.MinInstLength; + { + uint64_t AddrOffset = + DebugLineData.getULEB128(OffsetPtr) * Prologue.MinInstLength; + State.Row.Address += AddrOffset; + if (OS) + *OS << " (" << AddrOffset << ")"; + } break; case DW_LNS_advance_line: // Takes a single signed LEB128 operand and adds that value to // the line register of the state machine. State.Row.Line += DebugLineData.getSLEB128(OffsetPtr); + if (OS) + *OS << " (" << State.Row.Line << ")"; break; case DW_LNS_set_file: // Takes a single unsigned LEB128 operand and stores it in the file // register of the state machine. State.Row.File = DebugLineData.getULEB128(OffsetPtr); + if (OS) + *OS << " (" << State.Row.File << ")"; break; case DW_LNS_set_column: // Takes a single unsigned LEB128 operand and stores it in the // column register of the state machine. State.Row.Column = DebugLineData.getULEB128(OffsetPtr); + if (OS) + *OS << " (" << State.Row.Column << ")"; break; case DW_LNS_negate_stmt: @@ -551,6 +645,9 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, uint64_t AddrOffset = (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength; State.Row.Address += AddrOffset; + if (OS) + *OS + << format(" (0x%16.16" PRIx64 ")", AddrOffset); } break; @@ -564,7 +661,13 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, // judge when the computation of a special opcode overflows and // requires the use of DW_LNS_advance_pc. Such assemblers, however, // can use DW_LNS_fixed_advance_pc instead, sacrificing compression. - State.Row.Address += DebugLineData.getU16(OffsetPtr); + { + uint16_t PCOffset = DebugLineData.getU16(OffsetPtr); + State.Row.Address += PCOffset; + if (OS) + *OS + << format(" (0x%16.16" PRIx64 ")", PCOffset); + } break; case DW_LNS_set_prologue_end: @@ -583,6 +686,8 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, // Takes a single unsigned LEB128 operand and stores it in the // column register of the state machine. State.Row.Isa = DebugLineData.getULEB128(OffsetPtr); + if (OS) + *OS << " (" << State.Row.Isa << ")"; break; default: @@ -592,8 +697,12 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, { assert(Opcode - 1U < Prologue.StandardOpcodeLengths.size()); uint8_t OpcodeLength = Prologue.StandardOpcodeLengths[Opcode - 1]; - for (uint8_t I = 0; I < OpcodeLength; ++I) - DebugLineData.getULEB128(OffsetPtr); + for (uint8_t I = 0; I < OpcodeLength; ++I) { + uint64_t Value = DebugLineData.getULEB128(OffsetPtr); + if (OS) + *OS << format("Skipping ULEB128 value: 0x%16.16" PRIx64 ")\n", + Value); + } } break; } @@ -638,10 +747,20 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, Prologue.LineBase + (AdjustOpcode % Prologue.LineRange); State.Row.Line += LineOffset; State.Row.Address += AddrOffset; + + if (OS) { + *OS << "address += " << ((uint32_t)AdjustOpcode) + << ", line += " << LineOffset << "\n"; + OS->indent(12); + State.Row.dump(*OS); + } + State.appendRowToMatrix(*OffsetPtr); // Reset discriminator to 0. State.Row.Discriminator = 0; } + if(OS) + *OS << "\n"; } if (!State.Sequence.Empty) { diff --git a/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp index c240dd7406d9..58f88536f317 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp @@ -11,7 +11,10 @@ #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -20,104 +23,202 @@ using namespace llvm; -void DWARFDebugLoc::dump(raw_ostream &OS) const { - for (const LocationList &L : Locations) { +// When directly dumping the .debug_loc without a compile unit, we have to guess +// at the DWARF version. This only affects DW_OP_call_ref, which is a rare +// expression that LLVM doesn't produce. Guessing the wrong version means we +// won't be able to pretty print expressions in DWARF2 binaries produced by +// non-LLVM tools. +static void dumpExpression(raw_ostream &OS, ArrayRef<char> Data, + bool IsLittleEndian, unsigned AddressSize, + const MCRegisterInfo *MRI) { + DWARFDataExtractor Extractor(StringRef(Data.data(), Data.size()), + IsLittleEndian, AddressSize); + DWARFExpression(Extractor, AddressSize, dwarf::DWARF_VERSION).print(OS, MRI); +} + +void DWARFDebugLoc::LocationList::dump(raw_ostream &OS, bool IsLittleEndian, + unsigned AddressSize, + const MCRegisterInfo *MRI, + unsigned Indent) const { + for (const Entry &E : Entries) { + OS << '\n'; + OS.indent(Indent); + OS << format("0x%016" PRIx64, E.Begin) << " - " + << format("0x%016" PRIx64, E.End) << ": "; + + dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI); + } +} + +DWARFDebugLoc::LocationList const * +DWARFDebugLoc::getLocationListAtOffset(uint64_t Offset) const { + auto It = std::lower_bound( + Locations.begin(), Locations.end(), Offset, + [](const LocationList &L, uint64_t Offset) { return L.Offset < Offset; }); + if (It != Locations.end() && It->Offset == Offset) + return &(*It); + return nullptr; +} + +void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI, + Optional<uint64_t> Offset) const { + auto DumpLocationList = [&](const LocationList &L) { OS << format("0x%8.8x: ", L.Offset); - const unsigned Indent = 12; - for (const Entry &E : L.Entries) { - if (&E != L.Entries.begin()) - OS.indent(Indent); - OS << "Beginning address offset: " << format("0x%016" PRIx64, E.Begin) - << '\n'; - OS.indent(Indent) << " Ending address offset: " - << format("0x%016" PRIx64, E.End) << '\n'; - OS.indent(Indent) << " Location description: "; - for (unsigned char Loc : E.Loc) { - OS << format("%2.2x ", Loc); - } - OS << "\n\n"; + L.dump(OS, IsLittleEndian, AddressSize, MRI, 12); + OS << "\n\n"; + }; + + if (Offset) { + if (auto *L = getLocationListAtOffset(*Offset)) + DumpLocationList(*L); + return; + } + + for (const LocationList &L : Locations) { + DumpLocationList(L); + } +} + +Optional<DWARFDebugLoc::LocationList> +DWARFDebugLoc::parseOneLocationList(DWARFDataExtractor Data, unsigned *Offset) { + LocationList LL; + LL.Offset = *Offset; + + // 2.6.2 Location Lists + // A location list entry consists of: + while (true) { + Entry E; + if (!Data.isValidOffsetForDataOfSize(*Offset, 2 * Data.getAddressSize())) { + llvm::errs() << "Location list overflows the debug_loc section.\n"; + return None; + } + + // 1. A beginning address offset. ... + E.Begin = Data.getRelocatedAddress(Offset); + + // 2. An ending address offset. ... + E.End = Data.getRelocatedAddress(Offset); + + // The end of any given location list is marked by an end of list entry, + // which consists of a 0 for the beginning address offset and a 0 for the + // ending address offset. + if (E.Begin == 0 && E.End == 0) + return LL; + + if (!Data.isValidOffsetForDataOfSize(*Offset, 2)) { + llvm::errs() << "Location list overflows the debug_loc section.\n"; + return None; + } + + unsigned Bytes = Data.getU16(Offset); + if (!Data.isValidOffsetForDataOfSize(*Offset, Bytes)) { + llvm::errs() << "Location list overflows the debug_loc section.\n"; + return None; } + // A single location description describing the location of the object... + StringRef str = Data.getData().substr(*Offset, Bytes); + *Offset += Bytes; + E.Loc.reserve(str.size()); + std::copy(str.begin(), str.end(), std::back_inserter(E.Loc)); + LL.Entries.push_back(std::move(E)); } } void DWARFDebugLoc::parse(const DWARFDataExtractor &data) { + IsLittleEndian = data.isLittleEndian(); + AddressSize = data.getAddressSize(); + uint32_t Offset = 0; - while (data.isValidOffset(Offset+data.getAddressSize()-1)) { - Locations.resize(Locations.size() + 1); - LocationList &Loc = Locations.back(); - Loc.Offset = Offset; - // 2.6.2 Location Lists - // A location list entry consists of: - while (true) { - // A beginning and ending address offsets. - Entry E; - E.Begin = data.getRelocatedAddress(&Offset); - E.End = data.getRelocatedAddress(&Offset); + while (data.isValidOffset(Offset + data.getAddressSize() - 1)) { + if (auto LL = parseOneLocationList(data, &Offset)) + Locations.push_back(std::move(*LL)); + else + break; + } + if (data.isValidOffset(Offset)) + errs() << "error: failed to consume entire .debug_loc section\n"; +} - // The end of any given location list is marked by an end of list entry, - // which consists of a 0 for the beginning address offset and a 0 for the - // ending address offset. - if (E.Begin == 0 && E.End == 0) - break; +Optional<DWARFDebugLocDWO::LocationList> +DWARFDebugLocDWO::parseOneLocationList(DataExtractor Data, unsigned *Offset) { + LocationList LL; + LL.Offset = *Offset; - unsigned Bytes = data.getU16(&Offset); - // A single location description describing the location of the object... - StringRef str = data.getData().substr(Offset, Bytes); - Offset += Bytes; - E.Loc.append(str.begin(), str.end()); - Loc.Entries.push_back(std::move(E)); + // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list. + while (auto Kind = + static_cast<dwarf::LocationListEntry>(Data.getU8(Offset))) { + if (Kind != dwarf::DW_LLE_startx_length) { + llvm::errs() << "error: dumping support for LLE of kind " << (int)Kind + << " not implemented\n"; + return None; } + + Entry E; + E.Start = Data.getULEB128(Offset); + E.Length = Data.getU32(Offset); + + unsigned Bytes = Data.getU16(Offset); + // A single location description describing the location of the object... + StringRef str = Data.getData().substr(*Offset, Bytes); + *Offset += Bytes; + E.Loc.resize(str.size()); + std::copy(str.begin(), str.end(), E.Loc.begin()); + + LL.Entries.push_back(std::move(E)); } - if (data.isValidOffset(Offset)) - errs() << "error: failed to consume entire .debug_loc section\n"; + return LL; } void DWARFDebugLocDWO::parse(DataExtractor data) { + IsLittleEndian = data.isLittleEndian(); + AddressSize = data.getAddressSize(); + uint32_t Offset = 0; while (data.isValidOffset(Offset)) { - Locations.resize(Locations.size() + 1); - LocationList &Loc = Locations.back(); - Loc.Offset = Offset; - dwarf::LocationListEntry Kind; - while ((Kind = static_cast<dwarf::LocationListEntry>( - data.getU8(&Offset))) != dwarf::DW_LLE_end_of_list) { - - if (Kind != dwarf::DW_LLE_startx_length) { - errs() << "error: dumping support for LLE of kind " << (int)Kind - << " not implemented\n"; - return; - } + if (auto LL = parseOneLocationList(data, &Offset)) + Locations.push_back(std::move(*LL)); + else + return; + } +} - Entry E; +DWARFDebugLocDWO::LocationList const * +DWARFDebugLocDWO::getLocationListAtOffset(uint64_t Offset) const { + auto It = std::lower_bound( + Locations.begin(), Locations.end(), Offset, + [](const LocationList &L, uint64_t Offset) { return L.Offset < Offset; }); + if (It != Locations.end() && It->Offset == Offset) + return &(*It); + return nullptr; +} - E.Start = data.getULEB128(&Offset); - E.Length = data.getU32(&Offset); +void DWARFDebugLocDWO::LocationList::dump(raw_ostream &OS, bool IsLittleEndian, + unsigned AddressSize, + const MCRegisterInfo *MRI, + unsigned Indent) const { + for (const Entry &E : Entries) { + OS << '\n'; + OS.indent(Indent); + OS << "Addr idx " << E.Start << " (w/ length " << E.Length << "): "; + dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI); + } +} - unsigned Bytes = data.getU16(&Offset); - // A single location description describing the location of the object... - StringRef str = data.getData().substr(Offset, Bytes); - Offset += Bytes; - E.Loc.resize(str.size()); - std::copy(str.begin(), str.end(), E.Loc.begin()); +void DWARFDebugLocDWO::dump(raw_ostream &OS, const MCRegisterInfo *MRI, + Optional<uint64_t> Offset) const { + auto DumpLocationList = [&](const LocationList &L) { + OS << format("0x%8.8x: ", L.Offset); + L.dump(OS, IsLittleEndian, AddressSize, MRI, /*Indent=*/12); + OS << "\n\n"; + }; - Loc.Entries.push_back(std::move(E)); - } + if (Offset) { + if (auto *L = getLocationListAtOffset(*Offset)) + DumpLocationList(*L); + return; } -} -void DWARFDebugLocDWO::dump(raw_ostream &OS) const { for (const LocationList &L : Locations) { - OS << format("0x%8.8x: ", L.Offset); - const unsigned Indent = 12; - for (const Entry &E : L.Entries) { - if (&E != L.Entries.begin()) - OS.indent(Indent); - OS << "Beginning address index: " << E.Start << '\n'; - OS.indent(Indent) << " Length: " << E.Length << '\n'; - OS.indent(Indent) << " Location description: "; - for (unsigned char Loc : E.Loc) - OS << format("%2.2x ", Loc); - OS << "\n\n"; - } + DumpLocationList(L); } } diff --git a/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp b/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp index 5a4e39f3c2af..956a91e9c4d6 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp @@ -44,8 +44,7 @@ DWARFDebugPubTable::DWARFDebugPubTable(StringRef Data, bool LittleEndian, } } -void DWARFDebugPubTable::dump(StringRef Name, raw_ostream &OS) const { - OS << "\n." << Name << " contents:\n"; +void DWARFDebugPubTable::dump(raw_ostream &OS) const { for (const Set &S : Sets) { OS << "length = " << format("0x%08x", S.Length); OS << " version = " << format("0x%04x", S.Version); diff --git a/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp b/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp index 0b6ae86fd94b..f0b7ec2751de 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp @@ -17,6 +17,11 @@ using namespace llvm; +raw_ostream &llvm::operator<<(raw_ostream &OS, const DWARFAddressRange &R) { + return OS << format("[0x%16.16" PRIx64 ", 0x%16.16" PRIx64 ")", R.LowPC, + R.HighPC); +} + void DWARFDebugRangeList::clear() { Offset = -1U; AddressSize = 0; @@ -33,20 +38,22 @@ bool DWARFDebugRangeList::extract(const DWARFDataExtractor &data, return false; Offset = *offset_ptr; while (true) { - RangeListEntry entry; + RangeListEntry Entry; + Entry.SectionIndex = -1ULL; + uint32_t prev_offset = *offset_ptr; - entry.StartAddress = - data.getRelocatedAddress(offset_ptr, &entry.SectionIndex); - entry.EndAddress = data.getRelocatedAddress(offset_ptr); + Entry.StartAddress = data.getRelocatedAddress(offset_ptr); + Entry.EndAddress = + data.getRelocatedAddress(offset_ptr, &Entry.SectionIndex); // Check that both values were extracted correctly. if (*offset_ptr != prev_offset + 2 * AddressSize) { clear(); return false; } - if (entry.isEndOfListEntry()) + if (Entry.isEndOfListEntry()) break; - Entries.push_back(entry); + Entries.push_back(Entry); } return true; } @@ -61,16 +68,29 @@ void DWARFDebugRangeList::dump(raw_ostream &OS) const { OS << format("%08x <End of list>\n", Offset); } -DWARFAddressRangesVector -DWARFDebugRangeList::getAbsoluteRanges(uint64_t BaseAddress) const { +DWARFAddressRangesVector DWARFDebugRangeList::getAbsoluteRanges( + llvm::Optional<BaseAddress> BaseAddr) const { DWARFAddressRangesVector Res; for (const RangeListEntry &RLE : Entries) { if (RLE.isBaseAddressSelectionEntry(AddressSize)) { - BaseAddress = RLE.EndAddress; - } else { - Res.push_back({BaseAddress + RLE.StartAddress, - BaseAddress + RLE.EndAddress, RLE.SectionIndex}); + BaseAddr = {RLE.EndAddress, RLE.SectionIndex}; + continue; + } + + DWARFAddressRange E; + E.LowPC = RLE.StartAddress; + E.HighPC = RLE.EndAddress; + E.SectionIndex = RLE.SectionIndex; + // Base address of a range list entry is determined by the closest preceding + // base address selection entry in the same range list. It defaults to the + // base address of the compilation unit if there is no such entry. + if (BaseAddr) { + E.LowPC += BaseAddr->Address; + E.HighPC += BaseAddr->Address; + if (E.SectionIndex == -1ULL) + E.SectionIndex = BaseAddr->SectionIndex; } + Res.push_back(E); } return Res; } diff --git a/lib/DebugInfo/DWARF/DWARFDie.cpp b/lib/DebugInfo/DWARF/DWARFDie.cpp index 111f0bbd4444..91f0f8501f0c 100644 --- a/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -16,8 +16,10 @@ #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Format.h" #include "llvm/Support/MathExtras.h" @@ -31,6 +33,7 @@ using namespace llvm; using namespace dwarf; +using namespace object; using namespace syntax; static void dumpApplePropertyAttribute(raw_ostream &OS, uint64_t Val) { @@ -51,17 +54,131 @@ static void dumpApplePropertyAttribute(raw_ostream &OS, uint64_t Val) { OS << ")"; } -static void dumpRanges(raw_ostream &OS, const DWARFAddressRangesVector& Ranges, - unsigned AddressSize, unsigned Indent) { - if (Ranges.empty()) - return; - - for (const auto &Range: Ranges) { +static void dumpRanges(const DWARFObject &Obj, raw_ostream &OS, + const DWARFAddressRangesVector &Ranges, + unsigned AddressSize, unsigned Indent, + const DIDumpOptions &DumpOpts) { + ArrayRef<SectionName> SectionNames; + if (DumpOpts.Verbose) + SectionNames = Obj.getSectionNames(); + + for (size_t I = 0; I < Ranges.size(); ++I) { + const DWARFAddressRange &R = Ranges[I]; + OS << '\n'; OS.indent(Indent); - OS << format("[0x%0*" PRIx64 " - 0x%0*" PRIx64 ")", - AddressSize*2, Range.LowPC, - AddressSize*2, Range.HighPC); + OS << format("[0x%0*" PRIx64 " - 0x%0*" PRIx64 ")", AddressSize * 2, + R.LowPC, AddressSize * 2, R.HighPC); + + if (SectionNames.empty() || R.SectionIndex == -1ULL) + continue; + + StringRef Name = SectionNames[R.SectionIndex].Name; + OS << " \"" << Name << '\"'; + + // Print section index if name is not unique. + if (!SectionNames[R.SectionIndex].IsNameUnique) + OS << format(" [%" PRIu64 "]", R.SectionIndex); + } +} + +static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue, + DWARFUnit *U, unsigned Indent, + DIDumpOptions DumpOpts) { + DWARFContext &Ctx = U->getContext(); + const DWARFObject &Obj = Ctx.getDWARFObj(); + const MCRegisterInfo *MRI = Ctx.getRegisterInfo(); + if (FormValue.isFormClass(DWARFFormValue::FC_Block) || + FormValue.isFormClass(DWARFFormValue::FC_Exprloc)) { + ArrayRef<uint8_t> Expr = *FormValue.getAsBlock(); + DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()), + Ctx.isLittleEndian(), 0); + DWARFExpression(Data, U->getVersion(), U->getAddressByteSize()) + .print(OS, MRI); + return; + } + + FormValue.dump(OS, DumpOpts); + if (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) { + const DWARFSection &LocSection = Obj.getLocSection(); + const DWARFSection &LocDWOSection = Obj.getLocDWOSection(); + uint32_t Offset = *FormValue.getAsSectionOffset(); + + if (!LocSection.Data.empty()) { + DWARFDebugLoc DebugLoc; + DWARFDataExtractor Data(Obj, LocSection, Ctx.isLittleEndian(), + Obj.getAddressSize()); + auto LL = DebugLoc.parseOneLocationList(Data, &Offset); + if (LL) + LL->dump(OS, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, Indent); + else + OS << "error extracting location list."; + } else if (!LocDWOSection.Data.empty()) { + DataExtractor Data(LocDWOSection.Data, Ctx.isLittleEndian(), 0); + auto LL = DWARFDebugLocDWO::parseOneLocationList(Data, &Offset); + if (LL) + LL->dump(OS, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, Indent); + else + OS << "error extracting location list."; + } + } +} + +/// Dump the name encoded in the type tag. +static void dumpTypeTagName(raw_ostream &OS, dwarf::Tag T) { + StringRef TagStr = TagString(T); + if (!TagStr.startswith("DW_TAG_") || !TagStr.endswith("_type")) + return; + OS << TagStr.substr(7, TagStr.size() - 12) << " "; +} + +/// Recursively dump the DIE type name when applicable. +static void dumpTypeName(raw_ostream &OS, const DWARFDie &Die) { + DWARFDie D = Die.getAttributeValueAsReferencedDie(DW_AT_type); + + if (!D.isValid()) + return; + + if (const char *Name = D.getName(DINameKind::LinkageName)) { + OS << Name; + return; + } + + // FIXME: We should have pretty printers per language. Currently we print + // everything as if it was C++ and fall back to the TAG type name. + const dwarf::Tag T = D.getTag(); + switch (T) { + case DW_TAG_array_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + case DW_TAG_reference_type: + case DW_TAG_rvalue_reference_type: + break; + default: + dumpTypeTagName(OS, T); + } + + // Follow the DW_AT_type if possible. + dumpTypeName(OS, D); + + switch (T) { + case DW_TAG_array_type: + OS << "[]"; + break; + case DW_TAG_pointer_type: + OS << '*'; + break; + case DW_TAG_ptr_to_member_type: + OS << '*'; + break; + case DW_TAG_reference_type: + OS << '&'; + break; + case DW_TAG_rvalue_reference_type: + OS << "&&"; + break; + default: + break; } } @@ -73,14 +190,14 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, return; const char BaseIndent[] = " "; OS << BaseIndent; - OS.indent(Indent+2); + OS.indent(Indent + 2); auto attrString = AttributeString(Attr); if (!attrString.empty()) WithColor(OS, syntax::Attribute) << attrString; else WithColor(OS, syntax::Attribute).get() << format("DW_AT_Unknown_%x", Attr); - if (!DumpOpts.Brief) { + if (DumpOpts.Verbose || DumpOpts.ShowForm) { auto formString = FormEncodingString(Form); if (!formString.empty()) OS << " [" << formString << ']'; @@ -90,60 +207,81 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, DWARFUnit *U = Die.getDwarfUnit(); DWARFFormValue formValue(Form); - - if (!formValue.extractValue(U->getDebugInfoExtractor(), OffsetPtr, U)) + + if (!formValue.extractValue(U->getDebugInfoExtractor(), OffsetPtr, + U->getFormParams(), U)) return; - + OS << "\t("; - + StringRef Name; std::string File; auto Color = syntax::Enumerator; if (Attr == DW_AT_decl_file || Attr == DW_AT_call_file) { Color = syntax::String; if (const auto *LT = U->getContext().getLineTableForUnit(U)) - if (LT->getFileNameByIndex(formValue.getAsUnsignedConstant().getValue(), U->getCompilationDir(), DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) { + if (LT->getFileNameByIndex( + formValue.getAsUnsignedConstant().getValue(), + U->getCompilationDir(), + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) { File = '"' + File + '"'; Name = File; } } else if (Optional<uint64_t> Val = formValue.getAsUnsignedConstant()) Name = AttributeValueString(Attr, *Val); - + if (!Name.empty()) WithColor(OS, Color) << Name; else if (Attr == DW_AT_decl_line || Attr == DW_AT_call_line) OS << *formValue.getAsUnsignedConstant(); + else if (Attr == DW_AT_high_pc && !DumpOpts.ShowForm && !DumpOpts.Verbose && + formValue.getAsUnsignedConstant()) { + if (DumpOpts.ShowAddresses) { + // Print the actual address rather than the offset. + uint64_t LowPC, HighPC, Index; + if (Die.getLowAndHighPC(LowPC, HighPC, Index)) + OS << format("0x%016" PRIx64, HighPC); + else + formValue.dump(OS, DumpOpts); + } + } else if (Attr == DW_AT_location || Attr == DW_AT_frame_base || + Attr == DW_AT_data_member_location || + Attr == DW_AT_GNU_call_site_value) + dumpLocation(OS, formValue, U, sizeof(BaseIndent) + Indent + 4, DumpOpts); else - formValue.dump(OS); - + formValue.dump(OS, DumpOpts); + // We have dumped the attribute raw value. For some attributes // having both the raw value and the pretty-printed value is // interesting. These attributes are handled below. if (Attr == DW_AT_specification || Attr == DW_AT_abstract_origin) { - if (const char *Name = Die.getAttributeValueAsReferencedDie(Attr).getName(DINameKind::LinkageName)) - OS << " \"" << Name << '\"'; + if (const char *Name = Die.getAttributeValueAsReferencedDie(Attr).getName( + DINameKind::LinkageName)) + OS << " \"" << Name << '\"'; + } else if (Attr == DW_AT_type) { + OS << " \""; + dumpTypeName(OS, Die); + OS << '"'; } else if (Attr == DW_AT_APPLE_property_attribute) { if (Optional<uint64_t> OptVal = formValue.getAsUnsignedConstant()) dumpApplePropertyAttribute(OS, *OptVal); } else if (Attr == DW_AT_ranges) { - dumpRanges(OS, Die.getAddressRanges(), U->getAddressByteSize(), - sizeof(BaseIndent)+Indent+4); + const DWARFObject &Obj = Die.getDwarfUnit()->getContext().getDWARFObj(); + dumpRanges(Obj, OS, Die.getAddressRanges(), U->getAddressByteSize(), + sizeof(BaseIndent) + Indent + 4, DumpOpts); } - + OS << ")\n"; } -bool DWARFDie::isSubprogramDIE() const { - return getTag() == DW_TAG_subprogram; -} +bool DWARFDie::isSubprogramDIE() const { return getTag() == DW_TAG_subprogram; } bool DWARFDie::isSubroutineDIE() const { auto Tag = getTag(); return Tag == DW_TAG_subprogram || Tag == DW_TAG_inlined_subroutine; } -Optional<DWARFFormValue> -DWARFDie::find(dwarf::Attribute Attr) const { +Optional<DWARFFormValue> DWARFDie::find(dwarf::Attribute Attr) const { if (!isValid()) return None; auto AbbrevDecl = getAbbreviationDeclarationPtr(); @@ -170,33 +308,29 @@ Optional<DWARFFormValue> DWARFDie::findRecursively(ArrayRef<dwarf::Attribute> Attrs) const { if (!isValid()) return None; - auto Die = *this; - if (auto Value = Die.find(Attrs)) - return Value; - if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin)) - Die = D; - if (auto Value = Die.find(Attrs)) - return Value; - if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_specification)) - Die = D; - if (auto Value = Die.find(Attrs)) + if (auto Value = find(Attrs)) return Value; + if (auto Die = getAttributeValueAsReferencedDie(DW_AT_abstract_origin)) { + if (auto Value = Die.findRecursively(Attrs)) + return Value; + } + if (auto Die = getAttributeValueAsReferencedDie(DW_AT_specification)) { + if (auto Value = Die.findRecursively(Attrs)) + return Value; + } return None; } DWARFDie DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const { - auto SpecRef = toReference(find(Attr)); - if (SpecRef) { - auto SpecUnit = U->getUnitSection().getUnitForOffset(*SpecRef); - if (SpecUnit) + if (auto SpecRef = toReference(find(Attr))) { + if (auto SpecUnit = U->getUnitSection().getUnitForOffset(*SpecRef)) return SpecUnit->getDIEForOffset(*SpecRef); } return DWARFDie(); } -Optional<uint64_t> -DWARFDie::getRangesBaseAttribute() const { +Optional<uint64_t> DWARFDie::getRangesBaseAttribute() const { return toSectionOffset(find({DW_AT_rnglists_base, DW_AT_GNU_ranges_base})); } @@ -229,8 +363,7 @@ bool DWARFDie::getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC, return false; } -DWARFAddressRangesVector -DWARFDie::getAddressRanges() const { +DWARFAddressRangesVector DWARFDie::getAddressRanges() const { if (isNULL()) return DWARFAddressRangesVector(); // Single range specified by low/high PC. @@ -248,8 +381,8 @@ DWARFDie::getAddressRanges() const { return DWARFAddressRangesVector(); } -void -DWARFDie::collectChildrenAddressRanges(DWARFAddressRangesVector& Ranges) const { +void DWARFDie::collectChildrenAddressRanges( + DWARFAddressRangesVector &Ranges) const { if (isNULL()) return; if (isSubprogramDIE()) { @@ -257,33 +390,32 @@ DWARFDie::collectChildrenAddressRanges(DWARFAddressRangesVector& Ranges) const { Ranges.insert(Ranges.end(), DIERanges.begin(), DIERanges.end()); } - for (auto Child: children()) + for (auto Child : children()) Child.collectChildrenAddressRanges(Ranges); } bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const { - for (const auto& R : getAddressRanges()) { + for (const auto &R : getAddressRanges()) { if (R.LowPC <= Address && Address < R.HighPC) return true; } return false; } -const char * -DWARFDie::getSubroutineName(DINameKind Kind) const { +const char *DWARFDie::getSubroutineName(DINameKind Kind) const { if (!isSubroutineDIE()) return nullptr; return getName(Kind); } -const char * -DWARFDie::getName(DINameKind Kind) const { +const char *DWARFDie::getName(DINameKind Kind) const { if (!isValid() || Kind == DINameKind::None) return nullptr; // Try to get mangled name only if it was asked for. if (Kind == DINameKind::LinkageName) { - if (auto Name = dwarf::toString(findRecursively({DW_AT_MIPS_linkage_name, - DW_AT_linkage_name}), nullptr)) + if (auto Name = dwarf::toString( + findRecursively({DW_AT_MIPS_linkage_name, DW_AT_linkage_name}), + nullptr)) return Name; } if (auto Name = dwarf::toString(findRecursively(DW_AT_name), nullptr)) @@ -304,18 +436,33 @@ void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine, CallDiscriminator = toUnsigned(find(DW_AT_GNU_discriminator), 0); } -void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, unsigned Indent, +/// Helper to dump a DIE with all of its parents, but no siblings. +static unsigned dumpParentChain(DWARFDie Die, raw_ostream &OS, unsigned Indent, + DIDumpOptions DumpOpts) { + if (!Die) + return Indent; + Indent = dumpParentChain(Die.getParent(), OS, Indent, DumpOpts); + Die.dump(OS, Indent, DumpOpts); + return Indent + 2; +} + +void DWARFDie::dump(raw_ostream &OS, unsigned Indent, DIDumpOptions DumpOpts) const { if (!isValid()) return; DWARFDataExtractor debug_info_data = U->getDebugInfoExtractor(); const uint32_t Offset = getOffset(); uint32_t offset = Offset; - + if (DumpOpts.ShowParents) { + DumpOpts.ShowParents = false; + Indent = dumpParentChain(getParent(), OS, Indent, DumpOpts); + } + if (debug_info_data.isValidOffset(offset)) { uint32_t abbrCode = debug_info_data.getULEB128(&offset); - WithColor(OS, syntax::Address).get() << format("\n0x%8.8x: ", Offset); - + if (DumpOpts.ShowAddresses) + WithColor(OS, syntax::Address).get() << format("\n0x%8.8x: ", Offset); + if (abbrCode) { auto AbbrevDecl = getAbbreviationDeclarationPtr(); if (AbbrevDecl) { @@ -324,9 +471,9 @@ void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, unsigned Indent, WithColor(OS, syntax::Tag).get().indent(Indent) << tagString; else WithColor(OS, syntax::Tag).get().indent(Indent) - << format("DW_TAG_Unknown_%x", getTag()); + << format("DW_TAG_Unknown_%x", getTag()); - if (!DumpOpts.Brief) + if (DumpOpts.Verbose) OS << format(" [%u] %c", abbrCode, AbbrevDecl->hasChildren() ? '*' : ' '); OS << '\n'; @@ -342,17 +489,18 @@ void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, unsigned Indent, dumpAttribute(OS, *this, &offset, AttrSpec.Attr, AttrSpec.Form, Indent, DumpOpts); } - + DWARFDie child = getFirstChild(); - if (RecurseDepth > 0 && child) { + if (DumpOpts.ShowChildren && DumpOpts.RecurseDepth > 0 && child) { + DumpOpts.RecurseDepth--; while (child) { - child.dump(OS, RecurseDepth-1, Indent+2, DumpOpts); + child.dump(OS, Indent + 2, DumpOpts); child = child.getSibling(); } } } else { OS << "Abbreviation code not found in 'debug_abbrev' class for code: " - << abbrCode << '\n'; + << abbrCode << '\n'; } } else { OS.indent(Indent) << "NULL\n"; @@ -360,6 +508,8 @@ void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, unsigned Indent, } } +LLVM_DUMP_METHOD void DWARFDie::dump() const { dump(llvm::errs(), 0); } + DWARFDie DWARFDie::getParent() const { if (isValid()) return U->getParent(Die); @@ -372,14 +522,19 @@ DWARFDie DWARFDie::getSibling() const { return DWARFDie(); } -iterator_range<DWARFDie::attribute_iterator> -DWARFDie::attributes() const { +DWARFDie DWARFDie::getFirstChild() const { + if (isValid()) + return U->getFirstChild(Die); + return DWARFDie(); +} + +iterator_range<DWARFDie::attribute_iterator> DWARFDie::attributes() const { return make_range(attribute_iterator(*this, false), attribute_iterator(*this, true)); } -DWARFDie::attribute_iterator::attribute_iterator(DWARFDie D, bool End) : - Die(D), AttrValue(0), Index(0) { +DWARFDie::attribute_iterator::attribute_iterator(DWARFDie D, bool End) + : Die(D), AttrValue(0), Index(0) { auto AbbrDecl = Die.getAbbreviationDeclarationPtr(); assert(AbbrDecl && "Must have abbreviation declaration"); if (End) { @@ -406,7 +561,7 @@ void DWARFDie::attribute_iterator::updateForIndex( auto U = Die.getDwarfUnit(); assert(U && "Die must have valid DWARF unit"); bool b = AttrValue.Value.extractValue(U->getDebugInfoExtractor(), - &ParseOffset, U); + &ParseOffset, U->getFormParams(), U); (void)b; assert(b && "extractValue cannot fail on fully parsed DWARF"); AttrValue.ByteSize = ParseOffset - AttrValue.Offset; diff --git a/lib/DebugInfo/DWARF/DWARFExpression.cpp b/lib/DebugInfo/DWARF/DWARFExpression.cpp new file mode 100644 index 000000000000..c704c2901aef --- /dev/null +++ b/lib/DebugInfo/DWARF/DWARFExpression.cpp @@ -0,0 +1,274 @@ +//===-- DWARFExpression.cpp -----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Support/Format.h" +#include <cassert> +#include <cstdint> +#include <vector> + +using namespace llvm; +using namespace dwarf; + +namespace llvm { + +typedef std::vector<DWARFExpression::Operation::Description> DescVector; + +static DescVector getDescriptions() { + DescVector Descriptions; + typedef DWARFExpression::Operation Op; + typedef Op::Description Desc; + + Descriptions.resize(0xff); + Descriptions[DW_OP_addr] = Desc(Op::Dwarf2, Op::SizeAddr); + Descriptions[DW_OP_deref] = Desc(Op::Dwarf2); + Descriptions[DW_OP_const1u] = Desc(Op::Dwarf2, Op::Size1); + Descriptions[DW_OP_const1s] = Desc(Op::Dwarf2, Op::SignedSize1); + Descriptions[DW_OP_const2u] = Desc(Op::Dwarf2, Op::Size2); + Descriptions[DW_OP_const2s] = Desc(Op::Dwarf2, Op::SignedSize2); + Descriptions[DW_OP_const4u] = Desc(Op::Dwarf2, Op::Size4); + Descriptions[DW_OP_const4s] = Desc(Op::Dwarf2, Op::SignedSize4); + Descriptions[DW_OP_const8u] = Desc(Op::Dwarf2, Op::Size8); + Descriptions[DW_OP_const8s] = Desc(Op::Dwarf2, Op::SignedSize8); + Descriptions[DW_OP_constu] = Desc(Op::Dwarf2, Op::SizeLEB); + Descriptions[DW_OP_consts] = Desc(Op::Dwarf2, Op::SignedSizeLEB); + Descriptions[DW_OP_dup] = Desc(Op::Dwarf2); + Descriptions[DW_OP_drop] = Desc(Op::Dwarf2); + Descriptions[DW_OP_over] = Desc(Op::Dwarf2); + Descriptions[DW_OP_pick] = Desc(Op::Dwarf2, Op::Size1); + Descriptions[DW_OP_swap] = Desc(Op::Dwarf2); + Descriptions[DW_OP_rot] = Desc(Op::Dwarf2); + Descriptions[DW_OP_xderef] = Desc(Op::Dwarf2); + Descriptions[DW_OP_abs] = Desc(Op::Dwarf2); + Descriptions[DW_OP_and] = Desc(Op::Dwarf2); + Descriptions[DW_OP_div] = Desc(Op::Dwarf2); + Descriptions[DW_OP_minus] = Desc(Op::Dwarf2); + Descriptions[DW_OP_mod] = Desc(Op::Dwarf2); + Descriptions[DW_OP_mul] = Desc(Op::Dwarf2); + Descriptions[DW_OP_neg] = Desc(Op::Dwarf2); + Descriptions[DW_OP_not] = Desc(Op::Dwarf2); + Descriptions[DW_OP_or] = Desc(Op::Dwarf2); + Descriptions[DW_OP_plus] = Desc(Op::Dwarf2); + Descriptions[DW_OP_plus_uconst] = Desc(Op::Dwarf2, Op::SizeLEB); + Descriptions[DW_OP_shl] = Desc(Op::Dwarf2); + Descriptions[DW_OP_shr] = Desc(Op::Dwarf2); + Descriptions[DW_OP_shra] = Desc(Op::Dwarf2); + Descriptions[DW_OP_xor] = Desc(Op::Dwarf2); + Descriptions[DW_OP_skip] = Desc(Op::Dwarf2, Op::SignedSize2); + Descriptions[DW_OP_bra] = Desc(Op::Dwarf2, Op::SignedSize2); + Descriptions[DW_OP_eq] = Desc(Op::Dwarf2); + Descriptions[DW_OP_ge] = Desc(Op::Dwarf2); + Descriptions[DW_OP_gt] = Desc(Op::Dwarf2); + Descriptions[DW_OP_le] = Desc(Op::Dwarf2); + Descriptions[DW_OP_lt] = Desc(Op::Dwarf2); + Descriptions[DW_OP_ne] = Desc(Op::Dwarf2); + for (uint16_t LA = DW_OP_lit0; LA <= DW_OP_lit31; ++LA) + Descriptions[LA] = Desc(Op::Dwarf2); + for (uint16_t LA = DW_OP_reg0; LA <= DW_OP_reg31; ++LA) + Descriptions[LA] = Desc(Op::Dwarf2); + for (uint16_t LA = DW_OP_breg0; LA <= DW_OP_breg31; ++LA) + Descriptions[LA] = Desc(Op::Dwarf2, Op::SignedSizeLEB); + Descriptions[DW_OP_regx] = Desc(Op::Dwarf2, Op::SizeLEB); + Descriptions[DW_OP_fbreg] = Desc(Op::Dwarf2, Op::SignedSizeLEB); + Descriptions[DW_OP_bregx] = Desc(Op::Dwarf2, Op::SizeLEB, Op::SignedSizeLEB); + Descriptions[DW_OP_piece] = Desc(Op::Dwarf2, Op::SizeLEB); + Descriptions[DW_OP_deref_size] = Desc(Op::Dwarf2, Op::Size1); + Descriptions[DW_OP_xderef_size] = Desc(Op::Dwarf2, Op::Size1); + Descriptions[DW_OP_nop] = Desc(Op::Dwarf2); + Descriptions[DW_OP_push_object_address] = Desc(Op::Dwarf3); + Descriptions[DW_OP_call2] = Desc(Op::Dwarf3, Op::Size2); + Descriptions[DW_OP_call4] = Desc(Op::Dwarf3, Op::Size4); + Descriptions[DW_OP_call_ref] = Desc(Op::Dwarf3, Op::SizeRefAddr); + Descriptions[DW_OP_form_tls_address] = Desc(Op::Dwarf3); + Descriptions[DW_OP_call_frame_cfa] = Desc(Op::Dwarf3); + Descriptions[DW_OP_bit_piece] = Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeLEB); + Descriptions[DW_OP_implicit_value] = + Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeBlock); + Descriptions[DW_OP_stack_value] = Desc(Op::Dwarf3); + Descriptions[DW_OP_GNU_push_tls_address] = Desc(Op::Dwarf3); + Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB); + Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB); + return Descriptions; +} + +static DWARFExpression::Operation::Description getOpDesc(unsigned OpCode) { + // FIXME: Make this constexpr once all compilers are smart enough to do it. + static DescVector Descriptions = getDescriptions(); + // Handle possible corrupted or unsupported operation. + if (OpCode >= Descriptions.size()) + return {}; + return Descriptions[OpCode]; +} + +static uint8_t getRefAddrSize(uint8_t AddrSize, uint16_t Version) { + return (Version == 2) ? AddrSize : 4; +} + +bool DWARFExpression::Operation::extract(DataExtractor Data, uint16_t Version, + uint8_t AddressSize, uint32_t Offset) { + Opcode = Data.getU8(&Offset); + + Desc = getOpDesc(Opcode); + if (Desc.Version == Operation::DwarfNA) { + EndOffset = Offset; + return false; + } + + for (unsigned Operand = 0; Operand < 2; ++Operand) { + unsigned Size = Desc.Op[Operand]; + unsigned Signed = Size & Operation::SignBit; + + if (Size == Operation::SizeNA) + break; + + switch (Size & ~Operation::SignBit) { + case Operation::Size1: + Operands[Operand] = Data.getU8(&Offset); + if (Signed) + Operands[Operand] = (int8_t)Operands[Operand]; + break; + case Operation::Size2: + Operands[Operand] = Data.getU16(&Offset); + if (Signed) + Operands[Operand] = (int16_t)Operands[Operand]; + break; + case Operation::Size4: + Operands[Operand] = Data.getU32(&Offset); + if (Signed) + Operands[Operand] = (int32_t)Operands[Operand]; + break; + case Operation::Size8: + Operands[Operand] = Data.getU64(&Offset); + break; + case Operation::SizeAddr: + if (AddressSize == 8) { + Operands[Operand] = Data.getU64(&Offset); + } else { + assert(AddressSize == 4); + Operands[Operand] = Data.getU32(&Offset); + } + break; + case Operation::SizeRefAddr: + if (getRefAddrSize(AddressSize, Version) == 8) { + Operands[Operand] = Data.getU64(&Offset); + } else { + assert(getRefAddrSize(AddressSize, Version) == 4); + Operands[Operand] = Data.getU32(&Offset); + } + break; + case Operation::SizeLEB: + if (Signed) + Operands[Operand] = Data.getSLEB128(&Offset); + else + Operands[Operand] = Data.getULEB128(&Offset); + break; + case Operation::SizeBlock: + // We need a size, so this cannot be the first operand + if (Operand == 0) + return false; + // Store the offset of the block as the value. + Operands[Operand] = Offset; + Offset += Operands[Operand - 1]; + break; + default: + llvm_unreachable("Unknown DWARFExpression Op size"); + } + } + + EndOffset = Offset; + return true; +} + +static bool prettyPrintRegisterOp(raw_ostream &OS, uint8_t Opcode, + uint64_t Operands[2], + const MCRegisterInfo *MRI, bool isEH) { + if (!MRI) + return false; + + uint64_t DwarfRegNum; + unsigned OpNum = 0; + + if (Opcode == DW_OP_bregx || Opcode == DW_OP_regx) + DwarfRegNum = Operands[OpNum++]; + else if (Opcode >= DW_OP_breg0 && Opcode < DW_OP_bregx) + DwarfRegNum = Opcode - DW_OP_breg0; + else + DwarfRegNum = Opcode - DW_OP_reg0; + + int LLVMRegNum = MRI->getLLVMRegNum(DwarfRegNum, isEH); + if (LLVMRegNum >= 0) { + if (const char *RegName = MRI->getName(LLVMRegNum)) { + if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) || + Opcode == DW_OP_bregx) + OS << format(" %s%+" PRId64, RegName, Operands[OpNum]); + else + OS << ' ' << RegName; + return true; + } + } + + return false; +} + +bool DWARFExpression::Operation::print(raw_ostream &OS, + const DWARFExpression *Expr, + const MCRegisterInfo *RegInfo, + bool isEH) { + if (Error) { + OS << "<decoding error>"; + return false; + } + + StringRef Name = OperationEncodingString(Opcode); + assert(!Name.empty() && "DW_OP has no name!"); + OS << Name; + + if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) || + (Opcode >= DW_OP_reg0 && Opcode <= DW_OP_reg31) || + Opcode == DW_OP_bregx || Opcode == DW_OP_regx) + if (prettyPrintRegisterOp(OS, Opcode, Operands, RegInfo, isEH)) + return true; + + for (unsigned Operand = 0; Operand < 2; ++Operand) { + unsigned Size = Desc.Op[Operand]; + unsigned Signed = Size & Operation::SignBit; + + if (Size == Operation::SizeNA) + break; + + if (Size == Operation::SizeBlock) { + uint32_t Offset = Operands[Operand]; + for (unsigned i = 0; i < Operands[Operand - 1]; ++i) + OS << format(" 0x%02x", Expr->Data.getU8(&Offset)); + } else { + if (Signed) + OS << format(" %+" PRId64, (int64_t)Operands[Operand]); + else + OS << format(" 0x%" PRIx64, Operands[Operand]); + } + } + return true; +} + +void DWARFExpression::print(raw_ostream &OS, const MCRegisterInfo *RegInfo) { + for (auto &Op : *this) { + if (!Op.print(OS, this, RegInfo, /* isEH */ false)) { + uint32_t FailOffset = Op.getEndOffset(); + while (FailOffset < Data.getData().size()) + OS << format(" %02x", Data.getU8(&FailOffset)); + return; + } + if (Op.getEndOffset() < Data.getData().size()) + OS << ", "; + } +} + +} // namespace llvm diff --git a/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/lib/DebugInfo/DWARF/DWARFFormValue.cpp index 83a7792e1244..44886de2e3d5 100644 --- a/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ b/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -186,6 +186,7 @@ bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData, case DW_FORM_data2: case DW_FORM_data4: case DW_FORM_data8: + case DW_FORM_data16: case DW_FORM_flag: case DW_FORM_ref1: case DW_FORM_ref2: @@ -276,7 +277,8 @@ bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { } bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data, - uint32_t *OffsetPtr, const DWARFUnit *CU) { + uint32_t *OffsetPtr, DWARFFormParams FP, + const DWARFUnit *CU) { U = CU; bool Indirect = false; bool IsBlock = false; @@ -288,10 +290,8 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data, switch (Form) { case DW_FORM_addr: case DW_FORM_ref_addr: { - if (!U) - return false; - uint16_t Size = (Form == DW_FORM_addr) ? U->getAddressByteSize() - : U->getRefAddrByteSize(); + uint16_t Size = + (Form == DW_FORM_addr) ? FP.AddrSize : FP.getRefAddrByteSize(); Value.uval = Data.getRelocatedValue(Size, OffsetPtr, &Value.SectionIndex); break; } @@ -340,6 +340,11 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data, case DW_FORM_ref_sup8: Value.uval = Data.getU64(OffsetPtr); break; + case DW_FORM_data16: + // Treat this like a 16-byte block. + Value.uval = 16; + IsBlock = true; + break; case DW_FORM_sdata: Value.sval = Data.getSLEB128(OffsetPtr); break; @@ -360,10 +365,8 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data, case DW_FORM_GNU_strp_alt: case DW_FORM_line_strp: case DW_FORM_strp_sup: { - if (!U) - return false; Value.uval = - Data.getRelocatedValue(U->getDwarfOffsetByteSize(), OffsetPtr); + Data.getRelocatedValue(FP.getDwarfOffsetByteSize(), OffsetPtr); break; } case DW_FORM_flag_present: @@ -396,21 +399,22 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data, return true; } -void DWARFFormValue::dump(raw_ostream &OS) const { +void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { uint64_t UValue = Value.uval; bool CURelativeOffset = false; - + raw_ostream &AddrOS = + DumpOpts.ShowAddresses ? WithColor(OS, syntax::Address).get() : nulls(); switch (Form) { case DW_FORM_addr: - OS << format("0x%016" PRIx64, UValue); + AddrOS << format("0x%016" PRIx64, UValue); break; case DW_FORM_GNU_addr_index: { - OS << format(" indexed (%8.8x) address = ", (uint32_t)UValue); + AddrOS << format(" indexed (%8.8x) address = ", (uint32_t)UValue); uint64_t Address; if (U == nullptr) OS << "<invalid dwarf unit>"; else if (U->getAddrOffsetSectionItem(UValue, Address)) - OS << format("0x%016" PRIx64, Address); + AddrOS << format("0x%016" PRIx64, Address); else OS << "<no .debug_addr section>"; break; @@ -429,9 +433,14 @@ void DWARFFormValue::dump(raw_ostream &OS) const { OS << format("0x%08x", (uint32_t)UValue); break; case DW_FORM_ref_sig8: + AddrOS << format("0x%016" PRIx64, UValue); + break; case DW_FORM_data8: OS << format("0x%016" PRIx64, UValue); break; + case DW_FORM_data16: + OS << format_bytes(ArrayRef<uint8_t>(Value.data, 16), None, 16, 16); + break; case DW_FORM_string: OS << '"'; OS.write_escaped(Value.cstr); @@ -481,7 +490,8 @@ void DWARFFormValue::dump(raw_ostream &OS) const { OS << Value.uval; break; case DW_FORM_strp: - OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)UValue); + if (DumpOpts.Verbose) + OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)UValue); dumpString(OS); break; case DW_FORM_strx: @@ -490,38 +500,40 @@ void DWARFFormValue::dump(raw_ostream &OS) const { case DW_FORM_strx3: case DW_FORM_strx4: case DW_FORM_GNU_str_index: - OS << format(" indexed (%8.8x) string = ", (uint32_t)UValue); + if (DumpOpts.Verbose) + OS << format(" indexed (%8.8x) string = ", (uint32_t)UValue); dumpString(OS); break; case DW_FORM_GNU_strp_alt: - OS << format("alt indirect string, offset: 0x%" PRIx64 "", UValue); + if (DumpOpts.Verbose) + OS << format("alt indirect string, offset: 0x%" PRIx64 "", UValue); dumpString(OS); break; case DW_FORM_ref_addr: - OS << format("0x%016" PRIx64, UValue); + AddrOS << format("0x%016" PRIx64, UValue); break; case DW_FORM_ref1: CURelativeOffset = true; - OS << format("cu + 0x%2.2x", (uint8_t)UValue); + AddrOS << format("cu + 0x%2.2x", (uint8_t)UValue); break; case DW_FORM_ref2: CURelativeOffset = true; - OS << format("cu + 0x%4.4x", (uint16_t)UValue); + AddrOS << format("cu + 0x%4.4x", (uint16_t)UValue); break; case DW_FORM_ref4: CURelativeOffset = true; - OS << format("cu + 0x%4.4x", (uint32_t)UValue); + AddrOS << format("cu + 0x%4.4x", (uint32_t)UValue); break; case DW_FORM_ref8: CURelativeOffset = true; - OS << format("cu + 0x%8.8" PRIx64, UValue); + AddrOS << format("cu + 0x%8.8" PRIx64, UValue); break; case DW_FORM_ref_udata: CURelativeOffset = true; - OS << format("cu + 0x%" PRIx64, UValue); + AddrOS << format("cu + 0x%" PRIx64, UValue); break; case DW_FORM_GNU_ref_alt: - OS << format("<alt 0x%" PRIx64 ">", UValue); + AddrOS << format("<alt 0x%" PRIx64 ">", UValue); break; // All DW_FORM_indirect attributes should be resolved prior to calling @@ -532,7 +544,7 @@ void DWARFFormValue::dump(raw_ostream &OS) const { // Should be formatted to 64-bit for DWARF64. case DW_FORM_sec_offset: - OS << format("0x%08x", (uint32_t)UValue); + AddrOS << format("0x%08x", (uint32_t)UValue); break; default: @@ -540,7 +552,7 @@ void DWARFFormValue::dump(raw_ostream &OS) const { break; } - if (CURelativeOffset) { + if (CURelativeOffset && DumpOpts.Verbose) { OS << " => {"; WithColor(OS, syntax::Address).get() << format("0x%8.8" PRIx64, UValue + (U ? U->getOffset() : 0)); @@ -648,7 +660,8 @@ Optional<int64_t> DWARFFormValue::getAsSignedConstant() const { } Optional<ArrayRef<uint8_t>> DWARFFormValue::getAsBlock() const { - if (!isFormClass(FC_Block) && !isFormClass(FC_Exprloc)) + if (!isFormClass(FC_Block) && !isFormClass(FC_Exprloc) && + Form != DW_FORM_data16) return None; return makeArrayRef(Value.data, Value.uval); } diff --git a/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp b/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp index fd1684d33a16..206c12fa403f 100644 --- a/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp +++ b/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp @@ -31,11 +31,11 @@ bool DWARFTypeUnit::extractImpl(DataExtractor debug_info, return TypeOffset < getLength() + SizeOfLength; } -void DWARFTypeUnit::dump(raw_ostream &OS, bool SummarizeTypes) { +void DWARFTypeUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) { DWARFDie TD = getDIEForOffset(TypeOffset + getOffset()); const char *Name = TD.getName(DINameKind::ShortName); - if (SummarizeTypes) { + if (DumpOpts.SummarizeTypes) { OS << "name = '" << Name << "'" << " type_signature = " << format("0x%016" PRIx64, TypeHash) << " length = " << format("0x%08x", getLength()) << '\n'; @@ -55,7 +55,7 @@ void DWARFTypeUnit::dump(raw_ostream &OS, bool SummarizeTypes) { << " (next unit at " << format("0x%08x", getNextUnitOffset()) << ")\n"; if (DWARFDie TU = getUnitDIE(false)) - TU.dump(OS, -1U); + TU.dump(OS, 0, DumpOpts); else OS << "<type unit can't be parsed!>\n\n"; } diff --git a/lib/DebugInfo/DWARF/DWARFUnit.cpp b/lib/DebugInfo/DWARF/DWARFUnit.cpp index 043bdb874f43..c3d8ff2cbc29 100644 --- a/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -30,18 +30,20 @@ using namespace llvm; using namespace dwarf; void DWARFUnitSectionBase::parse(DWARFContext &C, const DWARFSection &Section) { - parseImpl(C, Section, C.getDebugAbbrev(), &C.getRangeSection(), - C.getStringSection(), C.getStringOffsetSection(), - &C.getAddrSection(), C.getLineSection(), C.isLittleEndian(), false); + const DWARFObject &D = C.getDWARFObj(); + parseImpl(C, Section, C.getDebugAbbrev(), &D.getRangeSection(), + D.getStringSection(), D.getStringOffsetSection(), + &D.getAddrSection(), D.getLineSection(), D.isLittleEndian(), false, + false); } void DWARFUnitSectionBase::parseDWO(DWARFContext &C, - const DWARFSection &DWOSection, - DWARFUnitIndex *Index) { - parseImpl(C, DWOSection, C.getDebugAbbrevDWO(), &C.getRangeDWOSection(), - C.getStringDWOSection(), C.getStringOffsetDWOSection(), - &C.getAddrSection(), C.getLineDWOSection(), C.isLittleEndian(), - true); + const DWARFSection &DWOSection, bool Lazy) { + const DWARFObject &D = C.getDWARFObj(); + parseImpl(C, DWOSection, C.getDebugAbbrevDWO(), &D.getRangeDWOSection(), + D.getStringDWOSection(), D.getStringOffsetDWOSection(), + &D.getAddrSection(), D.getLineDWOSection(), C.isLittleEndian(), + true, Lazy); } DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section, @@ -59,13 +61,18 @@ DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section, DWARFUnit::~DWARFUnit() = default; +DWARFDataExtractor DWARFUnit::getDebugInfoExtractor() const { + return DWARFDataExtractor(Context.getDWARFObj(), InfoSection, isLittleEndian, + getAddressByteSize()); +} + bool DWARFUnit::getAddrOffsetSectionItem(uint32_t Index, uint64_t &Result) const { uint32_t Offset = AddrOffsetSectionBase + Index * getAddressByteSize(); if (AddrOffsetSection->Data.size() < Offset + getAddressByteSize()) return false; - DWARFDataExtractor DA(*AddrOffsetSection, isLittleEndian, - getAddressByteSize()); + DWARFDataExtractor DA(Context.getDWARFObj(), *AddrOffsetSection, + isLittleEndian, getAddressByteSize()); Result = DA.getRelocatedAddress(&Offset); return true; } @@ -76,7 +83,8 @@ bool DWARFUnit::getStringOffsetSectionItem(uint32_t Index, uint32_t Offset = StringOffsetSectionBase + Index * ItemSize; if (StringOffsetSection.Data.size() < Offset + ItemSize) return false; - DWARFDataExtractor DA(StringOffsetSection, isLittleEndian, 0); + DWARFDataExtractor DA(Context.getDWARFObj(), StringOffsetSection, + isLittleEndian, 0); Result = DA.getRelocatedValue(ItemSize, &Offset); return true; } @@ -86,7 +94,6 @@ bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { // FIXME: Support DWARF64. FormParams.Format = DWARF32; FormParams.Version = debug_info.getU16(offset_ptr); - uint64_t AbbrOffset; if (FormParams.Version >= 5) { UnitType = debug_info.getU8(offset_ptr); FormParams.AddrSize = debug_info.getU8(offset_ptr); @@ -116,9 +123,7 @@ bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { // Keep track of the highest DWARF version we encounter across all units. Context.setMaxVersionIfGreater(getVersion()); - - Abbrevs = Abbrev->getAbbreviationDeclarationSet(AbbrOffset); - return Abbrevs != nullptr; + return true; } bool DWARFUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) { @@ -141,8 +146,8 @@ bool DWARFUnit::extractRangeList(uint32_t RangeListOffset, DWARFDebugRangeList &RangeList) const { // Require that compile unit is extracted. assert(!DieArray.empty()); - DWARFDataExtractor RangesData(*RangeSection, isLittleEndian, - getAddressByteSize()); + DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection, + isLittleEndian, getAddressByteSize()); uint32_t ActualRangeListOffset = RangeSectionBase + RangeListOffset; return RangeList.extract(RangesData, &ActualRangeListOffset); } @@ -152,7 +157,7 @@ void DWARFUnit::clear() { Length = 0; Abbrevs = nullptr; FormParams = DWARFFormParams({0, 0, DWARF32}); - BaseAddr = 0; + BaseAddr.reset(); RangeSectionBase = 0; AddrOffsetSectionBase = 0; clearDIEs(false); @@ -234,11 +239,17 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) { // If CU DIE was just parsed, copy several attribute values from it. if (!HasCUDie) { DWARFDie UnitDie = getUnitDIE(); - auto BaseAddr = toAddress(UnitDie.find({DW_AT_low_pc, DW_AT_entry_pc})); - if (BaseAddr) - setBaseAddress(*BaseAddr); - AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base), 0); - RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0); + Optional<DWARFFormValue> PC = UnitDie.find({DW_AT_low_pc, DW_AT_entry_pc}); + if (Optional<uint64_t> Addr = toAddress(PC)) + setBaseAddress({*Addr, PC->getSectionIndex()}); + + if (!isDWO) { + assert(AddrOffsetSectionBase == 0); + assert(RangeSectionBase == 0); + AddrOffsetSectionBase = + toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base), 0); + RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0); + } // In general, we derive the offset of the unit's contibution to the // debug_str_offsets{.dwo} section from the unit DIE's @@ -295,18 +306,8 @@ bool DWARFUnit::parseDWO() { void DWARFUnit::clearDIEs(bool KeepCUDie) { if (DieArray.size() > (unsigned)KeepCUDie) { - // std::vectors never get any smaller when resized to a smaller size, - // or when clear() or erase() are called, the size will report that it - // is smaller, but the memory allocated remains intact (call capacity() - // to see this). So we need to create a temporary vector and swap the - // contents which will cause just the internal pointers to be swapped - // so that when temporary vector goes out of scope, it will destroy the - // contents. - std::vector<DWARFDebugInfoEntry> TmpArray; - DieArray.swap(TmpArray); - // Save at least the compile unit DIE - if (KeepCUDie) - DieArray.push_back(TmpArray.front()); + DieArray.resize((unsigned)KeepCUDie); + DieArray.shrink_to_fit(); } } @@ -439,7 +440,7 @@ DWARFDie DWARFUnit::getSibling(const DWARFDebugInfoEntry *Die) { // NULL DIEs don't have siblings. if (Die->getAbbreviationDeclarationPtr() == nullptr) return DWARFDie(); - + // Find the next DIE whose depth is the same as the Die's depth. for (size_t I = getDIEIndex(Die) + 1, EndIdx = DieArray.size(); I < EndIdx; ++I) { @@ -448,3 +449,20 @@ DWARFDie DWARFUnit::getSibling(const DWARFDebugInfoEntry *Die) { } return DWARFDie(); } + +DWARFDie DWARFUnit::getFirstChild(const DWARFDebugInfoEntry *Die) { + if (!Die->hasChildren()) + return DWARFDie(); + + // We do not want access out of bounds when parsing corrupted debug data. + size_t I = getDIEIndex(Die) + 1; + if (I >= DieArray.size()) + return DWARFDie(); + return DWARFDie(this, &DieArray[I]); +} + +const DWARFAbbreviationDeclarationSet *DWARFUnit::getAbbreviations() const { + if (!Abbrevs) + Abbrevs = Abbrev->getAbbreviationDeclarationSet(AbbrOffset); + return Abbrevs; +} diff --git a/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp b/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp index 59b3d0ca55a6..17f17572a309 100644 --- a/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp +++ b/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp @@ -123,7 +123,7 @@ StringRef DWARFUnitIndex::getColumnHeader(DWARFSectionKind DS) { } void DWARFUnitIndex::dump(raw_ostream &OS) const { - if (!Header.NumBuckets) + if (!*this) return; Header.dump(OS); @@ -165,8 +165,25 @@ DWARFUnitIndex::Entry::getOffset() const { const DWARFUnitIndex::Entry * DWARFUnitIndex::getFromOffset(uint32_t Offset) const { for (uint32_t i = 0; i != Header.NumBuckets; ++i) - if (const auto &Contribs = Rows[i].Contributions) - if (Contribs[InfoColumn].Offset == Offset) + if (const auto &Contribs = Rows[i].Contributions) { + const auto &InfoContrib = Contribs[InfoColumn]; + if (InfoContrib.Offset <= Offset && + Offset < (InfoContrib.Offset + InfoContrib.Length)) return &Rows[i]; + } return nullptr; } + +const DWARFUnitIndex::Entry *DWARFUnitIndex::getFromHash(uint64_t S) const { + uint64_t Mask = Header.NumBuckets - 1; + + auto H = S & Mask; + auto HP = ((S >> 32) & Mask) | 1; + while (Rows[H].getSignature() != S && Rows[H].getSignature() != 0) + H = (H + HP) & Mask; + + if (Rows[H].getSignature() != S) + return nullptr; + + return &Rows[H]; +} diff --git a/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/lib/DebugInfo/DWARF/DWARFVerifier.cpp index 4de46bea301e..3d473698b463 100644 --- a/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ b/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -7,14 +7,17 @@ // //===----------------------------------------------------------------------===// +#include "SyntaxHighlighting.h" #include "llvm/DebugInfo/DWARF/DWARFVerifier.h" #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" #include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFSection.h" #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/raw_ostream.h" #include <map> #include <set> @@ -23,6 +26,86 @@ using namespace llvm; using namespace dwarf; using namespace object; +using namespace syntax; + +DWARFVerifier::DieRangeInfo::address_range_iterator +DWARFVerifier::DieRangeInfo::insert(const DWARFAddressRange &R) { + auto Begin = Ranges.begin(); + auto End = Ranges.end(); + auto Pos = std::lower_bound(Begin, End, R); + + if (Pos != End) { + if (Pos->intersects(R)) + return Pos; + if (Pos != Begin) { + auto Iter = Pos - 1; + if (Iter->intersects(R)) + return Iter; + } + } + + Ranges.insert(Pos, R); + return Ranges.end(); +} + +DWARFVerifier::DieRangeInfo::die_range_info_iterator +DWARFVerifier::DieRangeInfo::insert(const DieRangeInfo &RI) { + auto End = Children.end(); + auto Iter = Children.begin(); + while (Iter != End) { + if (Iter->intersects(RI)) + return Iter; + ++Iter; + } + Children.insert(RI); + return Children.end(); +} + +bool DWARFVerifier::DieRangeInfo::contains(const DieRangeInfo &RHS) const { + // Both list of ranges are sorted so we can make this fast. + + if (Ranges.empty() || RHS.Ranges.empty()) + return false; + + // Since the ranges are sorted we can advance where we start searching with + // this object's ranges as we traverse RHS.Ranges. + auto End = Ranges.end(); + auto Iter = findRange(RHS.Ranges.front()); + + // Now linearly walk the ranges in this object and see if they contain each + // ranges from RHS.Ranges. + for (const auto &R : RHS.Ranges) { + while (Iter != End) { + if (Iter->contains(R)) + break; + ++Iter; + } + if (Iter == End) + return false; + } + return true; +} + +bool DWARFVerifier::DieRangeInfo::intersects(const DieRangeInfo &RHS) const { + if (Ranges.empty() || RHS.Ranges.empty()) + return false; + + auto End = Ranges.end(); + auto Iter = findRange(RHS.Ranges.front()); + for (const auto &R : RHS.Ranges) { + if(Iter == End) + return false; + if (R.HighPC <= Iter->LowPC) + continue; + while (Iter != End) { + if (Iter->intersects(R)) + return true; + ++Iter; + } + } + + return false; +} bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData, uint32_t *Offset, unsigned UnitIndex, @@ -53,7 +136,7 @@ bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData, UnitType = DebugInfoData.getU8(Offset); AddrSize = DebugInfoData.getU8(Offset); AbbrOffset = DebugInfoData.getU32(Offset); - ValidType = DWARFUnit::isValidUnitType(UnitType); + ValidType = dwarf::isUnitType(UnitType); } else { UnitType = 0; AbbrOffset = DebugInfoData.getU32(Offset); @@ -69,25 +152,26 @@ bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData, if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset || !ValidType) { Success = false; - OS << format("Units[%d] - start offset: 0x%08x \n", UnitIndex, OffsetStart); + error() << format("Units[%d] - start offset: 0x%08x \n", UnitIndex, + OffsetStart); if (!ValidLength) - OS << "\tError: The length for this unit is too " + note() << "The length for this unit is too " "large for the .debug_info provided.\n"; if (!ValidVersion) - OS << "\tError: The 16 bit unit header version is not valid.\n"; + note() << "The 16 bit unit header version is not valid.\n"; if (!ValidType) - OS << "\tError: The unit type encoding is not valid.\n"; + note() << "The unit type encoding is not valid.\n"; if (!ValidAbbrevOffset) - OS << "\tError: The offset into the .debug_abbrev section is " + note() << "The offset into the .debug_abbrev section is " "not valid.\n"; if (!ValidAddrSize) - OS << "\tError: The address size is unsupported.\n"; + note() << "The address size is unsupported.\n"; } *Offset = OffsetStart + Length + 4; return Success; } -bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit) { +bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit, uint8_t UnitType) { uint32_t NumUnitErrors = 0; unsigned NumDies = Unit.getNumDIEs(); for (unsigned I = 0; I < NumDies; ++I) { @@ -99,20 +183,89 @@ bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit) { NumUnitErrors += verifyDebugInfoForm(Die, AttrValue); } } + + DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false); + if (!Die) { + error() << "Compilation unit without DIE.\n"; + NumUnitErrors++; + return NumUnitErrors == 0; + } + + if (!dwarf::isUnitType(Die.getTag())) { + error() << "Compilation unit root DIE is not a unit DIE: " + << dwarf::TagString(Die.getTag()) << ".\n"; + NumUnitErrors++; + } + + if (UnitType != 0 && + !DWARFUnit::isMatchingUnitTypeAndTag(UnitType, Die.getTag())) { + error() << "Compilation unit type (" << dwarf::UnitTypeString(UnitType) + << ") and root DIE (" << dwarf::TagString(Die.getTag()) + << ") do not match.\n"; + NumUnitErrors++; + } + + DieRangeInfo RI; + NumUnitErrors += verifyDieRanges(Die, RI); + return NumUnitErrors == 0; } +unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) { + unsigned NumErrors = 0; + if (Abbrev) { + const DWARFAbbreviationDeclarationSet *AbbrDecls = + Abbrev->getAbbreviationDeclarationSet(0); + for (auto AbbrDecl : *AbbrDecls) { + SmallDenseSet<uint16_t> AttributeSet; + for (auto Attribute : AbbrDecl.attributes()) { + auto Result = AttributeSet.insert(Attribute.Attr); + if (!Result.second) { + error() << "Abbreviation declaration contains multiple " + << AttributeString(Attribute.Attr) << " attributes.\n"; + AbbrDecl.dump(OS); + ++NumErrors; + } + } + } + } + return NumErrors; +} + +bool DWARFVerifier::handleDebugAbbrev() { + OS << "Verifying .debug_abbrev...\n"; + + const DWARFObject &DObj = DCtx.getDWARFObj(); + bool noDebugAbbrev = DObj.getAbbrevSection().empty(); + bool noDebugAbbrevDWO = DObj.getAbbrevDWOSection().empty(); + + if (noDebugAbbrev && noDebugAbbrevDWO) { + return true; + } + + unsigned NumErrors = 0; + if (!noDebugAbbrev) + NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev()); + + if (!noDebugAbbrevDWO) + NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO()); + return NumErrors == 0; +} + bool DWARFVerifier::handleDebugInfo() { OS << "Verifying .debug_info Unit Header Chain...\n"; - DWARFDataExtractor DebugInfoData(DCtx.getInfoSection(), DCtx.isLittleEndian(), - 0); + const DWARFObject &DObj = DCtx.getDWARFObj(); + DWARFDataExtractor DebugInfoData(DObj, DObj.getInfoSection(), + DCtx.isLittleEndian(), 0); uint32_t NumDebugInfoErrors = 0; uint32_t OffsetStart = 0, Offset = 0, UnitIdx = 0; uint8_t UnitType = 0; bool isUnitDWARF64 = false; bool isHeaderChainValid = true; bool hasDIE = DebugInfoData.isValidOffset(Offset); + DWARFUnitSection<DWARFTypeUnit> TUSection{}; + DWARFUnitSection<DWARFCompileUnit> CUSection{}; while (hasDIE) { OffsetStart = Offset; if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, UnitType, @@ -125,12 +278,11 @@ bool DWARFVerifier::handleDebugInfo() { switch (UnitType) { case dwarf::DW_UT_type: case dwarf::DW_UT_split_type: { - DWARFUnitSection<DWARFTypeUnit> TUSection{}; Unit.reset(new DWARFTypeUnit( - DCtx, DCtx.getInfoSection(), DCtx.getDebugAbbrev(), - &DCtx.getRangeSection(), DCtx.getStringSection(), - DCtx.getStringOffsetSection(), &DCtx.getAppleObjCSection(), - DCtx.getLineSection(), DCtx.isLittleEndian(), false, TUSection, + DCtx, DObj.getInfoSection(), DCtx.getDebugAbbrev(), + &DObj.getRangeSection(), DObj.getStringSection(), + DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(), + DObj.getLineSection(), DCtx.isLittleEndian(), false, TUSection, nullptr)); break; } @@ -141,72 +293,141 @@ bool DWARFVerifier::handleDebugInfo() { // UnitType = 0 means that we are // verifying a compile unit in DWARF v4. case 0: { - DWARFUnitSection<DWARFCompileUnit> CUSection{}; Unit.reset(new DWARFCompileUnit( - DCtx, DCtx.getInfoSection(), DCtx.getDebugAbbrev(), - &DCtx.getRangeSection(), DCtx.getStringSection(), - DCtx.getStringOffsetSection(), &DCtx.getAppleObjCSection(), - DCtx.getLineSection(), DCtx.isLittleEndian(), false, CUSection, + DCtx, DObj.getInfoSection(), DCtx.getDebugAbbrev(), + &DObj.getRangeSection(), DObj.getStringSection(), + DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(), + DObj.getLineSection(), DCtx.isLittleEndian(), false, CUSection, nullptr)); break; } default: { llvm_unreachable("Invalid UnitType."); } } Unit->extract(DebugInfoData, &OffsetStart); - if (!verifyUnitContents(*Unit)) + if (!verifyUnitContents(*Unit, UnitType)) ++NumDebugInfoErrors; } hasDIE = DebugInfoData.isValidOffset(Offset); ++UnitIdx; } if (UnitIdx == 0 && !hasDIE) { - OS << "Warning: .debug_info is empty.\n"; + warn() << ".debug_info is empty.\n"; isHeaderChainValid = true; } NumDebugInfoErrors += verifyDebugInfoReferences(); return (isHeaderChainValid && NumDebugInfoErrors == 0); } +unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die, + DieRangeInfo &ParentRI) { + unsigned NumErrors = 0; + + if (!Die.isValid()) + return NumErrors; + + DWARFAddressRangesVector Ranges = Die.getAddressRanges(); + + // Build RI for this DIE and check that ranges within this DIE do not + // overlap. + DieRangeInfo RI(Die); + for (auto Range : Ranges) { + if (!Range.valid()) { + ++NumErrors; + error() << "Invalid address range " << Range << "\n"; + continue; + } + + // Verify that ranges don't intersect. + const auto IntersectingRange = RI.insert(Range); + if (IntersectingRange != RI.Ranges.end()) { + ++NumErrors; + error() << "DIE has overlapping address ranges: " << Range << " and " + << *IntersectingRange << "\n"; + break; + } + } + + // Verify that children don't intersect. + const auto IntersectingChild = ParentRI.insert(RI); + if (IntersectingChild != ParentRI.Children.end()) { + ++NumErrors; + error() << "DIEs have overlapping address ranges:"; + Die.dump(OS, 0); + IntersectingChild->Die.dump(OS, 0); + OS << "\n"; + } + + // Verify that ranges are contained within their parent. + bool ShouldBeContained = !Ranges.empty() && !ParentRI.Ranges.empty() && + !(Die.getTag() == DW_TAG_subprogram && + ParentRI.Die.getTag() == DW_TAG_subprogram); + if (ShouldBeContained && !ParentRI.contains(RI)) { + ++NumErrors; + error() << "DIE address ranges are not " + "contained in its parent's ranges:"; + Die.dump(OS, 0); + ParentRI.Die.dump(OS, 0); + OS << "\n"; + } + + // Recursively check children. + for (DWARFDie Child : Die) + NumErrors += verifyDieRanges(Child, RI); + + return NumErrors; +} + unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, DWARFAttribute &AttrValue) { unsigned NumErrors = 0; + auto ReportError = [&](const Twine &TitleMsg) { + ++NumErrors; + error() << TitleMsg << '\n'; + Die.dump(OS, 0, DumpOpts); + OS << "\n"; + }; + + const DWARFObject &DObj = DCtx.getDWARFObj(); const auto Attr = AttrValue.Attr; switch (Attr) { case DW_AT_ranges: // Make sure the offset in the DW_AT_ranges attribute is valid. if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { - if (*SectionOffset >= DCtx.getRangeSection().Data.size()) { - ++NumErrors; - OS << "error: DW_AT_ranges offset is beyond .debug_ranges " - "bounds:\n"; - Die.dump(OS, 0); - OS << "\n"; - } - } else { - ++NumErrors; - OS << "error: DIE has invalid DW_AT_ranges encoding:\n"; - Die.dump(OS, 0); - OS << "\n"; + if (*SectionOffset >= DObj.getRangeSection().Data.size()) + ReportError("DW_AT_ranges offset is beyond .debug_ranges bounds:"); + break; } + ReportError("DIE has invalid DW_AT_ranges encoding:"); break; case DW_AT_stmt_list: // Make sure the offset in the DW_AT_stmt_list attribute is valid. if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { - if (*SectionOffset >= DCtx.getLineSection().Data.size()) { - ++NumErrors; - OS << "error: DW_AT_stmt_list offset is beyond .debug_line " - "bounds: " - << format("0x%08" PRIx64, *SectionOffset) << "\n"; - Die.dump(OS, 0); - OS << "\n"; - } - } else { - ++NumErrors; - OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n"; - Die.dump(OS, 0); - OS << "\n"; + if (*SectionOffset >= DObj.getLineSection().Data.size()) + ReportError("DW_AT_stmt_list offset is beyond .debug_line bounds: " + + llvm::formatv("{0:x8}", *SectionOffset)); + break; } + ReportError("DIE has invalid DW_AT_stmt_list encoding:"); + break; + case DW_AT_location: { + Optional<ArrayRef<uint8_t>> Expr = AttrValue.Value.getAsBlock(); + if (!Expr) { + ReportError("DIE has invalid DW_AT_location encoding:"); + break; + } + + DWARFUnit *U = Die.getDwarfUnit(); + DataExtractor Data( + StringRef(reinterpret_cast<const char *>(Expr->data()), Expr->size()), + DCtx.isLittleEndian(), 0); + DWARFExpression Expression(Data, U->getVersion(), U->getAddressByteSize()); + bool Error = llvm::any_of(Expression, [](DWARFExpression::Operation &Op) { + return Op.isError(); + }); + if (Error) + ReportError("DIE contains invalid DWARF expression:"); break; + } default: break; @@ -216,6 +437,7 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, DWARFAttribute &AttrValue) { + const DWARFObject &DObj = DCtx.getDWARFObj(); unsigned NumErrors = 0; const auto Form = AttrValue.Value.getForm(); switch (Form) { @@ -233,11 +455,11 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, auto CUOffset = AttrValue.Value.getRawUValue(); if (CUOffset >= CUSize) { ++NumErrors; - OS << "error: " << FormEncodingString(Form) << " CU offset " - << format("0x%08" PRIx64, CUOffset) - << " is invalid (must be less than CU size of " - << format("0x%08" PRIx32, CUSize) << "):\n"; - Die.dump(OS, 0); + error() << FormEncodingString(Form) << " CU offset " + << format("0x%08" PRIx64, CUOffset) + << " is invalid (must be less than CU size of " + << format("0x%08" PRIx32, CUSize) << "):\n"; + Die.dump(OS, 0, DumpOpts); OS << "\n"; } else { // Valid reference, but we will verify it points to an actual @@ -253,11 +475,11 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, Optional<uint64_t> RefVal = AttrValue.Value.getAsReference(); assert(RefVal); if (RefVal) { - if (*RefVal >= DCtx.getInfoSection().Data.size()) { + if (*RefVal >= DObj.getInfoSection().Data.size()) { ++NumErrors; - OS << "error: DW_FORM_ref_addr offset beyond .debug_info " - "bounds:\n"; - Die.dump(OS, 0); + error() << "DW_FORM_ref_addr offset beyond .debug_info " + "bounds:\n"; + Die.dump(OS, 0, DumpOpts); OS << "\n"; } else { // Valid reference, but we will verify it points to an actual @@ -270,10 +492,10 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, case DW_FORM_strp: { auto SecOffset = AttrValue.Value.getAsSectionOffset(); assert(SecOffset); // DW_FORM_strp is a section offset. - if (SecOffset && *SecOffset >= DCtx.getStringSection().size()) { + if (SecOffset && *SecOffset >= DObj.getStringSection().size()) { ++NumErrors; - OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n"; - Die.dump(OS, 0); + error() << "DW_FORM_strp offset beyond .debug_str bounds:\n"; + Die.dump(OS, 0, DumpOpts); OS << "\n"; } break; @@ -294,11 +516,11 @@ unsigned DWARFVerifier::verifyDebugInfoReferences() { if (Die) continue; ++NumErrors; - OS << "error: invalid DIE reference " << format("0x%08" PRIx64, Pair.first) - << ". Offset is in between DIEs:\n"; + error() << "invalid DIE reference " << format("0x%08" PRIx64, Pair.first) + << ". Offset is in between DIEs:\n"; for (auto Offset : Pair.second) { auto ReferencingDie = DCtx.getDIEForOffset(Offset); - ReferencingDie.dump(OS, 0); + ReferencingDie.dump(OS, 0, DumpOpts); OS << "\n"; } OS << "\n"; @@ -318,12 +540,12 @@ void DWARFVerifier::verifyDebugLineStmtOffsets() { continue; const uint32_t LineTableOffset = *StmtSectionOffset; auto LineTable = DCtx.getLineTableForUnit(CU.get()); - if (LineTableOffset < DCtx.getLineSection().Data.size()) { + if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) { if (!LineTable) { ++NumDebugLineErrors; - OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset) - << "] was not able to be parsed for CU:\n"; - Die.dump(OS, 0); + error() << ".debug_line[" << format("0x%08" PRIx32, LineTableOffset) + << "] was not able to be parsed for CU:\n"; + Die.dump(OS, 0, DumpOpts); OS << '\n'; continue; } @@ -337,12 +559,12 @@ void DWARFVerifier::verifyDebugLineStmtOffsets() { auto Iter = StmtListToDie.find(LineTableOffset); if (Iter != StmtListToDie.end()) { ++NumDebugLineErrors; - OS << "error: two compile unit DIEs, " - << format("0x%08" PRIx32, Iter->second.getOffset()) << " and " - << format("0x%08" PRIx32, Die.getOffset()) - << ", have the same DW_AT_stmt_list section offset:\n"; - Iter->second.dump(OS, 0); - Die.dump(OS, 0); + error() << "two compile unit DIEs, " + << format("0x%08" PRIx32, Iter->second.getOffset()) << " and " + << format("0x%08" PRIx32, Die.getOffset()) + << ", have the same DW_AT_stmt_list section offset:\n"; + Iter->second.dump(OS, 0, DumpOpts); + Die.dump(OS, 0, DumpOpts); OS << '\n'; // Already verified this line table before, no need to do it again. continue; @@ -359,17 +581,57 @@ void DWARFVerifier::verifyDebugLineRows() { // .debug_info verifier or in verifyDebugLineStmtOffsets(). if (!LineTable) continue; + + // Verify prologue. uint32_t MaxFileIndex = LineTable->Prologue.FileNames.size(); + uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size(); + uint32_t FileIndex = 1; + StringMap<uint16_t> FullPathMap; + for (const auto &FileName : LineTable->Prologue.FileNames) { + // Verify directory index. + if (FileName.DirIdx > MaxDirIndex) { + ++NumDebugLineErrors; + error() << ".debug_line[" + << format("0x%08" PRIx64, + *toSectionOffset(Die.find(DW_AT_stmt_list))) + << "].prologue.file_names[" << FileIndex + << "].dir_idx contains an invalid index: " << FileName.DirIdx + << "\n"; + } + + // Check file paths for duplicates. + std::string FullPath; + const bool HasFullPath = LineTable->getFileNameByIndex( + FileIndex, CU->getCompilationDir(), + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FullPath); + assert(HasFullPath && "Invalid index?"); + (void)HasFullPath; + auto It = FullPathMap.find(FullPath); + if (It == FullPathMap.end()) + FullPathMap[FullPath] = FileIndex; + else if (It->second != FileIndex) { + warn() << ".debug_line[" + << format("0x%08" PRIx64, + *toSectionOffset(Die.find(DW_AT_stmt_list))) + << "].prologue.file_names[" << FileIndex + << "] is a duplicate of file_names[" << It->second << "]\n"; + } + + FileIndex++; + } + + // Verify rows. uint64_t PrevAddress = 0; uint32_t RowIndex = 0; for (const auto &Row : LineTable->Rows) { + // Verify row address. if (Row.Address < PrevAddress) { ++NumDebugLineErrors; - OS << "error: .debug_line[" - << format("0x%08" PRIx64, - *toSectionOffset(Die.find(DW_AT_stmt_list))) - << "] row[" << RowIndex - << "] decreases in address from previous row:\n"; + error() << ".debug_line[" + << format("0x%08" PRIx64, + *toSectionOffset(Die.find(DW_AT_stmt_list))) + << "] row[" << RowIndex + << "] decreases in address from previous row:\n"; DWARFDebugLine::Row::dumpTableHeader(OS); if (RowIndex > 0) @@ -378,13 +640,14 @@ void DWARFVerifier::verifyDebugLineRows() { OS << '\n'; } + // Verify file index. if (Row.File > MaxFileIndex) { ++NumDebugLineErrors; - OS << "error: .debug_line[" - << format("0x%08" PRIx64, - *toSectionOffset(Die.find(DW_AT_stmt_list))) - << "][" << RowIndex << "] has invalid file index " << Row.File - << " (valid values are [1," << MaxFileIndex << "]):\n"; + error() << ".debug_line[" + << format("0x%08" PRIx64, + *toSectionOffset(Die.find(DW_AT_stmt_list))) + << "][" << RowIndex << "] has invalid file index " << Row.File + << " (valid values are [1," << MaxFileIndex << "]):\n"; DWARFDebugLine::Row::dumpTableHeader(OS); Row.dump(OS); OS << '\n'; @@ -406,94 +669,137 @@ bool DWARFVerifier::handleDebugLine() { return NumDebugLineErrors == 0; } -bool DWARFVerifier::handleAppleNames() { - NumAppleNamesErrors = 0; +unsigned DWARFVerifier::verifyAccelTable(const DWARFSection *AccelSection, + DataExtractor *StrData, + const char *SectionName) { + unsigned NumErrors = 0; + DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), *AccelSection, + DCtx.isLittleEndian(), 0); + DWARFAcceleratorTable AccelTable(AccelSectionData, *StrData); - DWARFDataExtractor AppleNamesSection(DCtx.getAppleNamesSection(), - DCtx.isLittleEndian(), 0); - DataExtractor StrData(DCtx.getStringSection(), DCtx.isLittleEndian(), 0); - DWARFAcceleratorTable AppleNames(AppleNamesSection, StrData); + OS << "Verifying " << SectionName << "...\n"; - if (!AppleNames.extract()) { - return true; + // Verify that the fixed part of the header is not too short. + if (!AccelSectionData.isValidOffset(AccelTable.getSizeHdr())) { + error() << "Section is too small to fit a section header.\n"; + return 1; } - OS << "Verifying .apple_names...\n"; + // Verify that the section is not too short. + if (Error E = AccelTable.extract()) { + error() << toString(std::move(E)) << '\n'; + return 1; + } // Verify that all buckets have a valid hash index or are empty. - uint32_t NumBuckets = AppleNames.getNumBuckets(); - uint32_t NumHashes = AppleNames.getNumHashes(); + uint32_t NumBuckets = AccelTable.getNumBuckets(); + uint32_t NumHashes = AccelTable.getNumHashes(); uint32_t BucketsOffset = - AppleNames.getSizeHdr() + AppleNames.getHeaderDataLength(); + AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength(); uint32_t HashesBase = BucketsOffset + NumBuckets * 4; uint32_t OffsetsBase = HashesBase + NumHashes * 4; - for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) { - uint32_t HashIdx = AppleNamesSection.getU32(&BucketsOffset); + uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset); if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) { - OS << format("error: Bucket[%d] has invalid hash index: %u\n", BucketIdx, - HashIdx); - ++NumAppleNamesErrors; + error() << format("Bucket[%d] has invalid hash index: %u.\n", BucketIdx, + HashIdx); + ++NumErrors; } } - - uint32_t NumAtoms = AppleNames.getAtomsDesc().size(); + uint32_t NumAtoms = AccelTable.getAtomsDesc().size(); if (NumAtoms == 0) { - OS << "error: no atoms; failed to read HashData\n"; - ++NumAppleNamesErrors; - return false; + error() << "No atoms: failed to read HashData.\n"; + return 1; } - - if (!AppleNames.validateForms()) { - OS << "error: unsupported form; failed to read HashData\n"; - ++NumAppleNamesErrors; - return false; + if (!AccelTable.validateForms()) { + error() << "Unsupported form: failed to read HashData.\n"; + return 1; } for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) { uint32_t HashOffset = HashesBase + 4 * HashIdx; uint32_t DataOffset = OffsetsBase + 4 * HashIdx; - uint32_t Hash = AppleNamesSection.getU32(&HashOffset); - uint32_t HashDataOffset = AppleNamesSection.getU32(&DataOffset); - if (!AppleNamesSection.isValidOffsetForDataOfSize(HashDataOffset, - sizeof(uint64_t))) { - OS << format("error: Hash[%d] has invalid HashData offset: 0x%08x\n", - HashIdx, HashDataOffset); - ++NumAppleNamesErrors; + uint32_t Hash = AccelSectionData.getU32(&HashOffset); + uint32_t HashDataOffset = AccelSectionData.getU32(&DataOffset); + if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset, + sizeof(uint64_t))) { + error() << format("Hash[%d] has invalid HashData offset: 0x%08x.\n", + HashIdx, HashDataOffset); + ++NumErrors; } uint32_t StrpOffset; uint32_t StringOffset; uint32_t StringCount = 0; - uint32_t DieOffset = dwarf::DW_INVALID_OFFSET; - - while ((StrpOffset = AppleNamesSection.getU32(&HashDataOffset)) != 0) { + unsigned Offset; + unsigned Tag; + while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) { const uint32_t NumHashDataObjects = - AppleNamesSection.getU32(&HashDataOffset); + AccelSectionData.getU32(&HashDataOffset); for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects; ++HashDataIdx) { - DieOffset = AppleNames.readAtoms(HashDataOffset); - if (!DCtx.getDIEForOffset(DieOffset)) { + std::tie(Offset, Tag) = AccelTable.readAtoms(HashDataOffset); + auto Die = DCtx.getDIEForOffset(Offset); + if (!Die) { const uint32_t BucketIdx = NumBuckets ? (Hash % NumBuckets) : UINT32_MAX; StringOffset = StrpOffset; - const char *Name = StrData.getCStr(&StringOffset); + const char *Name = StrData->getCStr(&StringOffset); if (!Name) Name = "<NULL>"; - OS << format( - "error: .apple_names Bucket[%d] Hash[%d] = 0x%08x " + error() << format( + "%s Bucket[%d] Hash[%d] = 0x%08x " "Str[%u] = 0x%08x " "DIE[%d] = 0x%08x is not a valid DIE offset for \"%s\".\n", - BucketIdx, HashIdx, Hash, StringCount, StrpOffset, HashDataIdx, - DieOffset, Name); + SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset, + HashDataIdx, Offset, Name); - ++NumAppleNamesErrors; + ++NumErrors; + continue; + } + if ((Tag != dwarf::DW_TAG_null) && (Die.getTag() != Tag)) { + error() << "Tag " << dwarf::TagString(Tag) + << " in accelerator table does not match Tag " + << dwarf::TagString(Die.getTag()) << " of DIE[" << HashDataIdx + << "].\n"; + ++NumErrors; } } ++StringCount; } } - return NumAppleNamesErrors == 0; + return NumErrors; +} + +bool DWARFVerifier::handleAccelTables() { + const DWARFObject &D = DCtx.getDWARFObj(); + DataExtractor StrData(D.getStringSection(), DCtx.isLittleEndian(), 0); + unsigned NumErrors = 0; + if (!D.getAppleNamesSection().Data.empty()) + NumErrors += + verifyAccelTable(&D.getAppleNamesSection(), &StrData, ".apple_names"); + if (!D.getAppleTypesSection().Data.empty()) + NumErrors += + verifyAccelTable(&D.getAppleTypesSection(), &StrData, ".apple_types"); + if (!D.getAppleNamespacesSection().Data.empty()) + NumErrors += verifyAccelTable(&D.getAppleNamespacesSection(), &StrData, + ".apple_namespaces"); + if (!D.getAppleObjCSection().Data.empty()) + NumErrors += + verifyAccelTable(&D.getAppleObjCSection(), &StrData, ".apple_objc"); + return NumErrors == 0; +} + +raw_ostream &DWARFVerifier::error() const { + return WithColor(OS, syntax::Error).get() << "error: "; +} + +raw_ostream &DWARFVerifier::warn() const { + return WithColor(OS, syntax::Warning).get() << "warning: "; +} + +raw_ostream &DWARFVerifier::note() const { + return WithColor(OS, syntax::Note).get() << "note: "; } diff --git a/lib/DebugInfo/DWARF/LLVMBuild.txt b/lib/DebugInfo/DWARF/LLVMBuild.txt index 8242a7f2e7f7..a21276244ea7 100644 --- a/lib/DebugInfo/DWARF/LLVMBuild.txt +++ b/lib/DebugInfo/DWARF/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Library name = DebugInfoDWARF parent = DebugInfo -required_libraries = BinaryFormat Object Support +required_libraries = BinaryFormat Object MC Support diff --git a/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp b/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp index d4f44e446954..65d66fc8f514 100644 --- a/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp +++ b/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp @@ -24,12 +24,15 @@ WithColor::WithColor(raw_ostream &OS, enum HighlightColor Type) : OS(OS) { // Detect color from terminal type unless the user passed the --color option. if (UseColor == cl::BOU_UNSET ? OS.has_colors() : UseColor == cl::BOU_TRUE) { switch (Type) { - case Address: OS.changeColor(raw_ostream::YELLOW); break; - case String: OS.changeColor(raw_ostream::GREEN); break; - case Tag: OS.changeColor(raw_ostream::BLUE); break; - case Attribute: OS.changeColor(raw_ostream::CYAN); break; - case Enumerator: OS.changeColor(raw_ostream::MAGENTA); break; - case Macro: OS.changeColor(raw_ostream::RED); break; + case Address: OS.changeColor(raw_ostream::YELLOW); break; + case String: OS.changeColor(raw_ostream::GREEN); break; + case Tag: OS.changeColor(raw_ostream::BLUE); break; + case Attribute: OS.changeColor(raw_ostream::CYAN); break; + case Enumerator: OS.changeColor(raw_ostream::MAGENTA); break; + case Macro: OS.changeColor(raw_ostream::RED); break; + case Error: OS.changeColor(raw_ostream::RED, true); break; + case Warning: OS.changeColor(raw_ostream::MAGENTA, true); break; + case Note: OS.changeColor(raw_ostream::BLACK, true); break; } } } diff --git a/lib/DebugInfo/DWARF/SyntaxHighlighting.h b/lib/DebugInfo/DWARF/SyntaxHighlighting.h index 277de973dbf0..686cf2c77608 100644 --- a/lib/DebugInfo/DWARF/SyntaxHighlighting.h +++ b/lib/DebugInfo/DWARF/SyntaxHighlighting.h @@ -18,7 +18,17 @@ namespace dwarf { namespace syntax { // Symbolic names for various syntax elements. -enum HighlightColor { Address, String, Tag, Attribute, Enumerator, Macro }; +enum HighlightColor { + Address, + String, + Tag, + Attribute, + Enumerator, + Macro, + Error, + Warning, + Note +}; /// An RAII object that temporarily switches an output stream to a /// specific color. @@ -30,8 +40,8 @@ public: WithColor(raw_ostream &OS, enum HighlightColor Type); ~WithColor(); - raw_ostream& get() { return OS; } - operator raw_ostream& () { return OS; } + raw_ostream &get() { return OS; } + operator raw_ostream &() { return OS; } }; } // end namespace syntax |
