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