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 are only defined when _GNU_SOURCE is
36 #define MEGADRIVER_STUB_MAX_EXTENSIONS 10
37 #define LIB_PATH_SUFFIX "_dri.so"
38 #define LIB_PATH_SUFFIX_LENGTH (sizeof(LIB_PATH_SUFFIX)-1)
40 /* This is the table of extensions that the loader will dlsym() for.
42 * Initially it is empty for the megadriver stub, but the library
43 * constructor may initialize it based on the name of the library that
46 PUBLIC
const __DRIextension
*
47 __driDriverExtensions
[MEGADRIVER_STUB_MAX_EXTENSIONS
] = {
52 * This is a constructor function for the megadriver dynamic library.
54 * When the driver is dlopen'ed, this function will run. It will
55 * search for the name of the foo_dri.so file that was opened using
56 * the dladdr function.
58 * After finding foo's name, it will call __driDriverGetExtensions_foo
59 * and use the return to update __driDriverExtensions to enable
60 * compatibility with older DRI driver loaders.
62 __attribute__((constructor
)) static void
63 megadriver_stub_init(void)
68 char *get_extensions_name
;
69 const __DRIextension
**(*get_extensions
)(void);
70 const __DRIextension
**extensions
;
73 /* Call dladdr on __driDriverExtensions. We are really
74 * interested in the returned info.dli_fname so we can
75 * figure out the path name of the library being loaded.
77 i
= dladdr((void*) __driDriverExtensions
, &info
);
81 /* Search for the last '/' character in the path. */
82 driver_name
= strrchr(info
.dli_fname
, '/');
83 if (driver_name
!= NULL
) {
84 /* Skip '/' character */
87 /* Try using the start of the path */
88 driver_name
= (char*) info
.dli_fname
;
91 /* Make sure the path ends with _dri.so */
92 name_len
= strlen(driver_name
);
93 i
= name_len
- LIB_PATH_SUFFIX_LENGTH
;
94 if (i
< 0 || strcmp(driver_name
+ i
, LIB_PATH_SUFFIX
) != 0)
97 /* Duplicate the string so we can modify it.
98 * So far we've been using info.dli_fname.
100 driver_name
= strdup(driver_name
);
104 /* The path ends with _dri.so. Chop this part of the
105 * string off. Then we'll have the driver's final name.
107 driver_name
[i
] = '\0';
109 i
= asprintf(&get_extensions_name
, "%s_%s",
110 __DRI_DRIVER_GET_EXTENSIONS
, driver_name
);
115 /* dlsym to get the driver's get extensions function. We
116 * don't have the dlopen handle, so we have to use
117 * RTLD_DEFAULT. It seems unlikely that the symbol will
118 * be found in another library, but this isn't optimal.
120 get_extensions
= dlsym(RTLD_DEFAULT
, get_extensions_name
);
121 free(get_extensions_name
);
125 /* Use the newer DRI loader entrypoint to find extensions.
126 * We will then expose these extensions via the older
127 * __driDriverExtensions symbol.
129 extensions
= get_extensions();
131 /* Copy the extensions into the __driDriverExtensions array
134 for (i
= 0; i
< ARRAY_SIZE(__driDriverExtensions
); i
++) {
135 __driDriverExtensions
[i
] = extensions
[i
];
136 if (extensions
[i
] == NULL
)
140 /* If the driver had more extensions than we reserved, then
143 if (i
== ARRAY_SIZE(__driDriverExtensions
)) {
144 __driDriverExtensions
[0] = NULL
;
145 fprintf(stderr
, "Megadriver stub did not reserve enough extension "
151 #endif /* _GNU_SOURCE */
154 __DRIconfig
**stub_error_init_screen(__DRIscreen
*psp
)
156 fprintf(stderr
, "An updated DRI driver loader (libGL.so or X Server) is "
157 "required for this Mesa driver.\n");
162 * This is a stub driDriverAPI that is referenced by dri_util.c but should
165 const struct __DriverAPIRec driDriverAPI
= {
166 .InitScreen
= stub_error_init_screen
,