diff --git a/llvm/lib/ProfileData/GCOV.cpp b/llvm/lib/ProfileData/GCOV.cpp index 35d40db11716..71ea44a1a722 100644 --- a/llvm/lib/ProfileData/GCOV.cpp +++ b/llvm/lib/ProfileData/GCOV.cpp @@ -175,16 +175,24 @@ bool GCOVFile::readGCDA(GCOVBuffer &buf) { if (tag == GCOV_TAG_OBJECT_SUMMARY) { buf.readInt(RunCount); buf.readInt(dummy); + // clang<11 uses a fake 4.2 format which sets length to 9. + if (length == 9) + buf.readInt(RunCount); } else if (tag == GCOV_TAG_PROGRAM_SUMMARY) { - buf.readInt(dummy); - buf.readInt(dummy); - buf.readInt(RunCount); + // clang<11 uses a fake 4.2 format which sets length to 0. + if (length > 0) { + buf.readInt(dummy); + buf.readInt(dummy); + buf.readInt(RunCount); + } ++ProgramCount; } else if (tag == GCOV_TAG_FUNCTION) { if (length == 0) // Placeholder continue; // As of GCC 10, GCOV_TAG_FUNCTION_LENGTH has never been larger than 3. - if ((length != 2 && length != 3) || !buf.readInt(ident)) + // However, clang<11 uses a fake 4.2 format which may set length larger + // than 3. + if (length < 2 || !buf.readInt(ident)) return false; auto It = IdentToFunction.find(ident); uint32_t linenoChecksum, cfgChecksum = 0; diff --git a/llvm/test/tools/llvm-cov/Inputs/gcov-fake-4.2.gcda b/llvm/test/tools/llvm-cov/Inputs/gcov-fake-4.2.gcda new file mode 100644 index 000000000000..613e3a85c026 Binary files /dev/null and b/llvm/test/tools/llvm-cov/Inputs/gcov-fake-4.2.gcda differ diff --git a/llvm/test/tools/llvm-cov/Inputs/gcov-fake-4.2.gcno b/llvm/test/tools/llvm-cov/Inputs/gcov-fake-4.2.gcno new file mode 100644 index 000000000000..24f1c82476b2 Binary files /dev/null and b/llvm/test/tools/llvm-cov/Inputs/gcov-fake-4.2.gcno differ diff --git a/llvm/test/tools/llvm-cov/gcov-fake-4.2.c b/llvm/test/tools/llvm-cov/gcov-fake-4.2.c new file mode 100644 index 000000000000..7e8eb2f2a5ff --- /dev/null +++ b/llvm/test/tools/llvm-cov/gcov-fake-4.2.c @@ -0,0 +1,39 @@ +/// Test that llvm-cov supports a fake gcov 4.2 format used before clang 11. + +// RUN: rm -rf %t && mkdir %t && cd %t +// RUN: llvm-cov gcov test. --gcno=%S/Inputs/gcov-fake-4.2.gcno --gcda=%S/Inputs/gcov-fake-4.2.gcda | FileCheck %s +// RUN: FileCheck %s --check-prefix=C < test.cpp.gcov +// RUN: FileCheck %s --check-prefix=H < test.h.gcov + +// CHECK: File 'test.cpp' +// CHECK-NEXT: Lines executed:84.21% of 38 +// CHECK-NEXT: Creating 'test.cpp.gcov' +// CHECK-EMPTY: +// CHECK-NEXT: File './test.h' +// CHECK-NEXT: Lines executed:100.00% of 1 +// CHECK-NEXT: Creating 'test.h.gcov' +// CHECK-EMPTY: + +// C: -: 0:Source:test.cpp +// C-NEXT: -: 0:Graph:{{.*}}gcov-fake-4.2.gcno +// C-NEXT: -: 0:Data:{{.*}}gcov-fake-4.2.gcda +/// `Runs` is stored in GCOV_TAG_OBJECT_SUMMARY with a length of 9. +// C-NEXT: -: 0:Runs:2 +// C-NEXT: -: 0:Programs:1 +// C-NEXT: -: 1: +// C-NEXT: -: 2: +// C-NEXT: -: 3: +// C-NEXT: -: 4: +// C-NEXT: -: 5: +// C-NEXT: -: 6: +// C-NEXT: -: 7: +// C-NEXT: -: 8: +// C-NEXT: -: 9: +// C-NEXT:8589934592: 10: + +// H: -: 0:Source:./test.h +// H-NEXT: -: 0:Graph:{{.*}}gcov-fake-4.2.gcno +// H-NEXT: -: 0:Data:{{.*}}gcov-fake-4.2.gcda +// H-NEXT: -: 0:Runs:2 +// H-NEXT: -: 0:Programs:1 +// H-NEXT: 4: 1: