aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp')
-rw-r--r--llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp239
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;