diff options
Diffstat (limited to 'llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp')
-rw-r--r-- | llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp | 239 |
1 files changed, 161 insertions, 78 deletions
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp index 1acdcb4bebb9..9fffb249e72d 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -20,10 +20,10 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Object/Binary.h" +#include "llvm/Object/COFF.h" #include "llvm/Object/Error.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/Object/COFF.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compression.h" @@ -33,6 +33,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include <vector> @@ -97,9 +98,7 @@ Error RawCoverageReader::readString(StringRef &Result) { return Error::success(); } -Error RawCoverageFilenamesReader::read( - CovMapVersion Version, - BinaryCoverageReader::DecompressedData &Decompressed) { +Error RawCoverageFilenamesReader::read(CovMapVersion Version) { uint64_t NumFilenames; if (auto Err = readSize(NumFilenames)) return Err; @@ -107,7 +106,7 @@ Error RawCoverageFilenamesReader::read( return make_error<CoverageMapError>(coveragemap_error::malformed); if (Version < CovMapVersion::Version4) - return readUncompressed(NumFilenames); + return readUncompressed(Version, NumFilenames); // The uncompressed length may exceed the size of the encoded filenames. // Skip size validation. @@ -124,11 +123,8 @@ Error RawCoverageFilenamesReader::read( return make_error<CoverageMapError>( coveragemap_error::decompression_failed); - // Allocate memory for the decompressed filenames. Transfer ownership of - // the memory to BinaryCoverageReader. - auto DecompressedStorage = std::make_unique<SmallVector<char, 0>>(); - SmallVectorImpl<char> &StorageBuf = *DecompressedStorage.get(); - Decompressed.push_back(std::move(DecompressedStorage)); + // Allocate memory for the decompressed filenames. + SmallVector<char, 0> StorageBuf; // Read compressed filenames. StringRef CompressedFilenames = Data.substr(0, CompressedLen); @@ -142,20 +138,46 @@ Error RawCoverageFilenamesReader::read( } StringRef UncompressedFilenames(StorageBuf.data(), StorageBuf.size()); - RawCoverageFilenamesReader Delegate(UncompressedFilenames, Filenames); - return Delegate.readUncompressed(NumFilenames); + RawCoverageFilenamesReader Delegate(UncompressedFilenames, Filenames, + CompilationDir); + return Delegate.readUncompressed(Version, NumFilenames); } - return readUncompressed(NumFilenames); + return readUncompressed(Version, NumFilenames); } -Error RawCoverageFilenamesReader::readUncompressed(uint64_t NumFilenames) { +Error RawCoverageFilenamesReader::readUncompressed(CovMapVersion Version, + uint64_t NumFilenames) { // Read uncompressed filenames. - for (size_t I = 0; I < NumFilenames; ++I) { - StringRef Filename; - if (auto Err = readString(Filename)) + if (Version < CovMapVersion::Version6) { + for (size_t I = 0; I < NumFilenames; ++I) { + StringRef Filename; + if (auto Err = readString(Filename)) + return Err; + Filenames.push_back(Filename.str()); + } + } else { + StringRef CWD; + if (auto Err = readString(CWD)) return Err; - Filenames.push_back(Filename); + Filenames.push_back(CWD.str()); + + for (size_t I = 1; I < NumFilenames; ++I) { + StringRef Filename; + if (auto Err = readString(Filename)) + return Err; + if (sys::path::is_absolute(Filename)) { + Filenames.push_back(Filename.str()); + } else { + SmallString<256> P; + if (!CompilationDir.empty()) + P.assign(CompilationDir); + else + P.assign(CWD); + llvm::sys::path::append(P, Filename); + Filenames.push_back(static_cast<std::string>(P)); + } + } } return Error::success(); } @@ -481,9 +503,8 @@ struct CovMapFuncRecordReader { // // Returns a pointer to the next \c CovHeader if it exists, or to an address // greater than \p CovEnd if not. - virtual Expected<const char *> - readCoverageHeader(const char *CovBuf, const char *CovBufEnd, - BinaryCoverageReader::DecompressedData &Decompressed) = 0; + virtual Expected<const char *> readCoverageHeader(const char *CovBuf, + const char *CovBufEnd) = 0; // Read function records. // @@ -504,8 +525,8 @@ struct CovMapFuncRecordReader { template <class IntPtrT, support::endianness Endian> static Expected<std::unique_ptr<CovMapFuncRecordReader>> get(CovMapVersion Version, InstrProfSymtab &P, - std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, - std::vector<StringRef> &F); + std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, StringRef D, + std::vector<std::string> &F); }; // A class for reading coverage mapping function records for a module. @@ -519,7 +540,8 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader { // in \c Records. DenseMap<NameRefType, size_t> FunctionRecords; InstrProfSymtab &ProfileNames; - std::vector<StringRef> &Filenames; + StringRef CompilationDir; + std::vector<std::string> &Filenames; std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records; // Maps a hash of the filenames in a TU to a \c FileRange. The range @@ -578,15 +600,14 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader { public: VersionedCovMapFuncRecordReader( InstrProfSymtab &P, - std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, - std::vector<StringRef> &F) - : ProfileNames(P), Filenames(F), Records(R) {} + std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, StringRef D, + std::vector<std::string> &F) + : ProfileNames(P), CompilationDir(D), Filenames(F), Records(R) {} ~VersionedCovMapFuncRecordReader() override = default; - Expected<const char *> readCoverageHeader( - const char *CovBuf, const char *CovBufEnd, - BinaryCoverageReader::DecompressedData &Decompressed) override { + Expected<const char *> readCoverageHeader(const char *CovBuf, + const char *CovBufEnd) override { using namespace support; if (CovBuf + sizeof(CovMapHeader) > CovBufEnd) @@ -614,8 +635,9 @@ public: return make_error<CoverageMapError>(coveragemap_error::malformed); size_t FilenamesBegin = Filenames.size(); StringRef FilenameRegion(CovBuf, FilenamesSize); - RawCoverageFilenamesReader Reader(FilenameRegion, Filenames); - if (auto Err = Reader.read(Version, Decompressed)) + RawCoverageFilenamesReader Reader(FilenameRegion, Filenames, + CompilationDir); + if (auto Err = Reader.read(Version)) return std::move(Err); CovBuf += FilenamesSize; FilenameRange FileRange(FilenamesBegin, Filenames.size() - FilenamesBegin); @@ -720,33 +742,37 @@ public: template <class IntPtrT, support::endianness Endian> Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get( CovMapVersion Version, InstrProfSymtab &P, - std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, - std::vector<StringRef> &F) { + std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, StringRef D, + std::vector<std::string> &F) { using namespace coverage; switch (Version) { case CovMapVersion::Version1: return std::make_unique<VersionedCovMapFuncRecordReader< - CovMapVersion::Version1, IntPtrT, Endian>>(P, R, F); + CovMapVersion::Version1, IntPtrT, Endian>>(P, R, D, F); case CovMapVersion::Version2: case CovMapVersion::Version3: case CovMapVersion::Version4: case CovMapVersion::Version5: + case CovMapVersion::Version6: // Decompress the name data. if (Error E = P.create(P.getNameData())) return std::move(E); if (Version == CovMapVersion::Version2) return std::make_unique<VersionedCovMapFuncRecordReader< - CovMapVersion::Version2, IntPtrT, Endian>>(P, R, F); + CovMapVersion::Version2, IntPtrT, Endian>>(P, R, D, F); else if (Version == CovMapVersion::Version3) return std::make_unique<VersionedCovMapFuncRecordReader< - CovMapVersion::Version3, IntPtrT, Endian>>(P, R, F); + CovMapVersion::Version3, IntPtrT, Endian>>(P, R, D, F); else if (Version == CovMapVersion::Version4) return std::make_unique<VersionedCovMapFuncRecordReader< - CovMapVersion::Version4, IntPtrT, Endian>>(P, R, F); + CovMapVersion::Version4, IntPtrT, Endian>>(P, R, D, F); else if (Version == CovMapVersion::Version5) return std::make_unique<VersionedCovMapFuncRecordReader< - CovMapVersion::Version5, IntPtrT, Endian>>(P, R, F); + CovMapVersion::Version5, IntPtrT, Endian>>(P, R, D, F); + else if (Version == CovMapVersion::Version6) + return std::make_unique<VersionedCovMapFuncRecordReader< + CovMapVersion::Version6, IntPtrT, Endian>>(P, R, D, F); } llvm_unreachable("Unsupported version"); } @@ -755,8 +781,7 @@ template <typename T, support::endianness Endian> static Error readCoverageMappingData( InstrProfSymtab &ProfileNames, StringRef CovMap, StringRef FuncRecords, std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records, - std::vector<StringRef> &Filenames, - BinaryCoverageReader::DecompressedData &Decompressed) { + StringRef CompilationDir, std::vector<std::string> &Filenames) { using namespace coverage; // Read the records in the coverage data section. @@ -767,7 +792,7 @@ static Error readCoverageMappingData( return make_error<CoverageMapError>(coveragemap_error::unsupported_version); Expected<std::unique_ptr<CovMapFuncRecordReader>> ReaderExpected = CovMapFuncRecordReader::get<T, Endian>(Version, ProfileNames, Records, - Filenames); + CompilationDir, Filenames); if (Error E = ReaderExpected.takeError()) return E; auto Reader = std::move(ReaderExpected.get()); @@ -782,8 +807,7 @@ static Error readCoverageMappingData( // header. // // Return a pointer to the next coverage header. - auto NextOrErr = - Reader->readCoverageHeader(CovBuf, CovBufEnd, Decompressed); + auto NextOrErr = Reader->readCoverageHeader(CovBuf, CovBufEnd); if (auto E = NextOrErr.takeError()) return E; CovBuf = NextOrErr.get(); @@ -800,35 +824,34 @@ static const char *TestingFormatMagic = "llvmcovmtestdata"; Expected<std::unique_ptr<BinaryCoverageReader>> BinaryCoverageReader::createCoverageReaderFromBuffer( - StringRef Coverage, std::string &&FuncRecords, InstrProfSymtab &&ProfileNames, - uint8_t BytesInAddress, support::endianness Endian) { + StringRef Coverage, FuncRecordsStorage &&FuncRecords, + InstrProfSymtab &&ProfileNames, uint8_t BytesInAddress, + support::endianness Endian, StringRef CompilationDir) { std::unique_ptr<BinaryCoverageReader> Reader( new BinaryCoverageReader(std::move(FuncRecords))); Reader->ProfileNames = std::move(ProfileNames); - StringRef FuncRecordsRef = Reader->FuncRecords; + StringRef FuncRecordsRef = Reader->FuncRecords->getBuffer(); if (BytesInAddress == 4 && Endian == support::endianness::little) { if (Error E = readCoverageMappingData<uint32_t, support::endianness::little>( Reader->ProfileNames, Coverage, FuncRecordsRef, - Reader->MappingRecords, Reader->Filenames, - Reader->Decompressed)) + Reader->MappingRecords, CompilationDir, Reader->Filenames)) return std::move(E); } else if (BytesInAddress == 4 && Endian == support::endianness::big) { if (Error E = readCoverageMappingData<uint32_t, support::endianness::big>( Reader->ProfileNames, Coverage, FuncRecordsRef, - Reader->MappingRecords, Reader->Filenames, Reader->Decompressed)) + Reader->MappingRecords, CompilationDir, Reader->Filenames)) return std::move(E); } else if (BytesInAddress == 8 && Endian == support::endianness::little) { if (Error E = readCoverageMappingData<uint64_t, support::endianness::little>( Reader->ProfileNames, Coverage, FuncRecordsRef, - Reader->MappingRecords, Reader->Filenames, - Reader->Decompressed)) + Reader->MappingRecords, CompilationDir, Reader->Filenames)) return std::move(E); } else if (BytesInAddress == 8 && Endian == support::endianness::big) { if (Error E = readCoverageMappingData<uint64_t, support::endianness::big>( Reader->ProfileNames, Coverage, FuncRecordsRef, - Reader->MappingRecords, Reader->Filenames, Reader->Decompressed)) + Reader->MappingRecords, CompilationDir, Reader->Filenames)) return std::move(E); } else return make_error<CoverageMapError>(coveragemap_error::malformed); @@ -836,7 +859,7 @@ BinaryCoverageReader::createCoverageReaderFromBuffer( } static Expected<std::unique_ptr<BinaryCoverageReader>> -loadTestingFormat(StringRef Data) { +loadTestingFormat(StringRef Data, StringRef CompilationDir) { uint8_t BytesInAddress = 8; support::endianness Endian = support::endianness::little; @@ -860,16 +883,45 @@ loadTestingFormat(StringRef Data) { InstrProfSymtab ProfileNames; if (Error E = ProfileNames.create(Data.substr(0, ProfileNamesSize), Address)) return std::move(E); - StringRef CoverageMapping = Data.substr(ProfileNamesSize); + Data = Data.substr(ProfileNamesSize); // Skip the padding bytes because coverage map data has an alignment of 8. - if (CoverageMapping.empty()) - return make_error<CoverageMapError>(coveragemap_error::truncated); - size_t Pad = offsetToAlignedAddr(CoverageMapping.data(), Align(8)); - if (CoverageMapping.size() < Pad) + size_t Pad = offsetToAlignedAddr(Data.data(), Align(8)); + if (Data.size() < Pad) + return make_error<CoverageMapError>(coveragemap_error::malformed); + Data = Data.substr(Pad); + if (Data.size() < sizeof(CovMapHeader)) return make_error<CoverageMapError>(coveragemap_error::malformed); - CoverageMapping = CoverageMapping.substr(Pad); + auto const *CovHeader = reinterpret_cast<const CovMapHeader *>( + Data.substr(0, sizeof(CovMapHeader)).data()); + CovMapVersion Version = + (CovMapVersion)CovHeader->getVersion<support::endianness::little>(); + StringRef CoverageMapping; + BinaryCoverageReader::FuncRecordsStorage CoverageRecords; + if (Version < CovMapVersion::Version4) { + CoverageMapping = Data; + if (CoverageMapping.empty()) + return make_error<CoverageMapError>(coveragemap_error::truncated); + CoverageRecords = MemoryBuffer::getMemBuffer(""); + } else { + uint32_t FilenamesSize = + CovHeader->getFilenamesSize<support::endianness::little>(); + uint32_t CoverageMappingSize = sizeof(CovMapHeader) + FilenamesSize; + CoverageMapping = Data.substr(0, CoverageMappingSize); + if (CoverageMapping.empty()) + return make_error<CoverageMapError>(coveragemap_error::truncated); + Data = Data.substr(CoverageMappingSize); + // Skip the padding bytes because coverage records data has an alignment + // of 8. + Pad = offsetToAlignedAddr(Data.data(), Align(8)); + if (Data.size() < Pad) + return make_error<CoverageMapError>(coveragemap_error::malformed); + CoverageRecords = MemoryBuffer::getMemBuffer(Data.substr(Pad)); + if (CoverageRecords->getBufferSize() == 0) + return make_error<CoverageMapError>(coveragemap_error::truncated); + } return BinaryCoverageReader::createCoverageReaderFromBuffer( - CoverageMapping, "", std::move(ProfileNames), BytesInAddress, Endian); + CoverageMapping, std::move(CoverageRecords), std::move(ProfileNames), + BytesInAddress, Endian, CompilationDir); } /// Find all sections that match \p Name. There may be more than one if comdats @@ -899,7 +951,8 @@ static Expected<std::vector<SectionRef>> lookupSections(ObjectFile &OF, } static Expected<std::unique_ptr<BinaryCoverageReader>> -loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch) { +loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch, + StringRef CompilationDir = "") { std::unique_ptr<ObjectFile> OF; if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) { // If we have a universal binary, try to look up the object for the @@ -952,26 +1005,54 @@ loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch) { return std::move(E); // Look for the coverage records section (Version4 only). - std::string FuncRecords; auto CoverageRecordsSections = lookupSections(*OF, getInstrProfSectionName(IPSK_covfun, ObjFormat, /*AddSegmentInfo=*/false)); - if (auto E = CoverageRecordsSections.takeError()) + + BinaryCoverageReader::FuncRecordsStorage FuncRecords; + if (auto E = CoverageRecordsSections.takeError()) { consumeError(std::move(E)); - else { + FuncRecords = MemoryBuffer::getMemBuffer(""); + } else { + // Compute the FuncRecordsBuffer of the buffer, taking into account the + // padding between each record, and making sure the first block is aligned + // in memory to maintain consistency between buffer address and size + // alignment. + const Align RecordAlignment(8); + uint64_t FuncRecordsSize = 0; + for (SectionRef Section : *CoverageRecordsSections) { + auto CoverageRecordsOrErr = Section.getContents(); + if (!CoverageRecordsOrErr) + return CoverageRecordsOrErr.takeError(); + FuncRecordsSize += alignTo(CoverageRecordsOrErr->size(), RecordAlignment); + } + auto WritableBuffer = + WritableMemoryBuffer::getNewUninitMemBuffer(FuncRecordsSize); + char *FuncRecordsBuffer = WritableBuffer->getBufferStart(); + assert(isAddrAligned(RecordAlignment, FuncRecordsBuffer) && + "Allocated memory is correctly aligned"); + for (SectionRef Section : *CoverageRecordsSections) { auto CoverageRecordsOrErr = Section.getContents(); if (!CoverageRecordsOrErr) return CoverageRecordsOrErr.takeError(); - FuncRecords += CoverageRecordsOrErr.get(); - while (FuncRecords.size() % 8 != 0) - FuncRecords += '\0'; + const auto &CoverageRecords = CoverageRecordsOrErr.get(); + FuncRecordsBuffer = std::copy(CoverageRecords.begin(), + CoverageRecords.end(), FuncRecordsBuffer); + FuncRecordsBuffer = + std::fill_n(FuncRecordsBuffer, + alignAddr(FuncRecordsBuffer, RecordAlignment) - + (uintptr_t)FuncRecordsBuffer, + '\0'); } + assert(FuncRecordsBuffer == WritableBuffer->getBufferEnd() && + "consistent init"); + FuncRecords = std::move(WritableBuffer); } return BinaryCoverageReader::createCoverageReaderFromBuffer( CoverageMapping, std::move(FuncRecords), std::move(ProfileNames), - BytesInAddress, Endian); + BytesInAddress, Endian, CompilationDir); } /// Determine whether \p Arch is invalid or empty, given \p Bin. @@ -990,12 +1071,14 @@ static bool isArchSpecifierInvalidOrMissing(Binary *Bin, StringRef Arch) { Expected<std::vector<std::unique_ptr<BinaryCoverageReader>>> BinaryCoverageReader::create( MemoryBufferRef ObjectBuffer, StringRef Arch, - SmallVectorImpl<std::unique_ptr<MemoryBuffer>> &ObjectFileBuffers) { + SmallVectorImpl<std::unique_ptr<MemoryBuffer>> &ObjectFileBuffers, + StringRef CompilationDir) { std::vector<std::unique_ptr<BinaryCoverageReader>> Readers; if (ObjectBuffer.getBuffer().startswith(TestingFormatMagic)) { // This is a special format used for testing. - auto ReaderOrErr = loadTestingFormat(ObjectBuffer.getBuffer()); + auto ReaderOrErr = + loadTestingFormat(ObjectBuffer.getBuffer(), CompilationDir); if (!ReaderOrErr) return ReaderOrErr.takeError(); Readers.push_back(std::move(ReaderOrErr.get())); @@ -1028,7 +1111,8 @@ BinaryCoverageReader::create( } return BinaryCoverageReader::create( - ArchiveOrErr.get()->getMemoryBufferRef(), Arch, ObjectFileBuffers); + ArchiveOrErr.get()->getMemoryBufferRef(), Arch, ObjectFileBuffers, + CompilationDir); } } @@ -1041,7 +1125,7 @@ BinaryCoverageReader::create( return ChildBufOrErr.takeError(); auto ChildReadersOrErr = BinaryCoverageReader::create( - ChildBufOrErr.get(), Arch, ObjectFileBuffers); + ChildBufOrErr.get(), Arch, ObjectFileBuffers, CompilationDir); if (!ChildReadersOrErr) return ChildReadersOrErr.takeError(); for (auto &Reader : ChildReadersOrErr.get()) @@ -1060,7 +1144,7 @@ BinaryCoverageReader::create( return std::move(Readers); } - auto ReaderOrErr = loadBinaryFormat(std::move(Bin), Arch); + auto ReaderOrErr = loadBinaryFormat(std::move(Bin), Arch, CompilationDir); if (!ReaderOrErr) return ReaderOrErr.takeError(); Readers.push_back(std::move(ReaderOrErr.get())); @@ -1075,10 +1159,9 @@ Error BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) { Expressions.clear(); MappingRegions.clear(); auto &R = MappingRecords[CurrentRecord]; - RawCoverageMappingReader Reader( - R.CoverageMapping, - makeArrayRef(Filenames).slice(R.FilenamesBegin, R.FilenamesSize), - FunctionsFilenames, Expressions, MappingRegions); + auto F = makeArrayRef(Filenames).slice(R.FilenamesBegin, R.FilenamesSize); + RawCoverageMappingReader Reader(R.CoverageMapping, F, FunctionsFilenames, + Expressions, MappingRegions); if (auto Err = Reader.read()) return Err; |