+static std::error_code loadBinaryFormat(MemoryBufferRef ObjectBuffer,
+ SectionData &ProfileNames,
+ StringRef &CoverageMapping,
+ uint8_t &BytesInAddress,
+ support::endianness &Endian,
+ Triple::ArchType Arch) {
+ auto BinOrErr = object::createBinary(ObjectBuffer);
+ if (std::error_code EC = BinOrErr.getError())
+ return EC;
+ auto Bin = std::move(BinOrErr.get());
+ std::unique_ptr<ObjectFile> OF;
+ if (auto *Universal = dyn_cast<object::MachOUniversalBinary>(Bin.get())) {
+ // If we have a universal binary, try to look up the object for the
+ // appropriate architecture.
+ auto ObjectFileOrErr = Universal->getObjectForArch(Arch);
+ if (std::error_code EC = ObjectFileOrErr.getError())
+ return EC;
+ OF = std::move(ObjectFileOrErr.get());
+ } else if (isa<object::ObjectFile>(Bin.get())) {
+ // For any other object file, upcast and take ownership.
+ OF.reset(cast<object::ObjectFile>(Bin.release()));
+ // If we've asked for a particular arch, make sure they match.
+ if (Arch != Triple::ArchType::UnknownArch && OF->getArch() != Arch)
+ return object_error::arch_not_found;
+ } else
+ // We can only handle object files.
+ return 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;
+
+ // Look for the sections that we are interested in.
+ auto NamesSection = lookupSection(*OF, "__llvm_prf_names");
+ if (auto EC = NamesSection.getError())
+ return EC;
+ auto CoverageSection = lookupSection(*OF, "__llvm_covmap");
+ if (auto EC = CoverageSection.getError())
+ return EC;
+
+ // Get the contents of the given sections.
+ if (std::error_code EC = CoverageSection->getContents(CoverageMapping))
+ return EC;
+ if (std::error_code EC = ProfileNames.load(*NamesSection))
+ return EC;
+
+ return std::error_code();
+}
+
+ErrorOr<std::unique_ptr<BinaryCoverageReader>>
+BinaryCoverageReader::create(std::unique_ptr<MemoryBuffer> &ObjectBuffer,
+ Triple::ArchType Arch) {
+ std::unique_ptr<BinaryCoverageReader> Reader(new BinaryCoverageReader());
+
+ SectionData Profile;
+ StringRef Coverage;
+ uint8_t BytesInAddress;
+ support::endianness Endian;
+ std::error_code EC;
+ if (ObjectBuffer->getBuffer().startswith(TestingFormatMagic))
+ // This is a special format used for testing.
+ EC = loadTestingFormat(ObjectBuffer->getBuffer(), Profile, Coverage,
+ BytesInAddress, Endian);
+ else
+ EC = loadBinaryFormat(ObjectBuffer->getMemBufferRef(), Profile, Coverage,
+ BytesInAddress, Endian, Arch);
+ if (EC)
+ return EC;
+
+ if (BytesInAddress == 4 && Endian == support::endianness::little)
+ EC = readCoverageMappingData<uint32_t, support::endianness::little>(
+ Profile, Coverage, Reader->MappingRecords, Reader->Filenames);
+ else if (BytesInAddress == 4 && Endian == support::endianness::big)
+ EC = readCoverageMappingData<uint32_t, support::endianness::big>(
+ Profile, Coverage, Reader->MappingRecords, Reader->Filenames);
+ else if (BytesInAddress == 8 && Endian == support::endianness::little)
+ EC = readCoverageMappingData<uint64_t, support::endianness::little>(
+ Profile, Coverage, Reader->MappingRecords, Reader->Filenames);
+ else if (BytesInAddress == 8 && Endian == support::endianness::big)
+ EC = readCoverageMappingData<uint64_t, support::endianness::big>(
+ Profile, Coverage, Reader->MappingRecords, Reader->Filenames);
+ else
+ return coveragemap_error::malformed;
+ if (EC)
+ return EC;
+ return std::move(Reader);