VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/util/dll.c@ 75267

Last change on this file since 75267 was 75267, checked in by vboxsync, 6 years ago

OpenGL: make runtime loading of shared objects work without DT_RPATH.
bugref:8019: GCC sanitisers
Unfortunately gcc address sanitiser breaks DT_RPATH, and our host OpenGL test
tool depends on this when trying to load the libraries. The simple fix is to
retry loading the library in RTPathSharedLibs() if the first load attempt
fails.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.4 KB
Line 
1/* Copyright (c) 2001, Stanford University
2 * All rights reserved
3 *
4 * See the file LICENSE.txt for information on redistributing this software.
5 */
6
7#include "cr_mem.h"
8#include "cr_error.h"
9#include "cr_dll.h"
10#include "cr_string.h"
11#include "stdio.h"
12
13#ifndef IN_GUEST
14#include <string.h>
15#endif
16
17#if defined(IRIX) || defined(IRIX64) || defined(Linux) || defined(FreeBSD) || defined(AIX) || defined(DARWIN) || defined(SunOS) || defined(OSF1)
18# include <iprt/assert.h>
19# include <iprt/err.h>
20# include <iprt/path.h>
21#include <dlfcn.h>
22#endif
23
24#ifdef WINDOWS
25# ifdef VBOX
26# include <iprt/win/shlwapi.h>
27# else
28#include <Shlwapi.h>
29# endif
30#endif
31
32#ifdef DARWIN
33
34#include <Carbon/Carbon.h>
35#include <mach-o/dyld.h>
36
37char *__frameworkErr=NULL;
38
39CFBundleRef LoadFramework( const char *frameworkName ) {
40 CFBundleRef bundle;
41 CFURLRef bundleURL;
42 char fullfile[8096];
43
44 if( frameworkName[0] != '/' ) {
45 /* load a system framework */
46 /* XXX \todo should this folder be retrieved from somewhere else? */
47 crStrcpy( fullfile, "/System/Library/Frameworks/" );
48 crStrcat( fullfile, frameworkName );
49 } else {
50 /* load any framework */
51 crStrcpy( fullfile, frameworkName );
52 }
53
54 bundleURL = CFURLCreateWithString( NULL, CFStringCreateWithCStringNoCopy(NULL, fullfile, CFStringGetSystemEncoding(), NULL), NULL );
55 if( !bundleURL ) {
56 __frameworkErr = "Could not create OpenGL Framework bundle URL";
57 return NULL;
58 }
59
60 bundle = CFBundleCreate( kCFAllocatorDefault, bundleURL );
61 CFRelease( bundleURL );
62
63 if( !bundle ) {
64 __frameworkErr = "Could not create OpenGL Framework bundle";
65 return NULL;
66 }
67
68 if( !CFBundleLoadExecutable(bundle) ) {
69 __frameworkErr = "Could not load MachO executable";
70 return NULL;
71 }
72
73 return bundle;
74}
75
76char *__bundleErr=NULL;
77
78void *LoadBundle( const char *filename ) {
79 NSObjectFileImage fileImage;
80 NSModule handle = NULL;
81 char _filename[PATH_MAX];
82
83 __bundleErr = NULL;
84
85 if( filename[0] != '/' ) {
86 /* default to a chromium bundle */
87 crStrcpy( _filename, "/cr/lib/Darwin/" );
88 crStrcat( _filename, filename );
89 } else {
90 crStrcpy( _filename, filename );
91 }
92
93 switch( NSCreateObjectFileImageFromFile(_filename, &fileImage) ) {
94 default:
95 case NSObjectFileImageFailure:
96 __bundleErr = "NSObjectFileImageFailure: Failure.";
97 break;
98
99 case NSObjectFileImageInappropriateFile:
100 __bundleErr = "NSObjectFileImageInappropriateFile: The specified file is not of a valid type.";
101 break;
102
103 case NSObjectFileImageArch:
104 __bundleErr = "NSObjectFileImageArch: The specified file is for a different CPU architecture.";
105 break;
106
107 case NSObjectFileImageFormat:
108 __bundleErr = "NSObjectFileImageFormat: The specified file does not appear to be a Mach-O file";
109 break;
110
111 case NSObjectFileImageAccess:
112 __bundleErr = "NSObjectFileImageAccess: Permission to create image denied.";
113 break;
114
115 case NSObjectFileImageSuccess:
116 handle = NSLinkModule( fileImage, _filename,
117 NSLINKMODULE_OPTION_RETURN_ON_ERROR |
118 NSLINKMODULE_OPTION_PRIVATE );
119 NSDestroyObjectFileImage( fileImage );
120 if( !handle ) {
121 NSLinkEditErrors c;
122 int n;
123 const char *name;
124 NSLinkEditError(&c, &n, &name, (const char**)&__bundleErr);
125 }
126 break;
127 }
128
129 return handle;
130}
131
132int check_extension( const char *name, const char *extension ) {
133 int nam_len = crStrlen( name );
134 int ext_len = crStrlen( extension );
135 char *pos = crStrstr( name, extension );
136 return ( pos == &(name[nam_len-ext_len]) );
137}
138
139enum {
140 CR_DLL_NONE,
141 CR_DLL_FRAMEWORK,
142 CR_DLL_DYLIB,
143 CR_DLL_BUNDLE,
144 CR_DLL_UNKNOWN
145};
146
147#define NS_ADD 0
148
149int get_dll_type( const char *name ) {
150 if( check_extension(name, ".framework") )
151 return CR_DLL_FRAMEWORK;
152 if( check_extension(name, ".bundle") )
153 return CR_DLL_BUNDLE;
154 if( check_extension(name, ".dylib") )
155 return CR_DLL_DYLIB;
156 return CR_DLL_DYLIB;
157}
158
159#endif
160
161/*
162 * Open the named shared library.
163 * If resolveGlobal is non-zero, unresolved symbols can be satisfied by
164 * any matching symbol already defined globally. Otherwise, if resolveGlobal
165 * is zero, unresolved symbols should be resolved using symbols in that
166 * object (in preference to global symbols).
167 * NOTE: this came about because we found that for libGL, we need the
168 * global-resolve option but for SPU's we need the non-global option (consider
169 * the state tracker duplicated in the array, tilesort, etc. SPUs).
170 */
171CRDLL *crDLLOpen( const char *dllname, int resolveGlobal )
172{
173 CRDLL *dll;
174 char *dll_err;
175#if defined(WINDOWS)
176 WCHAR szwPath[MAX_PATH];
177 UINT cwcPath = 0;
178
179 (void) resolveGlobal;
180
181# ifndef CR_NO_GL_SYSTEM_PATH
182 if (PathIsRelative(dllname))
183 {
184 size_t cName = strlen(dllname) + 1;
185# ifdef IN_GUEST
186 cwcPath = GetSystemDirectoryW(szwPath, RT_ELEMENTS(szwPath));
187 if (!cwcPath || cwcPath >= MAX_PATH)
188 {
189 DWORD winEr = GetLastError();
190 crError("GetSystemDirectoryW failed err %d", winEr);
191 SetLastError(winEr);
192 return NULL;
193 }
194# else
195 WCHAR * pszwSlashFile;
196 cwcPath = GetModuleFileNameW(NULL, szwPath, RT_ELEMENTS(szwPath));
197 if (!cwcPath || cwcPath >= MAX_PATH)
198 {
199 DWORD winEr = GetLastError();
200 crError("GetModuleFileNameW failed err %d", winEr);
201 SetLastError(winEr);
202 return NULL;
203 }
204
205 pszwSlashFile = wcsrchr(szwPath, L'\\');
206 if (!pszwSlashFile)
207 {
208 crError("failed to match file name");
209 SetLastError(ERROR_PATH_NOT_FOUND);
210 return NULL;
211 }
212
213 cwcPath = pszwSlashFile - szwPath;
214# endif
215
216 if (cwcPath + 1 + cName > MAX_PATH)
217 {
218 crError("invalid path specified");
219 SetLastError(ERROR_FILENAME_EXCED_RANGE);
220 return NULL;
221 }
222 szwPath[cwcPath] = '\\';
223 ++cwcPath;
224 }
225# endif /* CR_NO_GL_SYSTEM_PATH */
226 if (!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, dllname, -1, &szwPath[cwcPath], MAX_PATH - cwcPath))
227 {
228 DWORD winEr = GetLastError();
229 crError("MultiByteToWideChar failed err %d", winEr);
230 SetLastError(winEr);
231 return NULL;
232 }
233#endif
234
235 dll = (CRDLL *) crAlloc( sizeof( CRDLL ) );
236 dll->name = crStrdup( dllname );
237
238#if defined(WINDOWS)
239 dll->hinstLib = LoadLibraryW( szwPath );
240 if (!dll->hinstLib)
241 {
242 crError("failed to load dll %s", dllname);
243 }
244 dll_err = NULL;
245#elif defined(DARWIN)
246 /* XXX \todo Get better error handling in here */
247 dll->type = get_dll_type( dllname );
248 dll_err = NULL;
249
250 switch( dll->type ) {
251 case CR_DLL_FRAMEWORK:
252 dll->hinstLib = LoadFramework( dllname );
253 dll_err = __frameworkErr;
254 break;
255
256 case CR_DLL_BUNDLE:
257 dll->hinstLib = LoadBundle( dllname );
258 dll_err = __bundleErr;
259 break;
260
261 case CR_DLL_DYLIB:
262#if NS_ADD
263 dll->hinstLib = (void*)NSAddImage( dllname, NSADDIMAGE_OPTION_RETURN_ON_ERROR );
264#else
265 if( resolveGlobal )
266 dll->hinstLib = dlopen( dllname, RTLD_LAZY | RTLD_GLOBAL );
267 else
268 dll->hinstLib = dlopen( dllname, RTLD_LAZY | RTLD_LOCAL );
269 dll_err = (char*) dlerror();
270#endif
271 break;
272
273 default:
274 dll->hinstLib = NULL;
275 dll_err = "Unknown DLL type";
276 break;
277 };
278#elif defined(IRIX) || defined(IRIX64) || defined(Linux) || defined(FreeBSD) || defined(AIX) || defined(SunOS) || defined(OSF1)
279 {
280 int flags = RTLD_LAZY;
281 if (resolveGlobal)
282 flags |= RTLD_GLOBAL;
283 dll->hinstLib = dlopen( dllname, flags );
284# ifndef IN_GUEST
285 /* GCC address sanitiser breaks DT_RPATH. */
286 if (!dll->hinstLib) do {
287 char szPath[RTPATH_MAX];
288 int rc = RTPathSharedLibs(szPath, sizeof(szPath));
289 AssertLogRelMsgRCBreak(rc, ("RTPathSharedLibs() failed: %Rrc\n", rc));
290 rc = RTPathAppend(szPath, sizeof(szPath), dllname);
291 AssertLogRelMsgRCBreak(rc, ("RTPathAppend() failed: %Rrc\n", rc));
292 dll->hinstLib = dlopen( szPath, flags );
293 } while(0);
294# endif
295 dll_err = (char*) dlerror();
296 }
297#else
298#error DSO
299#endif
300
301 if (!dll->hinstLib)
302 {
303 if (dll_err)
304 {
305 crDebug( "DLL_ERROR(%s): %s", dllname, dll_err );
306 }
307 crError( "DLL Loader couldn't find/open %s", dllname );
308 crFree(dll);
309 dll = NULL;
310 }
311 return dll;
312}
313
314CRDLLFunc crDLLGetNoError( CRDLL *dll, const char *symname )
315{
316#if defined(WINDOWS)
317 return (CRDLLFunc) GetProcAddress( dll->hinstLib, symname );
318#elif defined(DARWIN)
319 NSSymbol nssym;
320
321 if( dll->type == CR_DLL_FRAMEWORK )
322 return (CRDLLFunc) CFBundleGetFunctionPointerForName( (CFBundleRef) dll->hinstLib, CFStringCreateWithCStringNoCopy(NULL, symname, CFStringGetSystemEncoding(), NULL) );
323
324 if( dll->type == CR_DLL_DYLIB )
325#if NS_ADD
326 nssym = NSLookupSymbolInImage( dll->hinstLib, symname, NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR );
327#else
328 return (CRDLLFunc) dlsym( dll->hinstLib, symname );
329#endif
330 else
331 nssym = NSLookupSymbolInModule( dll->hinstLib, symname );
332
333 if( !nssym ) {
334 char name[PATH_MAX];
335 crStrcpy( name, "_" );
336 crStrcat( name, symname );
337
338 if( dll->type == CR_DLL_DYLIB )
339 nssym = NSLookupSymbolInImage( dll->hinstLib, name, NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR );
340 else
341 nssym = NSLookupSymbolInModule( dll->hinstLib, name );
342 }
343
344 return (CRDLLFunc) NSAddressOfSymbol( nssym );
345
346#elif defined(IRIX) || defined(IRIX64) || defined(Linux) || defined(FreeBSD) || defined(AIX) || defined(SunOS) || defined(OSF1)
347 return (CRDLLFunc)(uintptr_t)dlsym( dll->hinstLib, symname );
348#else
349#error CR DLL ARCHITETECTURE
350#endif
351}
352
353CRDLLFunc crDLLGet( CRDLL *dll, const char *symname )
354{
355 CRDLLFunc data = crDLLGetNoError( dll, symname );
356 if (!data)
357 {
358 /* Are you sure there isn't some C++ mangling messing you up? */
359 crWarning( "Couldn't get symbol \"%s\" in \"%s\"", symname, dll->name );
360 }
361 return data;
362}
363
364void crDLLClose( CRDLL *dll )
365{
366 int dll_err = 0;
367
368 if (!dll) return;
369
370#if defined(WINDOWS)
371 FreeLibrary( dll->hinstLib );
372#elif defined(DARWIN)
373 switch( dll->type ) {
374 case CR_DLL_FRAMEWORK:
375 CFBundleUnloadExecutable( dll->hinstLib );
376 CFRelease(dll->hinstLib);
377 dll->hinstLib = NULL;
378 break;
379
380 case CR_DLL_DYLIB:
381#if !NS_ADD
382 dlclose( dll->hinstLib );
383#endif
384 break;
385
386 case CR_DLL_BUNDLE:
387 NSUnLinkModule( (NSModule) dll->hinstLib, 0L );
388 break;
389 }
390#elif defined(IRIX) || defined(IRIX64) || defined(Linux) || defined(FreeBSD) || defined(AIX) || defined(SunOS) || defined(OSF1)
391 /*
392 * Unloading Nvidia's libGL will crash VirtualBox later during shutdown.
393 * Therefore we will skip unloading it. It will be unloaded later anway
394 * because we are already freeing all resources and VirtualBox will terminate
395 * soon.
396 */
397#ifndef IN_GUEST
398 if (strncmp(dll->name, "libGL", 5))
399#endif
400 dll_err = dlclose( dll->hinstLib );
401#else
402#error DSO
403#endif
404
405 if (dll_err)
406 crWarning("Error closing DLL %s\n",dll->name);
407
408 crFree( dll->name );
409 crFree( dll );
410}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette