xref: /aosp_15_r20/external/libepoxy/test/dlwrap.c (revision 706d0b42ae4182339789e08d473a0b312ecdc60f)
1*706d0b42SXin Li /* Copyright © 2013, Intel Corporation
2*706d0b42SXin Li  *
3*706d0b42SXin Li  * Permission is hereby granted, free of charge, to any person obtaining a copy
4*706d0b42SXin Li  * of this software and associated documentation files (the "Software"), to deal
5*706d0b42SXin Li  * in the Software without restriction, including without limitation the rights
6*706d0b42SXin Li  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*706d0b42SXin Li  * copies of the Software, and to permit persons to whom the Software is
8*706d0b42SXin Li  * furnished to do so, subject to the following conditions:
9*706d0b42SXin Li  *
10*706d0b42SXin Li  * The above copyright notice and this permission notice shall be included in
11*706d0b42SXin Li  * all copies or substantial portions of the Software.
12*706d0b42SXin Li  *
13*706d0b42SXin Li  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14*706d0b42SXin Li  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15*706d0b42SXin Li  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16*706d0b42SXin Li  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17*706d0b42SXin Li  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18*706d0b42SXin Li  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19*706d0b42SXin Li  * THE SOFTWARE.
20*706d0b42SXin Li  */
21*706d0b42SXin Li 
22*706d0b42SXin Li /** @file dlwrap.c
23*706d0b42SXin Li  *
24*706d0b42SXin Li  * Implements a wrapper for dlopen() and dlsym() so that epoxy will
25*706d0b42SXin Li  * end up finding symbols from the testcases named
26*706d0b42SXin Li  * "override_EGL_eglWhatever()" or "override_GLES2_glWhatever()" or
27*706d0b42SXin Li  * "override_GL_glWhatever()" when it tries to dlopen() and dlsym()
28*706d0b42SXin Li  * the real GL or EGL functions in question.
29*706d0b42SXin Li  *
30*706d0b42SXin Li  * This lets us simulate some target systems in the test suite, or
31*706d0b42SXin Li  * just stub out GL functions so we can be sure of what's being
32*706d0b42SXin Li  * called.
33*706d0b42SXin Li  */
34*706d0b42SXin Li 
35*706d0b42SXin Li /* dladdr is a glibc extension */
36*706d0b42SXin Li #define _GNU_SOURCE
37*706d0b42SXin Li #include <dlfcn.h>
38*706d0b42SXin Li 
39*706d0b42SXin Li #include <stdbool.h>
40*706d0b42SXin Li #include <stdio.h>
41*706d0b42SXin Li #include <stdlib.h>
42*706d0b42SXin Li #include <string.h>
43*706d0b42SXin Li #include <assert.h>
44*706d0b42SXin Li 
45*706d0b42SXin Li #include "dlwrap.h"
46*706d0b42SXin Li 
47*706d0b42SXin Li #define STRNCMP_LITERAL(var, literal) \
48*706d0b42SXin Li     strncmp ((var), (literal), sizeof (literal) - 1)
49*706d0b42SXin Li 
50*706d0b42SXin Li #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
51*706d0b42SXin Li 
52*706d0b42SXin Li void *libfips_handle;
53*706d0b42SXin Li 
54*706d0b42SXin Li typedef void *(*fips_dlopen_t)(const char *filename, int flag);
55*706d0b42SXin Li typedef void *(*fips_dlsym_t)(void *handle, const char *symbol);
56*706d0b42SXin Li 
57*706d0b42SXin Li void *override_EGL_eglGetProcAddress(const char *name);
58*706d0b42SXin Li void *override_GL_glXGetProcAddress(const char *name);
59*706d0b42SXin Li void *override_GL_glXGetProcAddressARB(const char *name);
60*706d0b42SXin Li void __dlclose(void *handle);
61*706d0b42SXin Li 
62*706d0b42SXin Li static struct libwrap {
63*706d0b42SXin Li     const char *filename;
64*706d0b42SXin Li     const char *symbol_prefix;
65*706d0b42SXin Li     void *handle;
66*706d0b42SXin Li } wrapped_libs[] = {
67*706d0b42SXin Li     { "libGL.so", "GL", NULL },
68*706d0b42SXin Li     { "libEGL.so", "EGL", NULL },
69*706d0b42SXin Li     { "libGLESv2.so", "GLES2", NULL },
70*706d0b42SXin Li     { "libOpenGL.so", "GL", NULL},
71*706d0b42SXin Li };
72*706d0b42SXin Li 
73*706d0b42SXin Li /* Match 'filename' against an internal list of libraries for which
74*706d0b42SXin Li  * libfips has wrappers.
75*706d0b42SXin Li  *
76*706d0b42SXin Li  * Returns true and sets *index_ret if a match is found.
77*706d0b42SXin Li  * Returns false if no match is found. */
78*706d0b42SXin Li static struct libwrap *
find_wrapped_library(const char * filename)79*706d0b42SXin Li find_wrapped_library(const char *filename)
80*706d0b42SXin Li {
81*706d0b42SXin Li     unsigned i;
82*706d0b42SXin Li 
83*706d0b42SXin Li     if (!filename)
84*706d0b42SXin Li         return NULL;
85*706d0b42SXin Li 
86*706d0b42SXin Li     for (i = 0; i < ARRAY_SIZE(wrapped_libs); i++) {
87*706d0b42SXin Li         if (strncmp(wrapped_libs[i].filename, filename,
88*706d0b42SXin Li                     strlen(wrapped_libs[i].filename)) == 0) {
89*706d0b42SXin Li             return &wrapped_libs[i];
90*706d0b42SXin Li         }
91*706d0b42SXin Li     }
92*706d0b42SXin Li 
93*706d0b42SXin Li     return NULL;
94*706d0b42SXin Li }
95*706d0b42SXin Li 
96*706d0b42SXin Li /* Many (most?) OpenGL programs dlopen libGL.so.1 rather than linking
97*706d0b42SXin Li  * against it directly, which means they would not be seeing our
98*706d0b42SXin Li  * wrapped GL symbols via LD_PRELOAD. So we catch the dlopen in a
99*706d0b42SXin Li  * wrapper here and redirect it to our library.
100*706d0b42SXin Li  */
101*706d0b42SXin Li void *
dlopen(const char * filename,int flag)102*706d0b42SXin Li dlopen(const char *filename, int flag)
103*706d0b42SXin Li {
104*706d0b42SXin Li     void *ret;
105*706d0b42SXin Li     struct libwrap *wrap;
106*706d0b42SXin Li 
107*706d0b42SXin Li     /* Before deciding whether to redirect this dlopen to our own
108*706d0b42SXin Li      * library, we call the real dlopen. This assures that any
109*706d0b42SXin Li      * expected side-effects from loading the intended library are
110*706d0b42SXin Li      * resolved. Below, we may still return a handle pointing to
111*706d0b42SXin Li      * our own library, and not what is opened here. */
112*706d0b42SXin Li     ret = dlwrap_real_dlopen(filename, flag);
113*706d0b42SXin Li 
114*706d0b42SXin Li     /* If filename is not a wrapped library, just return real dlopen */
115*706d0b42SXin Li     wrap = find_wrapped_library(filename);
116*706d0b42SXin Li     if (!wrap)
117*706d0b42SXin Li         return ret;
118*706d0b42SXin Li 
119*706d0b42SXin Li     wrap->handle = ret;
120*706d0b42SXin Li 
121*706d0b42SXin Li     /* We use wrapped_libs as our handles to libraries. */
122*706d0b42SXin Li     return wrap;
123*706d0b42SXin Li }
124*706d0b42SXin Li 
125*706d0b42SXin Li /**
126*706d0b42SXin Li  * Wraps dlclose to hide our faked handles from it.
127*706d0b42SXin Li  */
128*706d0b42SXin Li void
__dlclose(void * handle)129*706d0b42SXin Li __dlclose(void *handle)
130*706d0b42SXin Li {
131*706d0b42SXin Li     struct libwrap *wrap = handle;
132*706d0b42SXin Li 
133*706d0b42SXin Li     if (wrap < wrapped_libs ||
134*706d0b42SXin Li         wrap >= wrapped_libs + ARRAY_SIZE(wrapped_libs)) {
135*706d0b42SXin Li         void (*real_dlclose)(void *handle) = dlwrap_real_dlsym(RTLD_NEXT, "__dlclose");
136*706d0b42SXin Li         real_dlclose(handle);
137*706d0b42SXin Li     }
138*706d0b42SXin Li }
139*706d0b42SXin Li 
140*706d0b42SXin Li void *
dlwrap_real_dlopen(const char * filename,int flag)141*706d0b42SXin Li dlwrap_real_dlopen(const char *filename, int flag)
142*706d0b42SXin Li {
143*706d0b42SXin Li     static fips_dlopen_t real_dlopen = NULL;
144*706d0b42SXin Li 
145*706d0b42SXin Li     if (!real_dlopen) {
146*706d0b42SXin Li         real_dlopen = (fips_dlopen_t) dlwrap_real_dlsym(RTLD_NEXT, "dlopen");
147*706d0b42SXin Li         if (!real_dlopen) {
148*706d0b42SXin Li             fputs("Error: Failed to find symbol for dlopen.\n", stderr);
149*706d0b42SXin Li             exit(1);
150*706d0b42SXin Li         }
151*706d0b42SXin Li     }
152*706d0b42SXin Li 
153*706d0b42SXin Li     return real_dlopen(filename, flag);
154*706d0b42SXin Li }
155*706d0b42SXin Li 
156*706d0b42SXin Li /**
157*706d0b42SXin Li  * Return the dlsym() on the application's namespace for
158*706d0b42SXin Li  * "override_<prefix>_<name>"
159*706d0b42SXin Li  */
160*706d0b42SXin Li static void *
wrapped_dlsym(const char * prefix,const char * name)161*706d0b42SXin Li wrapped_dlsym(const char *prefix, const char *name)
162*706d0b42SXin Li {
163*706d0b42SXin Li     char *wrap_name;
164*706d0b42SXin Li     void *symbol;
165*706d0b42SXin Li 
166*706d0b42SXin Li     if (asprintf(&wrap_name, "override_%s_%s", prefix, name) < 0) {
167*706d0b42SXin Li         fputs("Error: Failed to allocate memory.\n", stderr);
168*706d0b42SXin Li         abort();
169*706d0b42SXin Li     }
170*706d0b42SXin Li 
171*706d0b42SXin Li     symbol = dlwrap_real_dlsym(RTLD_DEFAULT, wrap_name);
172*706d0b42SXin Li     free(wrap_name);
173*706d0b42SXin Li     return symbol;
174*706d0b42SXin Li }
175*706d0b42SXin Li 
176*706d0b42SXin Li /* Since we redirect dlopens of libGL.so and libEGL.so to libfips we
177*706d0b42SXin Li  * need to ensure that dlysm succeeds for all functions that might be
178*706d0b42SXin Li  * defined in the real, underlying libGL library. But we're far too
179*706d0b42SXin Li  * lazy to implement wrappers for function that would simply
180*706d0b42SXin Li  * pass-through, so instead we also wrap dlysm and arrange for it to
181*706d0b42SXin Li  * pass things through with RTLD_next if libfips does not have the
182*706d0b42SXin Li  * function desired.  */
183*706d0b42SXin Li void *
dlsym(void * handle,const char * name)184*706d0b42SXin Li dlsym(void *handle, const char *name)
185*706d0b42SXin Li {
186*706d0b42SXin Li     struct libwrap *wrap = handle;
187*706d0b42SXin Li 
188*706d0b42SXin Li     /* Make sure that handle is actually one of our wrapped libs. */
189*706d0b42SXin Li     if (wrap < wrapped_libs ||
190*706d0b42SXin Li         wrap >= wrapped_libs + ARRAY_SIZE(wrapped_libs)) {
191*706d0b42SXin Li         wrap = NULL;
192*706d0b42SXin Li     }
193*706d0b42SXin Li 
194*706d0b42SXin Li     /* Failing that, anything specifically requested from the
195*706d0b42SXin Li      * libfips library should be redirected to a real GL
196*706d0b42SXin Li      * library. */
197*706d0b42SXin Li 
198*706d0b42SXin Li     if (wrap) {
199*706d0b42SXin Li         void *symbol = wrapped_dlsym(wrap->symbol_prefix, name);
200*706d0b42SXin Li         if (symbol)
201*706d0b42SXin Li             return symbol;
202*706d0b42SXin Li         else
203*706d0b42SXin Li             return dlwrap_real_dlsym(wrap->handle, name);
204*706d0b42SXin Li     }
205*706d0b42SXin Li 
206*706d0b42SXin Li     /* And anything else is some unrelated dlsym. Just pass it
207*706d0b42SXin Li      * through.  (This also covers the cases of lookups with
208*706d0b42SXin Li      * special handles such as RTLD_DEFAULT or RTLD_NEXT.)
209*706d0b42SXin Li      */
210*706d0b42SXin Li     return dlwrap_real_dlsym(handle, name);
211*706d0b42SXin Li }
212*706d0b42SXin Li 
213*706d0b42SXin Li void *
dlwrap_real_dlsym(void * handle,const char * name)214*706d0b42SXin Li dlwrap_real_dlsym(void *handle, const char *name)
215*706d0b42SXin Li {
216*706d0b42SXin Li     static fips_dlsym_t real_dlsym = NULL;
217*706d0b42SXin Li 
218*706d0b42SXin Li     if (!real_dlsym) {
219*706d0b42SXin Li         /* FIXME: This brute-force, hard-coded searching for a versioned
220*706d0b42SXin Li          * symbol is really ugly. The only reason I'm doing this is because
221*706d0b42SXin Li          * I need some way to lookup the "dlsym" function in libdl, but
222*706d0b42SXin Li          * I can't use 'dlsym' to do it. So dlvsym works, but forces me
223*706d0b42SXin Li          * to guess what the right version is.
224*706d0b42SXin Li          *
225*706d0b42SXin Li          * Potential fixes here:
226*706d0b42SXin Li          *
227*706d0b42SXin Li          *   1. Use libelf to actually inspect libdl.so and
228*706d0b42SXin Li          *      find the right version, (finding the right
229*706d0b42SXin Li          *      libdl.so can be made easier with
230*706d0b42SXin Li          *      dl_iterate_phdr).
231*706d0b42SXin Li          *
232*706d0b42SXin Li          *   2. Use libelf to find the offset of the 'dlsym'
233*706d0b42SXin Li          *      symbol within libdl.so, (and then add this to
234*706d0b42SXin Li          *      the base address at which libdl.so is loaded
235*706d0b42SXin Li          *      as reported by dl_iterate_phdr).
236*706d0b42SXin Li          *
237*706d0b42SXin Li          * In the meantime, I'll just keep augmenting this
238*706d0b42SXin Li          * hard-coded version list as people report bugs. */
239*706d0b42SXin Li         const char *version[] = {
240*706d0b42SXin Li             "GLIBC_2.17",
241*706d0b42SXin Li             "GLIBC_2.4",
242*706d0b42SXin Li             "GLIBC_2.3",
243*706d0b42SXin Li             "GLIBC_2.2.5",
244*706d0b42SXin Li             "GLIBC_2.2",
245*706d0b42SXin Li             "GLIBC_2.0",
246*706d0b42SXin Li             "FBSD_1.0"
247*706d0b42SXin Li         };
248*706d0b42SXin Li         int num_versions = sizeof(version) / sizeof(version[0]);
249*706d0b42SXin Li         int i;
250*706d0b42SXin Li         for (i = 0; i < num_versions; i++) {
251*706d0b42SXin Li             real_dlsym = (fips_dlsym_t) dlvsym(RTLD_NEXT, "dlsym", version[i]);
252*706d0b42SXin Li             if (real_dlsym)
253*706d0b42SXin Li                 break;
254*706d0b42SXin Li         }
255*706d0b42SXin Li         if (i == num_versions) {
256*706d0b42SXin Li             fputs("Internal error: Failed to find real dlsym\n", stderr);
257*706d0b42SXin Li             fputs("This may be a simple matter of fips not knowing about the version of GLIBC that\n"
258*706d0b42SXin Li                   "your program is using. Current known versions are:\n\n\t",
259*706d0b42SXin Li                   stderr);
260*706d0b42SXin Li             for (i = 0; i < num_versions; i++)
261*706d0b42SXin Li                 fprintf(stderr, "%s ", version[i]);
262*706d0b42SXin Li             fputs("\n\nYou can inspect your version by first finding libdl.so.2:\n"
263*706d0b42SXin Li                   "\n"
264*706d0b42SXin Li                   "\tldd <your-program> | grep libdl.so\n"
265*706d0b42SXin Li                   "\n"
266*706d0b42SXin Li                   "And then inspecting the version attached to the dlsym symbol:\n"
267*706d0b42SXin Li                   "\n"
268*706d0b42SXin Li                   "\treadelf -s /path/to/libdl.so.2 | grep dlsym\n"
269*706d0b42SXin Li                   "\n"
270*706d0b42SXin Li                   "And finally, adding the version to dlwrap.c:dlwrap_real_dlsym.\n",
271*706d0b42SXin Li                   stderr);
272*706d0b42SXin Li 
273*706d0b42SXin Li             exit(1);
274*706d0b42SXin Li         }
275*706d0b42SXin Li     }
276*706d0b42SXin Li 
277*706d0b42SXin Li     return real_dlsym(handle, name);
278*706d0b42SXin Li }
279*706d0b42SXin Li 
280*706d0b42SXin Li void *
override_GL_glXGetProcAddress(const char * name)281*706d0b42SXin Li override_GL_glXGetProcAddress(const char *name)
282*706d0b42SXin Li {
283*706d0b42SXin Li     void *symbol;
284*706d0b42SXin Li 
285*706d0b42SXin Li     symbol = wrapped_dlsym("GL", name);
286*706d0b42SXin Li     if (symbol)
287*706d0b42SXin Li         return symbol;
288*706d0b42SXin Li 
289*706d0b42SXin Li     return DEFER_TO_GL("libGL.so.1", override_GL_glXGetProcAddress,
290*706d0b42SXin Li                        "glXGetProcAddress", (name));
291*706d0b42SXin Li }
292*706d0b42SXin Li 
293*706d0b42SXin Li void *
override_GL_glXGetProcAddressARB(const char * name)294*706d0b42SXin Li override_GL_glXGetProcAddressARB(const char *name)
295*706d0b42SXin Li {
296*706d0b42SXin Li     void *symbol;
297*706d0b42SXin Li 
298*706d0b42SXin Li     symbol = wrapped_dlsym("GL", name);
299*706d0b42SXin Li     if (symbol)
300*706d0b42SXin Li         return symbol;
301*706d0b42SXin Li 
302*706d0b42SXin Li     return DEFER_TO_GL("libGL.so.1", override_GL_glXGetProcAddressARB,
303*706d0b42SXin Li                        "glXGetProcAddressARB", (name));
304*706d0b42SXin Li }
305*706d0b42SXin Li 
306*706d0b42SXin Li void *
override_EGL_eglGetProcAddress(const char * name)307*706d0b42SXin Li override_EGL_eglGetProcAddress(const char *name)
308*706d0b42SXin Li {
309*706d0b42SXin Li     void *symbol;
310*706d0b42SXin Li 
311*706d0b42SXin Li     if (!STRNCMP_LITERAL(name, "gl")) {
312*706d0b42SXin Li         symbol = wrapped_dlsym("GLES2", name);
313*706d0b42SXin Li         if (symbol)
314*706d0b42SXin Li             return symbol;
315*706d0b42SXin Li     }
316*706d0b42SXin Li 
317*706d0b42SXin Li     if (!STRNCMP_LITERAL(name, "egl")) {
318*706d0b42SXin Li         symbol = wrapped_dlsym("EGL", name);
319*706d0b42SXin Li         if (symbol)
320*706d0b42SXin Li             return symbol;
321*706d0b42SXin Li     }
322*706d0b42SXin Li 
323*706d0b42SXin Li     return DEFER_TO_GL("libEGL.so.1", override_EGL_eglGetProcAddress,
324*706d0b42SXin Li                        "eglGetProcAddress", (name));
325*706d0b42SXin Li }
326