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