diff options
Diffstat (limited to 'llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp')
-rw-r--r-- | llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp | 196 |
1 files changed, 129 insertions, 67 deletions
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp index b93c1805665..9a240889ce6 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -586,12 +586,43 @@ 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 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()) @@ -610,9 +641,10 @@ static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames, 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); @@ -620,7 +652,8 @@ 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) { @@ -643,15 +676,8 @@ static Expected<SectionRef> lookupSection(ObjectFile &OF, StringRef Name) { 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 @@ -671,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(); @@ -681,66 +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 (Expected<StringRef> E = CoverageSection->getContents()) - CoverageMapping = *E; - else - return E.takeError(); + 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 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 Readers; + } + + auto ReaderOrErr = loadBinaryFormat(std::move(Bin), Arch); + if (!ReaderOrErr) + return ReaderOrErr.takeError(); + Readers.push_back(std::move(ReaderOrErr.get())); + return Readers; } Error BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) { |