Index: lib/profile/GCDAProfiling.c =================================================================== --- lib/profile/GCDAProfiling.c +++ lib/profile/GCDAProfiling.c @@ -96,8 +96,11 @@ struct writeout_fn_node *next; }; -static struct writeout_fn_node *writeout_fn_head = NULL; -static struct writeout_fn_node *writeout_fn_tail = NULL; +// This is the writeout node specific to a given dynamic object. +static struct writeout_fn_node *writeout_fn_this = NULL; +// This is the list shared between all dynamic objects. +struct writeout_fn_node *writeout_fn_head = NULL; +struct writeout_fn_node *writeout_fn_tail = NULL; /* * A list of flush functions that our __gcov_flush() function should call. @@ -109,8 +112,11 @@ struct flush_fn_node *next; }; -static struct flush_fn_node *flush_fn_head = NULL; -static struct flush_fn_node *flush_fn_tail = NULL; +// This is the flush node specific to a given dynamic object. +static struct flush_fn_node *flush_fn_this = NULL; +// This is the list shared between all dynamic objects. +struct flush_fn_node *flush_fn_head = NULL; +struct flush_fn_node *flush_fn_tail = NULL; static void resize_write_buffer(uint64_t size) { if (!new_file) return; @@ -403,6 +409,7 @@ 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; uint64_t save_cur_pos = cur_pos; @@ -429,7 +436,9 @@ read_32bit_value(); /* checksum, unused */ read_32bit_value(); /* num, unused */ - runs += read_32bit_value(); /* Add previous run count to new counter. */ + uint32_t prev_runs = 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; @@ -447,6 +456,8 @@ write_bytes("\0\0\0\xa3", 4); /* tag indicates 1 program */ write_32bit_value(0); /* 0 length */ + run_counted = 1; + #ifdef DEBUG_GCDAPROFILING fprintf(stderr, "llvmgcda: %u runs\n", runs); #endif @@ -480,15 +491,15 @@ COMPILER_RT_VISIBILITY void llvm_register_writeout_function(writeout_fn fn) { - struct writeout_fn_node *new_node = malloc(sizeof(struct writeout_fn_node)); - new_node->fn = fn; - new_node->next = NULL; + writeout_fn_this = malloc(sizeof(struct writeout_fn_node)); + writeout_fn_this->fn = fn; + writeout_fn_this->next = NULL; if (!writeout_fn_head) { - writeout_fn_head = writeout_fn_tail = new_node; + writeout_fn_head = writeout_fn_tail = writeout_fn_this; } else { - writeout_fn_tail->next = new_node; - writeout_fn_tail = new_node; + writeout_fn_tail->next = writeout_fn_this; + writeout_fn_tail = writeout_fn_this; } } @@ -504,26 +515,35 @@ COMPILER_RT_VISIBILITY void llvm_delete_writeout_function_list(void) { - while (writeout_fn_head) { - struct writeout_fn_node *node = writeout_fn_head; - writeout_fn_head = writeout_fn_head->next; - free(node); + struct writeout_fn_node *prev = NULL; + + if (writeout_fn_this == writeout_fn_head) { + writeout_fn_head = writeout_fn_this->next; + } else { + prev = writeout_fn_head; + while (prev->next != writeout_fn_this); + prev->next = writeout_fn_this->next; + } + + if (writeout_fn_this == writeout_fn_tail) { + writeout_fn_tail = prev; } - - writeout_fn_head = writeout_fn_tail = NULL; + + free(writeout_fn_this); + writeout_fn_this = NULL; } COMPILER_RT_VISIBILITY void llvm_register_flush_function(flush_fn fn) { - struct flush_fn_node *new_node = malloc(sizeof(struct flush_fn_node)); - new_node->fn = fn; - new_node->next = NULL; + flush_fn_this = malloc(sizeof(struct flush_fn_node)); + flush_fn_this->fn = fn; + flush_fn_this->next = NULL; if (!flush_fn_head) { - flush_fn_head = flush_fn_tail = new_node; + flush_fn_head = flush_fn_tail = flush_fn_this; } else { - flush_fn_tail->next = new_node; - flush_fn_tail = new_node; + flush_fn_tail->next = flush_fn_this; + flush_fn_tail = flush_fn_this; } } @@ -539,13 +559,22 @@ COMPILER_RT_VISIBILITY void llvm_delete_flush_function_list(void) { - while (flush_fn_head) { - struct flush_fn_node *node = flush_fn_head; - flush_fn_head = flush_fn_head->next; - free(node); + struct flush_fn_node *prev = NULL; + + if (flush_fn_this == flush_fn_head) { + flush_fn_head = flush_fn_this->next; + } else { + prev = flush_fn_head; + while (prev->next != flush_fn_this); + prev->next = flush_fn_this->next; + } + + if (flush_fn_this == flush_fn_tail) { + flush_fn_tail = prev; } - flush_fn_head = flush_fn_tail = NULL; + free(flush_fn_this); + flush_fn_this = NULL; } COMPILER_RT_VISIBILITY Index: test/profile/Inputs/instrprof-dlopen-dlclose-main.c =================================================================== --- test/profile/Inputs/instrprof-dlopen-dlclose-main.c +++ test/profile/Inputs/instrprof-dlopen-dlclose-main.c @@ -10,17 +10,41 @@ return EXIT_FAILURE; } + void (*func)(void) = (void (*)(void))dlsym(f1_handle, "func"); + if (func == NULL) { + fprintf(stderr, "unable to lookup symbol 'func': %s\n", dlerror()); + return EXIT_FAILURE; + } + void *f2_handle = dlopen("func2.shared", RTLD_LAZY | RTLD_GLOBAL); if (f2_handle == NULL) { fprintf(stderr, "unable to open 'func2.shared': %s\n", dlerror()); return EXIT_FAILURE; } + void (*func2)(void) = (void (*)(void))dlsym(f2_handle, "func2"); + if (func2 == NULL) { + fprintf(stderr, "unable to lookup symbol 'func2': %s\n", dlerror()); + return EXIT_FAILURE; + } + func2(); + if (dlclose(f2_handle) != 0) { fprintf(stderr, "unable to close 'func2.shared': %s\n", dlerror()); return EXIT_FAILURE; } + func(); + + int g1 = 0; + int g2 = 0; + int n = 10; + + if (n % 5 == 0) + g1++; + else + g2++; + return EXIT_SUCCESS; } Index: test/profile/Inputs/instrprof-dlopen-dlclose-main.c.gcov =================================================================== --- test/profile/Inputs/instrprof-dlopen-dlclose-main.c.gcov +++ test/profile/Inputs/instrprof-dlopen-dlclose-main.c.gcov @@ -0,0 +1,55 @@ +// CHECK: -: 0:Source:{{.*}}Inputs/instrprof-dlopen-dlclose-main.c +// CHECK-NEXT: -: 0:Graph:instrprof-dlopen-dlclose-main.gcno +// CHECK-NEXT: -: 0:Data:instrprof-dlopen-dlclose-main.gcda +// CHECK-NEXT: -: 0:Runs:1 +// CHECK-NEXT: -: 0:Programs:1 +// CHECK-NEXT: -: 1:#include +// CHECK-NEXT: -: 2:#include +// CHECK-NEXT: -: 3:#include +// CHECK-NEXT: -: 4: +// CHECK-NEXT: -: 5:int main(int argc, char *argv[]) { +// CHECK-NEXT: 1: 6: dlerror(); +// CHECK-NEXT: 1: 7: void *f1_handle = dlopen("func.shared", RTLD_LAZY | RTLD_GLOBAL); +// CHECK-NEXT: 1: 8: if (f1_handle == NULL) { +// CHECK-NEXT: #####: 9: fprintf(stderr, "unable to open 'func.shared': %s\n", dlerror()); +// CHECK-NEXT: #####: 10: return EXIT_FAILURE; +// CHECK-NEXT: -: 11: } +// CHECK-NEXT: -: 12: +// CHECK-NEXT: 1: 13: void (*func)(void) = (void (*)(void))dlsym(f1_handle, "func"); +// CHECK-NEXT: 1: 14: if (func == NULL) { +// CHECK-NEXT: #####: 15: fprintf(stderr, "unable to lookup symbol 'func': %s\n", dlerror()); +// CHECK-NEXT: #####: 16: return EXIT_FAILURE; +// CHECK-NEXT: -: 17: } +// CHECK-NEXT: -: 18: +// CHECK-NEXT: 1: 19: void *f2_handle = dlopen("func2.shared", RTLD_LAZY | RTLD_GLOBAL); +// CHECK-NEXT: 1: 20: if (f2_handle == NULL) { +// CHECK-NEXT: #####: 21: fprintf(stderr, "unable to open 'func2.shared': %s\n", dlerror()); +// CHECK-NEXT: #####: 22: return EXIT_FAILURE; +// CHECK-NEXT: -: 23: } +// CHECK-NEXT: -: 24: +// CHECK-NEXT: 1: 25: void (*func2)(void) = (void (*)(void))dlsym(f2_handle, "func2"); +// CHECK-NEXT: 1: 26: if (func2 == NULL) { +// CHECK-NEXT: #####: 27: fprintf(stderr, "unable to lookup symbol 'func2': %s\n", dlerror()); +// CHECK-NEXT: #####: 28: return EXIT_FAILURE; +// CHECK-NEXT: -: 29: } +// CHECK-NEXT: 1: 30: func2(); +// CHECK-NEXT: -: 31: +// CHECK-NEXT: 1: 32: if (dlclose(f2_handle) != 0) { +// CHECK-NEXT: #####: 33: fprintf(stderr, "unable to close 'func2.shared': %s\n", dlerror()); +// CHECK-NEXT: #####: 34: return EXIT_FAILURE; +// CHECK-NEXT: -: 35: } +// CHECK-NEXT: -: 36: +// CHECK-NEXT: 1: 37: func(); +// CHECK-NEXT: -: 38: +// CHECK-NEXT: 1: 39: int g1 = 0; +// CHECK-NEXT: 1: 40: int g2 = 0; +// CHECK-NEXT: 1: 41: int n = 10; +// CHECK-NEXT: -: 42: +// CHECK-NEXT: 1: 43: if (n % 5 == 0) +// CHECK-NEXT: 1: 44: g1++; +// CHECK-NEXT: -: 45: else +// CHECK-NEXT: #####: 46: g2++; +// CHECK-NEXT: -: 47: +// CHECK-NEXT: 1: 48: return EXIT_SUCCESS; +// CHECK-NEXT: 1: 49:} +// CHECK-NEXT: -: 50: Index: test/profile/Inputs/instrprof-dlopen-func.c.gcov =================================================================== --- test/profile/Inputs/instrprof-dlopen-func.c.gcov +++ test/profile/Inputs/instrprof-dlopen-func.c.gcov @@ -0,0 +1,6 @@ +// CHECK: -: 0:Source:{{.*}}Inputs/instrprof-dlopen-func.c +// CHECK-NEXT: -: 0:Graph:instrprof-dlopen-func.gcno +// CHECK-NEXT: -: 0:Data:instrprof-dlopen-func.gcda +// CHECK-NEXT: -: 0:Runs:1 +// CHECK-NEXT: -: 0:Programs:1 +// CHECK-NEXT: 3: 1:void func(int K) { if (K) {} } Index: test/profile/Inputs/instrprof-dlopen-func2.c.gcov =================================================================== --- test/profile/Inputs/instrprof-dlopen-func2.c.gcov +++ test/profile/Inputs/instrprof-dlopen-func2.c.gcov @@ -0,0 +1,6 @@ +// CHECK: -: 0:Source:{{.*}}Inputs/instrprof-dlopen-func2.c +// CHECK-NEXT: -: 0:Graph:instrprof-dlopen-func2.gcno +// CHECK-NEXT: -: 0:Data:instrprof-dlopen-func2.gcda +// CHECK-NEXT: -: 0:Runs:1 +// CHECK-NEXT: -: 0:Programs:1 +// CHECK-NEXT: 3: 1:void func2(int K) { if (K) {} } Index: test/profile/Inputs/instrprof-shared-lib.c.gcov =================================================================== --- test/profile/Inputs/instrprof-shared-lib.c.gcov +++ test/profile/Inputs/instrprof-shared-lib.c.gcov @@ -0,0 +1,14 @@ +// CHECK: -: 0:Source:{{.*}}Inputs/instrprof-shared-lib.c +// CHECK-NEXT: -: 0:Graph:instrprof-shared-lib.gcno +// CHECK-NEXT: -: 0:Data:instrprof-shared-lib.gcda +// CHECK-NEXT: -: 0:Runs:1 +// CHECK-NEXT: -: 0:Programs:1 +// CHECK-NEXT: -: 1:int g1 = 0; +// CHECK-NEXT: -: 2:int g2 = 1; +// CHECK-NEXT: -: 3: +// CHECK-NEXT: -: 4:void foo(int n) { +// CHECK-NEXT: 1: 5: if (n % 5 == 0) +// CHECK-NEXT: #####: 6: g1++; +// CHECK-NEXT: -: 7: else +// CHECK-NEXT: 1: 8: g2++; +// CHECK-NEXT: 1: 9:} Index: test/profile/Inputs/instrprof-shared-main-gcov-flush.c =================================================================== --- test/profile/Inputs/instrprof-shared-main-gcov-flush.c +++ test/profile/Inputs/instrprof-shared-main-gcov-flush.c @@ -0,0 +1,13 @@ +extern void foo(int n); +extern void __gcov_flush(void); + +int main(int argc, char *argv[]) { + foo(1); + + __gcov_flush(); + + int *ciao = 0; + *ciao = 42; + + return 0; +} Index: test/profile/Inputs/instrprof-shared-main-gcov-flush.c.gcov =================================================================== --- test/profile/Inputs/instrprof-shared-main-gcov-flush.c.gcov +++ test/profile/Inputs/instrprof-shared-main-gcov-flush.c.gcov @@ -0,0 +1,18 @@ +// CHECK: -: 0:Source:{{.*}}Inputs/instrprof-shared-main-gcov-flush.c +// CHECK-NEXT: -: 0:Graph:instrprof-shared-main-gcov-flush.gcno +// CHECK-NEXT: -: 0:Data:instrprof-shared-main-gcov-flush.gcda +// CHECK-NEXT: -: 0:Runs:1 +// CHECK-NEXT: -: 0:Programs:1 +// CHECK-NEXT: -: 1:extern void foo(int n); +// CHECK-NEXT: -: 2:extern void __gcov_flush(void); +// CHECK-NEXT: -: 3: +// CHECK-NEXT: -: 4:int main(int argc, char *argv[]) { +// CHECK-NEXT: 1: 5: foo(1); +// CHECK-NEXT: -: 6: +// CHECK-NEXT: 1: 7: __gcov_flush(); +// CHECK-NEXT: -: 8: +// CHECK-NEXT: 1: 9: int *ciao = 0; +// CHECK-NEXT: 1: 10: *ciao = 42; +// CHECK-NEXT: -: 11: +// CHECK-NEXT: 1: 12: return 0; +// CHECK-NEXT: -: 13:} Index: test/profile/instrprof-dlopen-dlclose-gcov.test =================================================================== --- test/profile/instrprof-dlopen-dlclose-gcov.test +++ test/profile/instrprof-dlopen-dlclose-gcov.test @@ -4,3 +4,9 @@ RUN: %clang --coverage -o %t -fPIC -rpath %t.d %S/Inputs/instrprof-dlopen-dlclose-main.c RUN: %run %t +RUN: llvm-cov gcov instrprof-dlopen-dlclose-main.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-dlopen-dlclose-main.c.gcov %S/Inputs/instrprof-dlopen-dlclose-main.c.gcov +RUN: llvm-cov gcov instrprof-dlopen-func.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-dlopen-func.c.gcov %S/Inputs/instrprof-dlopen-func.c.gcov +RUN: llvm-cov gcov instrprof-dlopen-func2.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-dlopen-func2.c.gcov %S/Inputs/instrprof-dlopen-func2.c.gcov Index: test/profile/instrprof-shared-gcov-flush.test =================================================================== --- test/profile/instrprof-shared-gcov-flush.test +++ test/profile/instrprof-shared-gcov-flush.test @@ -0,0 +1,14 @@ +RUN: mkdir -p %t.d +RUN: cd %t.d + +RUN: %clang --coverage -o libfunc.so -fPIC -shared %S/Inputs/instrprof-shared-lib.c +RUN: test -f instrprof-shared-lib.gcno + +RUN: %clang --coverage -o %t -L%t.d -rpath %t.d -lfunc %S/Inputs/instrprof-shared-main-gcov-flush.c +RUN: test -f instrprof-shared-main-gcov-flush.gcno + +RUN: %expect_crash %run %t +RUN: llvm-cov gcov instrprof-shared-main-gcov-flush.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-shared-main-gcov-flush.c.gcov %S/Inputs/instrprof-shared-main-gcov-flush.c.gcov +RUN: llvm-cov gcov instrprof-shared-lib.gcda +RUN: FileCheck --match-full-lines --strict-whitespace --input-file instrprof-shared-lib.c.gcov %S/Inputs/instrprof-shared-lib.c.gcov