*** empty log message ***
[chuck-blob.git] / exile / v1 / src / chuck_dl.cpp
blob4ba46c2cc08cebf5b50fdd471e240eefb9ce43dd
1 /*----------------------------------------------------------------------------
2 ChucK Concurrent, On-the-fly Audio Programming Language
3 Compiler and Virtual Machine
5 Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6 http://chuck.cs.princeton.edu/
7 http://soundlab.cs.princeton.edu/
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 U.S.A.
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
26 // name: chuck_dl.cpp
27 // desc: chuck dynamic linking
29 // authors: Ge Wang (gewang@cs.princeton.edu)
30 // Perry R. Cook (prc@cs.princeton.edu)
31 // mac code from apple
33 // date: spring 2004
34 //-----------------------------------------------------------------------------
35 #include "chuck_dl.h"
36 #ifndef __CKDL_NO_BBQ__
37 #include "chuck_bbq.h"
38 #endif
39 using namespace std;
43 //-----------------------------------------------------------------------------
44 // name: load()
45 // desc: load dynamic link library
46 //-----------------------------------------------------------------------------
47 t_CKBOOL Chuck_DLL::load( const char * filename, const char * func, t_CKBOOL lazy )
49 // open
50 m_handle = dlopen( filename, lazy ? RTLD_LAZY : RTLD_NOW );
52 // still not there
53 if( !m_handle )
55 m_last_error = dlerror();
56 return FALSE;
59 // save the filename
60 m_filename = filename;
61 m_done_query = FALSE;
62 m_func = func;
64 // if not lazy, do it
65 if( !lazy && !this->query() )
66 return FALSE;
68 return TRUE;
74 //-----------------------------------------------------------------------------
75 // name: load()
76 // desc: load dynamic link library
77 //-----------------------------------------------------------------------------
78 t_CKBOOL Chuck_DLL::load( f_ck_query query_func, t_CKBOOL lazy )
80 m_query_func = query_func;
81 m_done_query = FALSE;
82 m_func = "ck_query";
84 // if not lazy, do it
85 if( !lazy && !this->query() )
86 return FALSE;
88 return TRUE;
94 //-----------------------------------------------------------------------------
95 // name: good()
96 // desc: ...
97 //-----------------------------------------------------------------------------
98 t_CKBOOL Chuck_DLL::good() const
100 return ( m_handle != NULL || m_query_func != NULL );
106 //-----------------------------------------------------------------------------
107 // name: query()
108 // desc: ...
109 //-----------------------------------------------------------------------------
110 const Chuck_DL_Query * Chuck_DLL::query( )
112 if( !m_handle && !m_query_func )
114 m_last_error = "dynamic link library not loaded for query...";
115 return NULL;
118 // return if there already
119 if( m_done_query )
120 return &m_query;
122 // get the address of the query function from the DLL
123 if( !m_query_func )
124 m_query_func = (f_ck_query)this->get_addr( m_func.c_str() );
125 if( !m_query_func )
126 m_query_func = (f_ck_query)this->get_addr( (string("_")+m_func).c_str() );
127 if( !m_query_func )
129 m_last_error = string("no query function found in dll '")
130 + m_filename + string("'");
131 return NULL;
134 // get the address of the attach function from the DLL
135 if( !m_attach_func )
136 m_attach_func = (f_ck_attach)this->get_addr( "ck_attach" );
137 if( !m_attach_func )
138 m_attach_func = (f_ck_attach)this->get_addr( "_ck_attach" );
140 // get the address of the detach function from the DLL
141 if( !m_detach_func )
142 m_detach_func = (f_ck_detach)this->get_addr( "ck_detach" );
143 if( !m_detach_func )
144 m_detach_func = (f_ck_detach)this->get_addr( "_ck_detach" );
146 // do the query
147 m_query.clear();
148 if( !m_query_func( &m_query ) )
150 m_last_error = string("unsuccessful query in dll '") + m_filename
151 + string("'");
152 return NULL;
155 // load the proto table
156 Chuck_DL_Proto * proto;
157 m_name2proto.clear();
158 for( t_CKUINT i = 0; i < m_query.dll_exports.size(); i++ )
160 proto = &m_query.dll_exports[i];
161 if( m_name2proto[proto->name] )
163 m_last_error = string("duplicate export name '") + proto->name
164 + string("'");
165 return NULL;
168 // get the addr
169 if( !proto->addr )
170 proto->addr = (f_ck_func)this->get_addr( (char *)proto->name.c_str() );
171 if( !proto->addr )
173 m_last_error = string("no addr associated with export '") +
174 proto->name + string("'");
175 return NULL;
178 // put in the lookup table
179 m_name2proto[proto->name] = proto;
182 // load the proto table
183 Chuck_UGen_Info * info;
184 m_name2ugen.clear();
185 for( t_CKUINT j = 0; j < m_query.ugen_exports.size(); j++ )
187 info = &m_query.ugen_exports[j];
188 if( m_name2ugen[info->name] )
190 m_last_error = string("duplicate export ugen name '") + info->name
191 + string("'");
192 return NULL;
195 // put in the lookup table
196 m_name2ugen[info->name] = info;
199 m_done_query = TRUE;
201 // call attach
202 if( m_attach_func ) m_attach_func( 0, NULL );
204 return &m_query;
210 //-----------------------------------------------------------------------------
211 // name: unload()
212 // desc: ...
213 //-----------------------------------------------------------------------------
214 t_CKBOOL Chuck_DLL::unload()
216 if( !m_handle && !m_query_func )
218 m_last_error = "cannot unload dynamic library - nothing open...";
219 return FALSE;
222 if( m_detach_func ) m_detach_func( 0, NULL );
224 if( m_handle )
226 dlclose( m_handle );
227 m_handle = NULL;
229 else
230 m_query_func = NULL;
232 return TRUE;
238 //-----------------------------------------------------------------------------
239 // name: get_addr()
240 // desc: ...
241 //-----------------------------------------------------------------------------
242 void * Chuck_DLL::get_addr( const char * symbol )
244 if( !m_handle )
246 m_last_error = "cannot find addr from dynamic library - nothing open...";
247 return FALSE;
250 return dlsym( m_handle, symbol );
256 //-----------------------------------------------------------------------------
257 // name: proto()
258 // desc: ...
259 //-----------------------------------------------------------------------------
260 const Chuck_DL_Proto * Chuck_DLL::proto( const char * symbol )
262 if( !m_handle && !m_query_func )
264 m_last_error = "cannot find proto from dynamic library - nothing open...";
265 return NULL;
268 // get the proto from the hash
269 Chuck_DL_Proto * proto = m_name2proto[symbol];
270 if( !proto )
272 m_last_error = string("no prototype function '") + string(symbol)
273 + string("' found");
274 return NULL;
277 return proto;
283 //-----------------------------------------------------------------------------
284 // name: last_error()
285 // desc: ...
286 //-----------------------------------------------------------------------------
287 const char * Chuck_DLL::last_error() const
289 return m_last_error.c_str();
295 //-----------------------------------------------------------------------------
296 // name: Chuck_DL_Query
297 // desc: ...
298 //-----------------------------------------------------------------------------
299 Chuck_DL_Query::Chuck_DL_Query( )
300 { add_export = __ck_addexport; add_param = __ck_addparam;
301 ugen_add = __ck_ugen_add; ugen_func = __ck_ugen_func;
302 ugen_ctrl = __ck_ugen_ctrl; set_name = __ck_setname;
303 ugen_extends = __ck_ugen_extends; // XXX - pld
304 dll_name = "[noname]"; reserved = NULL;
306 #ifndef __CKDL_NO_BBQ__
307 srate = Digitalio::sampling_rate() ; bufsize = Digitalio::buffer_size();
308 #else
309 srate = 0; bufsize = 0;
310 #endif
312 ugen_exports.resize( 128 );
313 linepos = 0;
319 // add proto
320 extern "C" void CK_DLL_CALL __ck_addexport( Chuck_DL_Query * query,
321 const char * type, const char * name, f_ck_func addr,
322 t_CKBOOL is_func )
323 { query->dll_exports.push_back( Chuck_DL_Proto( type, name, (void *)addr, is_func ) ); }
325 // add param
326 extern "C" void CK_DLL_CALL __ck_addparam( Chuck_DL_Query * query,
327 const char * type, const char * name )
328 { if( query->dll_exports.size() )
329 query->dll_exports[query->dll_exports.size()-1].add_param( type, name ); }
331 // add ugen
332 extern "C" void CK_DLL_CALL __ck_ugen_add( Chuck_DL_Query * query,
333 const char * name, void * reserved )
334 { query->ugen_exports.push_back( Chuck_UGen_Info( name ) );
335 query->reserved = reserved; }
337 // set funcs
338 extern "C" void CK_DLL_CALL __ck_ugen_func( Chuck_DL_Query * query,
339 f_ctor c, f_dtor d, f_tick t, f_pmsg p )
340 { if( query->ugen_exports.size() )
341 query->ugen_exports[query->ugen_exports.size()-1].set( c, d, t, p ); }
343 // add ctrl
344 extern "C" void CK_DLL_CALL __ck_ugen_ctrl( Chuck_DL_Query * query,
345 f_ctrl c, f_cget g, const char * t, const char * n )
346 { if( query->ugen_exports.size() )
347 query->ugen_exports[query->ugen_exports.size()-1].add( c, g, t, n ); }
349 //XXX - pld inherit functions from 'parent' ugen
350 extern "C" void CK_DLL_CALL __ck_ugen_extends( Chuck_DL_Query * query,
351 const char * parent )
353 if( query->ugen_exports.size() > 1 )
354 for( int i= 0 ; i < query->ugen_exports.size() - 1 ; i++ )
355 if( strcmp ( parent, query->ugen_exports[i].name.c_str() ) == 0 )
357 query->ugen_exports[query->ugen_exports.size()-1].inherit(
358 &(query->ugen_exports[i]) );
359 return;
364 // set name
365 extern "C" void CK_DLL_CALL __ck_setname( Chuck_DL_Query * query,
366 const char * name )
367 { query->dll_name = name; }
369 // windows
370 #if defined(__WINDOWS_DS__)
371 extern "C"
373 #include <windows.h>
375 void *dlopen( const char *path, int mode)
377 return (void *)LoadLibrary(path);
380 int dlclose( void *handle)
382 FreeLibrary((HMODULE)handle);
383 return 1;
386 void *dlsym( void * handle, const char *symbol )
388 return (void *)GetProcAddress((HMODULE)handle, symbol);
391 const char * dlerror( void )
393 int error = GetLastError();
394 if( error == 0 ) return NULL;
395 sprintf( dlerror_buffer, "%i", error );
396 return dlerror_buffer;
399 #endif
401 // mac os x
402 #if defined(__MACOSX_CORE__) && MAC_OS_X_VERSION_MAX_ALLOWED <= 1030
404 extern "C"
407 #include <stdio.h>
408 #include <stdlib.h>
409 #include <string.h>
410 #include <errno.h>
411 #include <sys/types.h>
412 #include <sys/stat.h>
413 #include <limits.h>
414 #include "mach-o/dyld.h"
417 * debugging macros
419 #if DEBUG > 0
420 #define DEBUG_PRINT(format) fprintf(stderr,(format));fflush(stderr)
421 #define DEBUG_PRINT1(format,arg1) fprintf(stderr,(format),(arg1));\
422 fflush(stderr)
423 #define DEBUG_PRINT2(format,arg1,arg2) fprintf(stderr,(format),\
424 (arg1),(arg2));fflush(stderr)
425 #define DEBUG_PRINT3(format,arg1,arg2,arg3) fprintf(stderr,(format),\
426 (arg1),(arg2),(arg3));fflush(stderr)
427 #else
428 #define DEBUG_PRINT(format) /**/
429 #define DEBUG_PRINT1(format,arg1) /**/
430 #define DEBUG_PRINT2(format,arg1,arg2) /**/
431 #define DEBUG_PRINT3(format,arg1,arg2,arg3) /**/
432 #undef DEBUG
433 #endif
436 * The structure of a dlopen() handle.
438 struct dlopen_handle {
439 dev_t dev; /* the path's device and inode number from stat(2) */
440 ino_t ino;
441 int dlopen_mode; /* current dlopen mode for this handle */
442 int dlopen_count; /* number of times dlopen() called on this handle */
443 NSModule module; /* the NSModule returned by NSLinkModule() */
444 struct dlopen_handle *prev;
445 struct dlopen_handle *next;
447 static struct dlopen_handle *dlopen_handles = NULL;
448 static const struct dlopen_handle main_program_handle = {NULL};
449 static char *dlerror_pointer = NULL;
452 * NSMakePrivateModulePublic() is not part of the public dyld API so we define
453 * it here. The internal dyld function pointer for
454 * __dyld_NSMakePrivateModulePublic is returned so thats all that maters to get
455 * the functionality need to implement the dlopen() interfaces.
457 static
459 NSMakePrivateModulePublic(
460 NSModule module)
462 static int (*p)(NSModule module) = NULL;
464 if(p == NULL)
465 _dyld_func_lookup("__dyld_NSMakePrivateModulePublic",
466 (unsigned long *)&p);
467 if(p == NULL){
468 #ifdef DEBUG
469 printf("_dyld_func_lookup of __dyld_NSMakePrivateModulePublic "
470 "failed\n");
471 #endif
472 return(FALSE);
474 return(p(module));
478 * helper routine: search for a named module in various locations
480 static
482 _dl_search_paths(
483 const char *filename,
484 char *pathbuf,
485 struct stat *stat_buf)
487 const char *pathspec;
488 const char *element;
489 const char *p;
490 char *q;
491 char *pathbuf_end;
492 const char *envvars[] = {
493 "$DYLD_LIBRARY_PATH",
494 "$LD_LIBRARY_PATH",
495 "/usr/lib:/lib",
496 NULL };
497 int envvar_index;
499 pathbuf_end = pathbuf + PATH_MAX - 8;
501 for(envvar_index = 0; envvars[envvar_index]; envvar_index++){
502 if(envvars[envvar_index][0] == '$'){
503 pathspec = getenv(envvars[envvar_index]+1);
505 else {
506 pathspec = envvars[envvar_index];
509 if(pathspec != NULL){
510 element = pathspec;
511 while(*element){
512 /* extract path list element */
513 p = element;
514 q = pathbuf;
515 while(*p && *p != ':' && q < pathbuf_end) *q++ = *p++;
516 if(q == pathbuf){ /* empty element */
517 if(*p){
518 element = p+1;
519 continue;
521 break;
523 if (*p){
524 element = p+1;
526 else{
527 element = p; /* this terminates the loop */
530 /* add slash if neccessary */
531 if(*(q-1) != '/' && q < pathbuf_end){
532 *q++ = '/';
535 /* append module name */
536 p = filename;
537 while(*p && q < pathbuf_end) *q++ = *p++;
538 *q++ = 0;
540 if(q >= pathbuf_end){
541 /* maybe add an error message here */
542 break;
545 if(stat(pathbuf, stat_buf) == 0){
546 return 0;
552 /* we have searched everywhere, now we give up */
553 return -1;
557 * dlopen() the MacOS X version of the FreeBSD dlopen() interface.
559 void *
560 dlopen(
561 const char *path,
562 int mode)
564 const char *module_path;
565 void *retval;
566 struct stat stat_buf;
567 NSObjectFileImage objectFileImage;
568 NSObjectFileImageReturnCode ofile_result_code;
569 NSModule module;
570 struct dlopen_handle *p;
571 unsigned long options;
572 NSSymbol NSSymbol;
573 void (*init)(void);
574 char pathbuf[PATH_MAX];
576 DEBUG_PRINT2("libdl: dlopen(%s,0x%x) -> ", path, (unsigned int)mode);
578 dlerror_pointer = NULL;
580 * A NULL path is to indicate the caller wants a handle for the
581 * main program.
583 if(path == NULL){
584 retval = (void *)&main_program_handle;
585 DEBUG_PRINT1("main / %p\n", retval);
586 return(retval);
589 /* see if the path exists and if so get the device and inode number */
590 if(stat(path, &stat_buf) == -1){
591 dlerror_pointer = strerror(errno);
593 if(path[0] == '/'){
594 DEBUG_PRINT1("ERROR (stat): %s\n", dlerror_pointer);
595 return(NULL);
598 /* search for the module in various places */
599 if(_dl_search_paths(path, pathbuf, &stat_buf)){
600 /* dlerror_pointer is unmodified */
601 DEBUG_PRINT1("ERROR (stat): %s\n", dlerror_pointer);
602 return(NULL);
604 DEBUG_PRINT1("found %s -> ", pathbuf);
605 module_path = pathbuf;
606 dlerror_pointer = NULL;
608 else{
609 module_path = path;
613 * If we don't want an unshared handle see if we already have a handle
614 * for this path.
616 if((mode & RTLD_UNSHARED) != RTLD_UNSHARED){
617 p = dlopen_handles;
618 while(p != NULL){
619 if(p->dev == stat_buf.st_dev && p->ino == stat_buf.st_ino){
620 /* skip unshared handles */
621 if((p->dlopen_mode & RTLD_UNSHARED) == RTLD_UNSHARED)
622 continue;
624 * We have already created a handle for this path. The
625 * caller might be trying to promote an RTLD_LOCAL handle
626 * to a RTLD_GLOBAL. Or just looking it up with
627 * RTLD_NOLOAD.
629 if((p->dlopen_mode & RTLD_LOCAL) == RTLD_LOCAL &&
630 (mode & RTLD_GLOBAL) == RTLD_GLOBAL){
631 /* promote the handle */
632 if(NSMakePrivateModulePublic(p->module) == TRUE){
633 p->dlopen_mode &= ~RTLD_LOCAL;
634 p->dlopen_mode |= RTLD_GLOBAL;
635 p->dlopen_count++;
636 DEBUG_PRINT1("%p\n", p);
637 return(p);
639 else{
640 dlerror_pointer = "can't promote handle from "
641 "RTLD_LOCAL to RTLD_GLOBAL";
642 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
643 return(NULL);
646 p->dlopen_count++;
647 DEBUG_PRINT1("%p\n", p);
648 return(p);
650 p = p->next;
655 * We do not have a handle for this path if we were just trying to
656 * look it up return NULL to indicate we don't have it.
658 if((mode & RTLD_NOLOAD) == RTLD_NOLOAD){
659 dlerror_pointer = "no existing handle for path RTLD_NOLOAD test";
660 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
661 return(NULL);
664 /* try to create an object file image from this path */
665 ofile_result_code = NSCreateObjectFileImageFromFile(module_path,
666 &objectFileImage);
667 if(ofile_result_code != NSObjectFileImageSuccess){
668 switch(ofile_result_code){
669 case NSObjectFileImageFailure:
670 dlerror_pointer = "object file setup failure";
671 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
672 return(NULL);
673 case NSObjectFileImageInappropriateFile:
674 dlerror_pointer = "not a Mach-O MH_BUNDLE file type";
675 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
676 return(NULL);
677 case NSObjectFileImageArch:
678 dlerror_pointer = "no object for this architecture";
679 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
680 return(NULL);
681 case NSObjectFileImageFormat:
682 dlerror_pointer = "bad object file format";
683 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
684 return(NULL);
685 case NSObjectFileImageAccess:
686 dlerror_pointer = "can't read object file";
687 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
688 return(NULL);
689 default:
690 dlerror_pointer = "unknown error from "
691 "NSCreateObjectFileImageFromFile()";
692 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
693 return(NULL);
697 /* try to link in this object file image */
698 options = NSLINKMODULE_OPTION_PRIVATE;
699 if((mode & RTLD_NOW) == RTLD_NOW)
700 options |= NSLINKMODULE_OPTION_BINDNOW;
701 module = NSLinkModule(objectFileImage, module_path, options);
702 NSDestroyObjectFileImage(objectFileImage) ;
703 if(module == NULL){
704 dlerror_pointer = "NSLinkModule() failed for dlopen()";
705 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
706 return(NULL);
710 * If the handle is to be global promote the handle. It is done this
711 * way to avoid multiply defined symbols.
713 if((mode & RTLD_GLOBAL) == RTLD_GLOBAL){
714 if(NSMakePrivateModulePublic(module) == FALSE){
715 dlerror_pointer = "can't promote handle from RTLD_LOCAL to "
716 "RTLD_GLOBAL";
717 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
718 return(NULL);
722 p = (dlopen_handle *)malloc(sizeof(struct dlopen_handle));
723 if(p == NULL){
724 dlerror_pointer = "can't allocate memory for the dlopen handle";
725 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
726 return(NULL);
729 /* fill in the handle */
730 p->dev = stat_buf.st_dev;
731 p->ino = stat_buf.st_ino;
732 if(mode & RTLD_GLOBAL)
733 p->dlopen_mode = RTLD_GLOBAL;
734 else
735 p->dlopen_mode = RTLD_LOCAL;
736 p->dlopen_mode |= (mode & RTLD_UNSHARED) |
737 (mode & RTLD_NODELETE) |
738 (mode & RTLD_LAZY_UNDEF);
739 p->dlopen_count = 1;
740 p->module = module;
741 p->prev = NULL;
742 p->next = dlopen_handles;
743 if(dlopen_handles != NULL)
744 dlopen_handles->prev = p;
745 dlopen_handles = p;
747 /* call the init function if one exists */
748 NSSymbol = NSLookupSymbolInModule(p->module, "__init");
749 if(NSSymbol != NULL){
750 init = ( void(*)() )NSAddressOfSymbol(NSSymbol);
751 init();
754 DEBUG_PRINT1("%p\n", p);
755 return(p);
759 * dlsym() the MacOS X version of the FreeBSD dlopen() interface.
761 void *
762 dlsym(
763 void * handle,
764 const char *symbol)
766 struct dlopen_handle *dlopen_handle, *p;
767 NSSymbol NSSymbol;
768 void *address;
770 DEBUG_PRINT2("libdl: dlsym(%p,%s) -> ", handle, symbol);
772 dlopen_handle = (struct dlopen_handle *)handle;
775 * If this is the handle for the main program do a global lookup.
777 if(dlopen_handle == (struct dlopen_handle *)&main_program_handle){
778 if(NSIsSymbolNameDefined(symbol) == TRUE){
779 NSSymbol = NSLookupAndBindSymbol(symbol);
780 address = NSAddressOfSymbol(NSSymbol);
781 dlerror_pointer = NULL;
782 DEBUG_PRINT1("%p\n", address);
783 return(address);
785 else{
786 dlerror_pointer = "symbol not found";
787 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
788 return(NULL);
793 * Find this handle and do a lookup in just this module.
795 p = dlopen_handles;
796 while(p != NULL){
797 if(dlopen_handle == p){
798 NSSymbol = NSLookupSymbolInModule(p->module, symbol);
799 if(NSSymbol != NULL){
800 address = NSAddressOfSymbol(NSSymbol);
801 dlerror_pointer = NULL;
802 DEBUG_PRINT1("%p\n", address);
803 return(address);
805 else{
806 dlerror_pointer = "symbol not found";
807 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
808 return(NULL);
811 p = p->next;
814 dlerror_pointer = "bad handle passed to dlsym()";
815 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
816 return(NULL);
820 * dlerror() the MacOS X version of the FreeBSD dlopen() interface.
822 const char *
823 dlerror(
824 void)
826 const char *p;
828 p = (const char *)dlerror_pointer;
829 dlerror_pointer = NULL;
830 return(p);
834 * dlclose() the MacOS X version of the FreeBSD dlopen() interface.
837 dlclose(
838 void * handle)
840 struct dlopen_handle *p, *q;
841 unsigned long options;
842 NSSymbol NSSymbol;
843 void (*fini)(void);
845 DEBUG_PRINT1("libdl: dlclose(%p) -> ", handle);
847 dlerror_pointer = NULL;
848 q = (struct dlopen_handle *)handle;
849 p = dlopen_handles;
850 while(p != NULL){
851 if(p == q){
852 /* if the dlopen() count is not zero we are done */
853 p->dlopen_count--;
854 if(p->dlopen_count != 0){
855 DEBUG_PRINT("OK");
856 return(0);
859 /* call the fini function if one exists */
860 NSSymbol = NSLookupSymbolInModule(p->module, "__fini");
861 if(NSSymbol != NULL){
862 fini = ( void(*)() )NSAddressOfSymbol(NSSymbol);
863 fini();
866 /* unlink the module for this handle */
867 options = 0;
868 if(p->dlopen_mode & RTLD_NODELETE)
869 options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
870 if(p->dlopen_mode & RTLD_LAZY_UNDEF)
871 options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
872 if(NSUnLinkModule(p->module, options) == FALSE){
873 dlerror_pointer = "NSUnLinkModule() failed for dlclose()";
874 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
875 return(-1);
877 if(p->prev != NULL)
878 p->prev->next = p->next;
879 if(p->next != NULL)
880 p->next->prev = p->prev;
881 if(dlopen_handles == p)
882 dlopen_handles = p->next;
883 free(p);
884 DEBUG_PRINT("OK");
885 return(0);
887 p = p->next;
889 dlerror_pointer = "invalid handle passed to dlclose()";
890 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
891 return(-1);
896 #else
898 // do nothing, it's all in dlfcn
900 #endif