diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h index bf0dffc9653cf1..2f285bf54a6a93 100644 --- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -55,7 +55,8 @@ enum class coveragemap_error { unsupported_version, truncated, malformed, - decompression_failed + decompression_failed, + invalid_or_missing_arch_specifier }; const std::error_category &coveragemap_category(); diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index ec840a3f628e2e..87dab212bdcd42 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -816,6 +816,8 @@ static std::string getCoverageMapErrString(coveragemap_error Err) { return "Malformed coverage data"; case coveragemap_error::decompression_failed: return "Failed to decompress coverage data (zlib)"; + case coveragemap_error::invalid_or_missing_arch_specifier: + return "`-arch` specifier is invalid or missing for universal binary"; } llvm_unreachable("A value of coveragemap_error has no message."); } diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp index b75738bc360ce3..4936638c61cc9d 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -950,6 +950,19 @@ loadBinaryFormat(std::unique_ptr Bin, StringRef Arch) { BytesInAddress, Endian); } +/// Determine whether \p Arch is invalid or empty, given \p Bin. +static bool isArchSpecifierInvalidOrMissing(Binary *Bin, StringRef Arch) { + // If we have a universal binary and Arch doesn't identify any of its slices, + // it's user error. + if (auto *Universal = dyn_cast(Bin)) { + for (auto &ObjForArch : Universal->objects()) + if (Arch == ObjForArch.getArchFlagName()) + return false; + return true; + } + return false; +} + Expected>> BinaryCoverageReader::create( MemoryBufferRef ObjectBuffer, StringRef Arch, @@ -970,6 +983,10 @@ BinaryCoverageReader::create( return BinOrErr.takeError(); std::unique_ptr Bin = std::move(BinOrErr.get()); + if (isArchSpecifierInvalidOrMissing(Bin.get(), Arch)) + return make_error( + coveragemap_error::invalid_or_missing_arch_specifier); + // MachO universal binaries which contain archives need to be treated as // archives, not as regular binaries. if (auto *Universal = dyn_cast(Bin.get())) { diff --git a/llvm/test/tools/llvm-cov/universal-binary.c b/llvm/test/tools/llvm-cov/universal-binary.c index 635cd32146eba7..f8d5346bc57949 100644 --- a/llvm/test/tools/llvm-cov/universal-binary.c +++ b/llvm/test/tools/llvm-cov/universal-binary.c @@ -10,8 +10,9 @@ int main(int argc, const char *argv[]) {} // COMBINED: showTemplateInstantiations.cpp // COMBINED-NEXT: universal-binary.c +// RUN: not llvm-cov show %S/Inputs/universal-binary -instr-profile %t.profdata -path-equivalence=/tmp,%S %s 2>&1 | FileCheck --check-prefix=WRONG-ARCH %s // RUN: not llvm-cov show %S/Inputs/universal-binary -instr-profile %t.profdata -path-equivalence=/tmp,%S %s -arch i386 2>&1 | FileCheck --check-prefix=WRONG-ARCH %s -// WRONG-ARCH: Failed to load coverage +// WRONG-ARCH: Failed to load coverage: `-arch` specifier is invalid or missing for universal binary // RUN: not llvm-cov show %S/Inputs/universal-binary -instr-profile %t.profdata -path-equivalence=/tmp,%S %s -arch definitly_a_made_up_architecture 2>&1 | FileCheck --check-prefix=MADE-UP-ARCH %s // MADE-UP-ARCH: Unknown architecture: definitly_a_made_up_architecture