llvm.org GIT mirror llvm / 235358f
[Coverage] Load code coverage data from archives Support loading code coverage data from regular archives, thin archives, and from MachO universal binaries which contain archives. Testing: check-llvm, check-profile (with {A,UB}San enabled) rdar://51538999 Differential Revision: https://reviews.llvm.org/D63232 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@363325 91177308-0d34-0410-b5e6-96231b3b80d8 Vedant Kumar a month ago
11 changed file(s) with 210 addition(s) and 79 deletion(s). Raw diff Collapse all Expand all
180180 binaries *BIN*,... using the profile data *PROFILE*. It can optionally be
181181 filtered to only show the coverage for the files listed in *SOURCES*.
182182
183 *BIN* may be an executable, object file, dynamic library, or archive (thin or
184 otherwise).
185
183186 To use :program:`llvm-cov show`, you need a program that is compiled with
184187 instrumentation to emit profile and coverage data. To build such a program with
185188 ``clang`` use the ``-fprofile-instr-generate`` and ``-fcoverage-mapping``
330333 the binaries *BIN*,... using the profile data *PROFILE*. It can optionally be
331334 filtered to only show the coverage for the files listed in *SOURCES*.
332335
336 *BIN* may be an executable, object file, dynamic library, or archive (thin or
337 otherwise).
338
333339 If no source files are provided, a summary line is printed for each file in the
334340 coverage data. If any files are provided, summaries can be shown for each
335341 function in the listed files if the ``-show-functions`` option is enabled.
202202 BinaryCoverageReader(const BinaryCoverageReader &) = delete;
203203 BinaryCoverageReader &operator=(const BinaryCoverageReader &) = delete;
204204
205 static Expected>>
206 create(MemoryBufferRef ObjectBuffer, StringRef Arch,
207 SmallVectorImpl> &ObjectFileBuffers);
208
205209 static Expected>
206 create(std::unique_ptr &ObjectBuffer,
207 StringRef Arch);
210 createCoverageReaderFromBuffer(StringRef Coverage,
211 InstrProfSymtab &&ProfileNames,
212 uint8_t BytesInAddress,
213 support::endianness Endian);
208214
209215 Error readNextRecord(CoverageMappingRecord &Record) override;
210216 };
284284 if (std::error_code EC = CovMappingBufOrErr.getError())
285285 return errorCodeToError(EC);
286286 StringRef Arch = Arches.empty() ? StringRef() : Arches[File.index()];
287 auto CoverageReaderOrErr =
288 BinaryCoverageReader::create(CovMappingBufOrErr.get(), Arch);
289 if (Error E = CoverageReaderOrErr.takeError())
287 MemoryBufferRef CovMappingBufRef =
288 CovMappingBufOrErr.get()->getMemBufferRef();
289 auto CoverageReadersOrErr =
290 BinaryCoverageReader::create(CovMappingBufRef, Arch, Buffers);
291 if (Error E = CoverageReadersOrErr.takeError())
290292 return std::move(E);
291 Readers.push_back(std::move(CoverageReaderOrErr.get()));
293 for (auto &Reader : CoverageReadersOrErr.get())
294 Readers.push_back(std::move(Reader));
292295 Buffers.push_back(std::move(CovMappingBufOrErr.get()));
293296 }
294297 return load(Readers, *ProfileReader);
585585
586586 static const char *TestingFormatMagic = "llvmcovmtestdata";
587587
588 static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames,
589 StringRef &CoverageMapping,
590 uint8_t &BytesInAddress,
591 support::endianness &Endian) {
592 BytesInAddress = 8;
593 Endian = support::endianness::little;
588 Expected>
589 BinaryCoverageReader::createCoverageReaderFromBuffer(
590 StringRef Coverage, InstrProfSymtab &&ProfileNames, uint8_t BytesInAddress,
591 support::endianness Endian) {
592 std::unique_ptr Reader(new BinaryCoverageReader());
593 Reader->ProfileNames = std::move(ProfileNames);
594 if (BytesInAddress == 4 && Endian == support::endianness::little) {
595 if (Error E =
596 readCoverageMappingData(
597 Reader->ProfileNames, Coverage, Reader->MappingRecords,
598 Reader->Filenames))
599 return std::move(E);
600 } else if (BytesInAddress == 4 && Endian == support::endianness::big) {
601 if (Error E = readCoverageMappingData(
602 Reader->ProfileNames, Coverage, Reader->MappingRecords,
603 Reader->Filenames))
604 return std::move(E);
605 } else if (BytesInAddress == 8 && Endian == support::endianness::little) {
606 if (Error E =
607 readCoverageMappingData(
608 Reader->ProfileNames, Coverage, Reader->MappingRecords,
609 Reader->Filenames))
610 return std::move(E);
611 } else if (BytesInAddress == 8 && Endian == support::endianness::big) {
612 if (Error E = readCoverageMappingData(
613 Reader->ProfileNames, Coverage, Reader->MappingRecords,
614 Reader->Filenames))
615 return std::move(E);
616 } else
617 return make_error(coveragemap_error::malformed);
618 return Reader;
619 }
620
621 static Expected>
622 loadTestingFormat(StringRef Data) {
623 uint8_t BytesInAddress = 8;
624 support::endianness Endian = support::endianness::little;
594625
595626 Data = Data.substr(StringRef(TestingFormatMagic).size());
596627 if (Data.empty())
609640 Data = Data.substr(N);
610641 if (Data.size() < ProfileNamesSize)
611642 return make_error(coveragemap_error::malformed);
643 InstrProfSymtab ProfileNames;
612644 if (Error E = ProfileNames.create(Data.substr(0, ProfileNamesSize), Address))
613 return E;
614 CoverageMapping = Data.substr(ProfileNamesSize);
645 return std::move(E);
646 StringRef CoverageMapping = Data.substr(ProfileNamesSize);
615647 // Skip the padding bytes because coverage map data has an alignment of 8.
616648 if (CoverageMapping.empty())
617649 return make_error(coveragemap_error::truncated);
619651 if (CoverageMapping.size() < Pad)
620652 return make_error(coveragemap_error::malformed);
621653 CoverageMapping = CoverageMapping.substr(Pad);
622 return Error::success();
654 return BinaryCoverageReader::createCoverageReaderFromBuffer(
655 CoverageMapping, std::move(ProfileNames), BytesInAddress, Endian);
623656 }
624657
625658 static Expected lookupSection(ObjectFile &OF, StringRef Name) {
642675 return make_error(coveragemap_error::no_data_found);
643676 }
644677
645 static Error loadBinaryFormat(MemoryBufferRef ObjectBuffer,
646 InstrProfSymtab &ProfileNames,
647 StringRef &CoverageMapping,
648 uint8_t &BytesInAddress,
649 support::endianness &Endian, StringRef Arch) {
650 auto BinOrErr = createBinary(ObjectBuffer);
651 if (!BinOrErr)
652 return BinOrErr.takeError();
653 auto Bin = std::move(BinOrErr.get());
678 static Expected>
679 loadBinaryFormat(std::unique_ptr Bin, StringRef Arch) {
654680 std::unique_ptr OF;
655681 if (auto *Universal = dyn_cast(Bin.get())) {
656682 // If we have a universal binary, try to look up the object for the
670696 return make_error(coveragemap_error::malformed);
671697
672698 // The coverage uses native pointer sizes for the object it's written in.
673 BytesInAddress = OF->getBytesInAddress();
674 Endian = OF->isLittleEndian() ? support::endianness::little
675 : support::endianness::big;
699 uint8_t BytesInAddress = OF->getBytesInAddress();
700 support::endianness Endian = OF->isLittleEndian()
701 ? support::endianness::little
702 : support::endianness::big;
676703
677704 // Look for the sections that we are interested in.
678705 auto ObjFormat = OF->getTripleObjectFormat();
680707 lookupSection(*OF, getInstrProfSectionName(IPSK_name, ObjFormat,
681708 /*AddSegmentInfo=*/false));
682709 if (auto E = NamesSection.takeError())
683 return E;
710 return std::move(E);
684711 auto CoverageSection =
685712 lookupSection(*OF, getInstrProfSectionName(IPSK_covmap, ObjFormat,
686713 /*AddSegmentInfo=*/false));
687714 if (auto E = CoverageSection.takeError())
688 return E;
715 return std::move(E);
689716
690717 // Get the contents of the given sections.
691 if (Expected E = CoverageSection->getContents())
692 CoverageMapping = *E;
693 else
694 return E.takeError();
695
718 auto CoverageMappingOrErr = CoverageSection->getContents();
719 if (!CoverageMappingOrErr)
720 return CoverageMappingOrErr.takeError();
721
722 InstrProfSymtab ProfileNames;
696723 if (Error E = ProfileNames.create(*NamesSection))
697 return E;
698
699 return Error::success();
700 }
701
702 Expected>
703 BinaryCoverageReader::create(std::unique_ptr &ObjectBuffer,
704 StringRef Arch) {
705 std::unique_ptr Reader(new BinaryCoverageReader());
706
707 StringRef Coverage;
708 uint8_t BytesInAddress;
709 support::endianness Endian;
710 Error E = Error::success();
711 consumeError(std::move(E));
712 if (ObjectBuffer->getBuffer().startswith(TestingFormatMagic))
724 return std::move(E);
725
726 return BinaryCoverageReader::createCoverageReaderFromBuffer(
727 CoverageMappingOrErr.get(), std::move(ProfileNames), BytesInAddress,
728 Endian);
729 }
730
731 Expected>>
732 BinaryCoverageReader::create(
733 MemoryBufferRef ObjectBuffer, StringRef Arch,
734 SmallVectorImpl> &ObjectFileBuffers) {
735 std::vector> Readers;
736
737 if (ObjectBuffer.getBuffer().startswith(TestingFormatMagic)) {
713738 // This is a special format used for testing.
714 E = loadTestingFormat(ObjectBuffer->getBuffer(), Reader->ProfileNames,
715 Coverage, BytesInAddress, Endian);
716 else
717 E = loadBinaryFormat(ObjectBuffer->getMemBufferRef(), Reader->ProfileNames,
718 Coverage, BytesInAddress, Endian, Arch);
719 if (E)
720 return std::move(E);
721
722 if (BytesInAddress == 4 && Endian == support::endianness::little)
723 E = readCoverageMappingData(
724 Reader->ProfileNames, Coverage, Reader->MappingRecords,
725 Reader->Filenames);
726 else if (BytesInAddress == 4 && Endian == support::endianness::big)
727 E = readCoverageMappingData(
728 Reader->ProfileNames, Coverage, Reader->MappingRecords,
729 Reader->Filenames);
730 else if (BytesInAddress == 8 && Endian == support::endianness::little)
731 E = readCoverageMappingData(
732 Reader->ProfileNames, Coverage, Reader->MappingRecords,
733 Reader->Filenames);
734 else if (BytesInAddress == 8 && Endian == support::endianness::big)
735 E = readCoverageMappingData(
736 Reader->ProfileNames, Coverage, Reader->MappingRecords,
737 Reader->Filenames);
738 else
739 return make_error(coveragemap_error::malformed);
740 if (E)
741 return std::move(E);
742 return std::move(Reader);
739 auto ReaderOrErr = loadTestingFormat(ObjectBuffer.getBuffer());
740 if (!ReaderOrErr)
741 return ReaderOrErr.takeError();
742 Readers.push_back(std::move(ReaderOrErr.get()));
743 return Readers;
744 }
745
746 auto BinOrErr = createBinary(ObjectBuffer);
747 if (!BinOrErr)
748 return BinOrErr.takeError();
749 std::unique_ptr Bin = std::move(BinOrErr.get());
750
751 // MachO universal binaries which contain archives need to be treated as
752 // archives, not as regular binaries.
753 if (auto *Universal = dyn_cast(Bin.get())) {
754 for (auto &ObjForArch : Universal->objects()) {
755 // Skip slices within the universal binary which target the wrong arch.
756 std::string ObjArch = ObjForArch.getArchFlagName();
757 if (Arch != ObjArch)
758 continue;
759
760 auto ArchiveOrErr = ObjForArch.getAsArchive();
761 if (!ArchiveOrErr) {
762 // If this is not an archive, try treating it as a regular object.
763 consumeError(ArchiveOrErr.takeError());
764 break;
765 }
766
767 return BinaryCoverageReader::create(
768 ArchiveOrErr.get()->getMemoryBufferRef(), Arch, ObjectFileBuffers);
769 }
770 }
771
772 // Load coverage out of archive members.
773 if (auto *Ar = dyn_cast(Bin.get())) {
774 Error Err = Error::success();
775 for (auto &Child : Ar->children(Err)) {
776 Expected ChildBufOrErr = Child.getMemoryBufferRef();
777 if (!ChildBufOrErr)
778 return ChildBufOrErr.takeError();
779
780 auto ChildReadersOrErr = BinaryCoverageReader::create(
781 ChildBufOrErr.get(), Arch, ObjectFileBuffers);
782 if (!ChildReadersOrErr)
783 return ChildReadersOrErr.takeError();
784 for (auto &Reader : ChildReadersOrErr.get())
785 Readers.push_back(std::move(Reader));
786 }
787 if (Err)
788 return std::move(Err);
789
790 // Thin archives reference object files outside of the archive file, i.e.
791 // files which reside in memory not owned by the caller. Transfer ownership
792 // to the caller.
793 if (Ar->isThin())
794 for (auto &Buffer : Ar->takeThinBuffers())
795 ObjectFileBuffers.push_back(std::move(Buffer));
796
797 return Readers;
798 }
799
800 auto ReaderOrErr = loadBinaryFormat(std::move(Bin), Arch);
801 if (!ReaderOrErr)
802 return ReaderOrErr.takeError();
803 Readers.push_back(std::move(ReaderOrErr.get()));
804 return Readers;
743805 }
744806
745807 Error BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) {
0 The coverage reader should be able to handle archives, and archives embedded within
1 MachO universal binaries.
2
3 ---
4 Steps to re-generate these files on macOS:
5
6 clang -fprofile-instr-generate -fcoverage-mapping -c obj1.c -o obj1_32.o -arch i386
7 clang -fprofile-instr-generate -fcoverage-mapping -c obj2.c -o obj2_32.o -arch i386
8 clang -fprofile-instr-generate -fcoverage-mapping -c obj1.c -o obj1_64.o -arch x86_64
9 clang -fprofile-instr-generate -fcoverage-mapping -c obj2.c -o obj2_64.o -arch x86_64
10 ar -q archive_32 obj1_32.o obj2_32.o
11 ar -q archive_64 obj1_64.o obj2_64.o
12 lipo -output universal_bin_wrapping_archives -create archive_32 archive_64
13 ---
14
15 RUN: llvm-profdata merge %S/Inputs/universal_bin_wrapping_archives/universal_bin_wrapping_archives.proftext -o %t.profdata
16
17 RUN: llvm-cov show %S/Inputs/universal_bin_wrapping_archives/universal_bin_wrapping_archives \
18 RUN: -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs/universal_bin_wrapping_archives %s -arch i386 \
19 RUN: | FileCheck %s --check-prefix=SHOW_ARCHIVE
20
21 RUN: llvm-cov show %S/Inputs/universal_bin_wrapping_archives/universal_bin_wrapping_archives \
22 RUN: -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs/universal_bin_wrapping_archives %s -arch x86_64 \
23 RUN: | FileCheck %s --check-prefix=SHOW_ARCHIVE
24
25 SHOW_ARCHIVE: {{.*}}obj1.c:
26 SHOW_ARCHIVE-NEXT: 1| 100|void f1() {}
27 SHOW_ARCHIVE: {{.*}}obj2.c:
28 SHOW_ARCHIVE-NEXT: 1| 100|void f2() {}
29
30 RUN: llvm-cov report %S/Inputs/universal_bin_wrapping_archives/universal_bin_wrapping_archives \
31 RUN: -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs/universal_bin_wrapping_archives %s -arch i386 \
32 RUN: | FileCheck %s --check-prefix=REPORT_ARCHIVE
33
34 RUN: llvm-cov report %S/Inputs/universal_bin_wrapping_archives/universal_bin_wrapping_archives \
35 RUN: -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs/universal_bin_wrapping_archives %s -arch x86_64 \
36 RUN: | FileCheck %s --check-prefix=REPORT_ARCHIVE
37
38 RUN: llvm-ar rcT %t.thin32.a %S/Inputs/universal_bin_wrapping_archives/obj1_32.o %S/Inputs/universal_bin_wrapping_archives/obj2_32.o
39 RUN: llvm-cov report %t.thin32.a -instr-profile %t.profdata | FileCheck %s --check-prefix=REPORT_ARCHIVE
40
41 REPORT_ARCHIVE: obj1.c 1 0 100.00% 1 0 100.00% 1 0 100.00%
42 REPORT_ARCHIVE: obj2.c 1 0 100.00% 1 0 100.00% 1 0 100.00%
43 REPORT_ARCHIVE: TOTAL 2 0 100.00% 2 0 100.00% 2 0 100.00%