1/// atexit(3) not supported in dlopen(3)ed+dlclose(3)d DSO
2// XFAIL: target={{.*netbsd.*}}
3
4// RUN: mkdir -p %t.d && cd %t.d
5
6// RUN: echo 'void func1(int k) {}' > func1.c
7// RUN: echo 'void func2(int k) {}' > func2.c
8// RUN: echo 'void func3(int k) {}' > func3.c
9// RUN: %clang --coverage -fPIC -shared func1.c -o func1.so -dumpdir ./
10// RUN: %clang --coverage -fPIC -shared func2.c -o func2.so -dumpdir ./
11// RUN: %clang --coverage -fPIC -shared func3.c -o func3.so -dumpdir ./
12// RUN: %clang --coverage -fPIC -rpath %t.d %s -o %t -dumpdir ./
13
14/// Test with two dlopened libraries.
15// RUN: rm -f gcov-dlopen.gcda func1.gcda func2.gcda
16// RUN: %run %t
17// RUN: llvm-cov gcov -t gcov-dlopen.gcda | FileCheck %s
18// RUN: llvm-cov gcov -t func1.gcda | FileCheck %s --check-prefix=FUNC1
19// RUN: llvm-cov gcov -t func2.gcda | FileCheck %s --check-prefix=FUNC2
20
21// FUNC1: 1: 1:void func1(int k) {}
22// FUNC2: 1: 1:void func2(int k) {}
23
24/// Test with three dlopened libraries.
25// RUN: %clang -DUSE_LIB3 --coverage -fPIC -rpath %t.d %s -o %t -dumpdir ./
26// RUN: rm -f gcov-dlopen.gcda func1.gcda func2.gcda func3.gcda
27// RUN: %run %t
28// RUN: llvm-cov gcov -t gcov-dlopen.gcda | FileCheck %s --check-prefix=LIB3
29// RUN: llvm-cov gcov -t func1.gcda | FileCheck %s --check-prefix=FUNC1
30// RUN: llvm-cov gcov -t func2.gcda | FileCheck %s --check-prefix=FUNC2
31// RUN: llvm-cov gcov -t func3.gcda | FileCheck %s --check-prefix=FUNC3
32
33// FUNC3: 1: 1:void func3(int k) {}
34
35#include <dlfcn.h>
36#include <stdio.h>
37#include <stdlib.h>
38
39int main(int argc, char *argv[]) {
40 void *f1_handle = dlopen(file: "func1.so", RTLD_LAZY | RTLD_GLOBAL);
41 if (f1_handle == NULL)
42 return fprintf(stderr, format: "unable to open 'func1.so': %s\n", dlerror());
43 void (*func1)(void) = (void (*)(void))dlsym(handle: f1_handle, name: "func1");
44 if (func1 == NULL)
45 return fprintf(stderr, format: "unable to lookup symbol 'func1': %s\n", dlerror());
46
47 void *f2_handle = dlopen(file: "func2.so", RTLD_LAZY | RTLD_GLOBAL);
48 if (f2_handle == NULL)
49 return fprintf(stderr, format: "unable to open 'func2.so': %s\n", dlerror());
50 void (*func2)(void) = (void (*)(void))dlsym(handle: f2_handle, name: "func2");
51 if (func2 == NULL)
52 return fprintf(stderr, format: "unable to lookup symbol 'func2': %s\n", dlerror());
53 func2();
54
55#ifdef USE_LIB3
56// CHECK: -: [[#@LINE+2]]: void *f3_handle
57// LIB3: 1: [[#@LINE+1]]: void *f3_handle
58 void *f3_handle = dlopen("func3.so", RTLD_LAZY | RTLD_GLOBAL);
59 if (f3_handle == NULL)
60 return fprintf(stderr, "unable to open 'func3.so': %s\n", dlerror());
61 void (*func3)(void) = (void (*)(void))dlsym(f3_handle, "func3");
62 if (func3 == NULL)
63 return fprintf(stderr, "unable to lookup symbol 'func3': %s\n", dlerror());
64 func3();
65#endif
66
67 void (*gcov_reset1)() = (void (*)())dlsym(handle: f1_handle, name: "__gcov_reset");
68 if (gcov_reset1 == NULL)
69 return fprintf(stderr, format: "unable to find __gcov_reset in func1.so': %s\n", dlerror());
70 void (*gcov_reset2)() = (void (*)())dlsym(handle: f2_handle, name: "__gcov_reset");
71 if (gcov_reset2 == NULL)
72 return fprintf(stderr, format: "unable to find __gcov_reset in func2.so': %s\n", dlerror());
73 if (gcov_reset1 == gcov_reset2)
74 return fprintf(stderr, format: "same __gcov_reset found in func1.so and func2.so\n");
75
76 /// Test that __gcov_dump is in the dynamic symbol table.
77 void (*gcov_dump1)() = (void (*)())dlsym(handle: f1_handle, name: "__gcov_dump");
78 if (gcov_dump1 == NULL)
79 return fprintf(stderr, format: "unable to find __gcov_dump in func1.so': %s\n", dlerror());
80
81 if (dlclose(handle: f2_handle) != 0)
82 return fprintf(stderr, format: "unable to close 'func2.so': %s\n", dlerror());
83
84 func1();
85
86 return 0;
87}
88

source code of compiler-rt/test/profile/Posix/gcov-dlopen.c