2 * Copyright © 2013 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27 #include "main/macros.h"
29 /* We need GNU extensions to dlfcn.h in order to provide backward
30 * compatibility for the older DRI driver loader mechanism. (dladdr,
31 * Dl_info, and RTLD_DEFAULT)
33 #if defined(RTLD_DEFAULT) && defined(HAVE_DLADDR)
35 #define MEGADRIVER_STUB_MAX_EXTENSIONS 10
36 #define LIB_PATH_SUFFIX "_dri.so"
37 #define LIB_PATH_SUFFIX_LENGTH (sizeof(LIB_PATH_SUFFIX)-1)
39 /* This is the table of extensions that the loader will dlsym() for.
41 * Initially it is empty for the megadriver stub, but the library
42 * constructor may initialize it based on the name of the library that
45 PUBLIC
const __DRIextension
*
46 __driDriverExtensions
[MEGADRIVER_STUB_MAX_EXTENSIONS
] = {
51 * This is a constructor function for the megadriver dynamic library.
53 * When the driver is dlopen'ed, this function will run. It will
54 * search for the name of the foo_dri.so file that was opened using
55 * the dladdr function.
57 * After finding foo's name, it will call __driDriverGetExtensions_foo
58 * and use the return to update __driDriverExtensions to enable
59 * compatibility with older DRI driver loaders.
61 __attribute__((constructor
)) static void
62 megadriver_stub_init(void)
67 char *get_extensions_name
;
68 const __DRIextension
**(*get_extensions
)(void);
69 const __DRIextension
**extensions
;
72 /* Call dladdr on __driDriverExtensions. We are really
73 * interested in the returned info.dli_fname so we can
74 * figure out the path name of the library being loaded.
76 i
= dladdr((void*) __driDriverExtensions
, &info
);
80 /* Search for the last '/' character in the path. */
81 driver_name
= strrchr(info
.dli_fname
, '/');
82 if (driver_name
!= NULL
) {
83 /* Skip '/' character */
86 /* Try using the start of the path */
87 driver_name
= (char*) info
.dli_fname
;
90 /* Make sure the path ends with _dri.so */
91 name_len
= strlen(driver_name
);
92 i
= name_len
- LIB_PATH_SUFFIX_LENGTH
;
93 if (i
< 0 || strcmp(driver_name
+ i
, LIB_PATH_SUFFIX
) != 0)
96 /* Duplicate the string so we can modify it.
97 * So far we've been using info.dli_fname.
99 driver_name
= strdup(driver_name
);
103 /* The path ends with _dri.so. Chop this part of the
104 * string off. Then we'll have the driver's final name.
106 driver_name
[i
] = '\0';
108 i
= asprintf(&get_extensions_name
, "%s_%s",
109 __DRI_DRIVER_GET_EXTENSIONS
, driver_name
);
114 /* dlsym to get the driver's get extensions function. We
115 * don't have the dlopen handle, so we have to use
116 * RTLD_DEFAULT. It seems unlikely that the symbol will
117 * be found in another library, but this isn't optimal.
119 get_extensions
= dlsym(RTLD_DEFAULT
, get_extensions_name
);
120 free(get_extensions_name
);
124 /* Use the newer DRI loader entrypoint to find extensions.
125 * We will then expose these extensions via the older
126 * __driDriverExtensions symbol.
128 extensions
= get_extensions();
130 /* Copy the extensions into the __driDriverExtensions array
133 for (i
= 0; i
< ARRAY_SIZE(__driDriverExtensions
); i
++) {
134 __driDriverExtensions
[i
] = extensions
[i
];
135 if (extensions
[i
] == NULL
)
139 /* If the driver had more extensions than we reserved, then
142 if (i
== ARRAY_SIZE(__driDriverExtensions
)) {
143 __driDriverExtensions
[0] = NULL
;
144 fprintf(stderr
, "Megadriver stub did not reserve enough extension "
150 #endif /* RTLD_DEFAULT && HAVE_DLADDR */
153 __DRIconfig
**stub_error_init_screen(__DRIscreen
*psp
)
155 fprintf(stderr
, "An updated DRI driver loader (libGL.so or X Server) is "
156 "required for this Mesa driver.\n");
161 * This is a stub driDriverAPI that is referenced by dri_util.c but should
164 const struct __DriverAPIRec driDriverAPI
= {
165 .InitScreen
= stub_error_init_screen
,