1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 02:33:06 +01:00

[llvm-cov] Enforce alignment of function records

Function Records are required to be aligned on 8 bytes. This is enforced for each
records except the first, when one relies on the default alignment within an
std::string. There's no such guarantee, and indeed on 32 bits for some
implementation of std::string this is not enforced.

Provide a portable implementation based on llvm's MemoryBuffer.

Differential Revision: https://reviews.llvm.org/D104745
This commit is contained in:
serge-sans-paille 2021-06-22 22:50:37 +02:00
parent a7b0e064e3
commit b7c46d66e4
2 changed files with 48 additions and 15 deletions

View File

@ -179,6 +179,8 @@ public:
FilenamesBegin(FilenamesBegin), FilenamesSize(FilenamesSize) {}
};
using FuncRecordsStorage = std::unique_ptr<MemoryBuffer>;
private:
std::vector<std::string> Filenames;
std::vector<ProfileMappingRecord> MappingRecords;
@ -191,9 +193,9 @@ private:
// Used to tie the lifetimes of coverage function records to the lifetime of
// this BinaryCoverageReader instance. Needed to support the format change in
// D69471, which can split up function records into multiple sections on ELF.
std::string FuncRecords;
FuncRecordsStorage FuncRecords;
BinaryCoverageReader(std::string &&FuncRecords)
BinaryCoverageReader(FuncRecordsStorage &&FuncRecords)
: FuncRecords(std::move(FuncRecords)) {}
public:
@ -206,7 +208,8 @@ public:
StringRef CompilationDir = "");
static Expected<std::unique_ptr<BinaryCoverageReader>>
createCoverageReaderFromBuffer(StringRef Coverage, std::string &&FuncRecords,
createCoverageReaderFromBuffer(StringRef Coverage,
FuncRecordsStorage &&FuncRecords,
InstrProfSymtab &&ProfileNames,
uint8_t BytesInAddress,
support::endianness Endian,

View File

@ -824,13 +824,13 @@ static const char *TestingFormatMagic = "llvmcovmtestdata";
Expected<std::unique_ptr<BinaryCoverageReader>>
BinaryCoverageReader::createCoverageReaderFromBuffer(
StringRef Coverage, std::string &&FuncRecords,
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>(
@ -895,11 +895,13 @@ loadTestingFormat(StringRef Data, StringRef CompilationDir) {
Data.substr(0, sizeof(CovMapHeader)).data());
CovMapVersion Version =
(CovMapVersion)CovHeader->getVersion<support::endianness::little>();
StringRef CoverageMapping, CoverageRecords;
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>();
@ -913,12 +915,12 @@ loadTestingFormat(StringRef Data, StringRef CompilationDir) {
Pad = offsetToAlignedAddr(Data.data(), Align(8));
if (Data.size() < Pad)
return make_error<CoverageMapError>(coveragemap_error::malformed);
CoverageRecords = Data.substr(Pad);
if (CoverageRecords.empty())
CoverageRecords = MemoryBuffer::getMemBuffer(Data.substr(Pad));
if (CoverageRecords->getBufferSize() == 0)
return make_error<CoverageMapError>(coveragemap_error::truncated);
}
return BinaryCoverageReader::createCoverageReaderFromBuffer(
CoverageMapping, CoverageRecords.str(), std::move(ProfileNames),
CoverageMapping, std::move(CoverageRecords), std::move(ProfileNames),
BytesInAddress, Endian, CompilationDir);
}
@ -1003,21 +1005,49 @@ 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();
FuncRecords += CoverageRecordsOrErr.get();
while (FuncRecords.size() % 8 != 0)
FuncRecords += '\0';
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();
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(