diff options
Diffstat (limited to 'lib/DebugInfo/DWARF/DWARFContext.cpp')
-rw-r--r-- | lib/DebugInfo/DWARF/DWARFContext.cpp | 153 |
1 files changed, 96 insertions, 57 deletions
diff --git a/lib/DebugInfo/DWARF/DWARFContext.cpp b/lib/DebugInfo/DWARF/DWARFContext.cpp index a5defa90eb35..eb23ca8229a3 100644 --- a/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -88,70 +88,101 @@ static void dumpUUID(raw_ostream &OS, const ObjectFile &Obj) { } } -static void -dumpDWARFv5StringOffsetsSection(raw_ostream &OS, StringRef SectionName, - const DWARFObject &Obj, - const DWARFSection &StringOffsetsSection, - StringRef StringSection, bool LittleEndian) { +using ContributionCollection = + std::vector<Optional<StrOffsetsContributionDescriptor>>; + +// Collect all the contributions to the string offsets table from all units, +// sort them by their starting offsets and remove duplicates. +static ContributionCollection +collectContributionData(DWARFContext::cu_iterator_range CUs, + DWARFContext::tu_section_iterator_range TUSs) { + ContributionCollection Contributions; + for (const auto &CU : CUs) + Contributions.push_back(CU->getStringOffsetsTableContribution()); + for (const auto &TUS : TUSs) + for (const auto &TU : TUS) + Contributions.push_back(TU->getStringOffsetsTableContribution()); + + // Sort the contributions so that any invalid ones are placed at + // the start of the contributions vector. This way they are reported + // first. + std::sort(Contributions.begin(), Contributions.end(), + [](const Optional<StrOffsetsContributionDescriptor> &L, + const Optional<StrOffsetsContributionDescriptor> &R) { + if (L && R) return L->Base < R->Base; + return R.hasValue(); + }); + + // Uniquify contributions, as it is possible that units (specifically + // type units in dwo or dwp files) share contributions. We don't want + // to report them more than once. + Contributions.erase( + std::unique(Contributions.begin(), Contributions.end(), + [](const Optional<StrOffsetsContributionDescriptor> &L, + const Optional<StrOffsetsContributionDescriptor> &R) { + if (L && R) + return L->Base == R->Base && L->Size == R->Size; + return false; + }), + Contributions.end()); + return Contributions; +} + +static void dumpDWARFv5StringOffsetsSection( + raw_ostream &OS, StringRef SectionName, const DWARFObject &Obj, + const DWARFSection &StringOffsetsSection, StringRef StringSection, + DWARFContext::cu_iterator_range CUs, + DWARFContext::tu_section_iterator_range TUSs, bool LittleEndian) { + auto Contributions = collectContributionData(CUs, TUSs); DWARFDataExtractor StrOffsetExt(Obj, StringOffsetsSection, LittleEndian, 0); - uint32_t Offset = 0; + DataExtractor StrData(StringSection, LittleEndian, 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)) { + uint32_t Offset = 0; + for (auto &Contribution : Contributions) { + // Report an ill-formed contribution. + if (!Contribution) { 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 ." + + dwarf::DwarfFormat Format = Contribution->getFormat(); + uint16_t Version = Contribution->getVersion(); + uint64_t ContributionHeader = Contribution->Base; + // In DWARF v5 there is a contribution header that immediately precedes + // the string offsets base (the location we have previously retrieved from + // the CU DIE's DW_AT_str_offsets attribute). The header is located either + // 8 or 16 bytes before the base, depending on the contribution's format. + if (Version >= 5) + ContributionHeader -= Format == DWARF32 ? 8 : 16; + + // Detect overlapping contributions. + if (Offset > ContributionHeader) { + OS << "error: overlapping contributions 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; + // Report a gap in the table. + if (Offset < ContributionHeader) { + OS << format("0x%8.8x: Gap, length = ", Offset); + OS << (ContributionHeader - Offset) << "\n"; } - - Version = StrOffsetExt.getU16(&Offset); - Offset += 2; - OS << format("0x%8.8x: ", ContributionStart); - OS << "Contribution size = " << ContributionSize + OS << format("0x%8.8x: ", (uint32_t)ContributionHeader); + OS << "Contribution size = " << Contribution->Size + << ", Format = " << (Format == DWARF32 ? "DWARF32" : "DWARF64") << ", Version = " << Version << "\n"; - uint32_t ContributionBase = Offset; - DataExtractor StrData(StringSection, LittleEndian, 0); - while (Offset - ContributionBase < ContributionSize) { + Offset = Contribution->Base; + unsigned EntrySize = Contribution->getDwarfOffsetByteSize(); + while (Offset - Contribution->Base < Contribution->Size) { OS << format("0x%8.8x: ", Offset); - // FIXME: We can only extract strings in DWARF32 format at the moment. + // FIXME: We can only extract strings if the offset fits in 32 bits. uint64_t StringOffset = StrOffsetExt.getRelocatedValue(EntrySize, &Offset); - if (Format == DWARF32) { + // Extract the string if we can and display it. Otherwise just report + // the offset. + if (StringOffset <= std::numeric_limits<uint32_t>::max()) { uint32_t StringOffset32 = (uint32_t)StringOffset; OS << format("%8.8x ", StringOffset32); const char *S = StrData.getCStr(&StringOffset32); @@ -162,6 +193,11 @@ dumpDWARFv5StringOffsetsSection(raw_ostream &OS, StringRef SectionName, OS << "\n"; } } + // Report a gap at the end of the table. + if (Offset < SectionSize) { + OS << format("0x%8.8x: Gap, length = ", Offset); + OS << (SectionSize - Offset) << "\n"; + } } // Dump a DWARF string offsets section. This may be a DWARF v5 formatted @@ -170,17 +206,18 @@ dumpDWARFv5StringOffsetsSection(raw_ostream &OS, StringRef SectionName, // 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 DWARFObject &Obj, - const DWARFSection &StringOffsetsSection, - StringRef StringSection, bool LittleEndian, - unsigned MaxVersion) { +static void dumpStringOffsetsSection( + raw_ostream &OS, StringRef SectionName, const DWARFObject &Obj, + const DWARFSection &StringOffsetsSection, StringRef StringSection, + DWARFContext::cu_iterator_range CUs, + DWARFContext::tu_section_iterator_range TUSs, bool LittleEndian, + unsigned MaxVersion) { // 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, Obj, StringOffsetsSection, - StringSection, LittleEndian); + StringSection, CUs, TUSs, LittleEndian); else { DataExtractor strOffsetExt(StringOffsetsSection.Data, LittleEndian, 0); uint32_t offset = 0; @@ -468,12 +505,14 @@ void DWARFContext::dump( DObj->getStringOffsetSection().Data)) dumpStringOffsetsSection( OS, "debug_str_offsets", *DObj, DObj->getStringOffsetSection(), - DObj->getStringSection(), isLittleEndian(), getMaxVersion()); + DObj->getStringSection(), compile_units(), type_unit_sections(), + isLittleEndian(), getMaxVersion()); if (shouldDump(ExplicitDWO, ".debug_str_offsets.dwo", DIDT_ID_DebugStrOffsets, DObj->getStringOffsetDWOSection().Data)) dumpStringOffsetsSection( OS, "debug_str_offsets.dwo", *DObj, DObj->getStringOffsetDWOSection(), - DObj->getStringDWOSection(), isLittleEndian(), getMaxVersion()); + DObj->getStringDWOSection(), dwo_compile_units(), + dwo_type_unit_sections(), isLittleEndian(), getMaxVersion()); if (shouldDump(Explicit, ".gnu_index", DIDT_ID_GdbIndex, DObj->getGdbIndexSection())) { |