diff options
Diffstat (limited to 'contrib/llvm/lib/DebugInfo/DWARF')
24 files changed, 2331 insertions, 1220 deletions
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp index 08bc74a..bb475a6 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp @@ -1,4 +1,4 @@ -//===-- DWARFAbbreviationDeclaration.cpp ----------------------------------===// +//===- DWARFAbbreviationDeclaration.cpp -----------------------------------===// // // The LLVM Compiler Infrastructure // @@ -8,11 +8,18 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" + +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFUnit.h" -#include "llvm/Support/Dwarf.h" +#include "llvm/Support/DataExtractor.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include <cstddef> +#include <cstdint> + using namespace llvm; using namespace dwarf; @@ -58,47 +65,52 @@ DWARFAbbreviationDeclaration::extract(DataExtractor Data, if (A && F) { Optional<int64_t> V; bool IsImplicitConst = (F == DW_FORM_implicit_const); - if (IsImplicitConst) + if (IsImplicitConst) { V = Data.getSLEB128(OffsetPtr); - else if (auto Size = DWARFFormValue::getFixedByteSize(F)) - V = *Size; - AttributeSpecs.push_back(AttributeSpec(A, F, V)); - if (IsImplicitConst) + AttributeSpecs.push_back(AttributeSpec(A, F, V)); continue; + } // If this abbrevation still has a fixed byte size, then update the // FixedAttributeSize as needed. - if (FixedAttributeSize) { - if (V) - FixedAttributeSize->NumBytes += *V; - else { - switch (F) { - case DW_FORM_addr: - ++FixedAttributeSize->NumAddrs; - break; - - case DW_FORM_ref_addr: - ++FixedAttributeSize->NumRefAddrs; - break; - - case DW_FORM_strp: - case DW_FORM_GNU_ref_alt: - case DW_FORM_GNU_strp_alt: - case DW_FORM_line_strp: - case DW_FORM_sec_offset: - case DW_FORM_strp_sup: - case DW_FORM_ref_sup: - ++FixedAttributeSize->NumDwarfOffsets; - break; - - default: - // Indicate we no longer have a fixed byte size for this - // abbreviation by clearing the FixedAttributeSize optional value - // so it doesn't have a value. - FixedAttributeSize.reset(); - break; - } + switch (F) { + case DW_FORM_addr: + if (FixedAttributeSize) + ++FixedAttributeSize->NumAddrs; + break; + + case DW_FORM_ref_addr: + if (FixedAttributeSize) + ++FixedAttributeSize->NumRefAddrs; + break; + + case DW_FORM_strp: + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + case DW_FORM_line_strp: + case DW_FORM_sec_offset: + case DW_FORM_strp_sup: + if (FixedAttributeSize) + ++FixedAttributeSize->NumDwarfOffsets; + break; + + 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 (FixedAttributeSize) + FixedAttributeSize->NumBytes += *V; + break; } + // Indicate we no longer have a fixed byte size for this + // abbreviation by clearing the FixedAttributeSize optional value + // so it doesn't have a value. + FixedAttributeSize.reset(); + break; } + // Record this attribute and its fixed size if it has one. + AttributeSpecs.push_back(AttributeSpec(A, F, V)); } else if (A == 0 && F == 0) { // We successfully reached the end of this abbreviation declaration // since both attribute and form are zero. @@ -180,7 +192,8 @@ Optional<DWARFFormValue> DWARFAbbreviationDeclaration::getAttributeValue( if (auto FixedSize = Spec.getByteSize(U)) Offset += *FixedSize; else - DWARFFormValue::skipValue(Spec.Form, DebugInfoData, &Offset, &U); + DWARFFormValue::skipValue(Spec.Form, DebugInfoData, &Offset, + U.getFormParams()); ++AttrIndex; } return None; @@ -205,7 +218,8 @@ Optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize( if (ByteSizeOrValue) return ByteSizeOrValue; Optional<int64_t> S; - auto FixedByteSize = DWARFFormValue::getFixedByteSize(Form, &U); + auto FixedByteSize = + DWARFFormValue::getFixedByteSize(Form, U.getFormParams()); if (FixedByteSize) S = *FixedByteSize; return S; diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp index 7111ad3..9ae7c9a 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -1,4 +1,4 @@ -//===--- DWARFAcceleratorTable.cpp ----------------------------------------===// +//===- DWARFAcceleratorTable.cpp ------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -8,11 +8,20 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" -#include "llvm/Support/Dwarf.h" + +#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" #include "llvm/Support/raw_ostream.h" +#include <cstddef> +#include <cstdint> +#include <utility> -namespace llvm { +using namespace llvm; bool DWARFAcceleratorTable::extract() { uint32_t Offset = 0; @@ -46,7 +55,53 @@ bool DWARFAcceleratorTable::extract() { return true; } -void DWARFAcceleratorTable::dump(raw_ostream &OS) const { +uint32_t DWARFAcceleratorTable::getNumBuckets() { return Hdr.NumBuckets; } +uint32_t DWARFAcceleratorTable::getNumHashes() { return Hdr.NumHashes; } +uint32_t DWARFAcceleratorTable::getSizeHdr() { return sizeof(Hdr); } +uint32_t DWARFAcceleratorTable::getHeaderDataLength() { + return Hdr.HeaderDataLength; +} + +ArrayRef<std::pair<DWARFAcceleratorTable::HeaderData::AtomType, + DWARFAcceleratorTable::HeaderData::Form>> +DWARFAcceleratorTable::getAtomsDesc() { + return HdrData.Atoms; +} + +bool DWARFAcceleratorTable::validateForms() { + for (auto Atom : getAtomsDesc()) { + DWARFFormValue FormValue(Atom.second); + switch (Atom.first) { + case dwarf::DW_ATOM_die_offset: + if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) && + !FormValue.isFormClass(DWARFFormValue::FC_Flag)) || + FormValue.getForm() == dwarf::DW_FORM_sdata) + return false; + default: + break; + } + } + return true; +} + +uint32_t DWARFAcceleratorTable::readAtoms(uint32_t &HashDataOffset) { + uint32_t DieOffset = dwarf::DW_INVALID_OFFSET; + + for (auto Atom : getAtomsDesc()) { + DWARFFormValue FormValue(Atom.second); + FormValue.extractValue(AccelSection, &HashDataOffset, NULL); + switch (Atom.first) { + case dwarf::DW_ATOM_die_offset: + DieOffset = *FormValue.getAsUnsignedConstant(); + break; + default: + break; + } + } + return DieOffset; +} + +LLVM_DUMP_METHOD void DWARFAcceleratorTable::dump(raw_ostream &OS) const { // Dump the header. OS << "Magic = " << format("0x%08x", Hdr.Magic) << '\n' << "Version = " << format("0x%04x", Hdr.Version) << '\n' @@ -105,10 +160,7 @@ void DWARFAcceleratorTable::dump(raw_ostream &OS) const { continue; } while (AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) { - unsigned StringOffset = AccelSection.getU32(&DataOffset); - RelocAddrMap::const_iterator Reloc = Relocs.find(DataOffset-4); - if (Reloc != Relocs.end()) - StringOffset += Reloc->second.second; + unsigned StringOffset = AccelSection.getRelocatedValue(4, &DataOffset); if (!StringOffset) break; OS << format(" Name: %08x \"%s\"\n", StringOffset, @@ -131,4 +183,3 @@ void DWARFAcceleratorTable::dump(raw_ostream &OS) const { } } } -} diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp index 948972f..358e9bf 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp @@ -15,17 +15,19 @@ using namespace llvm; -void DWARFCompileUnit::dump(raw_ostream &OS) { +void DWARFCompileUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) { OS << format("0x%08x", getOffset()) << ": Compile Unit:" << " length = " << format("0x%08x", getLength()) - << " version = " << format("0x%04x", getVersion()) - << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset()) + << " version = " << format("0x%04x", getVersion()); + if (getVersion() >= 5) + OS << " unit_type = " << dwarf::UnitTypeString(getUnitType()); + OS << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset()) << " addr_size = " << format("0x%02x", getAddressByteSize()) << " (next unit at " << format("0x%08x", getNextUnitOffset()) << ")\n"; if (DWARFDie CUDie = getUnitDIE(false)) - CUDie.dump(OS, -1U); + CUDie.dump(OS, -1U, 0, DumpOpts); else OS << "<compile unit can't be parsed!>\n\n"; } diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp index 77f6f65..dd32352 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -1,4 +1,4 @@ -//===-- DWARFContext.cpp --------------------------------------------------===// +//===- DWARFContext.cpp ---------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -8,46 +8,191 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" +#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h" +#include "llvm/DebugInfo/DWARF/DWARFSection.h" #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" +#include "llvm/DebugInfo/DWARF/DWARFVerifier.h" #include "llvm/Object/Decompressor.h" #include "llvm/Object/MachO.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Object/RelocVisitor.h" -#include "llvm/Support/Compression.h" -#include "llvm/Support/Dwarf.h" -#include "llvm/Support/ELF.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Error.h" #include "llvm/Support/Format.h" -#include "llvm/Support/Path.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> +#include <cstdint> +#include <map> +#include <string> +#include <tuple> +#include <utility> +#include <vector> + using namespace llvm; using namespace dwarf; using namespace object; #define DEBUG_TYPE "dwarf" -typedef DWARFDebugLine::LineTable DWARFLineTable; -typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind; -typedef DILineInfoSpecifier::FunctionNameKind FunctionNameKind; +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) { - DataExtractor AccelSection(Section.Data, LittleEndian, 0); + DWARFDataExtractor AccelSection(Section, LittleEndian, 0); DataExtractor StrData(StringSection, LittleEndian, 0); OS << "\n." << Name << " contents:\n"; - DWARFAcceleratorTable Accel(AccelSection, StrData, Section.Relocs); + DWARFAcceleratorTable Accel(AccelSection, StrData); if (!Accel.extract()) return; Accel.dump(OS); } -void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH, - bool SummarizeTypes) { +static void +dumpDWARFv5StringOffsetsSection(raw_ostream &OS, StringRef SectionName, + const DWARFSection &StringOffsetsSection, + StringRef StringSection, bool LittleEndian) { + DWARFDataExtractor StrOffsetExt(StringOffsetsSection, LittleEndian, 0); + uint32_t Offset = 0; + uint64_t SectionSize = StringOffsetsSection.Data.size(); + + while (Offset < SectionSize) { + unsigned Version = 0; + DwarfFormat Format = DWARF32; + unsigned EntrySize = 4; + // Perform validation and extract the segment size from the header. + if (!StrOffsetExt.isValidOffsetForDataOfSize(Offset, 4)) { + OS << "error: invalid contribution to string offsets table in section ." + << SectionName << ".\n"; + return; + } + uint32_t ContributionStart = Offset; + uint64_t ContributionSize = StrOffsetExt.getU32(&Offset); + // A contribution size of 0xffffffff indicates DWARF64, with the actual size + // in the following 8 bytes. Otherwise, the DWARF standard mandates that + // the contribution size must be at most 0xfffffff0. + if (ContributionSize == 0xffffffff) { + if (!StrOffsetExt.isValidOffsetForDataOfSize(Offset, 8)) { + OS << "error: invalid contribution to string offsets table in section ." + << SectionName << ".\n"; + return; + } + Format = DWARF64; + EntrySize = 8; + ContributionSize = StrOffsetExt.getU64(&Offset); + } else if (ContributionSize > 0xfffffff0) { + OS << "error: invalid contribution to string offsets table in section ." + << SectionName << ".\n"; + return; + } + + // We must ensure that we don't read a partial record at the end, so we + // validate for a multiple of EntrySize. Also, we're expecting a version + // number and padding, which adds an additional 4 bytes. + uint64_t ValidationSize = + 4 + ((ContributionSize + EntrySize - 1) & (-(uint64_t)EntrySize)); + if (!StrOffsetExt.isValidOffsetForDataOfSize(Offset, ValidationSize)) { + OS << "error: contribution to string offsets table in section ." + << SectionName << " has invalid length.\n"; + return; + } + + Version = StrOffsetExt.getU16(&Offset); + Offset += 2; + OS << format("0x%8.8x: ", ContributionStart); + OS << "Contribution size = " << ContributionSize + << ", Version = " << Version << "\n"; + + uint32_t ContributionBase = Offset; + DataExtractor StrData(StringSection, LittleEndian, 0); + while (Offset - ContributionBase < ContributionSize) { + OS << format("0x%8.8x: ", Offset); + // FIXME: We can only extract strings in DWARF32 format at the moment. + uint64_t StringOffset = + StrOffsetExt.getRelocatedValue(EntrySize, &Offset); + if (Format == DWARF32) { + uint32_t StringOffset32 = (uint32_t)StringOffset; + OS << format("%8.8x ", StringOffset32); + const char *S = StrData.getCStr(&StringOffset32); + if (S) + OS << format("\"%s\"", S); + } else + OS << format("%16.16" PRIx64 " ", StringOffset); + OS << "\n"; + } + } +} + +// Dump a DWARF string offsets section. This may be a DWARF v5 formatted +// string offsets section, where each compile or type unit contributes a +// number of entries (string offsets), with each contribution preceded by +// a header containing size and version number. Alternatively, it may be a +// 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 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, + StringSection, LittleEndian); + else { + DataExtractor strOffsetExt(StringOffsetsSection.Data, LittleEndian, 0); + uint32_t offset = 0; + uint64_t size = StringOffsetsSection.Data.size(); + // Ensure that size is a multiple of the size of an entry. + if (size & ((uint64_t)(sizeof(uint32_t) - 1))) { + OS << "error: size of ." << SectionName << " is not a multiple of " + << sizeof(uint32_t) << ".\n"; + size &= -(uint64_t)sizeof(uint32_t); + } + DataExtractor StrData(StringSection, LittleEndian, 0); + while (offset < size) { + OS << format("0x%8.8x: ", offset); + uint32_t StringOffset = strOffsetExt.getU32(&offset); + OS << format("%8.8x ", StringOffset); + const char *S = StrData.getCStr(&StringOffset); + if (S) + OS << format("\"%s\"", S); + OS << "\n"; + } + } +} + +void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) { + DIDumpType DumpType = DumpOpts.DumpType; + bool DumpEH = DumpOpts.DumpEH; + bool SummarizeTypes = DumpOpts.SummarizeTypes; + if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) { OS << ".debug_abbrev contents:\n"; getDebugAbbrev()->dump(OS); @@ -62,14 +207,14 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH, if (DumpType == DIDT_All || DumpType == DIDT_Info) { OS << "\n.debug_info contents:\n"; for (const auto &CU : compile_units()) - CU->dump(OS); + CU->dump(OS, DumpOpts); } 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); + DWOCU->dump(OS, DumpOpts); } if ((DumpType == DIDT_All || DumpType == DIDT_Types) && getNumTypeUnits()) { @@ -128,13 +273,12 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH, auto CUDIE = CU->getUnitDIE(); if (!CUDIE) continue; - if (auto StmtOffset = - CUDIE.getAttributeValueAsSectionOffset(DW_AT_stmt_list)) { - DataExtractor lineData(getLineSection().Data, isLittleEndian(), - savedAddressByteSize); + 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, &getLineSection().Relocs, &Offset); + LineTable.parse(lineData, &Offset); LineTable.dump(OS); } } @@ -153,8 +297,8 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH, if (DumpType == DIDT_All || DumpType == DIDT_LineDwo) { OS << "\n.debug_line.dwo contents:\n"; unsigned stmtOffset = 0; - DataExtractor lineData(getLineDWOSection().Data, isLittleEndian(), - savedAddressByteSize); + DWARFDataExtractor lineData(getLineDWOSection(), isLittleEndian(), + savedAddressByteSize); DWARFDebugLine::LineTable LineTable; while (LineTable.Prologue.parse(lineData, &stmtOffset)) { LineTable.dump(OS); @@ -191,8 +335,8 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH, // 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). - DataExtractor rangesData(getRangeSection(), isLittleEndian(), - savedAddressByteSize); + DWARFDataExtractor rangesData(getRangeSection(), isLittleEndian(), + savedAddressByteSize); offset = 0; DWARFDebugRangeList rangeList; while (rangeList.extract(rangesData, &offset)) @@ -217,17 +361,15 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH, true /* GnuStyle */) .dump("debug_gnu_pubtypes", OS); - if ((DumpType == DIDT_All || DumpType == DIDT_StrOffsetsDwo) && - !getStringOffsetDWOSection().empty()) { - OS << "\n.debug_str_offsets.dwo contents:\n"; - DataExtractor strOffsetExt(getStringOffsetDWOSection(), isLittleEndian(), - 0); - offset = 0; - uint64_t size = getStringOffsetDWOSection().size(); - while (offset < size) { - OS << format("0x%8.8x: ", offset); - OS << format("%8.8x\n", strOffsetExt.getU32(&offset)); - } + if (DumpType == DIDT_All || DumpType == DIDT_StrOffsets) + dumpStringOffsetsSection(OS, "debug_str_offsets", getStringOffsetSection(), + getStringSection(), isLittleEndian(), + getMaxVersion()); + + if (DumpType == DIDT_All || DumpType == DIDT_StrOffsetsDwo) { + dumpStringOffsetsSection(OS, "debug_str_offsets.dwo", + getStringOffsetDWOSection(), getStringDWOSection(), + isLittleEndian(), getMaxVersion()); } if ((DumpType == DIDT_All || DumpType == DIDT_GdbIndex) && @@ -253,6 +395,40 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH, getStringSection(), isLittleEndian()); } +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. + for (const auto &DWOCU : dwo_compile_units()) + if (DWOCU->getDWOId() == Hash) + return DWOCU.get(); + return nullptr; +} + +DWARFDie DWARFContext::getDIEForOffset(uint32_t Offset) { + parseCompileUnits(); + if (auto *CU = CUs.getUnitForOffset(Offset)) + return CU->getDIEForOffset(Offset); + return DWARFDie(); +} + +bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) { + 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; + } + return Success; +} + const DWARFUnitIndex &DWARFContext::getCUIndex() { if (CUIndex) return *CUIndex; @@ -310,11 +486,13 @@ const DWARFDebugLoc *DWARFContext::getDebugLoc() { if (Loc) return Loc.get(); - DataExtractor LocData(getLocSection().Data, isLittleEndian(), 0); - Loc.reset(new DWARFDebugLoc(getLocSection().Relocs)); + Loc.reset(new DWARFDebugLoc); // assume all compile units have the same address byte size - if (getNumCompileUnits()) - Loc->parse(LocData, getCompileUnitAtIndex(0)->getAddressByteSize()); + if (getNumCompileUnits()) { + DWARFDataExtractor LocData(getLocSection(), isLittleEndian(), + getCompileUnitAtIndex(0)->getAddressByteSize()); + Loc->parse(LocData); + } return Loc.get(); } @@ -381,13 +559,13 @@ const DWARFDebugMacro *DWARFContext::getDebugMacro() { const DWARFLineTable * DWARFContext::getLineTableForUnit(DWARFUnit *U) { if (!Line) - Line.reset(new DWARFDebugLine(&getLineSection().Relocs)); + Line.reset(new DWARFDebugLine); auto UnitDIE = U->getUnitDIE(); if (!UnitDIE) return nullptr; - auto Offset = UnitDIE.getAttributeValueAsSectionOffset(DW_AT_stmt_list); + auto Offset = toSectionOffset(UnitDIE.find(DW_AT_stmt_list)); if (!Offset) return nullptr; // No line table for this compile unit. @@ -396,9 +574,13 @@ DWARFContext::getLineTableForUnit(DWARFUnit *U) { if (const DWARFLineTable *lt = Line->getLineTable(stmtOffset)) return lt; + // Make sure the offset is good before we try to parse. + if (stmtOffset >= U->getLineSection().Data.size()) + return nullptr; + // We have to parse it first. - DataExtractor lineData(U->getLineSection(), isLittleEndian(), - U->getAddressByteSize()); + DWARFDataExtractor lineData(U->getLineSection(), isLittleEndian(), + U->getAddressByteSize()); return Line->getOrParseLineTable(lineData, stmtOffset); } @@ -409,10 +591,10 @@ void DWARFContext::parseCompileUnits() { void DWARFContext::parseTypeUnits() { if (!TUs.empty()) return; - for (const auto &I : getTypesSections()) { + forEachTypesSections([&](const DWARFSection &S) { TUs.emplace_back(); - TUs.back().parse(*this, I.second); - } + TUs.back().parse(*this, S); + }); } void DWARFContext::parseDWOCompileUnits() { @@ -422,10 +604,10 @@ void DWARFContext::parseDWOCompileUnits() { void DWARFContext::parseDWOTypeUnits() { if (!DWOTUs.empty()) return; - for (const auto &I : getTypesDWOSections()) { + forEachTypesDWOSections([&](const DWARFSection &S) { DWOTUs.emplace_back(); - DWOTUs.back().parseDWO(*this, I.second); - } + DWOTUs.back().parseDWO(*this, S); + }); } DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint32_t Offset) { @@ -440,23 +622,32 @@ DWARFCompileUnit *DWARFContext::getCompileUnitForAddress(uint64_t Address) { return getCompileUnitForOffset(CUOffset); } -static bool getFunctionNameForAddress(DWARFCompileUnit *CU, uint64_t Address, - FunctionNameKind Kind, - std::string &FunctionName) { - if (Kind == FunctionNameKind::None) - return false; +static bool getFunctionNameAndStartLineForAddress(DWARFCompileUnit *CU, + uint64_t Address, + FunctionNameKind Kind, + std::string &FunctionName, + uint32_t &StartLine) { // The address may correspond to instruction in some inlined function, // so we have to build the chain of inlined functions and take the - // name of the topmost function in it.SmallVectorImpl<DWARFDie> &InlinedChain + // name of the topmost function in it. SmallVector<DWARFDie, 4> InlinedChain; CU->getInlinedChainForAddress(Address, InlinedChain); - if (InlinedChain.size() == 0) + if (InlinedChain.empty()) return false; - if (const char *Name = InlinedChain[0].getSubroutineName(Kind)) { + + const DWARFDie &DIE = InlinedChain[0]; + bool FoundResult = false; + const char *Name = nullptr; + if (Kind != FunctionNameKind::None && (Name = DIE.getSubroutineName(Kind))) { FunctionName = Name; - return true; + FoundResult = true; + } + if (auto DeclLineResult = DIE.getDeclLine()) { + StartLine = DeclLineResult; + FoundResult = true; } - return false; + + return FoundResult; } DILineInfo DWARFContext::getLineInfoForAddress(uint64_t Address, @@ -466,7 +657,9 @@ DILineInfo DWARFContext::getLineInfoForAddress(uint64_t Address, DWARFCompileUnit *CU = getCompileUnitForAddress(Address); if (!CU) return Result; - getFunctionNameForAddress(CU, Address, Spec.FNKind, Result.FunctionName); + getFunctionNameAndStartLineForAddress(CU, Address, Spec.FNKind, + Result.FunctionName, + Result.StartLine); if (Spec.FLIKind != FileLineInfoKind::None) { if (const DWARFLineTable *LineTable = getLineTableForUnit(CU)) LineTable->getFileLineInfoForAddress(Address, CU->getCompilationDir(), @@ -484,13 +677,16 @@ DWARFContext::getLineInfoForAddressRange(uint64_t Address, uint64_t Size, return Lines; std::string FunctionName = "<invalid>"; - getFunctionNameForAddress(CU, Address, Spec.FNKind, FunctionName); + uint32_t StartLine = 0; + getFunctionNameAndStartLineForAddress(CU, Address, Spec.FNKind, FunctionName, + StartLine); // If the Specifier says we don't need FileLineInfo, just // return the top-most function at the starting address. if (Spec.FLIKind == FileLineInfoKind::None) { DILineInfo Result; Result.FunctionName = FunctionName; + Result.StartLine = StartLine; Lines.push_back(std::make_pair(Address, Result)); return Lines; } @@ -511,6 +707,7 @@ DWARFContext::getLineInfoForAddressRange(uint64_t Address, uint64_t Size, Result.FunctionName = FunctionName; Result.Line = Row.Line; Result.Column = Row.Column; + Result.StartLine = StartLine; Lines.push_back(std::make_pair(Row.Address, Result)); } @@ -543,13 +740,15 @@ DWARFContext::getInliningInfoForAddress(uint64_t Address, return InliningInfo; } - uint32_t CallFile = 0, CallLine = 0, CallColumn = 0; + uint32_t CallFile = 0, CallLine = 0, CallColumn = 0, CallDiscriminator = 0; for (uint32_t i = 0, n = InlinedChain.size(); i != n; i++) { DWARFDie &FunctionDIE = InlinedChain[i]; DILineInfo Frame; // Get function name if necessary. if (const char *Name = FunctionDIE.getSubroutineName(Spec.FNKind)) Frame.FunctionName = Name; + if (auto DeclLineResult = FunctionDIE.getDeclLine()) + Frame.StartLine = DeclLineResult; if (Spec.FLIKind != FileLineInfoKind::None) { if (i == 0) { // For the topmost frame, initialize the line table of this @@ -567,10 +766,12 @@ DWARFContext::getInliningInfoForAddress(uint64_t Address, Spec.FLIKind, Frame.FileName); Frame.Line = CallLine; Frame.Column = CallColumn; + Frame.Discriminator = CallDiscriminator; } // Get call file/line/column of a current DIE. if (i + 1 < n) { - FunctionDIE.getCallerFrame(CallFile, CallLine, CallColumn); + FunctionDIE.getCallerFrame(CallFile, CallLine, CallColumn, + CallDiscriminator); } } InliningInfo.addFrame(Frame); @@ -578,91 +779,207 @@ DWARFContext::getInliningInfoForAddress(uint64_t Address, return InliningInfo; } -DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, - const LoadedObjectInfo *L) - : IsLittleEndian(Obj.isLittleEndian()), +std::shared_ptr<DWARFContext> +DWARFContext::getDWOContext(StringRef AbsolutePath) { + if (auto S = DWP.lock()) { + DWARFContext *Ctxt = S->Context.get(); + return std::shared_ptr<DWARFContext>(std::move(S), Ctxt); + } + + std::weak_ptr<DWOFile> *Entry = &DWOFiles[AbsolutePath]; + + if (auto S = Entry->lock()) { + DWARFContext *Ctxt = S->Context.get(); + 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); + if (Obj) { + Entry = &DWP; + return Obj; + } else { + CheckedForDWP = true; + // TODO: Should this error be handled (maybe in a high verbosity mode) + // before falling back to .dwo files? + consumeError(Obj.takeError()); + } + } + + return object::ObjectFile::createObjectFile(AbsolutePath); + }(); + + if (!Obj) { + // TODO: Actually report errors helpfully. + consumeError(Obj.takeError()); + return nullptr; + } + + auto S = std::make_shared<DWOFile>(); + S->File = std::move(Obj.get()); + S->Context = llvm::make_unique<DWARFContextInMemory>(*S->File.getBinary()); + *Entry = S; + auto *Ctxt = S->Context.get(); + return std::shared_ptr<DWARFContext>(std::move(S), Ctxt); +} + +static Error createError(const Twine &Reason, llvm::Error E) { + return make_error<StringError>(Reason + toString(std::move(E)), + inconvertibleErrorCode()); +} + +/// SymInfo contains information about symbol: it's address +/// and section index which is -1LL for absolute symbols. +struct SymInfo { + uint64_t Address; + uint64_t SectionIndex; +}; + +/// Returns the address of symbol relocation used against and a section index. +/// Used for futher relocations computation. Symbol's section load address is +static Expected<SymInfo> getSymbolInfo(const object::ObjectFile &Obj, + const RelocationRef &Reloc, + const LoadedObjectInfo *L, + std::map<SymbolRef, SymInfo> &Cache) { + SymInfo Ret = {0, (uint64_t)-1LL}; + object::section_iterator RSec = Obj.section_end(); + object::symbol_iterator Sym = Reloc.getSymbol(); + + std::map<SymbolRef, SymInfo>::iterator CacheIt = Cache.end(); + // First calculate the address of the symbol or section as it appears + // in the object file + if (Sym != Obj.symbol_end()) { + bool New; + std::tie(CacheIt, New) = Cache.insert({*Sym, {0, 0}}); + if (!New) + return CacheIt->second; + + Expected<uint64_t> SymAddrOrErr = Sym->getAddress(); + if (!SymAddrOrErr) + return createError("failed to compute symbol address: ", + SymAddrOrErr.takeError()); + + // Also remember what section this symbol is in for later + auto SectOrErr = Sym->getSection(); + if (!SectOrErr) + return createError("failed to get symbol section: ", + SectOrErr.takeError()); + + RSec = *SectOrErr; + Ret.Address = *SymAddrOrErr; + } else if (auto *MObj = dyn_cast<MachOObjectFile>(&Obj)) { + RSec = MObj->getRelocationSection(Reloc.getRawDataRefImpl()); + Ret.Address = RSec->getAddress(); + } + + if (RSec != Obj.section_end()) + Ret.SectionIndex = RSec->getIndex(); + + // If we are given load addresses for the sections, we need to adjust: + // SymAddr = (Address of Symbol Or Section in File) - + // (Address of Section in File) + + // (Load Address of Section) + // RSec is now either the section being targeted or the section + // containing the symbol being targeted. In either case, + // we need to perform the same computation. + if (L && RSec != Obj.section_end()) + if (uint64_t SectionLoadAddress = L->getSectionLoadAddress(*RSec)) + Ret.Address += SectionLoadAddress - RSec->getAddress(); + + if (CacheIt != Cache.end()) + CacheIt->second = Ret; + + return Ret; +} + +static bool isRelocScattered(const object::ObjectFile &Obj, + const RelocationRef &Reloc) { + const MachOObjectFile *MachObj = dyn_cast<MachOObjectFile>(&Obj); + if (!MachObj) + return false; + // MachO also has relocations that point to sections and + // scattered relocations. + auto RelocInfo = MachObj->getRelocation(Reloc.getRawDataRefImpl()); + return MachObj->isRelocationScattered(RelocInfo); +} + +Error DWARFContextInMemory::maybeDecompress(const SectionRef &Sec, + StringRef Name, StringRef &Data) { + if (!Decompressor::isCompressed(Sec)) + return Error::success(); + + 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(); +} + +ErrorPolicy DWARFContextInMemory::defaultErrorHandler(Error E) { + errs() << "error: " + toString(std::move(E)) << '\n'; + return ErrorPolicy::Continue; +} + +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); + StringRef Name; + Section.getName(Name); // Skip BSS and Virtual sections, they aren't interesting. - bool IsBSS = Section.isBSS(); - if (IsBSS) - continue; - bool IsVirtual = Section.isVirtual(); - if (IsVirtual) + if (Section.isBSS() || Section.isVirtual()) continue; - StringRef data; + 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 (Decompressor::isCompressed(Section)) { - Expected<Decompressor> Decompressor = - Decompressor::create(name, data, IsLittleEndian, AddressSize == 8); - if (!Decompressor) - continue; - SmallString<32> Out; - if (auto Err = Decompressor->decompress(Out)) - continue; - UncompressedSections.emplace_back(std::move(Out)); - data = UncompressedSections.back(); + if (!L || !L->getLoadedSectionContents(*RelocatedSection, Data)) + Section.getContents(Data); + + if (auto Err = maybeDecompress(Section, Name, Data)) { + ErrorPolicy EP = HandleError( + createError("failed to decompress '" + Name + "', ", std::move(Err))); + if (EP == ErrorPolicy::Halt) + return; + 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. - - StringRef *SectionData = - StringSwitch<StringRef *>(name) - .Case("debug_info", &InfoSection.Data) - .Case("debug_abbrev", &AbbrevSection) - .Case("debug_loc", &LocSection.Data) - .Case("debug_line", &LineSection.Data) - .Case("debug_aranges", &ARangeSection) - .Case("debug_frame", &DebugFrameSection) - .Case("eh_frame", &EHFrameSection) - .Case("debug_str", &StringSection) - .Case("debug_ranges", &RangeSection) - .Case("debug_macinfo", &MacinfoSection) - .Case("debug_pubnames", &PubNamesSection) - .Case("debug_pubtypes", &PubTypesSection) - .Case("debug_gnu_pubnames", &GnuPubNamesSection) - .Case("debug_gnu_pubtypes", &GnuPubTypesSection) - .Case("debug_info.dwo", &InfoDWOSection.Data) - .Case("debug_abbrev.dwo", &AbbrevDWOSection) - .Case("debug_loc.dwo", &LocDWOSection.Data) - .Case("debug_line.dwo", &LineDWOSection.Data) - .Case("debug_str.dwo", &StringDWOSection) - .Case("debug_str_offsets.dwo", &StringOffsetDWOSection) - .Case("debug_addr", &AddrSection) - .Case("apple_names", &AppleNamesSection.Data) - .Case("apple_types", &AppleTypesSection.Data) - .Case("apple_namespaces", &AppleNamespacesSection.Data) - .Case("apple_namespac", &AppleNamespacesSection.Data) - .Case("apple_objc", &AppleObjCSection.Data) - .Case("debug_cu_index", &CUIndexSection) - .Case("debug_tu_index", &TUIndexSection) - .Case("gdb_index", &GdbIndexSection) - // Any more debug info sections go here. - .Default(nullptr); - if (SectionData) { - *SectionData = data; - if (name == "debug_ranges") { + Name = Name.substr( + Name.find_first_not_of("._z")); // Skip ".", "z" and "_" prefixes. + + // Map platform specific debug section names to DWARF standard section + // names. + Name = Obj.mapDebugSectionName(Name); + + if (StringRef *SectionData = mapSectionToMember(Name)) { + *SectionData = Data; + if (Name == "debug_ranges") { // FIXME: Use the other dwo range section when we emit it. - RangeDWOSection = data; + RangeDWOSection.Data = Data; } - } else if (name == "debug_types") { + } 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; + TypesSections[Section].Data = Data; + } else if (Name == "debug_types.dwo") { + TypesDWOSections[Section].Data = Data; } if (RelocatedSection == Obj.section_end()) @@ -675,7 +992,7 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, // 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)) + if (L && L->getLoadedSectionContents(*RelocatedSection, RelSecData)) continue; // In Mach-o files, the relocations do not need to be applied if @@ -687,21 +1004,12 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, continue; RelSecName = RelSecName.substr( - RelSecName.find_first_not_of("._")); // Skip . and _ prefixes. + 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. - RelocAddrMap *Map = StringSwitch<RelocAddrMap*>(RelSecName) - .Case("debug_info", &InfoSection.Relocs) - .Case("debug_loc", &LocSection.Relocs) - .Case("debug_info.dwo", &InfoDWOSection.Relocs) - .Case("debug_line", &LineSection.Relocs) - .Case("apple_names", &AppleNamesSection.Relocs) - .Case("apple_types", &AppleTypesSection.Relocs) - .Case("apple_namespaces", &AppleNamespacesSection.Relocs) - .Case("apple_namespac", &AppleNamespacesSection.Relocs) - .Case("apple_objc", &AppleObjCSection.Relocs) - .Default(nullptr); + 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. @@ -713,103 +1021,93 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, continue; } - if (Section.relocation_begin() != Section.relocation_end()) { - uint64_t SectionSize = RelocatedSection->getSize(); - for (const RelocationRef &Reloc : Section.relocations()) { - uint64_t Address = Reloc.getOffset(); - uint64_t Type = Reloc.getType(); - uint64_t SymAddr = 0; - uint64_t SectionLoadAddress = 0; - object::symbol_iterator Sym = Reloc.getSymbol(); - object::section_iterator RSec = Obj.section_end(); - - // First calculate the address of the symbol or section as it appears - // in the objct file - if (Sym != Obj.symbol_end()) { - Expected<uint64_t> SymAddrOrErr = Sym->getAddress(); - if (!SymAddrOrErr) { - std::string Buf; - raw_string_ostream OS(Buf); - logAllUnhandledErrors(SymAddrOrErr.takeError(), OS, ""); - OS.flush(); - errs() << "error: failed to compute symbol address: " - << Buf << '\n'; - continue; - } - SymAddr = *SymAddrOrErr; - // Also remember what section this symbol is in for later - auto SectOrErr = Sym->getSection(); - if (!SectOrErr) { - std::string Buf; - raw_string_ostream OS(Buf); - logAllUnhandledErrors(SectOrErr.takeError(), OS, ""); - OS.flush(); - errs() << "error: failed to get symbol section: " - << Buf << '\n'; - continue; - } - RSec = *SectOrErr; - } else if (auto *MObj = dyn_cast<MachOObjectFile>(&Obj)) { - // MachO also has relocations that point to sections and - // scattered relocations. - auto RelocInfo = MObj->getRelocation(Reloc.getRawDataRefImpl()); - if (MObj->isRelocationScattered(RelocInfo)) { - // FIXME: it's not clear how to correctly handle scattered - // relocations. - continue; - } else { - RSec = MObj->getRelocationSection(Reloc.getRawDataRefImpl()); - SymAddr = RSec->getAddress(); - } - } - - // If we are given load addresses for the sections, we need to adjust: - // SymAddr = (Address of Symbol Or Section in File) - - // (Address of Section in File) + - // (Load Address of Section) - if (L != nullptr && RSec != Obj.section_end()) { - // RSec is now either the section being targeted or the section - // containing the symbol being targeted. In either case, - // we need to perform the same computation. - StringRef SecName; - RSec->getName(SecName); -// llvm::dbgs() << "Name: '" << SecName -// << "', RSec: " << RSec->getRawDataRefImpl() -// << ", Section: " << Section.getRawDataRefImpl() << "\n"; - SectionLoadAddress = L->getSectionLoadAddress(*RSec); - if (SectionLoadAddress != 0) - SymAddr += SectionLoadAddress - RSec->getAddress(); - } - - object::RelocVisitor V(Obj); - object::RelocToApply R(V.visit(Type, Reloc, SymAddr)); - if (V.error()) { - SmallString<32> Name; - Reloc.getTypeName(Name); - errs() << "error: failed to compute relocation: " - << Name << "\n"; - continue; - } - - if (Address + R.Width > SectionSize) { - errs() << "error: " << R.Width << "-byte relocation starting " - << Address << " bytes into section " << name << " which is " - << SectionSize << " bytes long.\n"; - continue; - } - if (R.Width > 8) { - errs() << "error: can't handle a relocation of more than 8 bytes at " - "a time.\n"; - continue; - } - DEBUG(dbgs() << "Writing " << format("%p", R.Value) - << " at " << format("%p", Address) - << " with width " << format("%d", R.Width) - << "\n"); - Map->insert(std::make_pair(Address, std::make_pair(R.Width, R.Value))); + 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}); } } } -void DWARFContextInMemory::anchor() { } +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(); + } +} + +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); +} + +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); +} + +void DWARFContextInMemory::anchor() {} diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp new file mode 100644 index 0000000..001097e --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp @@ -0,0 +1,24 @@ +//===- DWARFDataExtractor.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/DWARFDataExtractor.h" + +using namespace llvm; + +uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint32_t *Off, + uint64_t *SecNdx) const { + if (!RelocMap) + return getUnsigned(Off, Size); + RelocAddrMap::const_iterator AI = RelocMap->find(*Off); + if (AI == RelocMap->end()) + return getUnsigned(Off, Size); + if (SecNdx) + *SecNdx = AI->second.SectionIndex; + return getUnsigned(Off, Size) + AI->second.Value; +} diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp index e63e289..76dd2e4 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugAbbrev.cpp ----------------------------------------------===// +//===- DWARFDebugAbbrev.cpp -----------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -10,6 +10,10 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cinttypes> +#include <cstdint> + using namespace llvm; DWARFAbbreviationDeclarationSet::DWARFAbbreviationDeclarationSet() { diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp index 67589cd..ed5d726 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugArangeSet.cpp -------------------------------------------===// +//===- DWARFDebugArangeSet.cpp --------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -10,8 +10,11 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" -#include <algorithm> #include <cassert> +#include <cinttypes> +#include <cstdint> +#include <cstring> + using namespace llvm; void DWARFDebugArangeSet::clear() { diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp index 27a02c4..6601393 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugAranges.cpp -----------------------------------*- C++ -*-===// +//===- DWARFDebugAranges.cpp ----------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -11,11 +11,13 @@ #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/DataExtractor.h" #include <algorithm> #include <cassert> +#include <cstdint> #include <set> +#include <vector> + using namespace llvm; void DWARFDebugAranges::extract(DataExtractor DebugArangesData) { @@ -52,9 +54,8 @@ void DWARFDebugAranges::generate(DWARFContext *CTX) { if (ParsedCUOffsets.insert(CUOffset).second) { DWARFAddressRangesVector CURanges; CU->collectAddressRanges(CURanges); - for (const auto &R : CURanges) { - appendRange(CUOffset, R.first, R.second); - } + for (const auto &R : CURanges) + appendRange(CUOffset, R.LowPC, R.HighPC); } } @@ -81,7 +82,7 @@ void DWARFDebugAranges::construct() { std::sort(Endpoints.begin(), Endpoints.end()); uint64_t PrevAddress = -1ULL; for (const auto &E : Endpoints) { - if (PrevAddress < E.Address && ValidCUs.size() > 0) { + if (PrevAddress < E.Address && !ValidCUs.empty()) { // If the address range between two endpoints is described by some // CU, first try to extend the last range in Aranges. If we can't // do it, start a new range. diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp index 32b8320..475cf25 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugFrame.h - Parsing of .debug_frame -------------*- C++ -*-===// +//===- DWARFDebugFrame.h - Parsing of .debug_frame ------------------------===// // // The LLVM Compiler Infrastructure // @@ -11,14 +11,14 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataExtractor.h" -#include "llvm/Support/Dwarf.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -70,7 +70,7 @@ protected: /// An entry may contain CFI instructions. An instruction consists of an /// opcode and an optional sequence of operands. - typedef std::vector<uint64_t> Operands; + using Operands = std::vector<uint64_t>; struct Instruction { Instruction(uint8_t Opcode) : Opcode(Opcode) @@ -465,8 +465,7 @@ void FrameEntry::dumpInstructions(raw_ostream &OS) const { } } -DWARFDebugFrame::DWARFDebugFrame(bool IsEH) : IsEH(IsEH) { -} +DWARFDebugFrame::DWARFDebugFrame(bool IsEH) : IsEH(IsEH) {} DWARFDebugFrame::~DWARFDebugFrame() = default; @@ -485,17 +484,17 @@ static unsigned getSizeForEncoding(const DataExtractor &Data, unsigned format = symbolEncoding & 0x0f; switch (format) { default: llvm_unreachable("Unknown Encoding"); - case dwarf::DW_EH_PE_absptr: - case dwarf::DW_EH_PE_signed: + case DW_EH_PE_absptr: + case DW_EH_PE_signed: return Data.getAddressSize(); - case dwarf::DW_EH_PE_udata2: - case dwarf::DW_EH_PE_sdata2: + case DW_EH_PE_udata2: + case DW_EH_PE_sdata2: return 2; - case dwarf::DW_EH_PE_udata4: - case dwarf::DW_EH_PE_sdata4: + case DW_EH_PE_udata4: + case DW_EH_PE_sdata4: return 4; - case dwarf::DW_EH_PE_udata8: - case dwarf::DW_EH_PE_sdata8: + case DW_EH_PE_udata8: + case DW_EH_PE_sdata8: return 8; } } @@ -514,6 +513,19 @@ static uint64_t readPointer(const DataExtractor &Data, uint32_t &Offset, } } +// This is a workaround for old compilers which do not allow +// noreturn attribute usage in lambdas. Once the support for those +// compilers are phased out, we can remove this and return back to +// a ReportError lambda: [StartOffset](const char *ErrorMsg). +static void LLVM_ATTRIBUTE_NORETURN ReportError(uint32_t StartOffset, + const char *ErrorMsg) { + std::string Str; + raw_string_ostream OS(Str); + OS << format(ErrorMsg, StartOffset); + OS.flush(); + report_fatal_error(Str); +} + void DWARFDebugFrame::parse(DataExtractor Data) { uint32_t Offset = 0; DenseMap<uint32_t, CIE *> CIEs; @@ -521,14 +533,6 @@ void DWARFDebugFrame::parse(DataExtractor Data) { while (Data.isValidOffset(Offset)) { uint32_t StartOffset = Offset; - auto ReportError = [StartOffset](const char *ErrorMsg) { - std::string Str; - raw_string_ostream OS(Str); - OS << format(ErrorMsg, StartOffset); - OS.flush(); - report_fatal_error(Str); - }; - bool IsDWARF64 = false; uint64_t Length = Data.getU32(&Offset); uint64_t Id; @@ -584,13 +588,15 @@ void DWARFDebugFrame::parse(DataExtractor Data) { for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) { switch (AugmentationString[i]) { default: - ReportError("Unknown augmentation character in entry at %lx"); + ReportError(StartOffset, + "Unknown augmentation character in entry at %lx"); case 'L': LSDAPointerEncoding = Data.getU8(&Offset); break; case 'P': { if (Personality) - ReportError("Duplicate personality in entry at %lx"); + ReportError(StartOffset, + "Duplicate personality in entry at %lx"); PersonalityEncoding = Data.getU8(&Offset); Personality = readPointer(Data, Offset, *PersonalityEncoding); break; @@ -600,7 +606,8 @@ void DWARFDebugFrame::parse(DataExtractor Data) { break; case 'z': if (i) - ReportError("'z' must be the first character at %lx"); + ReportError(StartOffset, + "'z' must be the first character at %lx"); // Parse the augmentation length first. We only parse it if // the string contains a 'z'. AugmentationLength = Data.getULEB128(&Offset); @@ -612,7 +619,7 @@ void DWARFDebugFrame::parse(DataExtractor Data) { if (AugmentationLength.hasValue()) { if (Offset != EndAugmentationOffset) - ReportError("Parsing augmentation data at %lx failed"); + ReportError(StartOffset, "Parsing augmentation data at %lx failed"); AugmentationData = Data.getData().slice(StartAugmentationOffset, EndAugmentationOffset); @@ -639,7 +646,8 @@ void DWARFDebugFrame::parse(DataExtractor Data) { if (IsEH) { // The address size is encoded in the CIE we reference. if (!Cie) - ReportError("Parsing FDE data at %lx failed due to missing CIE"); + ReportError(StartOffset, + "Parsing FDE data at %lx failed due to missing CIE"); InitialLocation = readPointer(Data, Offset, Cie->getFDEPointerEncoding()); @@ -659,7 +667,7 @@ void DWARFDebugFrame::parse(DataExtractor Data) { readPointer(Data, Offset, Cie->getLSDAPointerEncoding()); if (Offset != EndAugmentationOffset) - ReportError("Parsing augmentation data at %lx failed"); + ReportError(StartOffset, "Parsing augmentation data at %lx failed"); } } else { InitialLocation = Data.getAddress(&Offset); @@ -674,7 +682,7 @@ void DWARFDebugFrame::parse(DataExtractor Data) { Entries.back()->parseInstructions(Data, &Offset, EndStructureOffset); if (Offset != EndStructureOffset) - ReportError("Parsing entry instructions at %lx failed"); + ReportError(StartOffset, "Parsing entry instructions at %lx failed"); } } diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp index c487e1d..976bc46 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugInfoEntry.cpp -------------------------------------------===// +//===- DWARFDebugInfoEntry.cpp --------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,29 +7,27 @@ // //===----------------------------------------------------------------------===// -#include "SyntaxHighlighting.h" -#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" +#include "llvm/ADT/Optional.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/Support/DataTypes.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Dwarf.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Support/DataExtractor.h" +#include <cstddef> +#include <cstdint> + using namespace llvm; using namespace dwarf; -using namespace syntax; bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint32_t *OffsetPtr) { - DataExtractor DebugInfoData = U.getDebugInfoExtractor(); + DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor(); const uint32_t UEndOffset = U.getNextUnitOffset(); return extractFast(U, OffsetPtr, DebugInfoData, UEndOffset, 0); } + bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint32_t *OffsetPtr, - const DataExtractor &DebugInfoData, + const DWARFDataExtractor &DebugInfoData, uint32_t UEndOffset, uint32_t D) { Offset = *OffsetPtr; Depth = D; @@ -61,7 +59,7 @@ bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint32_t *OffsetPtr, // Attribute byte size if fixed, just add the size to the offset. *OffsetPtr += *FixedSize; } else if (!DWARFFormValue::skipValue(AttrSpec.Form, DebugInfoData, - OffsetPtr, &U)) { + OffsetPtr, U.getFormParams())) { // We failed to skip this attribute's value, restore the original offset // and return the failure status. *OffsetPtr = Offset; diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp index 4940594..7d18056 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugLine.cpp ------------------------------------------------===// +//===- DWARFDebugLine.cpp -------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -8,22 +8,47 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" -#include "llvm/Support/Dwarf.h" +#include "llvm/ADT/SmallString.h" +#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" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> +#include <cassert> +#include <cinttypes> +#include <cstdint> +#include <cstdio> +#include <utility> + using namespace llvm; using namespace dwarf; -typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind; + +using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind; + +namespace { + +struct ContentDescriptor { + dwarf::LineNumberEntryFormat Type; + dwarf::Form Form; +}; + +using ContentDescriptors = SmallVector<ContentDescriptor, 4>; + +} // end anonmyous namespace DWARFDebugLine::Prologue::Prologue() { clear(); } void DWARFDebugLine::Prologue::clear() { - TotalLength = Version = PrologueLength = 0; + TotalLength = PrologueLength = 0; + SegSelectorSize = 0; MinInstLength = MaxOpsPerInst = DefaultIsStmt = LineBase = LineRange = 0; OpcodeBase = 0; - IsDWARF64 = false; + FormParams = DWARFFormParams({0, 0, DWARF32}); StandardOpcodeLengths.clear(); IncludeDirectories.clear(); FileNames.clear(); @@ -32,104 +57,225 @@ void DWARFDebugLine::Prologue::clear() { void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const { OS << "Line table prologue:\n" << format(" total_length: 0x%8.8" PRIx64 "\n", TotalLength) - << format(" version: %u\n", Version) - << format(" prologue_length: 0x%8.8" PRIx64 "\n", PrologueLength) + << format(" version: %u\n", getVersion()); + if (getVersion() >= 5) + OS << format(" address_size: %u\n", getAddressSize()) + << format(" seg_select_size: %u\n", SegSelectorSize); + OS << format(" prologue_length: 0x%8.8" PRIx64 "\n", PrologueLength) << format(" min_inst_length: %u\n", MinInstLength) - << format(Version >= 4 ? "max_ops_per_inst: %u\n" : "", MaxOpsPerInst) + << format(getVersion() >= 4 ? "max_ops_per_inst: %u\n" : "", MaxOpsPerInst) << format(" default_is_stmt: %u\n", DefaultIsStmt) << format(" line_base: %i\n", LineBase) << format(" line_range: %u\n", LineRange) << format(" opcode_base: %u\n", OpcodeBase); - for (uint32_t i = 0; i < StandardOpcodeLengths.size(); ++i) + for (uint32_t I = 0; I != StandardOpcodeLengths.size(); ++I) OS << format("standard_opcode_lengths[%s] = %u\n", - LNStandardString(i + 1).data(), StandardOpcodeLengths[i]); + LNStandardString(I + 1).data(), StandardOpcodeLengths[I]); if (!IncludeDirectories.empty()) - for (uint32_t i = 0; i < IncludeDirectories.size(); ++i) - OS << format("include_directories[%3u] = '", i + 1) - << IncludeDirectories[i] << "'\n"; + for (uint32_t I = 0; I != IncludeDirectories.size(); ++I) + OS << format("include_directories[%3u] = '", I + 1) + << IncludeDirectories[I] << "'\n"; if (!FileNames.empty()) { 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'; + 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'; } } } -bool DWARFDebugLine::Prologue::parse(DataExtractor debug_line_data, - uint32_t *offset_ptr) { - const uint64_t prologue_offset = *offset_ptr; +// Parse v2-v4 directory and file tables. +static void +parseV2DirFileTables(const DWARFDataExtractor &DebugLineData, + uint32_t *OffsetPtr, uint64_t EndPrologueOffset, + std::vector<StringRef> &IncludeDirectories, + std::vector<DWARFDebugLine::FileNameEntry> &FileNames) { + while (*OffsetPtr < EndPrologueOffset) { + StringRef S = DebugLineData.getCStrRef(OffsetPtr); + if (S.empty()) + break; + IncludeDirectories.push_back(S); + } + + while (*OffsetPtr < EndPrologueOffset) { + StringRef Name = DebugLineData.getCStrRef(OffsetPtr); + if (Name.empty()) + break; + DWARFDebugLine::FileNameEntry FileEntry; + FileEntry.Name = Name; + FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr); + FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr); + FileEntry.Length = DebugLineData.getULEB128(OffsetPtr); + FileNames.push_back(FileEntry); + } +} - clear(); - TotalLength = debug_line_data.getU32(offset_ptr); - if (TotalLength == UINT32_MAX) { - IsDWARF64 = true; - TotalLength = debug_line_data.getU64(offset_ptr); - } else if (TotalLength > 0xffffff00) { +// Parse v5 directory/file entry content descriptions. +// Returns the descriptors, or an empty vector if we did not find a path or +// ran off the end of the prologue. +static ContentDescriptors +parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, + uint64_t EndPrologueOffset) { + ContentDescriptors Descriptors; + int FormatCount = DebugLineData.getU8(OffsetPtr); + bool HasPath = false; + for (int I = 0; I != FormatCount; ++I) { + if (*OffsetPtr >= EndPrologueOffset) + return ContentDescriptors(); + ContentDescriptor Descriptor; + Descriptor.Type = + dwarf::LineNumberEntryFormat(DebugLineData.getULEB128(OffsetPtr)); + Descriptor.Form = dwarf::Form(DebugLineData.getULEB128(OffsetPtr)); + if (Descriptor.Type == dwarf::DW_LNCT_path) + HasPath = true; + Descriptors.push_back(Descriptor); + } + return HasPath ? Descriptors : ContentDescriptors(); +} + +static bool +parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, + uint32_t *OffsetPtr, uint64_t EndPrologueOffset, + const DWARFFormParams &FormParams, + std::vector<StringRef> &IncludeDirectories, + std::vector<DWARFDebugLine::FileNameEntry> &FileNames) { + // Get the directory entry description. + ContentDescriptors DirDescriptors = + parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset); + if (DirDescriptors.empty()) return false; + + // Get the directory entries, according to the format described above. + int DirEntryCount = DebugLineData.getU8(OffsetPtr); + for (int I = 0; I != DirEntryCount; ++I) { + if (*OffsetPtr >= EndPrologueOffset) + return false; + for (auto Descriptor : DirDescriptors) { + DWARFFormValue Value(Descriptor.Form); + switch (Descriptor.Type) { + case DW_LNCT_path: + if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr)) + return false; + IncludeDirectories.push_back(Value.getAsCString().getValue()); + break; + default: + if (!Value.skipValue(DebugLineData, OffsetPtr, FormParams)) + return false; + } + } } - Version = debug_line_data.getU16(offset_ptr); - if (Version < 2) + + // Get the file entry description. + ContentDescriptors FileDescriptors = + parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset); + if (FileDescriptors.empty()) return false; - PrologueLength = - debug_line_data.getUnsigned(offset_ptr, sizeofPrologueLength()); - const uint64_t end_prologue_offset = PrologueLength + *offset_ptr; - MinInstLength = debug_line_data.getU8(offset_ptr); - if (Version >= 4) - MaxOpsPerInst = debug_line_data.getU8(offset_ptr); - DefaultIsStmt = debug_line_data.getU8(offset_ptr); - LineBase = debug_line_data.getU8(offset_ptr); - LineRange = debug_line_data.getU8(offset_ptr); - OpcodeBase = debug_line_data.getU8(offset_ptr); + // Get the file entries, according to the format described above. + int FileEntryCount = DebugLineData.getU8(OffsetPtr); + for (int I = 0; I != FileEntryCount; ++I) { + if (*OffsetPtr >= EndPrologueOffset) + return false; + DWARFDebugLine::FileNameEntry FileEntry; + for (auto Descriptor : FileDescriptors) { + DWARFFormValue Value(Descriptor.Form); + if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr)) + return false; + switch (Descriptor.Type) { + case DW_LNCT_path: + FileEntry.Name = Value.getAsCString().getValue(); + break; + case DW_LNCT_directory_index: + FileEntry.DirIdx = Value.getAsUnsignedConstant().getValue(); + break; + case DW_LNCT_timestamp: + FileEntry.ModTime = Value.getAsUnsignedConstant().getValue(); + break; + case DW_LNCT_size: + FileEntry.Length = Value.getAsUnsignedConstant().getValue(); + break; + // FIXME: Add MD5 + default: + break; + } + } + FileNames.push_back(FileEntry); + } + return true; +} - StandardOpcodeLengths.reserve(OpcodeBase - 1); - for (uint32_t i = 1; i < OpcodeBase; ++i) { - uint8_t op_len = debug_line_data.getU8(offset_ptr); - StandardOpcodeLengths.push_back(op_len); +bool DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData, + uint32_t *OffsetPtr) { + const uint64_t PrologueOffset = *OffsetPtr; + + clear(); + TotalLength = DebugLineData.getU32(OffsetPtr); + if (TotalLength == UINT32_MAX) { + FormParams.Format = dwarf::DWARF64; + TotalLength = DebugLineData.getU64(OffsetPtr); + } else if (TotalLength >= 0xffffff00) { + return false; } + FormParams.Version = DebugLineData.getU16(OffsetPtr); + if (getVersion() < 2) + return false; - while (*offset_ptr < end_prologue_offset) { - const char *s = debug_line_data.getCStr(offset_ptr); - if (s && s[0]) - IncludeDirectories.push_back(s); - else - break; + if (getVersion() >= 5) { + FormParams.AddrSize = DebugLineData.getU8(OffsetPtr); + assert(getAddressSize() == DebugLineData.getAddressSize() && + "Line table header and data extractor disagree"); + SegSelectorSize = DebugLineData.getU8(OffsetPtr); } - while (*offset_ptr < end_prologue_offset) { - const char *name = debug_line_data.getCStr(offset_ptr); - if (name && name[0]) { - FileNameEntry fileEntry; - fileEntry.Name = name; - fileEntry.DirIdx = debug_line_data.getULEB128(offset_ptr); - fileEntry.ModTime = debug_line_data.getULEB128(offset_ptr); - fileEntry.Length = debug_line_data.getULEB128(offset_ptr); - FileNames.push_back(fileEntry); - } else { - break; - } + PrologueLength = DebugLineData.getUnsigned(OffsetPtr, sizeofPrologueLength()); + const uint64_t EndPrologueOffset = PrologueLength + *OffsetPtr; + MinInstLength = DebugLineData.getU8(OffsetPtr); + if (getVersion() >= 4) + MaxOpsPerInst = DebugLineData.getU8(OffsetPtr); + DefaultIsStmt = DebugLineData.getU8(OffsetPtr); + LineBase = DebugLineData.getU8(OffsetPtr); + LineRange = DebugLineData.getU8(OffsetPtr); + OpcodeBase = DebugLineData.getU8(OffsetPtr); + + StandardOpcodeLengths.reserve(OpcodeBase - 1); + for (uint32_t I = 1; I < OpcodeBase; ++I) { + uint8_t OpLen = DebugLineData.getU8(OffsetPtr); + StandardOpcodeLengths.push_back(OpLen); } - if (*offset_ptr != end_prologue_offset) { - fprintf(stderr, "warning: parsing line table prologue at 0x%8.8" PRIx64 - " should have ended at 0x%8.8" PRIx64 - " but it ended at 0x%8.8" PRIx64 "\n", - prologue_offset, end_prologue_offset, (uint64_t)*offset_ptr); + if (getVersion() >= 5) { + if (!parseV5DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset, + getFormParams(), IncludeDirectories, FileNames)) { + fprintf(stderr, + "warning: parsing line table prologue at 0x%8.8" PRIx64 + " found an invalid directory or file table description at" + " 0x%8.8" PRIx64 "\n", PrologueOffset, (uint64_t)*OffsetPtr); + return false; + } + } else + parseV2DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset, + IncludeDirectories, FileNames); + + if (*OffsetPtr != EndPrologueOffset) { + fprintf(stderr, + "warning: parsing line table prologue at 0x%8.8" PRIx64 + " should have ended at 0x%8.8" PRIx64 + " but it ended at 0x%8.8" PRIx64 "\n", + PrologueOffset, EndPrologueOffset, (uint64_t)*OffsetPtr); return false; } return true; } -DWARFDebugLine::Row::Row(bool default_is_stmt) { reset(default_is_stmt); } +DWARFDebugLine::Row::Row(bool DefaultIsStmt) { reset(DefaultIsStmt); } void DWARFDebugLine::Row::postAppend() { BasicBlock = false; @@ -137,20 +283,26 @@ void DWARFDebugLine::Row::postAppend() { EpilogueBegin = false; } -void DWARFDebugLine::Row::reset(bool default_is_stmt) { +void DWARFDebugLine::Row::reset(bool DefaultIsStmt) { Address = 0; Line = 1; Column = 0; File = 1; Isa = 0; Discriminator = 0; - IsStmt = default_is_stmt; + IsStmt = DefaultIsStmt; BasicBlock = false; EndSequence = false; PrologueEnd = false; EpilogueBegin = false; } +void DWARFDebugLine::Row::dumpTableHeader(raw_ostream &OS) { + OS << "Address Line Column File ISA Discriminator Flags\n" + << "------------------ ------ ------ ------ --- ------------- " + "-------------\n"; +} + void DWARFDebugLine::Row::dump(raw_ostream &OS) const { OS << format("0x%16.16" PRIx64 " %6u %6u", Address, Line, Column) << format(" %6u %3u %13u ", File, Isa, Discriminator) @@ -177,9 +329,7 @@ void DWARFDebugLine::LineTable::dump(raw_ostream &OS) const { OS << '\n'; if (!Rows.empty()) { - OS << "Address Line Column File ISA Discriminator Flags\n" - << "------------------ ------ ------ ------ --- ------------- " - "-------------\n"; + Row::dumpTableHeader(OS); for (const Row &R : Rows) { R.dump(OS); } @@ -193,7 +343,7 @@ void DWARFDebugLine::LineTable::clear() { } DWARFDebugLine::ParsingState::ParsingState(struct LineTable *LT) - : LineTable(LT), RowNumber(0) { + : LineTable(LT) { resetRowAndSequence(); } @@ -202,7 +352,7 @@ void DWARFDebugLine::ParsingState::resetRowAndSequence() { Sequence.reset(); } -void DWARFDebugLine::ParsingState::appendRowToMatrix(uint32_t offset) { +void DWARFDebugLine::ParsingState::appendRowToMatrix(uint32_t Offset) { if (Sequence.Empty) { // Record the beginning of instruction sequence. Sequence.Empty = false; @@ -223,56 +373,55 @@ void DWARFDebugLine::ParsingState::appendRowToMatrix(uint32_t offset) { } const DWARFDebugLine::LineTable * -DWARFDebugLine::getLineTable(uint32_t offset) const { - LineTableConstIter pos = LineTableMap.find(offset); - if (pos != LineTableMap.end()) - return &pos->second; +DWARFDebugLine::getLineTable(uint32_t Offset) const { + LineTableConstIter Pos = LineTableMap.find(Offset); + if (Pos != LineTableMap.end()) + return &Pos->second; return nullptr; } const DWARFDebugLine::LineTable * -DWARFDebugLine::getOrParseLineTable(DataExtractor debug_line_data, - uint32_t offset) { - std::pair<LineTableIter, bool> pos = - LineTableMap.insert(LineTableMapTy::value_type(offset, LineTable())); - LineTable *LT = &pos.first->second; - if (pos.second) { - if (!LT->parse(debug_line_data, RelocMap, &offset)) +DWARFDebugLine::getOrParseLineTable(const DWARFDataExtractor &DebugLineData, + uint32_t Offset) { + 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)) return nullptr; } return LT; } -bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, - const RelocAddrMap *RMap, - uint32_t *offset_ptr) { - const uint32_t debug_line_offset = *offset_ptr; +bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData, + uint32_t *OffsetPtr) { + const uint32_t DebugLineOffset = *OffsetPtr; clear(); - if (!Prologue.parse(debug_line_data, offset_ptr)) { + if (!Prologue.parse(DebugLineData, OffsetPtr)) { // Restore our offset and return false to indicate failure! - *offset_ptr = debug_line_offset; + *OffsetPtr = DebugLineOffset; return false; } - const uint32_t end_offset = - debug_line_offset + Prologue.TotalLength + Prologue.sizeofTotalLength(); + const uint32_t EndOffset = + DebugLineOffset + Prologue.TotalLength + Prologue.sizeofTotalLength(); ParsingState State(this); - while (*offset_ptr < end_offset) { - uint8_t opcode = debug_line_data.getU8(offset_ptr); + while (*OffsetPtr < EndOffset) { + uint8_t Opcode = DebugLineData.getU8(OffsetPtr); - if (opcode == 0) { + 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 ext_offset = *offset_ptr; - uint64_t len = debug_line_data.getULEB128(offset_ptr); - uint32_t arg_size = len - (*offset_ptr - ext_offset); + uint32_t ExtOffset = *OffsetPtr; + uint64_t Len = DebugLineData.getULEB128(OffsetPtr); + uint32_t ArgSize = Len - (*OffsetPtr - ExtOffset); - uint8_t sub_opcode = debug_line_data.getU8(offset_ptr); - switch (sub_opcode) { + uint8_t SubOpcode = DebugLineData.getU8(OffsetPtr); + switch (SubOpcode) { case DW_LNE_end_sequence: // Set the end_sequence register of the state machine to true and // append a row to the matrix using the current values of the @@ -282,7 +431,7 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // address is that of the byte after the last target machine instruction // of the sequence. State.Row.EndSequence = true; - State.appendRowToMatrix(*offset_ptr); + State.appendRowToMatrix(*OffsetPtr); State.resetRowAndSequence(); break; @@ -293,16 +442,7 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // 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. - { - // If this address is in our relocation map, apply the relocation. - RelocAddrMap::const_iterator AI = RMap->find(*offset_ptr); - if (AI != RMap->end()) { - const std::pair<uint8_t, int64_t> &R = AI->second; - State.Row.Address = - debug_line_data.getAddress(offset_ptr) + R.second; - } else - State.Row.Address = debug_line_data.getAddress(offset_ptr); - } + State.Row.Address = DebugLineData.getRelocatedAddress(OffsetPtr); break; case DW_LNE_define_file: @@ -327,33 +467,33 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // the DW_LNE_define_file instruction. These numbers are used in the // the file register of the state machine. { - FileNameEntry fileEntry; - fileEntry.Name = debug_line_data.getCStr(offset_ptr); - fileEntry.DirIdx = debug_line_data.getULEB128(offset_ptr); - fileEntry.ModTime = debug_line_data.getULEB128(offset_ptr); - fileEntry.Length = debug_line_data.getULEB128(offset_ptr); - Prologue.FileNames.push_back(fileEntry); + FileNameEntry FileEntry; + FileEntry.Name = DebugLineData.getCStr(OffsetPtr); + FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr); + FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr); + FileEntry.Length = DebugLineData.getULEB128(OffsetPtr); + Prologue.FileNames.push_back(FileEntry); } break; case DW_LNE_set_discriminator: - State.Row.Discriminator = debug_line_data.getULEB128(offset_ptr); + State.Row.Discriminator = DebugLineData.getULEB128(OffsetPtr); 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 - (*offset_ptr) += arg_size; + (*OffsetPtr) += ArgSize; break; } - } else if (opcode < Prologue.OpcodeBase) { - switch (opcode) { + } else if (Opcode < Prologue.OpcodeBase) { + switch (Opcode) { // Standard Opcodes case DW_LNS_copy: // Takes no arguments. Append a row to the matrix using the // current values of the state-machine registers. Then set // the basic_block register to false. - State.appendRowToMatrix(*offset_ptr); + State.appendRowToMatrix(*OffsetPtr); break; case DW_LNS_advance_pc: @@ -361,25 +501,25 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // min_inst_length field of the prologue, and adds the // result to the address register of the state machine. State.Row.Address += - debug_line_data.getULEB128(offset_ptr) * Prologue.MinInstLength; + DebugLineData.getULEB128(OffsetPtr) * Prologue.MinInstLength; 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 += debug_line_data.getSLEB128(offset_ptr); + State.Row.Line += DebugLineData.getSLEB128(OffsetPtr); 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 = debug_line_data.getULEB128(offset_ptr); + State.Row.File = DebugLineData.getULEB128(OffsetPtr); 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 = debug_line_data.getULEB128(offset_ptr); + State.Row.Column = DebugLineData.getULEB128(OffsetPtr); break; case DW_LNS_negate_stmt: @@ -407,10 +547,10 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // than twice that range will it need to use both DW_LNS_advance_pc // and a special opcode, requiring three or more bytes. { - uint8_t adjust_opcode = 255 - Prologue.OpcodeBase; - uint64_t addr_offset = - (adjust_opcode / Prologue.LineRange) * Prologue.MinInstLength; - State.Row.Address += addr_offset; + uint8_t AdjustOpcode = 255 - Prologue.OpcodeBase; + uint64_t AddrOffset = + (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength; + State.Row.Address += AddrOffset; } break; @@ -424,7 +564,7 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // 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 += debug_line_data.getU16(offset_ptr); + State.Row.Address += DebugLineData.getU16(OffsetPtr); break; case DW_LNS_set_prologue_end: @@ -442,7 +582,7 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, case DW_LNS_set_isa: // Takes a single unsigned LEB128 operand and stores it in the // column register of the state machine. - State.Row.Isa = debug_line_data.getULEB128(offset_ptr); + State.Row.Isa = DebugLineData.getULEB128(OffsetPtr); break; default: @@ -450,10 +590,10 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // of such opcodes because they are specified in the prologue // as a multiple of LEB128 operands for each opcode. { - assert(opcode - 1U < Prologue.StandardOpcodeLengths.size()); - uint8_t opcode_length = Prologue.StandardOpcodeLengths[opcode - 1]; - for (uint8_t i = 0; i < opcode_length; ++i) - debug_line_data.getULEB128(offset_ptr); + assert(Opcode - 1U < Prologue.StandardOpcodeLengths.size()); + uint8_t OpcodeLength = Prologue.StandardOpcodeLengths[Opcode - 1]; + for (uint8_t I = 0; I < OpcodeLength; ++I) + DebugLineData.getULEB128(OffsetPtr); } break; } @@ -491,14 +631,14 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // // line increment = line_base + (adjusted opcode % line_range) - uint8_t adjust_opcode = opcode - Prologue.OpcodeBase; - uint64_t addr_offset = - (adjust_opcode / Prologue.LineRange) * Prologue.MinInstLength; - int32_t line_offset = - Prologue.LineBase + (adjust_opcode % Prologue.LineRange); - State.Row.Line += line_offset; - State.Row.Address += addr_offset; - State.appendRowToMatrix(*offset_ptr); + uint8_t AdjustOpcode = Opcode - Prologue.OpcodeBase; + uint64_t AddrOffset = + (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength; + int32_t LineOffset = + Prologue.LineBase + (AdjustOpcode % Prologue.LineRange); + State.Row.Line += LineOffset; + State.Row.Address += AddrOffset; + State.appendRowToMatrix(*OffsetPtr); // Reset discriminator to 0. State.Row.Discriminator = 0; } @@ -520,124 +660,122 @@ bool DWARFDebugLine::LineTable::parse(DataExtractor debug_line_data, // rudimentary sequences for address ranges [0x0, 0xsomething). } - return end_offset; + return EndOffset; } uint32_t -DWARFDebugLine::LineTable::findRowInSeq(const DWARFDebugLine::Sequence &seq, - uint64_t address) const { - if (!seq.containsPC(address)) +DWARFDebugLine::LineTable::findRowInSeq(const DWARFDebugLine::Sequence &Seq, + uint64_t Address) const { + if (!Seq.containsPC(Address)) return UnknownRowIndex; // Search for instruction address in the rows describing the sequence. // Rows are stored in a vector, so we may use arithmetical operations with // iterators. - DWARFDebugLine::Row row; - row.Address = address; - RowIter first_row = Rows.begin() + seq.FirstRowIndex; - RowIter last_row = Rows.begin() + seq.LastRowIndex; - LineTable::RowIter row_pos = std::lower_bound( - first_row, last_row, row, DWARFDebugLine::Row::orderByAddress); - if (row_pos == last_row) { - return seq.LastRowIndex - 1; + DWARFDebugLine::Row Row; + Row.Address = Address; + RowIter FirstRow = Rows.begin() + Seq.FirstRowIndex; + RowIter LastRow = Rows.begin() + Seq.LastRowIndex; + LineTable::RowIter RowPos = std::lower_bound( + FirstRow, LastRow, Row, DWARFDebugLine::Row::orderByAddress); + if (RowPos == LastRow) { + return Seq.LastRowIndex - 1; } - uint32_t index = seq.FirstRowIndex + (row_pos - first_row); - if (row_pos->Address > address) { - if (row_pos == first_row) + uint32_t Index = Seq.FirstRowIndex + (RowPos - FirstRow); + if (RowPos->Address > Address) { + if (RowPos == FirstRow) return UnknownRowIndex; else - index--; + Index--; } - return index; + return Index; } -uint32_t DWARFDebugLine::LineTable::lookupAddress(uint64_t address) const { +uint32_t DWARFDebugLine::LineTable::lookupAddress(uint64_t Address) const { if (Sequences.empty()) return UnknownRowIndex; // First, find an instruction sequence containing the given address. - DWARFDebugLine::Sequence sequence; - sequence.LowPC = address; - SequenceIter first_seq = Sequences.begin(); - SequenceIter last_seq = Sequences.end(); - SequenceIter seq_pos = std::lower_bound( - first_seq, last_seq, sequence, DWARFDebugLine::Sequence::orderByLowPC); - DWARFDebugLine::Sequence found_seq; - if (seq_pos == last_seq) { - found_seq = Sequences.back(); - } else if (seq_pos->LowPC == address) { - found_seq = *seq_pos; + DWARFDebugLine::Sequence Sequence; + Sequence.LowPC = Address; + SequenceIter FirstSeq = Sequences.begin(); + SequenceIter LastSeq = Sequences.end(); + SequenceIter SeqPos = std::lower_bound( + FirstSeq, LastSeq, Sequence, DWARFDebugLine::Sequence::orderByLowPC); + DWARFDebugLine::Sequence FoundSeq; + if (SeqPos == LastSeq) { + FoundSeq = Sequences.back(); + } else if (SeqPos->LowPC == Address) { + FoundSeq = *SeqPos; } else { - if (seq_pos == first_seq) + if (SeqPos == FirstSeq) return UnknownRowIndex; - found_seq = *(seq_pos - 1); + FoundSeq = *(SeqPos - 1); } - return findRowInSeq(found_seq, address); + return findRowInSeq(FoundSeq, Address); } bool DWARFDebugLine::LineTable::lookupAddressRange( - uint64_t address, uint64_t size, std::vector<uint32_t> &result) const { + uint64_t Address, uint64_t Size, std::vector<uint32_t> &Result) const { if (Sequences.empty()) return false; - uint64_t end_addr = address + size; + uint64_t EndAddr = Address + Size; // First, find an instruction sequence containing the given address. - DWARFDebugLine::Sequence sequence; - sequence.LowPC = address; - SequenceIter first_seq = Sequences.begin(); - SequenceIter last_seq = Sequences.end(); - SequenceIter seq_pos = std::lower_bound( - first_seq, last_seq, sequence, DWARFDebugLine::Sequence::orderByLowPC); - if (seq_pos == last_seq || seq_pos->LowPC != address) { - if (seq_pos == first_seq) + DWARFDebugLine::Sequence Sequence; + Sequence.LowPC = Address; + SequenceIter FirstSeq = Sequences.begin(); + SequenceIter LastSeq = Sequences.end(); + SequenceIter SeqPos = std::lower_bound( + FirstSeq, LastSeq, Sequence, DWARFDebugLine::Sequence::orderByLowPC); + if (SeqPos == LastSeq || SeqPos->LowPC != Address) { + if (SeqPos == FirstSeq) return false; - seq_pos--; + SeqPos--; } - if (!seq_pos->containsPC(address)) + if (!SeqPos->containsPC(Address)) return false; - SequenceIter start_pos = seq_pos; + SequenceIter StartPos = SeqPos; // Add the rows from the first sequence to the vector, starting with the // index we just calculated - while (seq_pos != last_seq && seq_pos->LowPC < end_addr) { - const DWARFDebugLine::Sequence &cur_seq = *seq_pos; + while (SeqPos != LastSeq && SeqPos->LowPC < EndAddr) { + const DWARFDebugLine::Sequence &CurSeq = *SeqPos; // For the first sequence, we need to find which row in the sequence is the // first in our range. - uint32_t first_row_index = cur_seq.FirstRowIndex; - if (seq_pos == start_pos) - first_row_index = findRowInSeq(cur_seq, address); + uint32_t FirstRowIndex = CurSeq.FirstRowIndex; + if (SeqPos == StartPos) + FirstRowIndex = findRowInSeq(CurSeq, Address); // Figure out the last row in the range. - uint32_t last_row_index = findRowInSeq(cur_seq, end_addr - 1); - if (last_row_index == UnknownRowIndex) - last_row_index = cur_seq.LastRowIndex - 1; + uint32_t LastRowIndex = findRowInSeq(CurSeq, EndAddr - 1); + if (LastRowIndex == UnknownRowIndex) + LastRowIndex = CurSeq.LastRowIndex - 1; - assert(first_row_index != UnknownRowIndex); - assert(last_row_index != UnknownRowIndex); + assert(FirstRowIndex != UnknownRowIndex); + assert(LastRowIndex != UnknownRowIndex); - for (uint32_t i = first_row_index; i <= last_row_index; ++i) { - result.push_back(i); + for (uint32_t I = FirstRowIndex; I <= LastRowIndex; ++I) { + Result.push_back(I); } - ++seq_pos; + ++SeqPos; } return true; } -bool -DWARFDebugLine::LineTable::hasFileAtIndex(uint64_t FileIndex) const { +bool DWARFDebugLine::LineTable::hasFileAtIndex(uint64_t FileIndex) const { return FileIndex != 0 && FileIndex <= Prologue.FileNames.size(); } -bool -DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex, - const char *CompDir, - FileLineInfoKind Kind, - std::string &Result) const { +bool DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex, + const char *CompDir, + FileLineInfoKind Kind, + std::string &Result) const { if (Kind == FileLineInfoKind::None || !hasFileAtIndex(FileIndex)) return false; const FileNameEntry &Entry = Prologue.FileNames[FileIndex - 1]; - const char *FileName = Entry.Name; + StringRef FileName = Entry.Name; if (Kind != FileLineInfoKind::AbsoluteFilePath || sys::path::is_absolute(FileName)) { Result = FileName; @@ -646,7 +784,7 @@ DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex, SmallString<16> FilePath; uint64_t IncludeDirIndex = Entry.DirIdx; - const char *IncludeDir = ""; + StringRef IncludeDir; // Be defensive about the contents of Entry. if (IncludeDirIndex > 0 && IncludeDirIndex <= Prologue.IncludeDirectories.size()) diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp index ae5b9d7..c240dd7 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugLoc.cpp -------------------------------------------------===// +//===- DWARFDebugLoc.cpp --------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -8,9 +8,15 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" -#include "llvm/Support/Dwarf.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cinttypes> +#include <cstdint> using namespace llvm; @@ -34,27 +40,19 @@ void DWARFDebugLoc::dump(raw_ostream &OS) const { } } -void DWARFDebugLoc::parse(DataExtractor data, unsigned AddressSize) { +void DWARFDebugLoc::parse(const DWARFDataExtractor &data) { uint32_t Offset = 0; - while (data.isValidOffset(Offset+AddressSize-1)) { + 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; - RelocAddrMap::const_iterator AI = RelocMap.find(Offset); - // 1. A beginning address offset. ... - E.Begin = data.getUnsigned(&Offset, AddressSize); - if (AI != RelocMap.end()) - E.Begin += AI->second.second; - - AI = RelocMap.find(Offset); - // 2. An ending address offset. ... - E.End = data.getUnsigned(&Offset, AddressSize); - if (AI != RelocMap.end()) - E.End += AI->second.second; + E.Begin = data.getRelocatedAddress(&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 @@ -71,7 +69,7 @@ void DWARFDebugLoc::parse(DataExtractor data, unsigned AddressSize) { } } if (data.isValidOffset(Offset)) - llvm::errs() << "error: failed to consume entire .debug_loc section\n"; + errs() << "error: failed to consume entire .debug_loc section\n"; } void DWARFDebugLocDWO::parse(DataExtractor data) { @@ -85,8 +83,8 @@ void DWARFDebugLocDWO::parse(DataExtractor data) { data.getU8(&Offset))) != dwarf::DW_LLE_end_of_list) { if (Kind != dwarf::DW_LLE_startx_length) { - llvm::errs() << "error: dumping support for LLE of kind " << (int)Kind - << " not implemented\n"; + errs() << "error: dumping support for LLE of kind " << (int)Kind + << " not implemented\n"; return; } @@ -123,4 +121,3 @@ void DWARFDebugLocDWO::dump(raw_ostream &OS) const { } } } - diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp index 7710a90..1b77be6 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugMacro.cpp -----------------------------------------------===// +//===- DWARFDebugMacro.cpp ------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -9,9 +9,9 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" #include "SyntaxHighlighting.h" -#include "llvm/Support/Dwarf.h" -#include "llvm/Support/Format.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Support/raw_ostream.h" +#include <cstdint> using namespace llvm; using namespace dwarf; diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp index 3c1fe93..5a4e39f 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugPubTable.cpp ---------------------------------------------===// +//===- DWARFDebugPubTable.cpp ---------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -8,11 +8,15 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/Support/DataExtractor.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include <cstdint> using namespace llvm; -using namespace llvm::dwarf; +using namespace dwarf; DWARFDebugPubTable::DWARFDebugPubTable(StringRef Data, bool LittleEndian, bool GnuStyle) @@ -41,7 +45,7 @@ DWARFDebugPubTable::DWARFDebugPubTable(StringRef Data, bool LittleEndian, } void DWARFDebugPubTable::dump(StringRef Name, raw_ostream &OS) const { - OS << "\n." << Name << " contents: a\n"; + OS << "\n." << Name << " contents:\n"; for (const Set &S : Sets) { OS << "length = " << format("0x%08x", S.Length); OS << " version = " << format("0x%04x", S.Version); @@ -54,7 +58,7 @@ void DWARFDebugPubTable::dump(StringRef Name, raw_ostream &OS) const { OS << format("0x%8.8x ", E.SecOffset); if (GnuStyle) { StringRef EntryLinkage = - dwarf::GDBIndexEntryLinkageString(E.Descriptor.Linkage); + GDBIndexEntryLinkageString(E.Descriptor.Linkage); StringRef EntryKind = dwarf::GDBIndexEntryKindString(E.Descriptor.Kind); OS << format("%-8s", EntryLinkage.data()) << ' ' << format("%-8s", EntryKind.data()) << ' '; diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp index d5df688..0b6ae86 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugRangesList.cpp ------------------------------------------===// +//===- DWARFDebugRangesList.cpp -------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -8,8 +8,12 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include <cinttypes> +#include <cstdint> +#include <utility> using namespace llvm; @@ -19,7 +23,8 @@ void DWARFDebugRangeList::clear() { Entries.clear(); } -bool DWARFDebugRangeList::extract(DataExtractor data, uint32_t *offset_ptr) { +bool DWARFDebugRangeList::extract(const DWARFDataExtractor &data, + uint32_t *offset_ptr) { clear(); if (!data.isValidOffset(*offset_ptr)) return false; @@ -30,8 +35,10 @@ bool DWARFDebugRangeList::extract(DataExtractor data, uint32_t *offset_ptr) { while (true) { RangeListEntry entry; uint32_t prev_offset = *offset_ptr; - entry.StartAddress = data.getAddress(offset_ptr); - entry.EndAddress = data.getAddress(offset_ptr); + entry.StartAddress = + data.getRelocatedAddress(offset_ptr, &entry.SectionIndex); + entry.EndAddress = data.getRelocatedAddress(offset_ptr); + // Check that both values were extracted correctly. if (*offset_ptr != prev_offset + 2 * AddressSize) { clear(); @@ -61,8 +68,8 @@ DWARFDebugRangeList::getAbsoluteRanges(uint64_t BaseAddress) const { if (RLE.isBaseAddressSelectionEntry(AddressSize)) { BaseAddress = RLE.EndAddress; } else { - Res.push_back(std::make_pair(BaseAddress + RLE.StartAddress, - BaseAddress + RLE.EndAddress)); + Res.push_back({BaseAddress + RLE.StartAddress, + BaseAddress + RLE.EndAddress, RLE.SectionIndex}); } } return Res; diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp index 89b83b1..111f0bb 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDie.cpp ------------------------------------------------------===// +//===- DWARFDie.cpp -------------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -9,23 +9,31 @@ #include "llvm/DebugInfo/DWARF/DWARFDie.h" #include "SyntaxHighlighting.h" -#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/Support/DataTypes.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Support/DataExtractor.h" #include "llvm/Support/Format.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cinttypes> +#include <cstdint> +#include <string> +#include <utility> using namespace llvm; using namespace dwarf; using namespace syntax; -namespace { - static void dumpApplePropertyAttribute(raw_ostream &OS, uint64_t Val) { +static void dumpApplePropertyAttribute(raw_ostream &OS, uint64_t Val) { OS << " ("; do { uint64_t Shift = countTrailingZeros(Val); @@ -52,14 +60,15 @@ static void dumpRanges(raw_ostream &OS, const DWARFAddressRangesVector& Ranges, OS << '\n'; OS.indent(Indent); OS << format("[0x%0*" PRIx64 " - 0x%0*" PRIx64 ")", - AddressSize*2, Range.first, - AddressSize*2, Range.second); + AddressSize*2, Range.LowPC, + AddressSize*2, Range.HighPC); } } static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, uint32_t *OffsetPtr, dwarf::Attribute Attr, - dwarf::Form Form, unsigned Indent) { + dwarf::Form Form, unsigned Indent, + DIDumpOptions DumpOpts) { if (!Die.isValid()) return; const char BaseIndent[] = " "; @@ -70,13 +79,15 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, WithColor(OS, syntax::Attribute) << attrString; else WithColor(OS, syntax::Attribute).get() << format("DW_AT_Unknown_%x", Attr); - - auto formString = FormEncodingString(Form); - if (!formString.empty()) - OS << " [" << formString << ']'; - else - OS << format(" [DW_FORM_Unknown_%x]", Form); - + + if (!DumpOpts.Brief) { + auto formString = FormEncodingString(Form); + if (!formString.empty()) + OS << " [" << formString << ']'; + else + OS << format(" [DW_FORM_Unknown_%x]", Form); + } + DWARFUnit *U = Die.getDwarfUnit(); DWARFFormValue formValue(Form); @@ -122,8 +133,6 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, OS << ")\n"; } -} // end anonymous namespace - bool DWARFDie::isSubprogramDIE() const { return getTag() == DW_TAG_subprogram; } @@ -134,7 +143,7 @@ bool DWARFDie::isSubroutineDIE() const { } Optional<DWARFFormValue> -DWARFDie::getAttributeValue(dwarf::Attribute Attr) const { +DWARFDie::find(dwarf::Attribute Attr) const { if (!isValid()) return None; auto AbbrevDecl = getAbbreviationDeclarationPtr(); @@ -143,54 +152,41 @@ DWARFDie::getAttributeValue(dwarf::Attribute Attr) const { return None; } -const char *DWARFDie::getAttributeValueAsString(dwarf::Attribute Attr, - const char *FailValue) const { - auto FormValue = getAttributeValue(Attr); - if (!FormValue) - return FailValue; - Optional<const char *> Result = FormValue->getAsCString(); - return Result.hasValue() ? Result.getValue() : FailValue; -} - -Optional<uint64_t> -DWARFDie::getAttributeValueAsAddress(dwarf::Attribute Attr) const { - if (auto FormValue = getAttributeValue(Attr)) - return FormValue->getAsAddress(); - return None; -} - -Optional<int64_t> -DWARFDie::getAttributeValueAsSignedConstant(dwarf::Attribute Attr) const { - if (auto FormValue = getAttributeValue(Attr)) - return FormValue->getAsSignedConstant(); - return None; -} - -Optional<uint64_t> -DWARFDie::getAttributeValueAsUnsignedConstant(dwarf::Attribute Attr) const { - if (auto FormValue = getAttributeValue(Attr)) - return FormValue->getAsUnsignedConstant(); - return None; -} - -Optional<uint64_t> -DWARFDie::getAttributeValueAsReference(dwarf::Attribute Attr) const { - if (auto FormValue = getAttributeValue(Attr)) - return FormValue->getAsReference(); +Optional<DWARFFormValue> +DWARFDie::find(ArrayRef<dwarf::Attribute> Attrs) const { + if (!isValid()) + return None; + auto AbbrevDecl = getAbbreviationDeclarationPtr(); + if (AbbrevDecl) { + for (auto Attr : Attrs) { + if (auto Value = AbbrevDecl->getAttributeValue(getOffset(), Attr, *U)) + return Value; + } + } return None; } -Optional<uint64_t> -DWARFDie::getAttributeValueAsSectionOffset(dwarf::Attribute Attr) const { - if (auto FormValue = getAttributeValue(Attr)) - return FormValue->getAsSectionOffset(); +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)) + return Value; return None; } - DWARFDie DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const { - auto SpecRef = getAttributeValueAsReference(Attr); + auto SpecRef = toReference(find(Attr)); if (SpecRef) { auto SpecUnit = U->getUnitSection().getUnitForOffset(*SpecRef); if (SpecUnit) @@ -201,14 +197,11 @@ DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const { Optional<uint64_t> DWARFDie::getRangesBaseAttribute() const { - auto Result = getAttributeValueAsSectionOffset(DW_AT_rnglists_base); - if (Result) - return Result; - return getAttributeValueAsSectionOffset(DW_AT_GNU_ranges_base); + return toSectionOffset(find({DW_AT_rnglists_base, DW_AT_GNU_ranges_base})); } Optional<uint64_t> DWARFDie::getHighPC(uint64_t LowPC) const { - if (auto FormValue = getAttributeValue(DW_AT_high_pc)) { + if (auto FormValue = find(DW_AT_high_pc)) { if (auto Address = FormValue->getAsAddress()) { // High PC is an address. return Address; @@ -221,13 +214,16 @@ Optional<uint64_t> DWARFDie::getHighPC(uint64_t LowPC) const { return None; } -bool DWARFDie::getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC) const { - auto LowPcAddr = getAttributeValueAsAddress(DW_AT_low_pc); +bool DWARFDie::getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC, + uint64_t &SectionIndex) const { + auto F = find(DW_AT_low_pc); + auto LowPcAddr = toAddress(F); if (!LowPcAddr) return false; if (auto HighPcAddr = getHighPC(*LowPcAddr)) { LowPC = *LowPcAddr; HighPC = *HighPcAddr; + SectionIndex = F->getSectionIndex(); return true; } return false; @@ -238,12 +234,12 @@ DWARFDie::getAddressRanges() const { if (isNULL()) return DWARFAddressRangesVector(); // Single range specified by low/high PC. - uint64_t LowPC, HighPC; - if (getLowAndHighPC(LowPC, HighPC)) { - return DWARFAddressRangesVector(1, std::make_pair(LowPC, HighPC)); - } + uint64_t LowPC, HighPC, Index; + if (getLowAndHighPC(LowPC, HighPC, Index)) + return {{LowPC, HighPC, Index}}; + // Multiple ranges from .debug_ranges section. - auto RangesOffset = getAttributeValueAsSectionOffset(DW_AT_ranges); + auto RangesOffset = toSectionOffset(find(DW_AT_ranges)); if (RangesOffset) { DWARFDebugRangeList RangeList; if (U->extractRangeList(*RangesOffset, RangeList)) @@ -267,7 +263,7 @@ DWARFDie::collectChildrenAddressRanges(DWARFAddressRangesVector& Ranges) const { bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const { for (const auto& R : getAddressRanges()) { - if (R.first <= Address && Address < R.second) + if (R.LowPC <= Address && Address < R.HighPC) return true; } return false; @@ -284,40 +280,35 @@ const char * DWARFDie::getName(DINameKind Kind) const { if (!isValid() || Kind == DINameKind::None) return nullptr; - const char *name = nullptr; // Try to get mangled name only if it was asked for. if (Kind == DINameKind::LinkageName) { - if ((name = getAttributeValueAsString(DW_AT_MIPS_linkage_name, nullptr))) - return name; - if ((name = getAttributeValueAsString(DW_AT_linkage_name, nullptr))) - return name; + if (auto Name = dwarf::toString(findRecursively({DW_AT_MIPS_linkage_name, + DW_AT_linkage_name}), nullptr)) + return Name; } - if ((name = getAttributeValueAsString(DW_AT_name, nullptr))) - return name; - // Try to get name from specification DIE. - DWARFDie SpecDie = getAttributeValueAsReferencedDie(DW_AT_specification); - if (SpecDie && (name = SpecDie.getName(Kind))) - return name; - // Try to get name from abstract origin DIE. - DWARFDie AbsDie = getAttributeValueAsReferencedDie(DW_AT_abstract_origin); - if (AbsDie && (name = AbsDie.getName(Kind))) - return name; + if (auto Name = dwarf::toString(findRecursively(DW_AT_name), nullptr)) + return Name; return nullptr; } +uint64_t DWARFDie::getDeclLine() const { + return toUnsigned(findRecursively(DW_AT_decl_line), 0); +} + void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine, - uint32_t &CallColumn) const { - CallFile = getAttributeValueAsUnsignedConstant(DW_AT_call_file).getValueOr(0); - CallLine = getAttributeValueAsUnsignedConstant(DW_AT_call_line).getValueOr(0); - CallColumn = - getAttributeValueAsUnsignedConstant(DW_AT_call_column).getValueOr(0); + uint32_t &CallColumn, + uint32_t &CallDiscriminator) const { + CallFile = toUnsigned(find(DW_AT_call_file), 0); + CallLine = toUnsigned(find(DW_AT_call_line), 0); + CallColumn = toUnsigned(find(DW_AT_call_column), 0); + CallDiscriminator = toUnsigned(find(DW_AT_GNU_discriminator), 0); } -void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, - unsigned Indent) const { +void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, unsigned Indent, + DIDumpOptions DumpOpts) const { if (!isValid()) return; - DataExtractor debug_info_data = U->getDebugInfoExtractor(); + DWARFDataExtractor debug_info_data = U->getDebugInfoExtractor(); const uint32_t Offset = getOffset(); uint32_t offset = Offset; @@ -334,20 +325,28 @@ void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, else WithColor(OS, syntax::Tag).get().indent(Indent) << format("DW_TAG_Unknown_%x", getTag()); - - OS << format(" [%u] %c\n", abbrCode, - AbbrevDecl->hasChildren() ? '*' : ' '); - + + if (!DumpOpts.Brief) + OS << format(" [%u] %c", abbrCode, + AbbrevDecl->hasChildren() ? '*' : ' '); + OS << '\n'; + // Dump all data in the DIE for the attributes. for (const auto &AttrSpec : AbbrevDecl->attributes()) { + if (AttrSpec.Form == DW_FORM_implicit_const) { + // We are dumping .debug_info section , + // implicit_const attribute values are not really stored here, + // but in .debug_abbrev section. So we just skip such attrs. + continue; + } dumpAttribute(OS, *this, &offset, AttrSpec.Attr, AttrSpec.Form, - Indent); + Indent, DumpOpts); } DWARFDie child = getFirstChild(); if (RecurseDepth > 0 && child) { while (child) { - child.dump(OS, RecurseDepth-1, Indent+2); + child.dump(OS, RecurseDepth-1, Indent+2, DumpOpts); child = child.getSibling(); } } @@ -361,33 +360,6 @@ void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, } } - -void DWARFDie::getInlinedChainForAddress( - const uint64_t Address, SmallVectorImpl<DWARFDie> &InlinedChain) const { - if (isNULL()) - return; - DWARFDie DIE(*this); - while (DIE) { - // Append current DIE to inlined chain only if it has correct tag - // (e.g. it is not a lexical block). - if (DIE.isSubroutineDIE()) - InlinedChain.push_back(DIE); - - // Try to get child which also contains provided address. - DWARFDie Child = DIE.getFirstChild(); - while (Child) { - if (Child.addressRangeContainsAddress(Address)) { - // Assume there is only one such child. - break; - } - Child = Child.getSibling(); - } - DIE = Child; - } - // Reverse the obtained chain to make the root of inlined chain last. - std::reverse(InlinedChain.begin(), InlinedChain.end()); -} - DWARFDie DWARFDie::getParent() const { if (isValid()) return U->getParent(Die); @@ -399,3 +371,53 @@ DWARFDie DWARFDie::getSibling() const { return U->getSibling(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) { + auto AbbrDecl = Die.getAbbreviationDeclarationPtr(); + assert(AbbrDecl && "Must have abbreviation declaration"); + if (End) { + // This is the end iterator so we set the index to the attribute count. + Index = AbbrDecl->getNumAttributes(); + } else { + // This is the begin iterator so we extract the value for this->Index. + AttrValue.Offset = D.getOffset() + AbbrDecl->getCodeByteSize(); + updateForIndex(*AbbrDecl, 0); + } +} + +void DWARFDie::attribute_iterator::updateForIndex( + const DWARFAbbreviationDeclaration &AbbrDecl, uint32_t I) { + Index = I; + // AbbrDecl must be valid before calling this function. + auto NumAttrs = AbbrDecl.getNumAttributes(); + if (Index < NumAttrs) { + AttrValue.Attr = AbbrDecl.getAttrByIndex(Index); + // Add the previous byte size of any previous attribute value. + AttrValue.Offset += AttrValue.ByteSize; + AttrValue.Value.setForm(AbbrDecl.getFormByIndex(Index)); + uint32_t ParseOffset = AttrValue.Offset; + auto U = Die.getDwarfUnit(); + assert(U && "Die must have valid DWARF unit"); + bool b = AttrValue.Value.extractValue(U->getDebugInfoExtractor(), + &ParseOffset, U); + (void)b; + assert(b && "extractValue cannot fail on fully parsed DWARF"); + AttrValue.ByteSize = ParseOffset - AttrValue.Offset; + } else { + assert(Index == NumAttrs && "Indexes should be [0, NumAttrs) only"); + AttrValue.clear(); + } +} + +DWARFDie::attribute_iterator &DWARFDie::attribute_iterator::operator++() { + if (auto AbbrDecl = Die.getAbbreviationDeclarationPtr()) + updateForIndex(*AbbrDecl, Index + 1); + return *this; +} diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp index dc9310d..83a7792 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -1,4 +1,4 @@ -//===-- DWARFFormValue.cpp ------------------------------------------------===// +//===- DWARFFormValue.cpp -------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,264 +7,240 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "SyntaxHighlighting.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" -#include <cassert> +#include <cinttypes> +#include <cstdint> #include <limits> + using namespace llvm; using namespace dwarf; using namespace syntax; static const DWARFFormValue::FormClass DWARF4FormClasses[] = { - DWARFFormValue::FC_Unknown, // 0x0 - DWARFFormValue::FC_Address, // 0x01 DW_FORM_addr - DWARFFormValue::FC_Unknown, // 0x02 unused - DWARFFormValue::FC_Block, // 0x03 DW_FORM_block2 - DWARFFormValue::FC_Block, // 0x04 DW_FORM_block4 - DWARFFormValue::FC_Constant, // 0x05 DW_FORM_data2 - // --- These can be FC_SectionOffset in DWARF3 and below: - DWARFFormValue::FC_Constant, // 0x06 DW_FORM_data4 - DWARFFormValue::FC_Constant, // 0x07 DW_FORM_data8 - // --- - DWARFFormValue::FC_String, // 0x08 DW_FORM_string - DWARFFormValue::FC_Block, // 0x09 DW_FORM_block - DWARFFormValue::FC_Block, // 0x0a DW_FORM_block1 - DWARFFormValue::FC_Constant, // 0x0b DW_FORM_data1 - DWARFFormValue::FC_Flag, // 0x0c DW_FORM_flag - DWARFFormValue::FC_Constant, // 0x0d DW_FORM_sdata - DWARFFormValue::FC_String, // 0x0e DW_FORM_strp - DWARFFormValue::FC_Constant, // 0x0f DW_FORM_udata - DWARFFormValue::FC_Reference, // 0x10 DW_FORM_ref_addr - DWARFFormValue::FC_Reference, // 0x11 DW_FORM_ref1 - DWARFFormValue::FC_Reference, // 0x12 DW_FORM_ref2 - DWARFFormValue::FC_Reference, // 0x13 DW_FORM_ref4 - DWARFFormValue::FC_Reference, // 0x14 DW_FORM_ref8 - DWARFFormValue::FC_Reference, // 0x15 DW_FORM_ref_udata - DWARFFormValue::FC_Indirect, // 0x16 DW_FORM_indirect - DWARFFormValue::FC_SectionOffset, // 0x17 DW_FORM_sec_offset - DWARFFormValue::FC_Exprloc, // 0x18 DW_FORM_exprloc - DWARFFormValue::FC_Flag, // 0x19 DW_FORM_flag_present -}; - -namespace { - -/// A helper class that can be used in DWARFFormValue.cpp functions that need -/// to know the byte size of DW_FORM values that vary in size depending on the -/// DWARF version, address byte size, or DWARF32 or DWARF64. -class FormSizeHelper { - uint16_t Version; - uint8_t AddrSize; - llvm::dwarf::DwarfFormat Format; - -public: - FormSizeHelper(uint16_t V, uint8_t A, llvm::dwarf::DwarfFormat F) - : Version(V), AddrSize(A), Format(F) {} - uint8_t getAddressByteSize() const { return AddrSize; } - uint8_t getRefAddrByteSize() const { - if (Version == 2) - return AddrSize; - return getDwarfOffsetByteSize(); - } - uint8_t getDwarfOffsetByteSize() const { - switch (Format) { - case dwarf::DwarfFormat::DWARF32: - return 4; - case dwarf::DwarfFormat::DWARF64: - return 8; - } - llvm_unreachable("Invalid Format value"); - } + DWARFFormValue::FC_Unknown, // 0x0 + DWARFFormValue::FC_Address, // 0x01 DW_FORM_addr + DWARFFormValue::FC_Unknown, // 0x02 unused + DWARFFormValue::FC_Block, // 0x03 DW_FORM_block2 + DWARFFormValue::FC_Block, // 0x04 DW_FORM_block4 + DWARFFormValue::FC_Constant, // 0x05 DW_FORM_data2 + // --- These can be FC_SectionOffset in DWARF3 and below: + DWARFFormValue::FC_Constant, // 0x06 DW_FORM_data4 + DWARFFormValue::FC_Constant, // 0x07 DW_FORM_data8 + // --- + DWARFFormValue::FC_String, // 0x08 DW_FORM_string + DWARFFormValue::FC_Block, // 0x09 DW_FORM_block + DWARFFormValue::FC_Block, // 0x0a DW_FORM_block1 + DWARFFormValue::FC_Constant, // 0x0b DW_FORM_data1 + DWARFFormValue::FC_Flag, // 0x0c DW_FORM_flag + DWARFFormValue::FC_Constant, // 0x0d DW_FORM_sdata + DWARFFormValue::FC_String, // 0x0e DW_FORM_strp + DWARFFormValue::FC_Constant, // 0x0f DW_FORM_udata + DWARFFormValue::FC_Reference, // 0x10 DW_FORM_ref_addr + DWARFFormValue::FC_Reference, // 0x11 DW_FORM_ref1 + DWARFFormValue::FC_Reference, // 0x12 DW_FORM_ref2 + DWARFFormValue::FC_Reference, // 0x13 DW_FORM_ref4 + DWARFFormValue::FC_Reference, // 0x14 DW_FORM_ref8 + DWARFFormValue::FC_Reference, // 0x15 DW_FORM_ref_udata + DWARFFormValue::FC_Indirect, // 0x16 DW_FORM_indirect + DWARFFormValue::FC_SectionOffset, // 0x17 DW_FORM_sec_offset + DWARFFormValue::FC_Exprloc, // 0x18 DW_FORM_exprloc + DWARFFormValue::FC_Flag, // 0x19 DW_FORM_flag_present }; -} // end anonymous namespace - -template <class T> -static Optional<uint8_t> getFixedByteSize(dwarf::Form Form, const T *U) { +Optional<uint8_t> +DWARFFormValue::getFixedByteSize(dwarf::Form Form, + const DWARFFormParams Params) { switch (Form) { - case DW_FORM_addr: - if (U) - return U->getAddressByteSize(); - return None; + case DW_FORM_addr: + assert(Params.Version && Params.AddrSize && "Invalid Params for form"); + return Params.AddrSize; + + case DW_FORM_block: // ULEB128 length L followed by L bytes. + case DW_FORM_block1: // 1 byte length L followed by L bytes. + case DW_FORM_block2: // 2 byte length L followed by L bytes. + case DW_FORM_block4: // 4 byte length L followed by L bytes. + case DW_FORM_string: // C-string with null terminator. + case DW_FORM_sdata: // SLEB128. + case DW_FORM_udata: // ULEB128. + case DW_FORM_ref_udata: // ULEB128. + case DW_FORM_indirect: // ULEB128. + case DW_FORM_exprloc: // ULEB128 length L followed by L bytes. + case DW_FORM_strx: // ULEB128. + case DW_FORM_addrx: // ULEB128. + case DW_FORM_loclistx: // ULEB128. + case DW_FORM_rnglistx: // ULEB128. + case DW_FORM_GNU_addr_index: // ULEB128. + case DW_FORM_GNU_str_index: // ULEB128. + return None; - case DW_FORM_block: // ULEB128 length L followed by L bytes. - case DW_FORM_block1: // 1 byte length L followed by L bytes. - case DW_FORM_block2: // 2 byte length L followed by L bytes. - case DW_FORM_block4: // 4 byte length L followed by L bytes. - case DW_FORM_string: // C-string with null terminator. - case DW_FORM_sdata: // SLEB128. - case DW_FORM_udata: // ULEB128. - case DW_FORM_ref_udata: // ULEB128. - case DW_FORM_indirect: // ULEB128. - case DW_FORM_exprloc: // ULEB128 length L followed by L bytes. - case DW_FORM_strx: // ULEB128. - case DW_FORM_addrx: // ULEB128. - case DW_FORM_loclistx: // ULEB128. - case DW_FORM_rnglistx: // ULEB128. - case DW_FORM_GNU_addr_index: // ULEB128. - case DW_FORM_GNU_str_index: // ULEB128. - return None; + case DW_FORM_ref_addr: + assert(Params.Version && Params.AddrSize && "Invalid Params for form"); + return Params.getRefAddrByteSize(); - case DW_FORM_ref_addr: - if (U) - return U->getRefAddrByteSize(); - return None; + case DW_FORM_flag: + case DW_FORM_data1: + case DW_FORM_ref1: + case DW_FORM_strx1: + case DW_FORM_addrx1: + return 1; - case DW_FORM_flag: - case DW_FORM_data1: - case DW_FORM_ref1: - return 1; + case DW_FORM_data2: + case DW_FORM_ref2: + case DW_FORM_strx2: + case DW_FORM_addrx2: + return 2; - case DW_FORM_data2: - case DW_FORM_ref2: - return 2; + case DW_FORM_strx3: + return 3; - case DW_FORM_data4: - case DW_FORM_ref4: - return 4; + case DW_FORM_data4: + case DW_FORM_ref4: + case DW_FORM_ref_sup4: + case DW_FORM_strx4: + case DW_FORM_addrx4: + return 4; - case DW_FORM_strp: - case DW_FORM_GNU_ref_alt: - case DW_FORM_GNU_strp_alt: - case DW_FORM_line_strp: - case DW_FORM_sec_offset: - case DW_FORM_strp_sup: - case DW_FORM_ref_sup: - if (U) - return U->getDwarfOffsetByteSize(); - return None; + case DW_FORM_strp: + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + case DW_FORM_line_strp: + case DW_FORM_sec_offset: + case DW_FORM_strp_sup: + assert(Params.Version && Params.AddrSize && "Invalid Params for form"); + return Params.getDwarfOffsetByteSize(); - case DW_FORM_data8: - case DW_FORM_ref8: - case DW_FORM_ref_sig8: - return 8; + case DW_FORM_data8: + case DW_FORM_ref8: + case DW_FORM_ref_sig8: + case DW_FORM_ref_sup8: + return 8; - case DW_FORM_flag_present: - return 0; + case DW_FORM_flag_present: + return 0; - case DW_FORM_data16: - return 16; + case DW_FORM_data16: + return 16; - case DW_FORM_implicit_const: - // The implicit value is stored in the abbreviation as a SLEB128, and - // there no data in debug info. - return 0; + case DW_FORM_implicit_const: + // The implicit value is stored in the abbreviation as a SLEB128, and + // there no data in debug info. + return 0; - default: - llvm_unreachable("Handle this form in this switch statement"); + default: + llvm_unreachable("Handle this form in this switch statement"); } return None; } -template <class T> -static bool skipFormValue(dwarf::Form Form, const DataExtractor &DebugInfoData, - uint32_t *OffsetPtr, const T *U) { +bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData, + uint32_t *OffsetPtr, + const DWARFFormParams Params) { bool Indirect = false; do { switch (Form) { - // Blocks of inlined data that have a length field and the data bytes - // inlined in the .debug_info. - case DW_FORM_exprloc: - case DW_FORM_block: { - uint64_t size = DebugInfoData.getULEB128(OffsetPtr); - *OffsetPtr += size; - return true; - } - case DW_FORM_block1: { - uint8_t size = DebugInfoData.getU8(OffsetPtr); - *OffsetPtr += size; - return true; - } - case DW_FORM_block2: { - uint16_t size = DebugInfoData.getU16(OffsetPtr); - *OffsetPtr += size; - return true; - } - case DW_FORM_block4: { - uint32_t size = DebugInfoData.getU32(OffsetPtr); - *OffsetPtr += size; + // Blocks of inlined data that have a length field and the data bytes + // inlined in the .debug_info. + case DW_FORM_exprloc: + case DW_FORM_block: { + uint64_t size = DebugInfoData.getULEB128(OffsetPtr); + *OffsetPtr += size; + return true; + } + case DW_FORM_block1: { + uint8_t size = DebugInfoData.getU8(OffsetPtr); + *OffsetPtr += size; + return true; + } + case DW_FORM_block2: { + uint16_t size = DebugInfoData.getU16(OffsetPtr); + *OffsetPtr += size; + return true; + } + case DW_FORM_block4: { + uint32_t size = DebugInfoData.getU32(OffsetPtr); + *OffsetPtr += size; + return true; + } + + // Inlined NULL terminated C-strings. + case DW_FORM_string: + DebugInfoData.getCStr(OffsetPtr); + return true; + + case DW_FORM_addr: + case DW_FORM_ref_addr: + case DW_FORM_flag_present: + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + case DW_FORM_flag: + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_sig8: + case DW_FORM_ref_sup4: + case DW_FORM_ref_sup8: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx4: + case DW_FORM_addrx1: + case DW_FORM_addrx2: + case DW_FORM_addrx4: + case DW_FORM_sec_offset: + case DW_FORM_strp: + case DW_FORM_strp_sup: + case DW_FORM_line_strp: + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + if (Optional<uint8_t> FixedSize = + DWARFFormValue::getFixedByteSize(Form, Params)) { + *OffsetPtr += *FixedSize; return true; } + return false; - // Inlined NULL terminated C-strings. - case DW_FORM_string: - DebugInfoData.getCStr(OffsetPtr); - return true; + // signed or unsigned LEB 128 values. + case DW_FORM_sdata: + DebugInfoData.getSLEB128(OffsetPtr); + return true; - case DW_FORM_addr: - case DW_FORM_ref_addr: - case DW_FORM_flag_present: - case DW_FORM_data1: - case DW_FORM_data2: - case DW_FORM_data4: - case DW_FORM_data8: - case DW_FORM_flag: - case DW_FORM_ref1: - case DW_FORM_ref2: - case DW_FORM_ref4: - case DW_FORM_ref8: - case DW_FORM_ref_sig8: - case DW_FORM_ref_sup: - case DW_FORM_sec_offset: - case DW_FORM_strp: - case DW_FORM_strp_sup: - case DW_FORM_line_strp: - case DW_FORM_GNU_ref_alt: - case DW_FORM_GNU_strp_alt: - if (Optional<uint8_t> FixedSize = ::getFixedByteSize(Form, U)) { - *OffsetPtr += *FixedSize; - return true; - } - return false; + case DW_FORM_udata: + case DW_FORM_ref_udata: + case DW_FORM_strx: + case DW_FORM_addrx: + case DW_FORM_loclistx: + case DW_FORM_rnglistx: + case DW_FORM_GNU_addr_index: + case DW_FORM_GNU_str_index: + DebugInfoData.getULEB128(OffsetPtr); + return true; - // signed or unsigned LEB 128 values. - case DW_FORM_sdata: - DebugInfoData.getSLEB128(OffsetPtr); - return true; + case DW_FORM_indirect: + Indirect = true; + Form = static_cast<dwarf::Form>(DebugInfoData.getULEB128(OffsetPtr)); + break; - case DW_FORM_udata: - case DW_FORM_ref_udata: - case DW_FORM_strx: - case DW_FORM_addrx: - case DW_FORM_loclistx: - case DW_FORM_rnglistx: - case DW_FORM_GNU_addr_index: - case DW_FORM_GNU_str_index: - DebugInfoData.getULEB128(OffsetPtr); - return true; - - case DW_FORM_indirect: - Indirect = true; - Form = static_cast<dwarf::Form>(DebugInfoData.getULEB128(OffsetPtr)); - break; - - default: - return false; + default: + return false; } } while (Indirect); return true; } -Optional<uint8_t> DWARFFormValue::getFixedByteSize(dwarf::Form Form, - const DWARFUnit *U) { - return ::getFixedByteSize(Form, U); -} - -Optional<uint8_t> -DWARFFormValue::getFixedByteSize(dwarf::Form Form, uint16_t Version, - uint8_t AddrSize, - llvm::dwarf::DwarfFormat Format) { - FormSizeHelper FSH(Version, AddrSize, Format); - return ::getFixedByteSize(Form, &FSH); -} - bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { // First, check DWARF4 form classes. if (Form < makeArrayRef(DWARF4FormClasses).size() && @@ -279,6 +255,11 @@ bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { return (FC == FC_Address); case DW_FORM_GNU_str_index: case DW_FORM_GNU_strp_alt: + case DW_FORM_strx: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx3: + case DW_FORM_strx4: return (FC == FC_String); case DW_FORM_implicit_const: return (FC == FC_Constant); @@ -287,178 +268,170 @@ bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { } // In DWARF3 DW_FORM_data4 and DW_FORM_data8 served also as a section offset. // Don't check for DWARF version here, as some producers may still do this - // by mistake. - return (Form == DW_FORM_data4 || Form == DW_FORM_data8) && + // by mistake. Also accept DW_FORM_strp since this is .debug_str section + // offset. + return (Form == DW_FORM_data4 || Form == DW_FORM_data8 || + Form == DW_FORM_strp) && FC == FC_SectionOffset; } -bool DWARFFormValue::extractValue(const DataExtractor &data, - uint32_t *offset_ptr, - const DWARFUnit *cu) { - U = cu; - bool indirect = false; - bool is_block = false; +bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data, + uint32_t *OffsetPtr, const DWARFUnit *CU) { + U = CU; + bool Indirect = false; + bool IsBlock = false; Value.data = nullptr; // Read the value for the form into value and follow and DW_FORM_indirect // instances we run into do { - indirect = false; + Indirect = false; switch (Form) { case DW_FORM_addr: case DW_FORM_ref_addr: { if (!U) return false; - uint16_t AddrSize = - (Form == DW_FORM_addr) - ? U->getAddressByteSize() - : U->getRefAddrByteSize(); - RelocAddrMap::const_iterator AI = U->getRelocMap()->find(*offset_ptr); - if (AI != U->getRelocMap()->end()) { - Value.uval = data.getUnsigned(offset_ptr, AddrSize) + AI->second.second; - } else - Value.uval = data.getUnsigned(offset_ptr, AddrSize); + uint16_t Size = (Form == DW_FORM_addr) ? U->getAddressByteSize() + : U->getRefAddrByteSize(); + Value.uval = Data.getRelocatedValue(Size, OffsetPtr, &Value.SectionIndex); break; } case DW_FORM_exprloc: case DW_FORM_block: - Value.uval = data.getULEB128(offset_ptr); - is_block = true; + Value.uval = Data.getULEB128(OffsetPtr); + IsBlock = true; break; case DW_FORM_block1: - Value.uval = data.getU8(offset_ptr); - is_block = true; + Value.uval = Data.getU8(OffsetPtr); + IsBlock = true; break; case DW_FORM_block2: - Value.uval = data.getU16(offset_ptr); - is_block = true; + Value.uval = Data.getU16(OffsetPtr); + IsBlock = true; break; case DW_FORM_block4: - Value.uval = data.getU32(offset_ptr); - is_block = true; + Value.uval = Data.getU32(OffsetPtr); + IsBlock = true; break; case DW_FORM_data1: case DW_FORM_ref1: case DW_FORM_flag: - Value.uval = data.getU8(offset_ptr); + case DW_FORM_strx1: + case DW_FORM_addrx1: + Value.uval = Data.getU8(OffsetPtr); break; case DW_FORM_data2: case DW_FORM_ref2: - Value.uval = data.getU16(offset_ptr); + case DW_FORM_strx2: + case DW_FORM_addrx2: + Value.uval = Data.getU16(OffsetPtr); + break; + case DW_FORM_strx3: + Value.uval = Data.getU24(OffsetPtr); break; case DW_FORM_data4: - case DW_FORM_ref4: { - Value.uval = data.getU32(offset_ptr); - if (!U) - break; - RelocAddrMap::const_iterator AI = U->getRelocMap()->find(*offset_ptr-4); - if (AI != U->getRelocMap()->end()) - Value.uval += AI->second.second; + case DW_FORM_ref4: + case DW_FORM_ref_sup4: + case DW_FORM_strx4: + case DW_FORM_addrx4: + Value.uval = Data.getRelocatedValue(4, OffsetPtr); break; - } case DW_FORM_data8: case DW_FORM_ref8: - Value.uval = data.getU64(offset_ptr); + case DW_FORM_ref_sup8: + Value.uval = Data.getU64(OffsetPtr); break; case DW_FORM_sdata: - Value.sval = data.getSLEB128(offset_ptr); + Value.sval = Data.getSLEB128(OffsetPtr); break; case DW_FORM_udata: case DW_FORM_ref_udata: - Value.uval = data.getULEB128(offset_ptr); + Value.uval = Data.getULEB128(OffsetPtr); break; case DW_FORM_string: - Value.cstr = data.getCStr(offset_ptr); + Value.cstr = Data.getCStr(OffsetPtr); break; case DW_FORM_indirect: - Form = static_cast<dwarf::Form>(data.getULEB128(offset_ptr)); - indirect = true; + Form = static_cast<dwarf::Form>(Data.getULEB128(OffsetPtr)); + Indirect = true; break; case DW_FORM_strp: case DW_FORM_sec_offset: case DW_FORM_GNU_ref_alt: case DW_FORM_GNU_strp_alt: case DW_FORM_line_strp: - case DW_FORM_strp_sup: - case DW_FORM_ref_sup: { + case DW_FORM_strp_sup: { if (!U) return false; - RelocAddrMap::const_iterator AI = U->getRelocMap()->find(*offset_ptr); - uint8_t Size = U->getDwarfOffsetByteSize(); - Value.uval = data.getUnsigned(offset_ptr, Size); - if (AI != U->getRelocMap()->end()) - Value.uval += AI->second.second; + Value.uval = + Data.getRelocatedValue(U->getDwarfOffsetByteSize(), OffsetPtr); break; } case DW_FORM_flag_present: Value.uval = 1; break; case DW_FORM_ref_sig8: - Value.uval = data.getU64(offset_ptr); + Value.uval = Data.getU64(OffsetPtr); break; case DW_FORM_GNU_addr_index: case DW_FORM_GNU_str_index: - Value.uval = data.getULEB128(offset_ptr); + case DW_FORM_strx: + Value.uval = Data.getULEB128(OffsetPtr); break; default: - return false; + // DWARFFormValue::skipValue() will have caught this and caused all + // DWARF DIEs to fail to be parsed, so this code is not be reachable. + llvm_unreachable("unsupported form"); } - } while (indirect); + } while (Indirect); - if (is_block) { - StringRef str = data.getData().substr(*offset_ptr, Value.uval); + if (IsBlock) { + StringRef Str = Data.getData().substr(*OffsetPtr, Value.uval); Value.data = nullptr; - if (!str.empty()) { - Value.data = reinterpret_cast<const uint8_t *>(str.data()); - *offset_ptr += Value.uval; + if (!Str.empty()) { + Value.data = reinterpret_cast<const uint8_t *>(Str.data()); + *OffsetPtr += Value.uval; } } return true; } -bool DWARFFormValue::skipValue(DataExtractor DebugInfoData, - uint32_t *offset_ptr, const DWARFUnit *U) const { - return DWARFFormValue::skipValue(Form, DebugInfoData, offset_ptr, U); -} - -bool DWARFFormValue::skipValue(dwarf::Form form, DataExtractor DebugInfoData, - uint32_t *offset_ptr, const DWARFUnit *U) { - return skipFormValue(form, DebugInfoData, offset_ptr, U); -} - -bool DWARFFormValue::skipValue(dwarf::Form form, DataExtractor DebugInfoData, - uint32_t *offset_ptr, uint16_t Version, - uint8_t AddrSize, - llvm::dwarf::DwarfFormat Format) { - FormSizeHelper FSH(Version, AddrSize, Format); - return skipFormValue(form, DebugInfoData, offset_ptr, &FSH); -} - -void -DWARFFormValue::dump(raw_ostream &OS) const { - uint64_t uvalue = Value.uval; - bool cu_relative_offset = false; +void DWARFFormValue::dump(raw_ostream &OS) const { + uint64_t UValue = Value.uval; + bool CURelativeOffset = false; switch (Form) { - case DW_FORM_addr: OS << format("0x%016" PRIx64, uvalue); break; + case DW_FORM_addr: + OS << format("0x%016" PRIx64, UValue); + break; case DW_FORM_GNU_addr_index: { - OS << format(" indexed (%8.8x) address = ", (uint32_t)uvalue); + OS << format(" indexed (%8.8x) address = ", (uint32_t)UValue); uint64_t Address; if (U == nullptr) OS << "<invalid dwarf unit>"; - else if (U->getAddrOffsetSectionItem(uvalue, Address)) + else if (U->getAddrOffsetSectionItem(UValue, Address)) OS << format("0x%016" PRIx64, Address); else OS << "<no .debug_addr section>"; break; } - case DW_FORM_flag_present: OS << "true"; break; + case DW_FORM_flag_present: + OS << "true"; + break; case DW_FORM_flag: - case DW_FORM_data1: OS << format("0x%02x", (uint8_t)uvalue); break; - case DW_FORM_data2: OS << format("0x%04x", (uint16_t)uvalue); break; - case DW_FORM_data4: OS << format("0x%08x", (uint32_t)uvalue); break; + case DW_FORM_data1: + OS << format("0x%02x", (uint8_t)UValue); + break; + case DW_FORM_data2: + OS << format("0x%04x", (uint16_t)UValue); + break; + case DW_FORM_data4: + OS << format("0x%08x", (uint32_t)UValue); + break; case DW_FORM_ref_sig8: - case DW_FORM_data8: OS << format("0x%016" PRIx64, uvalue); break; + case DW_FORM_data8: + OS << format("0x%016" PRIx64, UValue); + break; case DW_FORM_string: OS << '"'; OS.write_escaped(Value.cstr); @@ -469,83 +442,97 @@ DWARFFormValue::dump(raw_ostream &OS) const { case DW_FORM_block1: case DW_FORM_block2: case DW_FORM_block4: - if (uvalue > 0) { + if (UValue > 0) { switch (Form) { case DW_FORM_exprloc: - case DW_FORM_block: OS << format("<0x%" PRIx64 "> ", uvalue); break; - case DW_FORM_block1: OS << format("<0x%2.2x> ", (uint8_t)uvalue); break; - case DW_FORM_block2: OS << format("<0x%4.4x> ", (uint16_t)uvalue); break; - case DW_FORM_block4: OS << format("<0x%8.8x> ", (uint32_t)uvalue); break; - default: break; + case DW_FORM_block: + OS << format("<0x%" PRIx64 "> ", UValue); + break; + case DW_FORM_block1: + OS << format("<0x%2.2x> ", (uint8_t)UValue); + break; + case DW_FORM_block2: + OS << format("<0x%4.4x> ", (uint16_t)UValue); + break; + case DW_FORM_block4: + OS << format("<0x%8.8x> ", (uint32_t)UValue); + break; + default: + break; } - const uint8_t* data_ptr = Value.data; - if (data_ptr) { - // uvalue contains size of block - const uint8_t* end_data_ptr = data_ptr + uvalue; - while (data_ptr < end_data_ptr) { - OS << format("%2.2x ", *data_ptr); - ++data_ptr; + const uint8_t *DataPtr = Value.data; + if (DataPtr) { + // UValue contains size of block + const uint8_t *EndDataPtr = DataPtr + UValue; + while (DataPtr < EndDataPtr) { + OS << format("%2.2x ", *DataPtr); + ++DataPtr; } - } - else + } else OS << "NULL"; } break; - case DW_FORM_sdata: OS << Value.sval; break; - case DW_FORM_udata: OS << Value.uval; break; - case DW_FORM_strp: { - OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)uvalue); + case DW_FORM_sdata: + OS << Value.sval; + break; + case DW_FORM_udata: + OS << Value.uval; + break; + case DW_FORM_strp: + OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)UValue); dumpString(OS); break; - } - case DW_FORM_GNU_str_index: { - OS << format(" indexed (%8.8x) string = ", (uint32_t)uvalue); + case DW_FORM_strx: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx3: + case DW_FORM_strx4: + case DW_FORM_GNU_str_index: + 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); + case DW_FORM_GNU_strp_alt: + OS << format("alt indirect string, offset: 0x%" PRIx64 "", UValue); dumpString(OS); break; - } case DW_FORM_ref_addr: - OS << format("0x%016" PRIx64, uvalue); + OS << format("0x%016" PRIx64, UValue); break; case DW_FORM_ref1: - cu_relative_offset = true; - OS << format("cu + 0x%2.2x", (uint8_t)uvalue); + CURelativeOffset = true; + OS << format("cu + 0x%2.2x", (uint8_t)UValue); break; case DW_FORM_ref2: - cu_relative_offset = true; - OS << format("cu + 0x%4.4x", (uint16_t)uvalue); + CURelativeOffset = true; + OS << format("cu + 0x%4.4x", (uint16_t)UValue); break; case DW_FORM_ref4: - cu_relative_offset = true; - OS << format("cu + 0x%4.4x", (uint32_t)uvalue); + CURelativeOffset = true; + OS << format("cu + 0x%4.4x", (uint32_t)UValue); break; case DW_FORM_ref8: - cu_relative_offset = true; - OS << format("cu + 0x%8.8" PRIx64, uvalue); + CURelativeOffset = true; + OS << format("cu + 0x%8.8" PRIx64, UValue); break; case DW_FORM_ref_udata: - cu_relative_offset = true; - OS << format("cu + 0x%" PRIx64, uvalue); + CURelativeOffset = true; + OS << format("cu + 0x%" PRIx64, UValue); break; case DW_FORM_GNU_ref_alt: - OS << format("<alt 0x%" PRIx64 ">", uvalue); + OS << format("<alt 0x%" PRIx64 ">", UValue); break; - // All DW_FORM_indirect attributes should be resolved prior to calling - // this function + // All DW_FORM_indirect attributes should be resolved prior to calling + // this function case DW_FORM_indirect: OS << "DW_FORM_indirect"; break; - // Should be formatted to 64-bit for DWARF64. + // Should be formatted to 64-bit for DWARF64. case DW_FORM_sec_offset: - OS << format("0x%08x", (uint32_t)uvalue); + OS << format("0x%08x", (uint32_t)UValue); break; default: @@ -553,10 +540,10 @@ DWARFFormValue::dump(raw_ostream &OS) const { break; } - if (cu_relative_offset) { + if (CURelativeOffset) { OS << " => {"; WithColor(OS, syntax::Address).get() - << format("0x%8.8" PRIx64, uvalue + (U ? U->getOffset() : 0)); + << format("0x%8.8" PRIx64, UValue + (U ? U->getOffset() : 0)); OS << "}"; } } @@ -580,8 +567,10 @@ Optional<const char *> DWARFFormValue::getAsCString() const { if (Form == DW_FORM_GNU_strp_alt || U == nullptr) return None; uint32_t Offset = Value.uval; - if (Form == DW_FORM_GNU_str_index) { - uint32_t StrOffset; + if (Form == DW_FORM_GNU_str_index || Form == DW_FORM_strx || + Form == DW_FORM_strx1 || Form == DW_FORM_strx2 || Form == DW_FORM_strx3 || + Form == DW_FORM_strx4) { + uint64_t StrOffset; if (!U->getStringOffsetSectionItem(Offset, StrOffset)) return None; Offset = StrOffset; @@ -633,15 +622,16 @@ Optional<uint64_t> DWARFFormValue::getAsSectionOffset() const { } Optional<uint64_t> DWARFFormValue::getAsUnsignedConstant() const { - if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag)) - || Form == DW_FORM_sdata) + if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag)) || + Form == DW_FORM_sdata) return None; return Value.uval; } Optional<int64_t> DWARFFormValue::getAsSignedConstant() const { if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag)) || - (Form == DW_FORM_udata && uint64_t(std::numeric_limits<int64_t>::max()) < Value.uval)) + (Form == DW_FORM_udata && + uint64_t(std::numeric_limits<int64_t>::max()) < Value.uval)) return None; switch (Form) { case DW_FORM_data4: @@ -674,4 +664,3 @@ Optional<uint64_t> DWARFFormValue::getAsReferenceUVal() const { return None; return Value.uval; } - diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp index ebb9961..ebd6104 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp @@ -1,4 +1,4 @@ -//===-- DWARFGdbIndex.cpp -------------------------------------------------===// +//===- DWARFGdbIndex.cpp --------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -8,9 +8,15 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Support/ErrorHandling.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cinttypes> +#include <cstdint> +#include <utility> using namespace llvm; @@ -33,8 +39,9 @@ void DWARFGdbIndex::dumpAddressArea(raw_ostream &OS) const { << '\n'; for (const AddressEntry &Addr : AddressArea) OS << format( - " Low address = 0x%llx, High address = 0x%llx, CU index = %d\n", - Addr.LowAddress, Addr.HighAddress, Addr.CuIndex); + " Low/High address = [0x%llx, 0x%llx) (Size: 0x%llx), CU id = %d\n", + Addr.LowAddress, Addr.HighAddress, Addr.HighAddress - Addr.LowAddress, + Addr.CuIndex); } void DWARFGdbIndex::dumpSymbolTable(raw_ostream &OS) const { diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp index 88fb203..fd1684d 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp @@ -1,4 +1,4 @@ -//===-- DWARFTypeUnit.cpp -------------------------------------------------===// +//===- DWARFTypeUnit.cpp --------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -8,10 +8,13 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" -#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/Support/Dwarf.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include <cinttypes> using namespace llvm; @@ -21,27 +24,33 @@ bool DWARFTypeUnit::extractImpl(DataExtractor debug_info, return false; TypeHash = debug_info.getU64(offset_ptr); TypeOffset = debug_info.getU32(offset_ptr); - return TypeOffset < getLength(); + // TypeOffset is relative to the beginning of the header, + // so we have to account for the leading length field. + // FIXME: The size of the length field is 12 in DWARF64. + unsigned SizeOfLength = 4; + return TypeOffset < getLength() + SizeOfLength; } void DWARFTypeUnit::dump(raw_ostream &OS, bool SummarizeTypes) { DWARFDie TD = getDIEForOffset(TypeOffset + getOffset()); - const char *Name = TD.getAttributeValueAsString(llvm::dwarf::DW_AT_name, ""); + const char *Name = TD.getName(DINameKind::ShortName); if (SummarizeTypes) { OS << "name = '" << Name << "'" - << " type_signature = " << format("0x%16" PRIx64, TypeHash) + << " type_signature = " << format("0x%016" PRIx64, TypeHash) << " length = " << format("0x%08x", getLength()) << '\n'; return; } OS << format("0x%08x", getOffset()) << ": Type Unit:" << " length = " << format("0x%08x", getLength()) - << " version = " << format("0x%04x", getVersion()) - << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset()) + << " version = " << format("0x%04x", getVersion()); + if (getVersion() >= 5) + OS << " unit_type = " << dwarf::UnitTypeString(getUnitType()); + OS << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset()) << " addr_size = " << format("0x%02x", getAddressByteSize()) << " name = '" << Name << "'" - << " type_signature = " << format("0x%16" PRIx64, TypeHash) + << " type_signature = " << format("0x%016" PRIx64, TypeHash) << " type_offset = " << format("0x%04x", TypeOffset) << " (next unit at " << format("0x%08x", getNextUnitOffset()) << ")\n"; diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp index ee2c569..043bdb8 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -1,4 +1,4 @@ -//===-- DWARFUnit.cpp -----------------------------------------------------===// +//===- DWARFUnit.cpp ------------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,54 +7,51 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/Casting.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Path.h" #include <algorithm> #include <cassert> +#include <cstddef> #include <cstdint> #include <cstdio> +#include <utility> #include <vector> -namespace llvm { - +using namespace llvm; using namespace dwarf; void DWARFUnitSectionBase::parse(DWARFContext &C, const DWARFSection &Section) { - parseImpl(C, Section, C.getDebugAbbrev(), C.getRangeSection(), - C.getStringSection(), StringRef(), C.getAddrSection(), - C.getLineSection().Data, C.isLittleEndian(), false); + parseImpl(C, Section, C.getDebugAbbrev(), &C.getRangeSection(), + C.getStringSection(), C.getStringOffsetSection(), + &C.getAddrSection(), C.getLineSection(), C.isLittleEndian(), false); } void DWARFUnitSectionBase::parseDWO(DWARFContext &C, const DWARFSection &DWOSection, DWARFUnitIndex *Index) { - parseImpl(C, DWOSection, C.getDebugAbbrevDWO(), C.getRangeDWOSection(), + parseImpl(C, DWOSection, C.getDebugAbbrevDWO(), &C.getRangeDWOSection(), C.getStringDWOSection(), C.getStringOffsetDWOSection(), - C.getAddrSection(), C.getLineDWOSection().Data, C.isLittleEndian(), + &C.getAddrSection(), C.getLineDWOSection(), C.isLittleEndian(), true); } DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section, - const DWARFDebugAbbrev *DA, StringRef RS, StringRef SS, - StringRef SOS, StringRef AOS, StringRef LS, bool LE, + const DWARFDebugAbbrev *DA, const DWARFSection *RS, + StringRef SS, const DWARFSection &SOS, + const DWARFSection *AOS, const DWARFSection &LS, bool LE, bool IsDWO, const DWARFUnitSectionBase &UnitSection, const DWARFUnitIndex::Entry *IndexEntry) : Context(DC), InfoSection(Section), Abbrev(DA), RangeSection(RS), - LineSection(LS), StringSection(SS), StringOffsetSection([&]() { - if (IndexEntry) - if (const auto *C = IndexEntry->getOffset(DW_SECT_STR_OFFSETS)) - return SOS.slice(C->Offset, C->Offset + C->Length); - return SOS; - }()), + LineSection(LS), StringSection(SS), StringOffsetSection(SOS), AddrOffsetSection(AOS), isLittleEndian(LE), isDWO(IsDWO), UnitSection(UnitSection), IndexEntry(IndexEntry) { clear(); @@ -64,30 +61,40 @@ DWARFUnit::~DWARFUnit() = default; bool DWARFUnit::getAddrOffsetSectionItem(uint32_t Index, uint64_t &Result) const { - uint32_t Offset = AddrOffsetSectionBase + Index * AddrSize; - if (AddrOffsetSection.size() < Offset + AddrSize) + uint32_t Offset = AddrOffsetSectionBase + Index * getAddressByteSize(); + if (AddrOffsetSection->Data.size() < Offset + getAddressByteSize()) return false; - DataExtractor DA(AddrOffsetSection, isLittleEndian, AddrSize); - Result = DA.getAddress(&Offset); + DWARFDataExtractor DA(*AddrOffsetSection, isLittleEndian, + getAddressByteSize()); + Result = DA.getRelocatedAddress(&Offset); return true; } bool DWARFUnit::getStringOffsetSectionItem(uint32_t Index, - uint32_t &Result) const { - // FIXME: string offset section entries are 8-byte for DWARF64. - const uint32_t ItemSize = 4; - uint32_t Offset = Index * ItemSize; - if (StringOffsetSection.size() < Offset + ItemSize) + uint64_t &Result) const { + unsigned ItemSize = getDwarfOffsetByteSize(); + uint32_t Offset = StringOffsetSectionBase + Index * ItemSize; + if (StringOffsetSection.Data.size() < Offset + ItemSize) return false; - DataExtractor DA(StringOffsetSection, isLittleEndian, 0); - Result = DA.getU32(&Offset); + DWARFDataExtractor DA(StringOffsetSection, isLittleEndian, 0); + Result = DA.getRelocatedValue(ItemSize, &Offset); return true; } bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { Length = debug_info.getU32(offset_ptr); - Version = debug_info.getU16(offset_ptr); - uint64_t AbbrOffset = debug_info.getU32(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); + AbbrOffset = debug_info.getU32(offset_ptr); + } else { + AbbrOffset = debug_info.getU32(offset_ptr); + FormParams.AddrSize = debug_info.getU8(offset_ptr); + } if (IndexEntry) { if (AbbrOffset) return false; @@ -99,15 +106,17 @@ bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { return false; AbbrOffset = AbbrEntry->Offset; } - AddrSize = debug_info.getU8(offset_ptr); bool LengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1); - bool VersionOK = DWARFContext::isSupportedVersion(Version); - bool AddrSizeOK = AddrSize == 4 || AddrSize == 8; + bool VersionOK = DWARFContext::isSupportedVersion(getVersion()); + bool AddrSizeOK = getAddressByteSize() == 4 || getAddressByteSize() == 8; if (!LengthOK || !VersionOK || !AddrSizeOK) return false; + // Keep track of the highest DWARF version we encounter across all units. + Context.setMaxVersionIfGreater(getVersion()); + Abbrevs = Abbrev->getAbbreviationDeclarationSet(AbbrOffset); return Abbrevs != nullptr; } @@ -129,10 +138,11 @@ bool DWARFUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) { } bool DWARFUnit::extractRangeList(uint32_t RangeListOffset, - DWARFDebugRangeList &RangeList) const { + DWARFDebugRangeList &RangeList) const { // Require that compile unit is extracted. assert(!DieArray.empty()); - DataExtractor RangesData(RangeSection, isLittleEndian, AddrSize); + DWARFDataExtractor RangesData(*RangeSection, isLittleEndian, + getAddressByteSize()); uint32_t ActualRangeListOffset = RangeSectionBase + RangeListOffset; return RangeList.extract(RangesData, &ActualRangeListOffset); } @@ -140,9 +150,8 @@ bool DWARFUnit::extractRangeList(uint32_t RangeListOffset, void DWARFUnit::clear() { Offset = 0; Length = 0; - Version = 0; Abbrevs = nullptr; - AddrSize = 0; + FormParams = DWARFFormParams({0, 0, DWARF32}); BaseAddr = 0; RangeSectionBase = 0; AddrOffsetSectionBase = 0; @@ -151,11 +160,11 @@ void DWARFUnit::clear() { } const char *DWARFUnit::getCompilationDir() { - return getUnitDIE().getAttributeValueAsString(DW_AT_comp_dir, nullptr); + return dwarf::toString(getUnitDIE().find(DW_AT_comp_dir), nullptr); } Optional<uint64_t> DWARFUnit::getDWOId() { - return getUnitDIE().getAttributeValueAsUnsignedConstant(DW_AT_GNU_dwo_id); + return toUnsigned(getUnitDIE().find(DW_AT_GNU_dwo_id)); } void DWARFUnit::extractDIEsToVector( @@ -169,7 +178,7 @@ void DWARFUnit::extractDIEsToVector( uint32_t DIEOffset = Offset + getHeaderSize(); uint32_t NextCUOffset = getNextUnitOffset(); DWARFDebugInfoEntry DIE; - DataExtractor DebugInfoData = getDebugInfoExtractor(); + DWARFDataExtractor DebugInfoData = getDebugInfoExtractor(); uint32_t Depth = 0; bool IsCUDie = true; @@ -225,17 +234,22 @@ 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 = UnitDie.getAttributeValueAsAddress(DW_AT_low_pc); - if (!BaseAddr) - BaseAddr = UnitDie.getAttributeValueAsAddress(DW_AT_entry_pc); + auto BaseAddr = toAddress(UnitDie.find({DW_AT_low_pc, DW_AT_entry_pc})); if (BaseAddr) setBaseAddress(*BaseAddr); - AddrOffsetSectionBase = - UnitDie.getAttributeValueAsSectionOffset(DW_AT_GNU_addr_base) - .getValueOr(0); - RangeSectionBase = - UnitDie.getAttributeValueAsSectionOffset(DW_AT_rnglists_base) - .getValueOr(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 + // DW_AT_str_offsets_base attribute. In dwp files we add to it the offset + // we get from the index table. + StringOffsetSectionBase = + toSectionOffset(UnitDie.find(DW_AT_str_offsets_base), 0); + if (IndexEntry) + if (const auto *C = IndexEntry->getOffset(DW_SECT_STR_OFFSETS)) + StringOffsetSectionBase += C->Offset; + // Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for // skeleton CU DIE, so that DWARF users not aware of it are not broken. } @@ -243,21 +257,6 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) { return DieArray.size(); } -DWARFUnit::DWOHolder::DWOHolder(StringRef DWOPath) - : DWOU(nullptr) { - auto Obj = object::ObjectFile::createObjectFile(DWOPath); - if (!Obj) { - // TODO: Actually report errors helpfully. - consumeError(Obj.takeError()); - return; - } - DWOFile = std::move(Obj.get()); - DWOContext.reset( - cast<DWARFContext>(new DWARFContextInMemory(*DWOFile.getBinary()))); - if (DWOContext->getNumDWOCompileUnits() > 0) - DWOU = DWOContext->getDWOCompileUnitAtIndex(0); -} - bool DWARFUnit::parseDWO() { if (isDWO) return false; @@ -266,28 +265,31 @@ bool DWARFUnit::parseDWO() { DWARFDie UnitDie = getUnitDIE(); if (!UnitDie) return false; - const char *DWOFileName = - UnitDie.getAttributeValueAsString(DW_AT_GNU_dwo_name, nullptr); + auto DWOFileName = dwarf::toString(UnitDie.find(DW_AT_GNU_dwo_name)); if (!DWOFileName) return false; - const char *CompilationDir = - UnitDie.getAttributeValueAsString(DW_AT_comp_dir, nullptr); + auto CompilationDir = dwarf::toString(UnitDie.find(DW_AT_comp_dir)); SmallString<16> AbsolutePath; - if (sys::path::is_relative(DWOFileName) && CompilationDir != nullptr) { - sys::path::append(AbsolutePath, CompilationDir); + if (sys::path::is_relative(*DWOFileName) && CompilationDir && + *CompilationDir) { + sys::path::append(AbsolutePath, *CompilationDir); } - sys::path::append(AbsolutePath, DWOFileName); - DWO = llvm::make_unique<DWOHolder>(AbsolutePath); - DWARFUnit *DWOCU = DWO->getUnit(); - // Verify that compile unit in .dwo file is valid. - if (!DWOCU || DWOCU->getDWOId() != getDWOId()) { - DWO.reset(); + sys::path::append(AbsolutePath, *DWOFileName); + auto DWOId = getDWOId(); + if (!DWOId) return false; - } + auto DWOContext = Context.getDWOContext(AbsolutePath); + if (!DWOContext) + return false; + + DWARFCompileUnit *DWOCU = DWOContext->getDWOCompileUnitForHash(*DWOId); + if (!DWOCU) + return false; + DWO = std::shared_ptr<DWARFCompileUnit>(std::move(DWOContext), DWOCU); // Share .debug_addr and .debug_ranges section with compile unit in .dwo - DWOCU->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase); + DWO->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase); auto DWORangesBase = UnitDie.getRangesBaseAttribute(); - DWOCU->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0); + DWO->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0); return true; } @@ -330,8 +332,8 @@ void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) { // Collect address ranges from DIEs in .dwo if necessary. bool DWOCreated = parseDWO(); - if (DWO.get()) - DWO->getUnit()->collectAddressRanges(CURanges); + if (DWO) + DWO->collectAddressRanges(CURanges); if (DWOCreated) DWO.reset(); @@ -341,41 +343,67 @@ void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) { clearDIEs(true); } -DWARFDie -DWARFUnit::getSubprogramForAddress(uint64_t Address) { - extractDIEsIfNeeded(false); - for (const DWARFDebugInfoEntry &D : DieArray) { - DWARFDie DIE(this, &D); - if (DIE.isSubprogramDIE() && - DIE.addressRangeContainsAddress(Address)) { - return DIE; +void DWARFUnit::updateAddressDieMap(DWARFDie Die) { + if (Die.isSubroutineDIE()) { + for (const auto &R : Die.getAddressRanges()) { + // Ignore 0-sized ranges. + if (R.LowPC == R.HighPC) + continue; + auto B = AddrDieMap.upper_bound(R.LowPC); + if (B != AddrDieMap.begin() && R.LowPC < (--B)->second.first) { + // The range is a sub-range of existing ranges, we need to split the + // existing range. + if (R.HighPC < B->second.first) + AddrDieMap[R.HighPC] = B->second; + if (R.LowPC > B->first) + AddrDieMap[B->first].first = R.LowPC; + } + AddrDieMap[R.LowPC] = std::make_pair(R.HighPC, Die); } } - return DWARFDie(); + // Parent DIEs are added to the AddrDieMap prior to the Children DIEs to + // simplify the logic to update AddrDieMap. The child's range will always + // be equal or smaller than the parent's range. With this assumption, when + // adding one range into the map, it will at most split a range into 3 + // sub-ranges. + for (DWARFDie Child = Die.getFirstChild(); Child; Child = Child.getSibling()) + updateAddressDieMap(Child); +} + +DWARFDie DWARFUnit::getSubroutineForAddress(uint64_t Address) { + extractDIEsIfNeeded(false); + if (AddrDieMap.empty()) + updateAddressDieMap(getUnitDIE()); + auto R = AddrDieMap.upper_bound(Address); + if (R == AddrDieMap.begin()) + return DWARFDie(); + // upper_bound's previous item contains Address. + --R; + if (Address >= R->second.first) + return DWARFDie(); + return R->second.second; } void DWARFUnit::getInlinedChainForAddress(uint64_t Address, SmallVectorImpl<DWARFDie> &InlinedChain) { - // First, find a subprogram that contains the given address (the root - // of inlined chain). - DWARFDie SubprogramDIE; + assert(InlinedChain.empty()); // Try to look for subprogram DIEs in the DWO file. parseDWO(); - if (DWO) - SubprogramDIE = DWO->getUnit()->getSubprogramForAddress(Address); - else - SubprogramDIE = getSubprogramForAddress(Address); - - // Get inlined chain rooted at this subprogram DIE. - if (SubprogramDIE) - SubprogramDIE.getInlinedChainForAddress(Address, InlinedChain); - else - InlinedChain.clear(); + // First, find the subroutine that contains the given address (the leaf + // of inlined chain). + DWARFDie SubroutineDIE = + (DWO ? DWO.get() : this)->getSubroutineForAddress(Address); + + while (SubroutineDIE) { + if (SubroutineDIE.isSubroutineDIE()) + InlinedChain.push_back(SubroutineDIE); + SubroutineDIE = SubroutineDIE.getParent(); + } } -const DWARFUnitIndex &getDWARFUnitIndex(DWARFContext &Context, - DWARFSectionKind Kind) { +const DWARFUnitIndex &llvm::getDWARFUnitIndex(DWARFContext &Context, + DWARFSectionKind Kind) { if (Kind == DW_SECT_INFO) return Context.getCUIndex(); assert(Kind == DW_SECT_TYPES); @@ -413,11 +441,10 @@ DWARFDie DWARFUnit::getSibling(const DWARFDebugInfoEntry *Die) { 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) { + for (size_t I = getDIEIndex(Die) + 1, EndIdx = DieArray.size(); I < EndIdx; + ++I) { if (DieArray[I].getDepth() == Depth) return DWARFDie(this, &DieArray[I]); } return DWARFDie(); } - -} // end namespace llvm diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp index 96b3169..59b3d0c 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp @@ -1,4 +1,4 @@ -//===-- DWARFUnitIndex.cpp ------------------------------------------------===// +//===- DWARFUnitIndex.cpp -------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -8,11 +8,15 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" - +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <cinttypes> +#include <cstdint> -namespace llvm { +using namespace llvm; bool DWARFUnitIndex::Header::parse(DataExtractor IndexData, uint32_t *OffsetPtr) { @@ -152,6 +156,7 @@ DWARFUnitIndex::Entry::getOffset(DWARFSectionKind Sec) const { return &Contributions[i]; return nullptr; } + const DWARFUnitIndex::Entry::SectionContribution * DWARFUnitIndex::Entry::getOffset() const { return &Contributions[Index->InfoColumn]; @@ -165,4 +170,3 @@ DWARFUnitIndex::getFromOffset(uint32_t Offset) const { return &Rows[i]; return nullptr; } -} diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp new file mode 100644 index 0000000..4de46be --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -0,0 +1,499 @@ +//===- DWARFVerifier.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/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/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFSection.h" +#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" +#include "llvm/Support/raw_ostream.h" +#include <map> +#include <set> +#include <vector> + +using namespace llvm; +using namespace dwarf; +using namespace object; + +bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData, + uint32_t *Offset, unsigned UnitIndex, + uint8_t &UnitType, bool &isUnitDWARF64) { + uint32_t AbbrOffset, Length; + uint8_t AddrSize = 0; + uint16_t Version; + bool Success = true; + + bool ValidLength = false; + bool ValidVersion = false; + bool ValidAddrSize = false; + bool ValidType = true; + bool ValidAbbrevOffset = true; + + uint32_t OffsetStart = *Offset; + Length = DebugInfoData.getU32(Offset); + if (Length == UINT32_MAX) { + isUnitDWARF64 = true; + OS << format( + "Unit[%d] is in 64-bit DWARF format; cannot verify from this point.\n", + UnitIndex); + return false; + } + Version = DebugInfoData.getU16(Offset); + + if (Version >= 5) { + UnitType = DebugInfoData.getU8(Offset); + AddrSize = DebugInfoData.getU8(Offset); + AbbrOffset = DebugInfoData.getU32(Offset); + ValidType = DWARFUnit::isValidUnitType(UnitType); + } else { + UnitType = 0; + AbbrOffset = DebugInfoData.getU32(Offset); + AddrSize = DebugInfoData.getU8(Offset); + } + + if (!DCtx.getDebugAbbrev()->getAbbreviationDeclarationSet(AbbrOffset)) + ValidAbbrevOffset = false; + + ValidLength = DebugInfoData.isValidOffset(OffsetStart + Length + 3); + ValidVersion = DWARFContext::isSupportedVersion(Version); + ValidAddrSize = AddrSize == 4 || AddrSize == 8; + if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset || + !ValidType) { + Success = false; + OS << format("Units[%d] - start offset: 0x%08x \n", UnitIndex, OffsetStart); + if (!ValidLength) + OS << "\tError: 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"; + if (!ValidType) + OS << "\tError: The unit type encoding is not valid.\n"; + if (!ValidAbbrevOffset) + OS << "\tError: The offset into the .debug_abbrev section is " + "not valid.\n"; + if (!ValidAddrSize) + OS << "\tError: The address size is unsupported.\n"; + } + *Offset = OffsetStart + Length + 4; + return Success; +} + +bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit) { + uint32_t NumUnitErrors = 0; + unsigned NumDies = Unit.getNumDIEs(); + for (unsigned I = 0; I < NumDies; ++I) { + auto Die = Unit.getDIEAtIndex(I); + if (Die.getTag() == DW_TAG_null) + continue; + for (auto AttrValue : Die.attributes()) { + NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue); + NumUnitErrors += verifyDebugInfoForm(Die, AttrValue); + } + } + return NumUnitErrors == 0; +} + +bool DWARFVerifier::handleDebugInfo() { + OS << "Verifying .debug_info Unit Header Chain...\n"; + + DWARFDataExtractor DebugInfoData(DCtx.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); + while (hasDIE) { + OffsetStart = Offset; + if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, UnitType, + isUnitDWARF64)) { + isHeaderChainValid = false; + if (isUnitDWARF64) + break; + } else { + std::unique_ptr<DWARFUnit> Unit; + 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, + nullptr)); + break; + } + case dwarf::DW_UT_skeleton: + case dwarf::DW_UT_split_compile: + case dwarf::DW_UT_compile: + case dwarf::DW_UT_partial: + // 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, + nullptr)); + break; + } + default: { llvm_unreachable("Invalid UnitType."); } + } + Unit->extract(DebugInfoData, &OffsetStart); + if (!verifyUnitContents(*Unit)) + ++NumDebugInfoErrors; + } + hasDIE = DebugInfoData.isValidOffset(Offset); + ++UnitIdx; + } + if (UnitIdx == 0 && !hasDIE) { + OS << "Warning: .debug_info is empty.\n"; + isHeaderChainValid = true; + } + NumDebugInfoErrors += verifyDebugInfoReferences(); + return (isHeaderChainValid && NumDebugInfoErrors == 0); +} + +unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, + DWARFAttribute &AttrValue) { + unsigned NumErrors = 0; + 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"; + } + 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"; + } + break; + + default: + break; + } + return NumErrors; +} + +unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, + DWARFAttribute &AttrValue) { + unsigned NumErrors = 0; + const auto Form = AttrValue.Value.getForm(); + switch (Form) { + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: { + // Verify all CU relative references are valid CU offsets. + Optional<uint64_t> RefVal = AttrValue.Value.getAsReference(); + assert(RefVal); + if (RefVal) { + auto DieCU = Die.getDwarfUnit(); + auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset(); + 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); + OS << "\n"; + } else { + // Valid reference, but we will verify it points to an actual + // DIE later. + ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); + } + } + break; + } + case DW_FORM_ref_addr: { + // Verify all absolute DIE references have valid offsets in the + // .debug_info section. + Optional<uint64_t> RefVal = AttrValue.Value.getAsReference(); + assert(RefVal); + if (RefVal) { + if (*RefVal >= DCtx.getInfoSection().Data.size()) { + ++NumErrors; + OS << "error: DW_FORM_ref_addr offset beyond .debug_info " + "bounds:\n"; + Die.dump(OS, 0); + OS << "\n"; + } else { + // Valid reference, but we will verify it points to an actual + // DIE later. + ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); + } + } + break; + } + case DW_FORM_strp: { + auto SecOffset = AttrValue.Value.getAsSectionOffset(); + assert(SecOffset); // DW_FORM_strp is a section offset. + if (SecOffset && *SecOffset >= DCtx.getStringSection().size()) { + ++NumErrors; + OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n"; + Die.dump(OS, 0); + OS << "\n"; + } + break; + } + default: + break; + } + return NumErrors; +} + +unsigned DWARFVerifier::verifyDebugInfoReferences() { + // Take all references and make sure they point to an actual DIE by + // getting the DIE by offset and emitting an error + OS << "Verifying .debug_info references...\n"; + unsigned NumErrors = 0; + for (auto Pair : ReferenceToDIEOffsets) { + auto Die = DCtx.getDIEForOffset(Pair.first); + if (Die) + continue; + ++NumErrors; + OS << "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); + OS << "\n"; + } + OS << "\n"; + } + return NumErrors; +} + +void DWARFVerifier::verifyDebugLineStmtOffsets() { + std::map<uint64_t, DWARFDie> StmtListToDie; + for (const auto &CU : DCtx.compile_units()) { + auto Die = CU->getUnitDIE(); + // Get the attribute value as a section offset. No need to produce an + // error here if the encoding isn't correct because we validate this in + // the .debug_info verifier. + auto StmtSectionOffset = toSectionOffset(Die.find(DW_AT_stmt_list)); + if (!StmtSectionOffset) + continue; + const uint32_t LineTableOffset = *StmtSectionOffset; + auto LineTable = DCtx.getLineTableForUnit(CU.get()); + if (LineTableOffset < DCtx.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); + OS << '\n'; + continue; + } + } else { + // Make sure we don't get a valid line table back if the offset is wrong. + assert(LineTable == nullptr); + // Skip this line table as it isn't valid. No need to create an error + // here because we validate this in the .debug_info verifier. + continue; + } + 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); + OS << '\n'; + // Already verified this line table before, no need to do it again. + continue; + } + StmtListToDie[LineTableOffset] = Die; + } +} + +void DWARFVerifier::verifyDebugLineRows() { + for (const auto &CU : DCtx.compile_units()) { + auto Die = CU->getUnitDIE(); + auto LineTable = DCtx.getLineTableForUnit(CU.get()); + // If there is no line table we will have created an error in the + // .debug_info verifier or in verifyDebugLineStmtOffsets(). + if (!LineTable) + continue; + uint32_t MaxFileIndex = LineTable->Prologue.FileNames.size(); + uint64_t PrevAddress = 0; + uint32_t RowIndex = 0; + for (const auto &Row : LineTable->Rows) { + 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"; + + DWARFDebugLine::Row::dumpTableHeader(OS); + if (RowIndex > 0) + LineTable->Rows[RowIndex - 1].dump(OS); + Row.dump(OS); + OS << '\n'; + } + + 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"; + DWARFDebugLine::Row::dumpTableHeader(OS); + Row.dump(OS); + OS << '\n'; + } + if (Row.EndSequence) + PrevAddress = 0; + else + PrevAddress = Row.Address; + ++RowIndex; + } + } +} + +bool DWARFVerifier::handleDebugLine() { + NumDebugLineErrors = 0; + OS << "Verifying .debug_line...\n"; + verifyDebugLineStmtOffsets(); + verifyDebugLineRows(); + return NumDebugLineErrors == 0; +} + +bool DWARFVerifier::handleAppleNames() { + NumAppleNamesErrors = 0; + + DWARFDataExtractor AppleNamesSection(DCtx.getAppleNamesSection(), + DCtx.isLittleEndian(), 0); + DataExtractor StrData(DCtx.getStringSection(), DCtx.isLittleEndian(), 0); + DWARFAcceleratorTable AppleNames(AppleNamesSection, StrData); + + if (!AppleNames.extract()) { + return true; + } + + OS << "Verifying .apple_names...\n"; + + // Verify that all buckets have a valid hash index or are empty. + uint32_t NumBuckets = AppleNames.getNumBuckets(); + uint32_t NumHashes = AppleNames.getNumHashes(); + + uint32_t BucketsOffset = + AppleNames.getSizeHdr() + AppleNames.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); + if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) { + OS << format("error: Bucket[%d] has invalid hash index: %u\n", BucketIdx, + HashIdx); + ++NumAppleNamesErrors; + } + } + + uint32_t NumAtoms = AppleNames.getAtomsDesc().size(); + if (NumAtoms == 0) { + OS << "error: no atoms; failed to read HashData\n"; + ++NumAppleNamesErrors; + return false; + } + + if (!AppleNames.validateForms()) { + OS << "error: unsupported form; failed to read HashData\n"; + ++NumAppleNamesErrors; + return false; + } + + 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 StrpOffset; + uint32_t StringOffset; + uint32_t StringCount = 0; + uint32_t DieOffset = dwarf::DW_INVALID_OFFSET; + + while ((StrpOffset = AppleNamesSection.getU32(&HashDataOffset)) != 0) { + const uint32_t NumHashDataObjects = + AppleNamesSection.getU32(&HashDataOffset); + for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects; + ++HashDataIdx) { + DieOffset = AppleNames.readAtoms(HashDataOffset); + if (!DCtx.getDIEForOffset(DieOffset)) { + const uint32_t BucketIdx = + NumBuckets ? (Hash % NumBuckets) : UINT32_MAX; + StringOffset = StrpOffset; + const char *Name = StrData.getCStr(&StringOffset); + if (!Name) + Name = "<NULL>"; + + OS << format( + "error: .apple_names 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); + + ++NumAppleNamesErrors; + } + } + ++StringCount; + } + } + return NumAppleNamesErrors == 0; +} diff --git a/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp b/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp index 4f561d0..d4f44e4 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp @@ -1,4 +1,4 @@ -//===-- SyntaxHighlighting.cpp ----------------------------------*- C++ -*-===// +//===- SyntaxHighlighting.cpp ---------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -9,6 +9,8 @@ #include "SyntaxHighlighting.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" + using namespace llvm; using namespace dwarf; using namespace syntax; @@ -18,16 +20,16 @@ static cl::opt<cl::boolOrDefault> cl::desc("use colored syntax highlighting (default=autodetect)"), cl::init(cl::BOU_UNSET)); -WithColor::WithColor(llvm::raw_ostream &OS, enum HighlightColor Type) : OS(OS) { +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(llvm::raw_ostream::YELLOW); break; - case String: OS.changeColor(llvm::raw_ostream::GREEN); break; - case Tag: OS.changeColor(llvm::raw_ostream::BLUE); break; - case Attribute: OS.changeColor(llvm::raw_ostream::CYAN); break; - case Enumerator: OS.changeColor(llvm::raw_ostream::MAGENTA); break; - case Macro: OS.changeColor(llvm::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; } } } diff --git a/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.h b/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.h index 16e6835..277de97 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.h +++ b/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.h @@ -1,4 +1,4 @@ -//===-- SyntaxHighlighting.h ------------------------------------*- C++ -*-===// +//===- SyntaxHighlighting.h -------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,9 +10,10 @@ #ifndef LLVM_LIB_DEBUGINFO_SYNTAXHIGHLIGHTING_H #define LLVM_LIB_DEBUGINFO_SYNTAXHIGHLIGHTING_H -#include "llvm/Support/raw_ostream.h" - namespace llvm { + +class raw_ostream; + namespace dwarf { namespace syntax { @@ -22,18 +23,20 @@ enum HighlightColor { Address, String, Tag, Attribute, Enumerator, Macro }; /// An RAII object that temporarily switches an output stream to a /// specific color. class WithColor { - llvm::raw_ostream &OS; + raw_ostream &OS; public: /// To be used like this: WithColor(OS, syntax::String) << "text"; - WithColor(llvm::raw_ostream &OS, enum HighlightColor Type); + WithColor(raw_ostream &OS, enum HighlightColor Type); ~WithColor(); - llvm::raw_ostream& get() { return OS; } - operator llvm::raw_ostream& () { return OS; } + raw_ostream& get() { return OS; } + operator raw_ostream& () { return OS; } }; -} -} -} -#endif +} // end namespace syntax +} // end namespace dwarf + +} // end namespace llvm + +#endif // LLVM_LIB_DEBUGINFO_SYNTAXHIGHLIGHTING_H |