diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformWindows.c b/compiler-rt/lib/profile/InstrProfilingPlatformWindows.c --- a/compiler-rt/lib/profile/InstrProfilingPlatformWindows.c +++ b/compiler-rt/lib/profile/InstrProfilingPlatformWindows.c @@ -16,9 +16,9 @@ #pragma comment(linker, "/MERGE:.lprfd=.data") #pragma comment(linker, "/MERGE:.lprfv=.data") #pragma comment(linker, "/MERGE:.lprfnd=.data") -/* Merge read-only sections into .rdata. */ -#pragma comment(linker, "/MERGE:.lprfn=.rdata") -#pragma comment(linker, "/MERGE:.lcovmap=.rdata") +/* Do *NOT* merge .lprfn and .lcovmap into .rdata. llvm-cov must be able to find + * after the fact. + */ /* Allocate read-only section bounds. */ #pragma section(".lprfn$A", read) diff --git a/compiler-rt/test/profile/instrprof-merging.cpp b/compiler-rt/test/profile/instrprof-merging.cpp --- a/compiler-rt/test/profile/instrprof-merging.cpp +++ b/compiler-rt/test/profile/instrprof-merging.cpp @@ -21,9 +21,6 @@ // and prefer it over others.) When only limited coverage information is // available (just from one binary), don't try to guess any region counts. -// FIXME: Fails with: "Failed to load coverage: No coverage data found" -// XFAIL: windows - struct A { A() {} // V1: [[@LINE]]{{ *}}|{{ *}}1 // V1-ONLY: [[@LINE+1]]{{ *}}|{{ *}}| diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp --- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -22,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" @@ -350,6 +351,13 @@ if (auto EC = Section.getContents(Data)) return errorCodeToError(EC); 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(Obj) && !Obj->isRelocatableObject()) + Data = Data.drop_front(1); + return Error::success(); } @@ -616,11 +624,20 @@ } static Expected 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(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(coveragemap_error::no_data_found);