From 7222e8e30bbd80e5fe93265e3d94ec36d55dc787 Mon Sep 17 00:00:00 2001 From: Chih-Hung Hsieh Date: Fri, 29 Jun 2018 21:45:55 +0000 Subject: [PATCH] [profile] Add llvm_gcov_flush to be called outside a shared library __gcov_flush is hidden. For applications to dump profiling data of selected .so files, they can use dlsym to find and call llvm_gcov_flush in each .so file. Differential Revision: https://reviews.llvm.org/D45454 llvm-svn: 336019 --- compiler-rt/lib/profile/GCDAProfiling.c | 10 ++++++++ .../profile/Inputs/instrprof-dlopen-dlclose-main.c | 30 ++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/compiler-rt/lib/profile/GCDAProfiling.c b/compiler-rt/lib/profile/GCDAProfiling.c index bb70ff0..68a0cab 100644 --- a/compiler-rt/lib/profile/GCDAProfiling.c +++ b/compiler-rt/lib/profile/GCDAProfiling.c @@ -527,6 +527,10 @@ void llvm_register_flush_function(flush_fn fn) { } } +// __gcov_flush is hidden. When called in a .so file, +// it dumps profile data of the calling .so file. +// If a main program needs to dump profile data of each linked +// .so files, it should use dlsym to find and call llvm_gcov_flush. COMPILER_RT_VISIBILITY void __gcov_flush() { struct flush_fn_node *curr = flush_fn_head; @@ -537,6 +541,12 @@ void __gcov_flush() { } } +// llvm_gcov_flush is not hidden for a program to use dlsym to +// find and call for any linked .so file. +void llvm_gcov_flush() { + __gcov_flush(); +} + COMPILER_RT_VISIBILITY void llvm_delete_flush_function_list(void) { while (flush_fn_head) { diff --git a/compiler-rt/test/profile/Inputs/instrprof-dlopen-dlclose-main.c b/compiler-rt/test/profile/Inputs/instrprof-dlopen-dlclose-main.c index fe7eaf0..198e4e8 100644 --- a/compiler-rt/test/profile/Inputs/instrprof-dlopen-dlclose-main.c +++ b/compiler-rt/test/profile/Inputs/instrprof-dlopen-dlclose-main.c @@ -10,12 +10,42 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } + dlerror(); 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; } + dlerror(); + void (*gcov_flush)() = (void (*)())dlsym(f1_handle, "__gcov_flush"); + if (gcov_flush != NULL || dlerror() == NULL) { + fprintf(stderr, "__gcov_flush should not be visible in func.shared'\n"); + return EXIT_FAILURE; + } + + dlerror(); + void (*f1_flush)() = (void (*)())dlsym(f1_handle, "llvm_gcov_flush"); + if (f1_flush == NULL) { + fprintf(stderr, "unable to find llvm_gcov_flush in func.shared': %s\n", dlerror()); + return EXIT_FAILURE; + } + f1_flush(); + + dlerror(); + void (*f2_flush)() = (void (*)())dlsym(f2_handle, "llvm_gcov_flush"); + if (f2_flush == NULL) { + fprintf(stderr, "unable to find llvm_gcov_flush in func2.shared': %s\n", dlerror()); + return EXIT_FAILURE; + } + f2_flush(); + + if (f1_flush == f2_flush) { + fprintf(stderr, "Same llvm_gcov_flush found in func.shared and func2.shared\n"); + return EXIT_FAILURE; + } + + dlerror(); if (dlclose(f2_handle) != 0) { fprintf(stderr, "unable to close 'func2.shared': %s\n", dlerror()); return EXIT_FAILURE; -- 2.7.4