Commit | Line | Data |
---|---|---|
3f7f208a | 1 | /* |
9d16b343 | 2 | * Copyright (C) 2018 Francis Deslauriers <francis.deslauriers@efficios.com> |
3f7f208a | 3 | * |
9d16b343 | 4 | * SPDX-License-Identifier: LGPL-2.1-only |
3f7f208a | 5 | * |
3f7f208a FD |
6 | */ |
7 | ||
8 | #include <dlfcn.h> | |
9 | #include <stdio.h> | |
10 | #include <stdlib.h> | |
11 | #include <unistd.h> | |
12 | #include <popt.h> | |
13 | ||
14 | #if HAS_CALLSITES | |
15 | #include "callsites.h" | |
16 | #endif | |
17 | ||
1831ae68 | 18 | void exec_callsite(); |
3f7f208a FD |
19 | void exec_callsite() |
20 | { | |
21 | #if HAS_CALLSITES | |
22 | call_tracepoint(); | |
23 | #endif | |
24 | } | |
25 | ||
1831ae68 | 26 | static void print_list(void) |
3f7f208a FD |
27 | { |
28 | fprintf(stderr, "Test list (-t X):\n"); | |
29 | fprintf(stderr, "\t0: dlopen() all libraries pass in arguments and execute " | |
30 | "the callsite.\n"); | |
31 | fprintf(stderr, "\t1: simulate the upgrade of a probe provider using dlopen() and dlclose(). \n"); | |
32 | fprintf(stderr, "\t2: simulate the upgrade of a library containing the callsites using dlopen() and dlclose(). \n"); | |
33 | } | |
34 | ||
1831ae68 FD |
35 | #if HAS_CALLSITES |
36 | static int dl_open_all(int nb_libraries, char **libraries) | |
3f7f208a FD |
37 | { |
38 | int i, ret = 0; | |
39 | void **handles; | |
40 | ||
41 | handles = malloc(nb_libraries * sizeof(void *)); | |
42 | if (!handles) { | |
43 | ret = -1; | |
44 | goto error; | |
45 | } | |
46 | ||
47 | /* Iterate over the libs to dlopen and save the handles. */ | |
48 | for (i = 0; i < nb_libraries; i++) { | |
49 | handles[i] = dlopen(libraries[i], RTLD_NOW); | |
50 | if (!handles[i]) { | |
51 | ret = -1; | |
52 | goto error; | |
53 | } | |
54 | } | |
55 | ||
56 | exec_callsite(); | |
57 | error: | |
58 | free(handles); | |
59 | return ret; | |
60 | } | |
1831ae68 | 61 | #endif |
3f7f208a | 62 | |
1831ae68 | 63 | #if HAS_CALLSITES |
3f7f208a FD |
64 | /* |
65 | * Takes 2 paths to libraries, dlopen() the first, trace, dlopen() the second, | |
66 | * and dlclose the first to simulate the upgrade of a library. | |
67 | */ | |
1831ae68 | 68 | static int upgrade_lib(int nb_libraries, char **libraries) |
3f7f208a FD |
69 | { |
70 | int i, ret = 0; | |
71 | void *handles[2]; | |
72 | ||
73 | if (nb_libraries != 2) { | |
74 | ret = -1; | |
75 | goto error; | |
76 | } | |
77 | ||
78 | /* Iterate over the libs to dlopen and save the handles. */ | |
79 | for (i = 0; i < nb_libraries; i++) { | |
80 | handles[i] = dlopen(libraries[i], RTLD_NOW); | |
81 | if (!handles[i]) { | |
82 | ret = -1; | |
83 | goto error; | |
84 | } | |
85 | ||
86 | exec_callsite(); | |
87 | } | |
88 | ||
89 | ret = dlclose(handles[0]); | |
90 | if (ret) { | |
91 | goto error; | |
92 | } | |
93 | ||
94 | exec_callsite(); | |
95 | ||
96 | error: | |
97 | return ret; | |
98 | } | |
1831ae68 | 99 | #endif |
3f7f208a | 100 | |
1831ae68 | 101 | #if !HAS_CALLSITES |
3f7f208a FD |
102 | /* |
103 | * Simulate the upgrade of a library containing a callsite. | |
104 | * Receives two libraries containing callsites for the same tracepoint. | |
105 | */ | |
1831ae68 | 106 | static int upgrade_callsite(int nb_libraries, char **libraries) |
3f7f208a FD |
107 | { |
108 | int ret = 0; | |
109 | void *handles[2]; | |
110 | void (*fct_ptr[2])(void); | |
111 | ||
112 | if (nb_libraries != 2) { | |
113 | ret = -1; | |
114 | goto error; | |
115 | } | |
116 | ||
117 | /* Load the probes in the first library. */ | |
118 | handles[0] = dlopen(libraries[0], RTLD_NOW); | |
119 | if (!handles[0]) { | |
120 | ret = -1; | |
121 | goto error; | |
122 | } | |
123 | ||
124 | /* | |
125 | * Get the pointer to the old function containing the callsite and call it. | |
126 | */ | |
127 | fct_ptr[0] = dlsym(handles[0], "call_tracepoint"); | |
128 | if (!fct_ptr[0]) { | |
129 | ret = -1; | |
130 | goto error; | |
131 | } | |
132 | fct_ptr[0](); | |
133 | ||
134 | /* Load the new callsite library. */ | |
135 | handles[1] = dlopen(libraries[1], RTLD_NOW); | |
136 | if (!handles[1]) { | |
137 | ret = -1; | |
138 | goto error; | |
139 | } | |
140 | ||
141 | /* | |
142 | * Get the pointer to the new function containing the callsite and call it. | |
143 | */ | |
144 | fct_ptr[1] = dlsym(handles[1], "call_tracepoint"); | |
145 | if (!fct_ptr[1]) { | |
146 | ret = -1; | |
147 | goto error; | |
148 | } | |
149 | fct_ptr[1](); | |
150 | ||
151 | /* Unload the old callsite library. */ | |
152 | ret = dlclose(handles[0]); | |
153 | if (ret) { | |
154 | goto error; | |
155 | } | |
156 | ||
157 | /* Call the function containing the callsite in the new library. */ | |
158 | fct_ptr[1](); | |
159 | ||
160 | ret = dlclose(handles[1]); | |
161 | if (ret) { | |
162 | goto error; | |
163 | } | |
164 | ||
165 | error: | |
166 | return ret; | |
167 | } | |
1831ae68 | 168 | #endif |
3f7f208a FD |
169 | |
170 | int main(int argc, const char **argv) | |
171 | { | |
172 | int c, ret = 0, test = -1, nb_libraries = 0; | |
173 | char **libraries = NULL; | |
174 | poptContext optCon; | |
175 | struct poptOption optionsTable[] = { | |
176 | { "test", 't', POPT_ARG_INT, &test, 0, "Test to run", NULL }, | |
177 | { "list", 'l', 0, 0, 'l', "List of tests (-t X)", NULL }, | |
178 | POPT_AUTOHELP | |
179 | { NULL, 0, 0, NULL, 0 } | |
180 | }; | |
181 | ||
182 | optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); | |
183 | if (argc < 2) { | |
184 | poptPrintUsage(optCon, stderr, 0); | |
185 | ret = -1; | |
186 | goto error; | |
187 | } | |
188 | ||
189 | while ((c = poptGetNextOpt(optCon)) >= 0) { | |
190 | switch(c) { | |
191 | case 'l': | |
192 | print_list(); | |
193 | goto error; | |
194 | } | |
195 | } | |
196 | ||
197 | /* | |
198 | * Populate the libraries array with the arguments passed to the process. | |
199 | */ | |
200 | while (poptPeekArg(optCon) != NULL) { | |
8ac478d0 JG |
201 | char **realloced_libraries = NULL; |
202 | ||
3f7f208a | 203 | nb_libraries++; |
8ac478d0 JG |
204 | realloced_libraries = realloc(libraries, nb_libraries * sizeof(char *)); |
205 | if (!realloced_libraries) { | |
3f7f208a FD |
206 | ret = -1; |
207 | goto error; | |
208 | } | |
8ac478d0 | 209 | libraries = realloced_libraries; |
3f7f208a FD |
210 | libraries[nb_libraries - 1] = (char *) poptGetArg(optCon); |
211 | } | |
212 | ||
213 | switch(test) { | |
214 | case 0: | |
215 | #if HAS_CALLSITES | |
216 | ret = dl_open_all(nb_libraries, libraries); | |
217 | #else | |
218 | fprintf(stderr, "Test not implemented for configuration " | |
219 | "(HAS_CALLSITES=%d)\n", HAS_CALLSITES == 1); | |
220 | #endif | |
221 | break; | |
222 | case 1: | |
223 | #if HAS_CALLSITES | |
224 | ret = upgrade_lib(nb_libraries, libraries); | |
225 | #else | |
226 | fprintf(stderr, "Test not implemented for configuration " | |
227 | "(HAS_CALLSITES=%d)\n", HAS_CALLSITES == 1); | |
228 | #endif | |
229 | break; | |
230 | case 2: | |
231 | #if !HAS_CALLSITES | |
232 | ret = upgrade_callsite(nb_libraries, libraries); | |
233 | #else | |
234 | fprintf(stderr, "Test not implemented for configuration " | |
235 | "(HAS_CALLSITES=%d)\n", HAS_CALLSITES == 1); | |
236 | #endif | |
237 | break; | |
238 | default: | |
239 | fprintf(stderr, "Test %d not implemented\n", test); | |
240 | ret = -1; | |
241 | break; | |
242 | } | |
243 | error: | |
244 | free(libraries); | |
245 | poptFreeContext(optCon); | |
246 | return ret; | |
247 | } |