Index: lib/profile/GCDAProfiling.c =================================================================== --- lib/profile/GCDAProfiling.c +++ lib/profile/GCDAProfiling.c @@ -231,6 +231,7 @@ * profiling enabled will emit to a different file. Only one file may be * started at a time. */ +COMPILER_RT_VISIBILITY void llvm_gcda_start_file(const char *orig_filename, const char version[4], uint32_t checksum) { const char *mode = "r+b"; @@ -298,6 +299,7 @@ /* Given an array of pointers to counters (counters), increment the n-th one, * where we're also given a pointer to n (predecessor). */ +COMPILER_RT_VISIBILITY void llvm_gcda_increment_indirect_counter(uint32_t *predecessor, uint64_t **counters) { uint64_t *counter; @@ -320,6 +322,7 @@ #endif } +COMPILER_RT_VISIBILITY void llvm_gcda_emit_function(uint32_t ident, const char *function_name, uint32_t func_checksum, uint8_t use_extra_checksum, uint32_t cfg_checksum) { @@ -346,6 +349,7 @@ write_string(function_name); } +COMPILER_RT_VISIBILITY void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) { uint32_t i; uint64_t *old_ctrs = NULL; @@ -397,6 +401,7 @@ #endif } +COMPILER_RT_VISIBILITY void llvm_gcda_summary_info() { const uint32_t obj_summary_len = 9; /* Length for gcov compatibility. */ uint32_t i; @@ -450,6 +455,7 @@ #endif } +COMPILER_RT_VISIBILITY void llvm_gcda_end_file() { /* Write out EOF record. */ if (output_file) { @@ -474,6 +480,7 @@ #endif } +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; @@ -487,6 +494,7 @@ } } +COMPILER_RT_VISIBILITY void llvm_writeout_files(void) { struct writeout_fn_node *curr = writeout_fn_head; @@ -496,6 +504,7 @@ } } +COMPILER_RT_VISIBILITY void llvm_delete_writeout_function_list(void) { while (writeout_fn_head) { struct writeout_fn_node *node = writeout_fn_head; @@ -506,6 +515,7 @@ writeout_fn_head = writeout_fn_tail = 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; @@ -519,6 +529,7 @@ } } +COMPILER_RT_VISIBILITY void __gcov_flush() { struct flush_fn_node *curr = flush_fn_head; @@ -528,6 +539,7 @@ } } +COMPILER_RT_VISIBILITY void llvm_delete_flush_function_list(void) { while (flush_fn_head) { struct flush_fn_node *node = flush_fn_head; @@ -538,6 +550,7 @@ flush_fn_head = flush_fn_tail = NULL; } +COMPILER_RT_VISIBILITY void llvm_gcov_init(writeout_fn wfn, flush_fn ffn) { static int atexit_ran = 0; Index: test/profile/Inputs/instrprof-dlopen-dlclose-main.c =================================================================== --- /dev/null +++ test/profile/Inputs/instrprof-dlopen-dlclose-main.c @@ -0,0 +1,26 @@ +#include +#include +#include + +int main(int argc, char *argv[]) { + dlerror(); + void *f1_handle = dlopen("func.shared", RTLD_LAZY | RTLD_GLOBAL); + if (f1_handle == NULL) { + fprintf(stderr, "unable to open 'func.shared': %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; + } + + if (dlclose(f2_handle) != 0) { + fprintf(stderr, "unable to close 'func2.shared': %s\n", dlerror()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + Index: test/profile/instrprof-dlopen-dlclose-gcov.test =================================================================== --- /dev/null +++ test/profile/instrprof-dlopen-dlclose-gcov.test @@ -0,0 +1,6 @@ +RUN: mkdir -p %t.d +RUN: %clang --coverage -o %t.d/func.shared -fPIC -shared %S/Inputs/instrprof-dlopen-func.c +RUN: %clang --coverage -o %t.d/func2.shared -fPIC -shared %S/Inputs/instrprof-dlopen-func2.c +RUN: %clang --coverage -o %t -fPIC -rpath %t.d %S/Inputs/instrprof-dlopen-dlclose-main.c + +RUN: %run %t