[gcov] Emit GCOV_TAG_OBJECT_SUMMARY/GCOV_TAG_PROGRAM_SUMMARY correctly and fix llvm-cov's decoding of runcount

gcov 9 (r264462) started to use GCOV_TAG_OBJECT_SUMMARY. Before,
GCOV_TAG_PROGRAM_SUMMARY was used.
libclang_rt.profile should emit just one tag according to the version.

Another bug introduced by rL194499 is that the wrong runcount field was
selected.

Fix the two bugs so that gcov can correctly decode "Runs:" from
libclang_rt.profile produced .gcda files, and llvm-cov gcov can
correctly decode "Runs:" from libgcov produced .gcda files.
This commit is contained in:
Fangrui Song 2020-05-11 18:43:15 -07:00
parent 2e9f1153c5
commit 013f06703e
21 changed files with 54 additions and 48 deletions

View File

@ -66,6 +66,14 @@ typedef unsigned long long uint64_t;
/* #define DEBUG_GCDAPROFILING */
enum {
GCOV_TAG_FUNCTION = 0x01000000,
GCOV_TAG_COUNTER_ARCS = 0x01a10000,
// GCOV_TAG_OBJECT_SUMMARY superseded GCOV_TAG_PROGRAM_SUMMARY in GCC 9.
GCOV_TAG_OBJECT_SUMMARY = 0xa1000000,
GCOV_TAG_PROGRAM_SUMMARY = 0xa3000000,
};
/*
* --- GCOV file format I/O primitives ---
*/
@ -538,8 +546,6 @@ void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) {
COMPILER_RT_VISIBILITY
void llvm_gcda_summary_info() {
const uint32_t obj_summary_len = 9; /* Length for gcov compatibility. */
uint32_t i;
uint32_t runs = 1;
static uint32_t run_counted = 0; // We only want to increase the run count once.
uint32_t val = 0;
@ -551,42 +557,43 @@ void llvm_gcda_summary_info() {
if (val != (uint32_t)-1) {
/* There are counters present in the file. Merge them. */
if (val != 0xa1000000) {
fprintf(stderr, "profiling: %s: cannot merge previous run count: "
"corrupt object tag (0x%08x)\n",
if (val != (gcov_version >= 90 ? GCOV_TAG_OBJECT_SUMMARY
: GCOV_TAG_PROGRAM_SUMMARY)) {
fprintf(stderr,
"profiling: %s: cannot merge previous run count: "
"corrupt object tag (0x%08x)\n",
filename, val);
return;
}
val = read_32bit_value(); /* length */
if (val != obj_summary_len) {
fprintf(stderr, "profiling: %s: cannot merge previous run count: "
"mismatched object length (%d)\n",
filename, val);
return;
}
read_32bit_value(); /* checksum, unused */
read_32bit_value(); /* num, unused */
read_32bit_value();
if (gcov_version < 90)
read_32bit_value();
uint32_t prev_runs = read_32bit_value();
for (uint32_t i = gcov_version < 90 ? 3 : 2; i < val; ++i)
read_32bit_value();
/* Add previous run count to new counter, if not already counted before. */
runs = run_counted ? prev_runs : prev_runs + 1;
}
cur_pos = save_cur_pos;
/* Object summary tag */
write_bytes("\0\0\0\xa1", 4);
write_32bit_value(obj_summary_len);
write_32bit_value(0); /* checksum, unused */
write_32bit_value(0); /* num, unused */
write_32bit_value(runs);
for (i = 3; i < obj_summary_len; ++i)
if (gcov_version >= 90) {
write_32bit_value(GCOV_TAG_OBJECT_SUMMARY);
write_32bit_value(2);
write_32bit_value(runs);
write_32bit_value(0); // sum_max
} else {
// Before gcov 4.8 (r190952), GCOV_TAG_SUMMARY_LENGTH was 9. r190952 set
// GCOV_TAG_SUMMARY_LENGTH to 22. We simply use the smallest length which
// can make gcov read "Runs:".
write_32bit_value(GCOV_TAG_PROGRAM_SUMMARY);
write_32bit_value(3);
write_32bit_value(0);
/* Program summary tag */
write_bytes("\0\0\0\xa3", 4); /* tag indicates 1 program */
write_32bit_value(0); /* 0 length */
write_32bit_value(0);
write_32bit_value(runs);
}
run_counted = 1;

View File

@ -97,10 +97,12 @@ bool GCOVFile::readGCDA(GCOVBuffer &buf) {
return false;
uint32_t cursor = buf.getCursor();
if (tag == GCOV_TAG_OBJECT_SUMMARY) {
buf.readInt(RunCount);
buf.readInt(dummy);
} else if (tag == GCOV_TAG_PROGRAM_SUMMARY) {
buf.readInt(dummy);
buf.readInt(dummy);
buf.readInt(RunCount);
} else if (tag == GCOV_TAG_PROGRAM_SUMMARY) {
++ProgramCount;
} else if (tag == GCOV_TAG_FUNCTION) {
if (length == 0) // Placeholder

View File

@ -1,7 +1,7 @@
-: 0:Source:test.cpp
-: 0:Graph:test.gcno
-: 0:Data:test.gcda
-: 0:Runs:2
-: 0:Runs:0
-: 0:Programs:1
-: 1:#include "test.h"
-: 2:#include <cstdlib>

View File

@ -1,7 +1,7 @@
-: 0:Source:./test.h
-: 0:Graph:test.gcno
-: 0:Data:test.gcda
-: 0:Runs:2
-: 0:Runs:0
-: 0:Programs:1
4: 1:struct A {
2: 1-block 0

View File

@ -1,7 +1,7 @@
-: 0:Source:test.cpp
-: 0:Graph:test.gcno
-: 0:Data:test.gcda
-: 0:Runs:2
-: 0:Runs:0
-: 0:Programs:1
-: 1:#include "test.h"
-: 2:#include <cstdlib>

View File

@ -1,7 +1,7 @@
-: 0:Source:./test.h
-: 0:Graph:test.gcno
-: 0:Data:test.gcda
-: 0:Runs:2
-: 0:Runs:0
-: 0:Programs:1
function _ZN1AC1Ev called 2 returned 100% blocks executed 100%
function _ZN1AC2Ev called 2 returned 100% blocks executed 100%

View File

@ -1,7 +1,7 @@
-: 0:Source:test.cpp
-: 0:Graph:test.gcno
-: 0:Data:test.gcda
-: 0:Runs:2
-: 0:Runs:0
-: 0:Programs:1
-: 1:#include "test.h"
-: 2:#include <cstdlib>

View File

@ -1,7 +1,7 @@
-: 0:Source:./test.h
-: 0:Graph:test.gcno
-: 0:Data:test.gcda
-: 0:Runs:2
-: 0:Runs:0
-: 0:Programs:1
function _ZN1AC1Ev called 2 returned 100% blocks executed 100%
function _ZN1AC2Ev called 2 returned 100% blocks executed 100%

View File

@ -1,7 +1,7 @@
-: 0:Source:test.cpp
-: 0:Graph:test.gcno
-: 0:Data:test.gcda
-: 0:Runs:2
-: 0:Runs:0
-: 0:Programs:1
-: 1:#include "test.h"
-: 2:#include <cstdlib>

View File

@ -1,7 +1,7 @@
-: 0:Source:./test.h
-: 0:Graph:test.gcno
-: 0:Data:test.gcda
-: 0:Runs:2
-: 0:Runs:0
-: 0:Programs:1
function _ZN1AC1Ev called 2 returned 100% blocks executed 100%
function _ZN1AC2Ev called 2 returned 100% blocks executed 100%

View File

@ -1,7 +1,7 @@
-: 0:Source:srcdir/./nested_dir/../test.cpp
-: 0:Graph:test_paths.gcno
-: 0:Data:test_paths.gcda
-: 0:Runs:3
-: 0:Runs:0
-: 0:Programs:1
-: 1:/*EOF*/
-: 2:/*EOF*/

View File

@ -1,6 +1,6 @@
-: 0:Source:srcdir/./nested_dir/../test.h
-: 0:Graph:test_paths.gcno
-: 0:Data:test_paths.gcda
-: 0:Runs:3
-: 0:Runs:0
-: 0:Programs:1
6: 1:/*EOF*/

View File

@ -1,7 +1,7 @@
-: 0:Source:test.cpp
-: 0:Graph:test.gcno
-: 0:Data:test.gcda
-: 0:Runs:2
-: 0:Runs:0
-: 0:Programs:1
-: 1:#include "test.h"
-: 2:#include <cstdlib>

View File

@ -1,7 +1,7 @@
-: 0:Source:./test.h
-: 0:Graph:test.gcno
-: 0:Data:test.gcda
-: 0:Runs:2
-: 0:Runs:0
-: 0:Programs:1
4: 1:struct A {
-: 2: virtual void B();

View File

@ -1,7 +1,7 @@
-: 0:Source:test.cpp
-: 0:Graph:objdir/test.gcno
-: 0:Data:objdir/test.gcda
-: 0:Runs:2
-: 0:Runs:0
-: 0:Programs:1
-: 1:#include "test.h"
-: 2:#include <cstdlib>

View File

@ -1,7 +1,7 @@
-: 0:Source:./test.h
-: 0:Graph:objdir/test.gcno
-: 0:Data:objdir/test.gcda
-: 0:Runs:2
-: 0:Runs:0
-: 0:Programs:1
4: 1:struct A {
-: 2: virtual void B();

View File

@ -1,7 +1,7 @@
-: 0:Source:srcdir/./nested_dir/../test.cpp
-: 0:Graph:test_paths.gcno
-: 0:Data:test_paths.gcda
-: 0:Runs:3
-: 0:Runs:0
-: 0:Programs:1
-: 1:#include "test.h"
-: 2:#include <cstdlib>

View File

@ -1,7 +1,7 @@
-: 0:Source:srcdir/./nested_dir/../test.h
-: 0:Graph:test_paths.gcno
-: 0:Data:test_paths.gcda
-: 0:Runs:3
-: 0:Runs:0
-: 0:Programs:1
6: 1:struct A {
-: 2: virtual void B();

View File

@ -27,11 +27,10 @@ int main() { // GCOV: #####: [[@LINE]]
// RUN: FileCheck --input-file=%t/gcov-4.7.c.gcov --check-prefix=HEADER %s
// RUN: FileCheck --input-file=%t/gcov-4.7.c.gcov --check-prefix=GCOV %s
/// FIXME Runs:1
// HEADER: {{^}} -: 0:Source:gcov-4.7.c
// HEADER-NEXT: -: 0:Graph:gcov-4.7.gcno
// HEADER-NEXT: -: 0:Data:gcov-4.7.gcda
// HEADER-NEXT: -: 0:Runs:0
// HEADER-NEXT: -: 0:Runs:1{{$}}
// HEADER-NEXT: -: 0:Programs:1
// HEADER-NEXT: -: 1:/// Test that llvm-cov

View File

@ -27,11 +27,10 @@ int main() { // GCOV: 1: [[@LINE]]:int
// RUN: FileCheck --input-file=%t/gcov-8.c.gcov --check-prefix=HEADER %s
// RUN: FileCheck --input-file=%t/gcov-8.c.gcov --check-prefix=GCOV %s
/// FIXME Runs:1
// HEADER: {{^}} -: 0:Source:gcov-8.c
// HEADER-NEXT: -: 0:Graph:gcov-8.gcno
// HEADER-NEXT: -: 0:Data:gcov-8.gcda
// HEADER-NEXT: -: 0:Runs:0
// HEADER-NEXT: -: 0:Runs:1{{$}}
// HEADER-NEXT: -: 0:Programs:1
// HEADER-NEXT: -: 1:/// Test that llvm-cov

View File

@ -27,11 +27,10 @@ int main() { // GCOV: 1: [[@LINE]]:int
// RUN: FileCheck --input-file=%t/gcov-9.c.gcov --check-prefix=HEADER %s
// RUN: FileCheck --input-file=%t/gcov-9.c.gcov --check-prefix=GCOV %s
/// FIXME Runs:1
// HEADER: {{^}} -: 0:Source:gcov-9.c
// HEADER-NEXT: -: 0:Graph:gcov-9.gcno
// HEADER-NEXT: -: 0:Data:gcov-9.gcda
// HEADER-NEXT: -: 0:Runs:16777216
// HEADER-NEXT: -: 0:Runs:1{{$}}
// HEADER-NEXT: -: 1:/// Test that llvm-cov
// XFAIL: host-byteorder-big-endian