aboutsummaryrefslogtreecommitdiff
path: root/lib/ProfileData/Coverage/CoverageMappingReader.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:12 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:12 +0000
commite6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch)
tree599ab169a01f1c86eda9adc774edaedde2f2db5b /lib/ProfileData/Coverage/CoverageMappingReader.cpp
parent1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff)
Notes
Diffstat (limited to 'lib/ProfileData/Coverage/CoverageMappingReader.cpp')
-rw-r--r--lib/ProfileData/Coverage/CoverageMappingReader.cpp235
1 files changed, 158 insertions, 77 deletions
diff --git a/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/lib/ProfileData/Coverage/CoverageMappingReader.cpp
index ee48256bc2e5..e193e10f91d9 100644
--- a/lib/ProfileData/Coverage/CoverageMappingReader.cpp
+++ b/lib/ProfileData/Coverage/CoverageMappingReader.cpp
@@ -1,9 +1,8 @@
//===- CoverageMappingReader.cpp - Code coverage mapping reader -----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -23,6 +22,7 @@
#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/Debug.h"
@@ -59,7 +59,7 @@ Error RawCoverageReader::readULEB128(uint64_t &Result) {
if (Data.empty())
return make_error<CoverageMapError>(coveragemap_error::truncated);
unsigned N = 0;
- Result = decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N);
+ Result = decodeULEB128(Data.bytes_begin(), &N);
if (N > Data.size())
return make_error<CoverageMapError>(coveragemap_error::malformed);
Data = Data.substr(N);
@@ -348,9 +348,18 @@ Expected<bool> RawCoverageMappingDummyChecker::isDummy() {
}
Error InstrProfSymtab::create(SectionRef &Section) {
- if (auto EC = Section.getContents(Data))
- return errorCodeToError(EC);
+ Expected<StringRef> DataOrErr = Section.getContents();
+ if (!DataOrErr)
+ return DataOrErr.takeError();
+ Data = *DataOrErr;
Address = Section.getAddress();
+
+ // 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.
+ const ObjectFile *Obj = Section.getObject();
+ if (isa<COFFObjectFile>(Obj) && !Obj->isRelocatableObject())
+ Data = Data.drop_front(1);
+
return Error::success();
}
@@ -577,35 +586,65 @@ static Error readCoverageMappingData(
static const char *TestingFormatMagic = "llvmcovmtestdata";
-static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames,
- StringRef &CoverageMapping,
- uint8_t &BytesInAddress,
- support::endianness &Endian) {
- BytesInAddress = 8;
- Endian = support::endianness::little;
+Expected<std::unique_ptr<BinaryCoverageReader>>
+BinaryCoverageReader::createCoverageReaderFromBuffer(
+ StringRef Coverage, InstrProfSymtab &&ProfileNames, uint8_t BytesInAddress,
+ support::endianness Endian) {
+ std::unique_ptr<BinaryCoverageReader> Reader(new BinaryCoverageReader());
+ Reader->ProfileNames = std::move(ProfileNames);
+ if (BytesInAddress == 4 && Endian == support::endianness::little) {
+ if (Error E =
+ readCoverageMappingData<uint32_t, support::endianness::little>(
+ Reader->ProfileNames, Coverage, Reader->MappingRecords,
+ 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, Reader->MappingRecords,
+ 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, Reader->MappingRecords,
+ 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, Reader->MappingRecords,
+ Reader->Filenames))
+ return std::move(E);
+ } else
+ return make_error<CoverageMapError>(coveragemap_error::malformed);
+ return std::move(Reader);
+}
+
+static Expected<std::unique_ptr<BinaryCoverageReader>>
+loadTestingFormat(StringRef Data) {
+ uint8_t BytesInAddress = 8;
+ support::endianness Endian = support::endianness::little;
Data = Data.substr(StringRef(TestingFormatMagic).size());
if (Data.empty())
return make_error<CoverageMapError>(coveragemap_error::truncated);
unsigned N = 0;
- auto ProfileNamesSize =
- decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N);
+ uint64_t ProfileNamesSize = decodeULEB128(Data.bytes_begin(), &N);
if (N > Data.size())
return make_error<CoverageMapError>(coveragemap_error::malformed);
Data = Data.substr(N);
if (Data.empty())
return make_error<CoverageMapError>(coveragemap_error::truncated);
N = 0;
- uint64_t Address =
- decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N);
+ uint64_t Address = decodeULEB128(Data.bytes_begin(), &N);
if (N > Data.size())
return make_error<CoverageMapError>(coveragemap_error::malformed);
Data = Data.substr(N);
if (Data.size() < ProfileNamesSize)
return make_error<CoverageMapError>(coveragemap_error::malformed);
+ InstrProfSymtab ProfileNames;
if (Error E = ProfileNames.create(Data.substr(0, ProfileNamesSize), Address))
- return E;
- CoverageMapping = Data.substr(ProfileNamesSize);
+ return std::move(E);
+ StringRef CoverageMapping = 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);
@@ -613,29 +652,32 @@ static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames,
if (CoverageMapping.size() < Pad)
return make_error<CoverageMapError>(coveragemap_error::malformed);
CoverageMapping = CoverageMapping.substr(Pad);
- return Error::success();
+ return BinaryCoverageReader::createCoverageReaderFromBuffer(
+ CoverageMapping, std::move(ProfileNames), BytesInAddress, Endian);
}
static Expected<SectionRef> lookupSection(ObjectFile &OF, StringRef Name) {
+ // 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.
+ bool IsCOFF = isa<COFFObjectFile>(OF);
+ auto stripSuffix = [IsCOFF](StringRef N) {
+ return IsCOFF ? N.split('$').first : N;
+ };
+ Name = stripSuffix(Name);
+
StringRef FoundName;
for (const auto &Section : OF.sections()) {
if (auto EC = Section.getName(FoundName))
return errorCodeToError(EC);
- if (FoundName == Name)
+ if (stripSuffix(FoundName) == Name)
return Section;
}
return make_error<CoverageMapError>(coveragemap_error::no_data_found);
}
-static Error loadBinaryFormat(MemoryBufferRef ObjectBuffer,
- InstrProfSymtab &ProfileNames,
- StringRef &CoverageMapping,
- uint8_t &BytesInAddress,
- support::endianness &Endian, StringRef Arch) {
- auto BinOrErr = createBinary(ObjectBuffer);
- if (!BinOrErr)
- return BinOrErr.takeError();
- auto Bin = std::move(BinOrErr.get());
+static Expected<std::unique_ptr<BinaryCoverageReader>>
+loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch) {
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
@@ -655,9 +697,10 @@ static Error loadBinaryFormat(MemoryBufferRef ObjectBuffer,
return make_error<CoverageMapError>(coveragemap_error::malformed);
// The coverage uses native pointer sizes for the object it's written in.
- BytesInAddress = OF->getBytesInAddress();
- Endian = OF->isLittleEndian() ? support::endianness::little
- : support::endianness::big;
+ uint8_t BytesInAddress = OF->getBytesInAddress();
+ support::endianness Endian = OF->isLittleEndian()
+ ? support::endianness::little
+ : support::endianness::big;
// Look for the sections that we are interested in.
auto ObjFormat = OF->getTripleObjectFormat();
@@ -665,63 +708,101 @@ static Error loadBinaryFormat(MemoryBufferRef ObjectBuffer,
lookupSection(*OF, getInstrProfSectionName(IPSK_name, ObjFormat,
/*AddSegmentInfo=*/false));
if (auto E = NamesSection.takeError())
- return E;
+ return std::move(E);
auto CoverageSection =
lookupSection(*OF, getInstrProfSectionName(IPSK_covmap, ObjFormat,
/*AddSegmentInfo=*/false));
if (auto E = CoverageSection.takeError())
- return E;
+ return std::move(E);
// Get the contents of the given sections.
- if (auto EC = CoverageSection->getContents(CoverageMapping))
- return errorCodeToError(EC);
+ auto CoverageMappingOrErr = CoverageSection->getContents();
+ if (!CoverageMappingOrErr)
+ return CoverageMappingOrErr.takeError();
+
+ InstrProfSymtab ProfileNames;
if (Error E = ProfileNames.create(*NamesSection))
- return E;
+ return std::move(E);
- return Error::success();
+ return BinaryCoverageReader::createCoverageReaderFromBuffer(
+ CoverageMappingOrErr.get(), std::move(ProfileNames), BytesInAddress,
+ Endian);
}
-Expected<std::unique_ptr<BinaryCoverageReader>>
-BinaryCoverageReader::create(std::unique_ptr<MemoryBuffer> &ObjectBuffer,
- StringRef Arch) {
- std::unique_ptr<BinaryCoverageReader> Reader(new BinaryCoverageReader());
+Expected<std::vector<std::unique_ptr<BinaryCoverageReader>>>
+BinaryCoverageReader::create(
+ MemoryBufferRef ObjectBuffer, StringRef Arch,
+ SmallVectorImpl<std::unique_ptr<MemoryBuffer>> &ObjectFileBuffers) {
+ std::vector<std::unique_ptr<BinaryCoverageReader>> Readers;
- StringRef Coverage;
- uint8_t BytesInAddress;
- support::endianness Endian;
- Error E = Error::success();
- consumeError(std::move(E));
- if (ObjectBuffer->getBuffer().startswith(TestingFormatMagic))
+ if (ObjectBuffer.getBuffer().startswith(TestingFormatMagic)) {
// This is a special format used for testing.
- E = loadTestingFormat(ObjectBuffer->getBuffer(), Reader->ProfileNames,
- Coverage, BytesInAddress, Endian);
- else
- E = loadBinaryFormat(ObjectBuffer->getMemBufferRef(), Reader->ProfileNames,
- Coverage, BytesInAddress, Endian, Arch);
- if (E)
- return std::move(E);
+ auto ReaderOrErr = loadTestingFormat(ObjectBuffer.getBuffer());
+ if (!ReaderOrErr)
+ return ReaderOrErr.takeError();
+ Readers.push_back(std::move(ReaderOrErr.get()));
+ return std::move(Readers);
+ }
- if (BytesInAddress == 4 && Endian == support::endianness::little)
- E = readCoverageMappingData<uint32_t, support::endianness::little>(
- Reader->ProfileNames, Coverage, Reader->MappingRecords,
- Reader->Filenames);
- else if (BytesInAddress == 4 && Endian == support::endianness::big)
- E = readCoverageMappingData<uint32_t, support::endianness::big>(
- Reader->ProfileNames, Coverage, Reader->MappingRecords,
- Reader->Filenames);
- else if (BytesInAddress == 8 && Endian == support::endianness::little)
- E = readCoverageMappingData<uint64_t, support::endianness::little>(
- Reader->ProfileNames, Coverage, Reader->MappingRecords,
- Reader->Filenames);
- else if (BytesInAddress == 8 && Endian == support::endianness::big)
- E = readCoverageMappingData<uint64_t, support::endianness::big>(
- Reader->ProfileNames, Coverage, Reader->MappingRecords,
- Reader->Filenames);
- else
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- if (E)
- return std::move(E);
- return std::move(Reader);
+ auto BinOrErr = createBinary(ObjectBuffer);
+ if (!BinOrErr)
+ return BinOrErr.takeError();
+ std::unique_ptr<Binary> Bin = std::move(BinOrErr.get());
+
+ // MachO universal binaries which contain archives need to be treated as
+ // archives, not as regular binaries.
+ if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) {
+ for (auto &ObjForArch : Universal->objects()) {
+ // Skip slices within the universal binary which target the wrong arch.
+ std::string ObjArch = ObjForArch.getArchFlagName();
+ if (Arch != ObjArch)
+ continue;
+
+ auto ArchiveOrErr = ObjForArch.getAsArchive();
+ if (!ArchiveOrErr) {
+ // If this is not an archive, try treating it as a regular object.
+ consumeError(ArchiveOrErr.takeError());
+ break;
+ }
+
+ return BinaryCoverageReader::create(
+ ArchiveOrErr.get()->getMemoryBufferRef(), Arch, ObjectFileBuffers);
+ }
+ }
+
+ // Load coverage out of archive members.
+ if (auto *Ar = dyn_cast<Archive>(Bin.get())) {
+ Error Err = Error::success();
+ for (auto &Child : Ar->children(Err)) {
+ Expected<MemoryBufferRef> ChildBufOrErr = Child.getMemoryBufferRef();
+ if (!ChildBufOrErr)
+ return ChildBufOrErr.takeError();
+
+ auto ChildReadersOrErr = BinaryCoverageReader::create(
+ ChildBufOrErr.get(), Arch, ObjectFileBuffers);
+ if (!ChildReadersOrErr)
+ return ChildReadersOrErr.takeError();
+ for (auto &Reader : ChildReadersOrErr.get())
+ Readers.push_back(std::move(Reader));
+ }
+ if (Err)
+ return std::move(Err);
+
+ // Thin archives reference object files outside of the archive file, i.e.
+ // files which reside in memory not owned by the caller. Transfer ownership
+ // to the caller.
+ if (Ar->isThin())
+ for (auto &Buffer : Ar->takeThinBuffers())
+ ObjectFileBuffers.push_back(std::move(Buffer));
+
+ return std::move(Readers);
+ }
+
+ auto ReaderOrErr = loadBinaryFormat(std::move(Bin), Arch);
+ if (!ReaderOrErr)
+ return ReaderOrErr.takeError();
+ Readers.push_back(std::move(ReaderOrErr.get()));
+ return std::move(Readers);
}
Error BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) {