Skip to content

Commit f2ad45c

Browse files
[llvm-cov][WebAssembly] Align coverage mapping section to 8 bytes
Wasm format does not have a good way to insert padding bytes to align the start of a section contents because the size of each section header depends on the size of the section contents (leb128 encoding). This design makes it difficult to align section contents to a specific alignment to load them by post-processing tools like llvm-cov. This patch copies the coverage mapping section to a new buffer that is aligned to 8 bytes if the original section is not aligned. This is not an ideal solution but it works for now.
1 parent 29cc14f commit f2ad45c

File tree

2 files changed

+28
-8
lines changed

2 files changed

+28
-8
lines changed

llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ class BinaryCoverageReader : public CoverageMappingReader {
180180
};
181181

182182
using FuncRecordsStorage = std::unique_ptr<MemoryBuffer>;
183+
using CoverageMapCopyStorage = std::unique_ptr<MemoryBuffer>;
183184

184185
private:
185186
std::vector<std::string> Filenames;
@@ -195,9 +196,16 @@ class BinaryCoverageReader : public CoverageMappingReader {
195196
// D69471, which can split up function records into multiple sections on ELF.
196197
FuncRecordsStorage FuncRecords;
197198

199+
// Used to tie the lifetimes of an optional copy of the coverage mapping data
200+
// to the lifetime of this BinaryCoverageReader instance. Needed to support
201+
// Wasm object format, which might require realignment of section contents.
202+
CoverageMapCopyStorage CoverageMapCopy;
203+
198204
BinaryCoverageReader(std::unique_ptr<InstrProfSymtab> Symtab,
199-
FuncRecordsStorage &&FuncRecords)
200-
: ProfileNames(std::move(Symtab)), FuncRecords(std::move(FuncRecords)) {}
205+
FuncRecordsStorage &&FuncRecords,
206+
CoverageMapCopyStorage &&CoverageMapCopy)
207+
: ProfileNames(std::move(Symtab)), FuncRecords(std::move(FuncRecords)),
208+
CoverageMapCopy(std::move(CoverageMapCopy)) {}
201209

202210
public:
203211
BinaryCoverageReader(const BinaryCoverageReader &) = delete;
@@ -212,6 +220,7 @@ class BinaryCoverageReader : public CoverageMappingReader {
212220
static Expected<std::unique_ptr<BinaryCoverageReader>>
213221
createCoverageReaderFromBuffer(
214222
StringRef Coverage, FuncRecordsStorage &&FuncRecords,
223+
CoverageMapCopyStorage &&CoverageMap,
215224
std::unique_ptr<InstrProfSymtab> ProfileNamesPtr, uint8_t BytesInAddress,
216225
llvm::endianness Endian, StringRef CompilationDir = "");
217226

llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -894,13 +894,15 @@ static Error readCoverageMappingData(
894894
Expected<std::unique_ptr<BinaryCoverageReader>>
895895
BinaryCoverageReader::createCoverageReaderFromBuffer(
896896
StringRef Coverage, FuncRecordsStorage &&FuncRecords,
897+
CoverageMapCopyStorage &&CoverageMap,
897898
std::unique_ptr<InstrProfSymtab> ProfileNamesPtr, uint8_t BytesInAddress,
898899
llvm::endianness Endian, StringRef CompilationDir) {
899900
if (ProfileNamesPtr == nullptr)
900901
return make_error<CoverageMapError>(coveragemap_error::malformed,
901902
"Caller must provide ProfileNames");
902-
std::unique_ptr<BinaryCoverageReader> Reader(new BinaryCoverageReader(
903-
std::move(ProfileNamesPtr), std::move(FuncRecords)));
903+
std::unique_ptr<BinaryCoverageReader> Reader(
904+
new BinaryCoverageReader(std::move(ProfileNamesPtr),
905+
std::move(FuncRecords), std::move(CoverageMap)));
904906
InstrProfSymtab &ProfileNames = *Reader->ProfileNames;
905907
StringRef FuncRecordsRef = Reader->FuncRecords->getBuffer();
906908
if (BytesInAddress == 4 && Endian == llvm::endianness::little) {
@@ -1035,8 +1037,8 @@ loadTestingFormat(StringRef Data, StringRef CompilationDir) {
10351037
MemoryBuffer::getMemBuffer(Data);
10361038

10371039
return BinaryCoverageReader::createCoverageReaderFromBuffer(
1038-
CoverageMapping, std::move(CoverageRecords), std::move(ProfileNames),
1039-
BytesInAddress, Endian, CompilationDir);
1040+
CoverageMapping, std::move(CoverageRecords), nullptr,
1041+
std::move(ProfileNames), BytesInAddress, Endian, CompilationDir);
10401042
}
10411043

10421044
/// Find all sections that match \p IPSK name. There may be more than one if
@@ -1136,6 +1138,15 @@ loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
11361138
return CoverageMappingOrErr.takeError();
11371139
StringRef CoverageMapping = CoverageMappingOrErr.get();
11381140

1141+
// If the coverage mapping section is not aligned to 8 bytes, copy it to a
1142+
// new buffer that is. Wasm format typically has unaligned section contents
1143+
// because it doesn't have a good way to insert padding bytes.
1144+
std::unique_ptr<MemoryBuffer> CoverageMapCopy;
1145+
if (!isAddrAligned(Align(8), CoverageMapping.data())) {
1146+
CoverageMapCopy = MemoryBuffer::getMemBufferCopy(CoverageMapping);
1147+
CoverageMapping = CoverageMapCopy->getBuffer();
1148+
}
1149+
11391150
// Look for the coverage records section (Version4 only).
11401151
auto CoverageRecordsSections = lookupSections(*OF, IPSK_covfun);
11411152

@@ -1184,8 +1195,8 @@ loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
11841195
*BinaryID = getBuildID(OF.get());
11851196

11861197
return BinaryCoverageReader::createCoverageReaderFromBuffer(
1187-
CoverageMapping, std::move(FuncRecords), std::move(ProfileNames),
1188-
BytesInAddress, Endian, CompilationDir);
1198+
CoverageMapping, std::move(FuncRecords), std::move(CoverageMapCopy),
1199+
std::move(ProfileNames), BytesInAddress, Endian, CompilationDir);
11891200
}
11901201

11911202
/// Determine whether \p Arch is invalid or empty, given \p Bin.

0 commit comments

Comments
 (0)