aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-12-18 20:30:12 +0000
committerDimitry Andric <dim@FreeBSD.org>2024-04-06 20:11:55 +0000
commit5f757f3ff9144b609b3c433dfd370cc6bdc191ad (patch)
tree1b4e980b866cd26a00af34c0a653eb640bd09caf /contrib/llvm-project/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
parent3e1c8a35f741a5d114d0ba670b15191355711fe9 (diff)
parent312c0ed19cc5276a17bacf2120097bec4515b0f1 (diff)
Diffstat (limited to 'contrib/llvm-project/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp333
1 files changed, 226 insertions, 107 deletions
diff --git a/contrib/llvm-project/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/contrib/llvm-project/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
index 05737323314a..ac8e6b56379f 100644
--- a/contrib/llvm-project/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
+++ b/contrib/llvm-project/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
@@ -68,7 +68,8 @@ Error RawCoverageReader::readULEB128(uint64_t &Result) {
unsigned N = 0;
Result = decodeULEB128(Data.bytes_begin(), &N);
if (N > Data.size())
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "the size of ULEB128 is too big");
Data = Data.substr(N);
return Error::success();
}
@@ -77,7 +78,9 @@ Error RawCoverageReader::readIntMax(uint64_t &Result, uint64_t MaxPlus1) {
if (auto Err = readULEB128(Result))
return Err;
if (Result >= MaxPlus1)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(
+ coveragemap_error::malformed,
+ "the value of ULEB128 is greater than or equal to MaxPlus1");
return Error::success();
}
@@ -85,7 +88,8 @@ Error RawCoverageReader::readSize(uint64_t &Result) {
if (auto Err = readULEB128(Result))
return Err;
if (Result > Data.size())
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "the value of ULEB128 is too big");
return Error::success();
}
@@ -103,7 +107,8 @@ Error RawCoverageFilenamesReader::read(CovMapVersion Version) {
if (auto Err = readSize(NumFilenames))
return Err;
if (!NumFilenames)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "number of filenames is zero");
if (Version < CovMapVersion::Version4)
return readUncompressed(Version, NumFilenames);
@@ -201,13 +206,15 @@ Error RawCoverageMappingReader::decodeCounter(unsigned Value, Counter &C) {
case CounterExpression::Add: {
auto ID = Value >> Counter::EncodingTagBits;
if (ID >= Expressions.size())
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "counter expression is invalid");
Expressions[ID].Kind = CounterExpression::ExprKind(Tag);
C = Counter::getExpression(ID);
break;
}
default:
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "counter expression kind is invalid");
}
return Error::success();
}
@@ -237,6 +244,7 @@ Error RawCoverageMappingReader::readMappingRegionsSubArray(
unsigned LineStart = 0;
for (size_t I = 0; I < NumRegions; ++I) {
Counter C, C2;
+ uint64_t BIDX = 0, NC = 0, ID = 0, TID = 0, FID = 0;
CounterMappingRegion::RegionKind Kind = CounterMappingRegion::CodeRegion;
// Read the combined counter + region kind.
@@ -268,7 +276,8 @@ Error RawCoverageMappingReader::readMappingRegionsSubArray(
ExpandedFileID = EncodedCounterAndRegion >>
Counter::EncodingCounterTagAndExpansionRegionTagBits;
if (ExpandedFileID >= NumFileIDs)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "ExpandedFileID is invalid");
} else {
switch (EncodedCounterAndRegion >>
Counter::EncodingCounterTagAndExpansionRegionTagBits) {
@@ -286,8 +295,30 @@ Error RawCoverageMappingReader::readMappingRegionsSubArray(
if (auto Err = readCounter(C2))
return Err;
break;
+ case CounterMappingRegion::MCDCBranchRegion:
+ // For a MCDC Branch Region, read two successive counters and 3 IDs.
+ Kind = CounterMappingRegion::MCDCBranchRegion;
+ if (auto Err = readCounter(C))
+ return Err;
+ if (auto Err = readCounter(C2))
+ return Err;
+ if (auto Err = readIntMax(ID, std::numeric_limits<unsigned>::max()))
+ return Err;
+ if (auto Err = readIntMax(TID, std::numeric_limits<unsigned>::max()))
+ return Err;
+ if (auto Err = readIntMax(FID, std::numeric_limits<unsigned>::max()))
+ return Err;
+ break;
+ case CounterMappingRegion::MCDCDecisionRegion:
+ Kind = CounterMappingRegion::MCDCDecisionRegion;
+ if (auto Err = readIntMax(BIDX, std::numeric_limits<unsigned>::max()))
+ return Err;
+ if (auto Err = readIntMax(NC, std::numeric_limits<unsigned>::max()))
+ return Err;
+ break;
default:
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "region kind is incorrect");
}
}
}
@@ -300,7 +331,8 @@ Error RawCoverageMappingReader::readMappingRegionsSubArray(
if (auto Err = readULEB128(ColumnStart))
return Err;
if (ColumnStart > std::numeric_limits<unsigned>::max())
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "start column is too big");
if (auto Err = readIntMax(NumLines, std::numeric_limits<unsigned>::max()))
return Err;
if (auto Err = readIntMax(ColumnEnd, std::numeric_limits<unsigned>::max()))
@@ -337,11 +369,18 @@ Error RawCoverageMappingReader::readMappingRegionsSubArray(
dbgs() << "\n";
});
- auto CMR = CounterMappingRegion(C, C2, InferredFileID, ExpandedFileID,
- LineStart, ColumnStart,
- LineStart + NumLines, ColumnEnd, Kind);
+ auto CMR = CounterMappingRegion(
+ C, C2,
+ CounterMappingRegion::MCDCParameters{
+ static_cast<unsigned>(BIDX), static_cast<unsigned>(NC),
+ static_cast<unsigned>(ID), static_cast<unsigned>(TID),
+ static_cast<unsigned>(FID)},
+ InferredFileID, ExpandedFileID, LineStart, ColumnStart,
+ LineStart + NumLines, ColumnEnd, Kind);
if (CMR.startLoc() > CMR.endLoc())
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(
+ coveragemap_error::malformed,
+ "counter mapping region locations are incorrect");
MappingRegions.push_back(CMR);
}
return Error::success();
@@ -454,9 +493,13 @@ Error InstrProfSymtab::create(SectionRef &Section) {
// If this is a linked PE/COFF file, then we have to skip over the null byte
// that is allocated in the .lprfn$A section in the LLVM profiling runtime.
+ // If the name section is .lprfcovnames, it doesn't have the null byte at the
+ // beginning.
const ObjectFile *Obj = Section.getObject();
if (isa<COFFObjectFile>(Obj) && !Obj->isRelocatableObject())
- Data = Data.drop_front(1);
+ if (Expected<StringRef> NameOrErr = Section.getName())
+ if (*NameOrErr != getInstrProfSectionName(IPSK_covname, Triple::COFF))
+ Data = Data.drop_front(1);
return Error::success();
}
@@ -523,7 +566,7 @@ struct CovMapFuncRecordReader {
const char *OutOfLineMappingBuf,
const char *OutOfLineMappingBufEnd) = 0;
- template <class IntPtrT, support::endianness Endian>
+ template <class IntPtrT, llvm::endianness Endian>
static Expected<std::unique_ptr<CovMapFuncRecordReader>>
get(CovMapVersion Version, InstrProfSymtab &P,
std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, StringRef D,
@@ -531,7 +574,7 @@ struct CovMapFuncRecordReader {
};
// A class for reading coverage mapping function records for a module.
-template <CovMapVersion Version, class IntPtrT, support::endianness Endian>
+template <CovMapVersion Version, class IntPtrT, llvm::endianness Endian>
class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
using FuncRecordType =
typename CovMapTraits<Version, IntPtrT>::CovMapFuncRecordType;
@@ -613,7 +656,9 @@ public:
using namespace support;
if (CovBuf + sizeof(CovMapHeader) > CovBufEnd)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(
+ coveragemap_error::malformed,
+ "coverage mapping header section is larger than buffer size");
auto CovHeader = reinterpret_cast<const CovMapHeader *>(CovBuf);
uint32_t NRecords = CovHeader->getNRecords<Endian>();
uint32_t FilenamesSize = CovHeader->getFilenamesSize<Endian>();
@@ -634,7 +679,9 @@ public:
// Get the filenames.
if (CovBuf + FilenamesSize > CovBufEnd)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(
+ coveragemap_error::malformed,
+ "filenames section is larger than buffer size");
size_t FilenamesBegin = Filenames.size();
StringRef FilenameRegion(CovBuf, FilenamesSize);
RawCoverageFilenamesReader Reader(FilenameRegion, Filenames,
@@ -673,12 +720,15 @@ public:
// coverage header).
const char *MappingBuf = CovBuf;
if (Version >= CovMapVersion::Version4 && CoverageSize != 0)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "coverage mapping size is not zero");
CovBuf += CoverageSize;
const char *MappingEnd = CovBuf;
if (CovBuf > CovBufEnd)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(
+ coveragemap_error::malformed,
+ "function records section is larger than buffer size");
if (Version < CovMapVersion::Version4) {
// Read each function record.
@@ -707,7 +757,9 @@ public:
CFR->template advanceByOne<Endian>(OutOfLineMappingBuf);
if (Version < CovMapVersion::Version4)
if (NextMappingBuf > OutOfLineMappingBufEnd)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(
+ coveragemap_error::malformed,
+ "next mapping buffer is larger than buffer size");
// Look up the set of filenames associated with this function record.
std::optional<FilenameRange> FileRange;
@@ -717,7 +769,10 @@ public:
uint64_t FilenamesRef = CFR->template getFilenamesRef<Endian>();
auto It = FileRangeMap.find(FilenamesRef);
if (It == FileRangeMap.end())
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(
+ coveragemap_error::malformed,
+ "no filename found for function with hash=0x" +
+ Twine::utohexstr(FilenamesRef));
else
FileRange = It->getSecond();
}
@@ -728,7 +783,9 @@ public:
CFR->template getCoverageMapping<Endian>(OutOfLineMappingBuf);
if (Version >= CovMapVersion::Version4 &&
Mapping.data() + Mapping.size() > FuncRecBufEnd)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(
+ coveragemap_error::malformed,
+ "coverage mapping data is larger than buffer size");
if (Error Err = insertFunctionRecordIfNeeded(CFR, Mapping, *FileRange))
return Err;
}
@@ -741,7 +798,7 @@ public:
} // end anonymous namespace
-template <class IntPtrT, support::endianness Endian>
+template <class IntPtrT, llvm::endianness Endian>
Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
CovMapVersion Version, InstrProfSymtab &P,
std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, StringRef D,
@@ -757,6 +814,7 @@ Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
case CovMapVersion::Version4:
case CovMapVersion::Version5:
case CovMapVersion::Version6:
+ case CovMapVersion::Version7:
// Decompress the name data.
if (Error E = P.create(P.getNameData()))
return std::move(E);
@@ -775,11 +833,14 @@ Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
else if (Version == CovMapVersion::Version6)
return std::make_unique<VersionedCovMapFuncRecordReader<
CovMapVersion::Version6, IntPtrT, Endian>>(P, R, D, F);
+ else if (Version == CovMapVersion::Version7)
+ return std::make_unique<VersionedCovMapFuncRecordReader<
+ CovMapVersion::Version7, IntPtrT, Endian>>(P, R, D, F);
}
llvm_unreachable("Unsupported version");
}
-template <typename T, support::endianness Endian>
+template <typename T, llvm::endianness Endian>
static Error readCoverageMappingData(
InstrProfSymtab &ProfileNames, StringRef CovMap, StringRef FuncRecords,
std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records,
@@ -822,114 +883,158 @@ static Error readCoverageMappingData(
return Error::success();
}
-static const char *TestingFormatMagic = "llvmcovmtestdata";
-
Expected<std::unique_ptr<BinaryCoverageReader>>
BinaryCoverageReader::createCoverageReaderFromBuffer(
StringRef Coverage, FuncRecordsStorage &&FuncRecords,
InstrProfSymtab &&ProfileNames, uint8_t BytesInAddress,
- support::endianness Endian, StringRef CompilationDir) {
+ llvm::endianness Endian, StringRef CompilationDir) {
std::unique_ptr<BinaryCoverageReader> Reader(
new BinaryCoverageReader(std::move(FuncRecords)));
Reader->ProfileNames = std::move(ProfileNames);
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, CompilationDir, Reader->Filenames))
+ if (BytesInAddress == 4 && Endian == llvm::endianness::little) {
+ if (Error E = readCoverageMappingData<uint32_t, llvm::endianness::little>(
+ Reader->ProfileNames, Coverage, FuncRecordsRef,
+ 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>(
+ } else if (BytesInAddress == 4 && Endian == llvm::endianness::big) {
+ if (Error E = readCoverageMappingData<uint32_t, llvm::endianness::big>(
Reader->ProfileNames, Coverage, FuncRecordsRef,
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, CompilationDir, Reader->Filenames))
+ } else if (BytesInAddress == 8 && Endian == llvm::endianness::little) {
+ if (Error E = readCoverageMappingData<uint64_t, llvm::endianness::little>(
+ Reader->ProfileNames, Coverage, FuncRecordsRef,
+ 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>(
+ } else if (BytesInAddress == 8 && Endian == llvm::endianness::big) {
+ if (Error E = readCoverageMappingData<uint64_t, llvm::endianness::big>(
Reader->ProfileNames, Coverage, FuncRecordsRef,
Reader->MappingRecords, CompilationDir, Reader->Filenames))
return std::move(E);
} else
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(
+ coveragemap_error::malformed,
+ "not supported endianness or bytes in address");
return std::move(Reader);
}
static Expected<std::unique_ptr<BinaryCoverageReader>>
loadTestingFormat(StringRef Data, StringRef CompilationDir) {
uint8_t BytesInAddress = 8;
- support::endianness Endian = support::endianness::little;
-
- Data = Data.substr(StringRef(TestingFormatMagic).size());
+ llvm::endianness Endian = llvm::endianness::little;
+
+ // Read the magic and version.
+ Data = Data.substr(sizeof(TestingFormatMagic));
+ if (Data.size() < sizeof(uint64_t))
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "the size of data is too small");
+ auto TestingVersion =
+ support::endian::byte_swap<uint64_t, llvm::endianness::little>(
+ *reinterpret_cast<const uint64_t *>(Data.data()));
+ Data = Data.substr(sizeof(uint64_t));
+
+ // Read the ProfileNames data.
if (Data.empty())
return make_error<CoverageMapError>(coveragemap_error::truncated);
unsigned N = 0;
uint64_t ProfileNamesSize = decodeULEB128(Data.bytes_begin(), &N);
if (N > Data.size())
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(
+ coveragemap_error::malformed,
+ "the size of TestingFormatMagic is too big");
Data = Data.substr(N);
if (Data.empty())
return make_error<CoverageMapError>(coveragemap_error::truncated);
N = 0;
uint64_t Address = decodeULEB128(Data.bytes_begin(), &N);
if (N > Data.size())
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "the size of ULEB128 is too big");
Data = Data.substr(N);
if (Data.size() < ProfileNamesSize)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "the size of ProfileNames is too big");
InstrProfSymtab ProfileNames;
if (Error E = ProfileNames.create(Data.substr(0, ProfileNamesSize), Address))
return std::move(E);
Data = Data.substr(ProfileNamesSize);
+
+ // In Version2, the size of CoverageMapping is stored directly.
+ uint64_t CoverageMappingSize;
+ if (TestingVersion == uint64_t(TestingFormatVersion::Version2)) {
+ N = 0;
+ CoverageMappingSize = decodeULEB128(Data.bytes_begin(), &N);
+ if (N > Data.size())
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "the size of ULEB128 is too big");
+ Data = Data.substr(N);
+ if (CoverageMappingSize < sizeof(CovMapHeader))
+ return make_error<CoverageMapError>(
+ coveragemap_error::malformed,
+ "the size of CoverageMapping is teoo small");
+ } else if (TestingVersion != uint64_t(TestingFormatVersion::Version1)) {
+ return make_error<CoverageMapError>(coveragemap_error::unsupported_version);
+ }
+
// Skip the padding bytes because coverage map data has an alignment of 8.
- size_t Pad = offsetToAlignedAddr(Data.data(), Align(8));
+ auto Pad = offsetToAlignedAddr(Data.data(), Align(8));
if (Data.size() < Pad)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "insufficient padding");
Data = Data.substr(Pad);
if (Data.size() < sizeof(CovMapHeader))
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(
+ coveragemap_error::malformed,
+ "coverage mapping header section is larger than data size");
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;
+ auto Version =
+ CovMapVersion(CovHeader->getVersion<llvm::endianness::little>());
+
+ // In Version1, the size of CoverageMapping is calculated.
+ if (TestingVersion == uint64_t(TestingFormatVersion::Version1)) {
+ if (Version < CovMapVersion::Version4) {
+ CoverageMappingSize = Data.size();
+ } else {
+ auto FilenamesSize =
+ CovHeader->getFilenamesSize<llvm::endianness::little>();
+ CoverageMappingSize = sizeof(CovMapHeader) + FilenamesSize;
+ }
+ }
+
+ auto CoverageMapping = Data.substr(0, CoverageMappingSize);
+ Data = Data.substr(CoverageMappingSize);
+
+ // Read the CoverageRecords data.
if (Version < CovMapVersion::Version4) {
- CoverageMapping = Data;
- if (CoverageMapping.empty())
- return make_error<CoverageMapError>(coveragemap_error::truncated);
- CoverageRecords = MemoryBuffer::getMemBuffer("");
+ if (!Data.empty())
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "data is not empty");
} 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 make_error<CoverageMapError>(coveragemap_error::malformed,
+ "insufficient padding");
+ Data = Data.substr(Pad);
}
+ BinaryCoverageReader::FuncRecordsStorage CoverageRecords =
+ MemoryBuffer::getMemBuffer(Data);
+
return BinaryCoverageReader::createCoverageReaderFromBuffer(
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
-/// are in use, e.g. for the __llvm_covfun section on ELF.
-static Expected<std::vector<SectionRef>> lookupSections(ObjectFile &OF,
- StringRef Name) {
+/// Find all sections that match \p IPSK name. There may be more than one if
+/// comdats are in use, e.g. for the __llvm_covfun section on ELF.
+static Expected<std::vector<SectionRef>>
+lookupSections(ObjectFile &OF, InstrProfSectKind IPSK) {
+ auto ObjFormat = OF.getTripleObjectFormat();
+ auto Name =
+ getInstrProfSectionName(IPSK, ObjFormat, /*AddSegmentInfo=*/false);
// On COFF, the object file section name may end in "$M". This tells the
// linker to sort these sections between "$A" and "$Z". The linker removes the
// dollar and everything after it in the final binary. Do the same to match.
@@ -944,8 +1049,13 @@ static Expected<std::vector<SectionRef>> lookupSections(ObjectFile &OF,
Expected<StringRef> NameOrErr = Section.getName();
if (!NameOrErr)
return NameOrErr.takeError();
- if (stripSuffix(*NameOrErr) == Name)
+ if (stripSuffix(*NameOrErr) == Name) {
+ // COFF profile name section contains two null bytes indicating the
+ // start/end of the section. If its size is 2 bytes, it's empty.
+ if (IsCOFF && IPSK == IPSK_name && Section.getSize() == 2)
+ continue;
Sections.push_back(Section);
+ }
}
if (Sections.empty())
return make_error<CoverageMapError>(coveragemap_error::no_data_found);
@@ -972,45 +1082,49 @@ loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
return errorCodeToError(object_error::arch_not_found);
} else
// We can only handle object files.
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "binary is not an object file");
// The coverage uses native pointer sizes for the object it's written in.
uint8_t BytesInAddress = OF->getBytesInAddress();
- support::endianness Endian = OF->isLittleEndian()
- ? support::endianness::little
- : support::endianness::big;
+ llvm::endianness Endian =
+ OF->isLittleEndian() ? llvm::endianness::little : llvm::endianness::big;
// Look for the sections that we are interested in.
- auto ObjFormat = OF->getTripleObjectFormat();
- auto NamesSection =
- lookupSections(*OF, getInstrProfSectionName(IPSK_name, ObjFormat,
- /*AddSegmentInfo=*/false));
- if (auto E = NamesSection.takeError())
+ InstrProfSymtab ProfileNames;
+ std::vector<SectionRef> NamesSectionRefs;
+ // If IPSK_name is not found, fallback to search for IPK_covname, which is
+ // used when binary correlation is enabled.
+ auto NamesSection = lookupSections(*OF, IPSK_name);
+ if (auto E = NamesSection.takeError()) {
+ consumeError(std::move(E));
+ NamesSection = lookupSections(*OF, IPSK_covname);
+ if (auto E = NamesSection.takeError())
+ return std::move(E);
+ }
+ NamesSectionRefs = *NamesSection;
+
+ if (NamesSectionRefs.size() != 1)
+ return make_error<CoverageMapError>(
+ coveragemap_error::malformed,
+ "the size of coverage mapping section is not one");
+ if (Error E = ProfileNames.create(NamesSectionRefs.back()))
return std::move(E);
- auto CoverageSection =
- lookupSections(*OF, getInstrProfSectionName(IPSK_covmap, ObjFormat,
- /*AddSegmentInfo=*/false));
+
+ auto CoverageSection = lookupSections(*OF, IPSK_covmap);
if (auto E = CoverageSection.takeError())
return std::move(E);
std::vector<SectionRef> CoverageSectionRefs = *CoverageSection;
if (CoverageSectionRefs.size() != 1)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return make_error<CoverageMapError>(coveragemap_error::malformed,
+ "the size of name section is not one");
auto CoverageMappingOrErr = CoverageSectionRefs.back().getContents();
if (!CoverageMappingOrErr)
return CoverageMappingOrErr.takeError();
StringRef CoverageMapping = CoverageMappingOrErr.get();
- InstrProfSymtab ProfileNames;
- std::vector<SectionRef> NamesSectionRefs = *NamesSection;
- if (NamesSectionRefs.size() != 1)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- if (Error E = ProfileNames.create(NamesSectionRefs.back()))
- return std::move(E);
-
// Look for the coverage records section (Version4 only).
- auto CoverageRecordsSections =
- lookupSections(*OF, getInstrProfSectionName(IPSK_covfun, ObjFormat,
- /*AddSegmentInfo=*/false));
+ auto CoverageRecordsSections = lookupSections(*OF, IPSK_covfun);
BinaryCoverageReader::FuncRecordsStorage FuncRecords;
if (auto E = CoverageRecordsSections.takeError()) {
@@ -1081,14 +1195,19 @@ BinaryCoverageReader::create(
StringRef CompilationDir, SmallVectorImpl<object::BuildIDRef> *BinaryIDs) {
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(), CompilationDir);
- if (!ReaderOrErr)
- return ReaderOrErr.takeError();
- Readers.push_back(std::move(ReaderOrErr.get()));
- return std::move(Readers);
+ if (ObjectBuffer.getBuffer().size() > sizeof(TestingFormatMagic)) {
+ uint64_t Magic =
+ support::endian::byte_swap<uint64_t, llvm::endianness::little>(
+ *reinterpret_cast<const uint64_t *>(ObjectBuffer.getBufferStart()));
+ if (Magic == TestingFormatMagic) {
+ // This is a special format used for testing.
+ auto ReaderOrErr =
+ loadTestingFormat(ObjectBuffer.getBuffer(), CompilationDir);
+ if (!ReaderOrErr)
+ return ReaderOrErr.takeError();
+ Readers.push_back(std::move(ReaderOrErr.get()));
+ return std::move(Readers);
+ }
}
auto BinOrErr = createBinary(ObjectBuffer);