*** empty log message ***
[chuck-blob.git] / v2 / chuck_dl.cpp
blobc77aa0e0927ee24db771fb5879dca1d5709a1626
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 // Ari Lazier (alazier@cs.princeton.edu)
32 // mac os code based on apple's open source
34 // date: spring 2004 - 1.1
35 // spring 2005 - 1.2
36 //-----------------------------------------------------------------------------
37 #include "chuck_dl.h"
38 #include "chuck_errmsg.h"
39 #include "chuck_bbq.h"
40 using namespace std;
45 //-----------------------------------------------------------------------------
46 // internal implementation of query functions
47 //-----------------------------------------------------------------------------
52 //-----------------------------------------------------------------------------
53 // name: ck_setname()
54 // desc: set the name of the module
55 //-----------------------------------------------------------------------------
56 void CK_DLL_CALL ck_setname( Chuck_DL_Query * query, const char * name )
58 // set the name
59 query->dll_name = name;
65 //-----------------------------------------------------------------------------
66 // name: ck_begin_class()
67 // desc: begin class/namespace, can be nexted
68 //-----------------------------------------------------------------------------
69 void CK_DLL_CALL ck_begin_class( Chuck_DL_Query * query, const char * name, const char * parent )
71 // push
72 query->stack.push_back( query->curr_class );
73 // allocate
74 Chuck_DL_Class * c = new Chuck_DL_Class;
76 // add class
77 if( query->curr_class )
78 // recursive
79 query->curr_class->classes.push_back( c );
80 else
81 // first level
82 query->classes.push_back( c );
84 // remember info
85 c->name = name;
86 c->parent = parent;
88 // curr
89 query->curr_class = c;
90 query->curr_func = NULL;
96 //-----------------------------------------------------------------------------
97 // name: ck_add_ctor()
98 // desc: add constructor, can be followed by add_arg
99 //-----------------------------------------------------------------------------
100 void CK_DLL_CALL ck_add_ctor( Chuck_DL_Query * query, f_ctor ctor )
102 // make sure there is class
103 if( !query->curr_class )
105 // error
106 EM_error2( 0, "class import: add_ctor invoked without begin_class..." );
107 return;
110 // allocate
111 Chuck_DL_Func * f = new Chuck_DL_Func;
112 f->name = "[ctor]";
113 f->type = "void";
114 f->ctor = ctor;
116 // add
117 query->curr_class->ctors.push_back( f );
118 query->curr_func = f;
124 //-----------------------------------------------------------------------------
125 // name: ck_add_dtor()
126 // add destructor, no args allowed
127 //-----------------------------------------------------------------------------
128 void CK_DLL_CALL ck_add_dtor( Chuck_DL_Query * query, f_dtor dtor )
130 // make sure there is class
131 if( !query->curr_class )
133 // error
134 EM_error2( 0, "class import: add_dtor invoked without begin_class..." );
135 return;
138 // make sure there are no duplicates
139 if( query->curr_class->dtor )
141 // error
142 EM_error2( 0, "class import: multiple dtor added ..." );
143 return;
146 // allocate
147 Chuck_DL_Func * f = new Chuck_DL_Func;
148 f->name = "[dtor]";
149 f->type = "void";
150 f->dtor = dtor;
152 // add
153 query->curr_class->dtor = f;
154 // set
155 query->curr_func = NULL;
161 //-----------------------------------------------------------------------------
162 // name: ck_add_mfun()
163 // desc: add member function, can be followed by add_arg
164 //-----------------------------------------------------------------------------
165 void CK_DLL_CALL ck_add_mfun( Chuck_DL_Query * query, f_mfun addr,
166 const char * type, const char * name )
168 // make sure there is class
169 if( !query->curr_class )
171 // error
172 EM_error2( 0, "class import: add_mfun invoked without begin_class..." );
173 return;
176 // allocate
177 Chuck_DL_Func * f = new Chuck_DL_Func;
178 f->name = name;
179 f->type = type;
180 f->mfun = addr;
182 // add
183 query->curr_class->mfuns.push_back( f );
184 query->curr_func = f;
190 //-----------------------------------------------------------------------------
191 // name: ck_add_sfun()
192 // desc: add static function, can be followed by add_arg
193 //-----------------------------------------------------------------------------
194 void CK_DLL_CALL ck_add_sfun( Chuck_DL_Query * query, f_sfun addr,
195 const char * type, const char * name )
197 // make sure there is class
198 if( !query->curr_class )
200 // error
201 EM_error2( 0, "class import: add_sfun invoked without begin_class..." );
202 return;
205 // allocate
206 Chuck_DL_Func * f = new Chuck_DL_Func;
207 f->name = name;
208 f->type = type;
209 f->sfun = addr;
211 // add
212 query->curr_class->sfuns.push_back( f );
213 query->curr_func = f;
219 //-----------------------------------------------------------------------------
220 // name: ck_add_mvar()
221 // desc: add member var
222 //-----------------------------------------------------------------------------
223 void CK_DLL_CALL ck_add_mvar( Chuck_DL_Query * query, const char * type, const char * name,
224 t_CKBOOL is_const )
226 // make sure there is class
227 if( !query->curr_class )
229 // error
230 EM_error2( 0, "class import: add_mvar invoked without begin_class..." );
231 return;
234 // allocate
235 Chuck_DL_Value * v = new Chuck_DL_Value;
236 v->name = name;
237 v->type = type;
238 v->is_const = is_const;
240 // add
241 query->curr_class->mvars.push_back( v );
242 query->curr_func = NULL;
248 //-----------------------------------------------------------------------------
249 // name: ck_add_svar()
250 // desc: add static var
251 //-----------------------------------------------------------------------------
252 void CK_DLL_CALL ck_add_svar( Chuck_DL_Query * query, const char * type, const char * name,
253 t_CKBOOL is_const, void * addr )
255 // make sure there is class
256 if( !query->curr_class )
258 // error
259 EM_error2( 0, "class import: add_svar invoked without begin_class..." );
260 return;
263 // allocate
264 Chuck_DL_Value * v = new Chuck_DL_Value;
265 v->name = name;
266 v->type = type;
267 v->is_const = is_const;
268 v->static_addr = addr;
270 // add
271 query->curr_class->svars.push_back( v );
272 query->curr_func = NULL;
278 //-----------------------------------------------------------------------------
279 // name: ck_add_arg()
280 // desc: add argument to function
281 //-----------------------------------------------------------------------------
282 void CK_DLL_CALL ck_add_arg( Chuck_DL_Query * query, const char * type, const char * name )
284 // make sure there is class
285 if( !query->curr_class )
287 // error
288 EM_error2( 0, "class import: add_arg invoked without begin_class..." );
289 return;
292 // make sure there is function
293 if( !query->curr_func )
295 // error
296 EM_error2( 0, "class import: add_arg can only follow 'ctor', 'mfun', 'sfun', 'arg'..." );
297 return;
300 // allocate
301 Chuck_DL_Value * v = new Chuck_DL_Value;
302 v->name = name;
303 v->type = type;
305 // add
306 query->curr_func->args.push_back( v );
312 //-----------------------------------------------------------------------------
313 // name: ck_add_ugen_func()
314 // desc: (ugen only) add tick and pmsg functions
315 //-----------------------------------------------------------------------------
316 void CK_DLL_CALL ck_add_ugen_func( Chuck_DL_Query * query, f_tick ugen_tick, f_pmsg ugen_pmsg )
318 // make sure there is class
319 if( !query->curr_class )
321 // error
322 EM_error2( 0, "class import: add_ugen_func invoked without begin_class..." );
323 return;
326 // make sure tick not defined already
327 if( query->curr_class->ugen_tick && ugen_tick )
329 // error
330 EM_error2( 0, "class import: ugen_tick already defined..." );
331 return;
334 // make sure pmsg not defined already
335 if( query->curr_class->ugen_pmsg && ugen_pmsg )
337 // error
338 EM_error2( 0, "class import: ugen_pmsg already defined..." );
339 return;
342 // set
343 if( ugen_tick ) query->curr_class->ugen_tick = ugen_tick;
344 if( ugen_pmsg ) query->curr_class->ugen_pmsg = ugen_pmsg;
345 query->curr_func = NULL;
351 //-----------------------------------------------------------------------------
352 // name: ck_add_ugen_ctrl()
353 // desc: (ugen only) add ctrl parameters
354 //-----------------------------------------------------------------------------
355 void CK_DLL_CALL ck_add_ugen_ctrl( Chuck_DL_Query * query, f_ctrl ugen_ctrl, f_cget ugen_cget,
356 const char * type, const char * name )
358 // make sure there is class
359 if( !query->curr_class )
361 // error
362 EM_error2( 0, "class import: add_ugen_func invoked without begin_class..." );
363 return;
366 // allocate
367 Chuck_DL_Ctrl * c = new Chuck_DL_Ctrl;
368 c->name = name;
369 c->type = type;
370 c->ctrl = ugen_ctrl;
371 c->cget = ugen_cget;
373 // set
374 query->curr_func = NULL;
380 //-----------------------------------------------------------------------------
381 // name: ck_end_class()
382 // desc: end class/namespace, compile it
383 //-----------------------------------------------------------------------------
384 t_CKBOOL CK_DLL_CALL ck_end_class( Chuck_DL_Query * query )
386 // make sure there is class
387 if( !query->curr_class )
389 // error
390 EM_error2( 0, "class import: end_class invoked without begin_class..." );
391 return FALSE;
394 // type check the class?
396 // pop
397 assert( query->stack.size() );
398 query->curr_class = query->stack.back();
399 query->stack.pop_back();
401 return TRUE;
407 //------------------------------------------------------------------------------
408 // alternative functions to make stuff
409 //------------------------------------------------------------------------------
410 Chuck_DL_Func * make_new_mfun( const char * t, const char * n, f_mfun mfun )
411 { return new Chuck_DL_Func( t, n, (t_CKUINT)mfun ); }
412 Chuck_DL_Func * make_new_sfun( const char * t, const char * n, f_sfun sfun )
413 { return new Chuck_DL_Func( t, n, (t_CKUINT)sfun ); }
414 Chuck_DL_Value * make_new_arg( const char * t, const char * n )
415 { return new Chuck_DL_Value( t, n ); }
416 Chuck_DL_Value * make_new_mvar( const char * t, const char * n, t_CKBOOL c )
417 { return new Chuck_DL_Value( t, n, c ); }
418 Chuck_DL_Value * make_new_svar( const char * t, const char * n, t_CKBOOL c, void * a )
419 { return new Chuck_DL_Value( t, n, c, a ); }
424 //-----------------------------------------------------------------------------
425 // name: load()
426 // desc: load dynamic link library
427 //-----------------------------------------------------------------------------
428 t_CKBOOL Chuck_DLL::load( const char * filename, const char * func, t_CKBOOL lazy )
430 // open
431 m_handle = dlopen( filename, lazy ? RTLD_LAZY : RTLD_NOW );
433 // still not there
434 if( !m_handle )
436 m_last_error = dlerror();
437 return FALSE;
440 // save the filename
441 m_filename = filename;
442 m_done_query = FALSE;
443 m_func = func;
445 // if not lazy, do it
446 if( !lazy && !this->query() )
447 return FALSE;
449 return TRUE;
455 //-----------------------------------------------------------------------------
456 // name: load()
457 // desc: load dynamic link library
458 //-----------------------------------------------------------------------------
459 t_CKBOOL Chuck_DLL::load( f_ck_query query_func, t_CKBOOL lazy )
461 m_query_func = query_func;
462 m_done_query = FALSE;
463 m_func = "ck_query";
465 // if not lazy, do it
466 if( !lazy && !this->query() )
467 return FALSE;
469 return TRUE;
475 //-----------------------------------------------------------------------------
476 // name: good()
477 // desc: ...
478 //-----------------------------------------------------------------------------
479 t_CKBOOL Chuck_DLL::good() const
481 return ( m_handle != NULL || m_query_func != NULL );
487 //-----------------------------------------------------------------------------
488 // name: query()
489 // desc: ...
490 //-----------------------------------------------------------------------------
491 const Chuck_DL_Query * Chuck_DLL::query( )
493 if( !m_handle && !m_query_func )
495 m_last_error = "dynamic link library not loaded for query...";
496 return NULL;
499 // return if there already
500 if( m_done_query )
501 return &m_query;
503 // get the address of the query function from the DLL
504 if( !m_query_func )
505 m_query_func = (f_ck_query)this->get_addr( m_func.c_str() );
506 if( !m_query_func )
507 m_query_func = (f_ck_query)this->get_addr( (string("_")+m_func).c_str() );
508 if( !m_query_func )
510 m_last_error = string("no query function found in dll '")
511 + m_filename + string("'");
512 return NULL;
515 // get the address of the attach function from the DLL
516 /* if( !m_attach_func )
517 m_attach_func = (f_ck_attach)this->get_addr( "ck_attach" );
518 if( !m_attach_func )
519 m_attach_func = (f_ck_attach)this->get_addr( "_ck_attach" );
521 // get the address of the detach function from the DLL
522 if( !m_detach_func )
523 m_detach_func = (f_ck_detach)this->get_addr( "ck_detach" );
524 if( !m_detach_func )
525 m_detach_func = (f_ck_detach)this->get_addr( "_ck_detach" ); */
527 // do the query
528 m_query.clear();
529 if( !m_query_func( &m_query ) )
531 m_last_error = string("unsuccessful query in dll '") + m_filename
532 + string("'");
533 return NULL;
536 // load the proto table
537 /* Chuck_DL_Proto * proto;
538 m_name2proto.clear();
539 for( t_CKUINT i = 0; i < m_query.dll_exports.size(); i++ )
541 proto = &m_query.dll_exports[i];
542 if( m_name2proto[proto->name] )
544 m_last_error = string("duplicate export name '") + proto->name
545 + string("'");
546 return NULL;
549 // get the addr
550 if( !proto->addr )
551 proto->addr = (f_ck_func)this->get_addr( (char *)proto->name.c_str() );
552 if( !proto->addr )
554 m_last_error = string("no addr associated with export '") +
555 proto->name + string("'");
556 return NULL;
559 // put in the lookup table
560 m_name2proto[proto->name] = proto;
563 // load the proto table
564 Chuck_UGen_Info * info;
565 m_name2ugen.clear();
566 for( t_CKUINT j = 0; j < m_query.ugen_exports.size(); j++ )
568 info = &m_query.ugen_exports[j];
569 if( m_name2ugen[info->name] )
571 m_last_error = string("duplicate export ugen name '") + info->name
572 + string("'");
573 return NULL;
576 // put in the lookup table
577 m_name2ugen[info->name] = info;
580 m_done_query = TRUE;
582 // call attach
583 // if( m_attach_func ) m_attach_func( 0, NULL );
585 return &m_query;
591 //-----------------------------------------------------------------------------
592 // name: unload()
593 // desc: ...
594 //-----------------------------------------------------------------------------
595 t_CKBOOL Chuck_DLL::unload()
597 if( !m_handle && !m_query_func )
599 m_last_error = "cannot unload dynamic library - nothing open...";
600 return FALSE;
603 // if( m_detach_func ) m_detach_func( 0, NULL );
605 if( m_handle )
607 dlclose( m_handle );
608 m_handle = NULL;
610 else
611 m_query_func = NULL;
613 return TRUE;
619 //-----------------------------------------------------------------------------
620 // name: get_addr()
621 // desc: ...
622 //-----------------------------------------------------------------------------
623 void * Chuck_DLL::get_addr( const char * symbol )
625 if( !m_handle )
627 m_last_error = "cannot find addr from dynamic library - nothing open...";
628 return FALSE;
631 return dlsym( m_handle, symbol );
637 //-----------------------------------------------------------------------------
638 // name: last_error()
639 // desc: ...
640 //-----------------------------------------------------------------------------
641 const char * Chuck_DLL::last_error() const
643 return m_last_error.c_str();
649 //-----------------------------------------------------------------------------
650 // name: name()
651 // desc: ...
652 //-----------------------------------------------------------------------------
653 const char * Chuck_DLL::name() const
655 return m_id.c_str();
661 //-----------------------------------------------------------------------------
662 // name: Chuck_DL_Query
663 // desc: ...
664 //-----------------------------------------------------------------------------
665 Chuck_DL_Query::Chuck_DL_Query( )
667 // set the pointers to functions so the module can call
668 setname = ck_setname;
669 begin_class = ck_begin_class;
670 add_ctor = ck_add_ctor;
671 add_dtor = ck_add_dtor;
672 add_mfun = ck_add_mfun;
673 add_sfun = ck_add_sfun;
674 add_mvar = ck_add_mvar;
675 add_svar = ck_add_svar;
676 add_arg = ck_add_arg;
677 add_ugen_func = ck_add_ugen_func;
678 add_ugen_ctrl = ck_add_ugen_ctrl;
679 end_class = ck_end_class;
680 dll_name = "[noname]";
681 reserved = NULL;
682 curr_class = NULL;
683 curr_func = NULL;
685 #ifndef __CKDL_NO_BBQ__
686 srate = Digitalio::sampling_rate() ; bufsize = Digitalio::buffer_size();
687 #else
688 srate = 0; bufsize = 0;
689 #endif
691 linepos = 0;
697 //-----------------------------------------------------------------------------
698 // name: clear()
699 // desc: ...
700 //-----------------------------------------------------------------------------
701 void Chuck_DL_Query::clear()
703 // set to 0
704 dll_name = "[noname]";
705 // line pos
706 linepos = 0;
707 // delete classes
708 for( t_CKUINT i = 0; i < classes.size(); i++ ) delete classes[i];
709 // clear
710 classes.clear();
716 //-----------------------------------------------------------------------------
717 // name: ~Chuck_DL_Class()
718 // desc: ...
719 //-----------------------------------------------------------------------------
720 Chuck_DL_Class::~Chuck_DL_Class()
722 t_CKUINT i;
724 // delete mfuns
725 for( i = 0; i < mfuns.size(); i++ ) delete mfuns[i];
726 // delete sfuns
727 for( i = 0; i < sfuns.size(); i++ ) delete sfuns[i];
728 // delete mvars
729 for( i = 0; i < mvars.size(); i++ ) delete mvars[i];
730 // delete svars
731 for( i = 0; i < svars.size(); i++ ) delete svars[i];
732 // delete classes
733 for( i = 0; i < classes.size(); i++ ) delete classes[i];
739 //-----------------------------------------------------------------------------
740 // name: ~Chuck_DL_Func()
741 // desc: ...
742 //-----------------------------------------------------------------------------
743 Chuck_DL_Func::~Chuck_DL_Func()
745 for( t_CKUINT i = 0; i < args.size(); i++ )
746 delete args[i];
752 // windows
753 #if defined(__WINDOWS_DS__)
754 extern "C"
756 #include <windows.h>
758 void *dlopen( const char *path, int mode )
760 return (void *)LoadLibrary(path);
763 int dlclose( void *handle )
765 FreeLibrary((HMODULE)handle);
766 return 1;
769 void *dlsym( void * handle, const char *symbol )
771 return (void *)GetProcAddress((HMODULE)handle, symbol);
774 const char * dlerror( void )
776 int error = GetLastError();
777 if( error == 0 ) return NULL;
778 sprintf( dlerror_buffer, "%i", error );
779 return dlerror_buffer;
782 #endif
784 // mac os x
785 #if defined(__MACOSX_CORE__) && MAC_OS_X_VERSION_MAX_ALLOWED <= 1030
787 extern "C"
790 #include <stdio.h>
791 #include <stdlib.h>
792 #include <string.h>
793 #include <errno.h>
794 #include <sys/types.h>
795 #include <sys/stat.h>
796 #include <limits.h>
797 #include "mach-o/dyld.h"
800 * debugging macros
802 #if DEBUG > 0
803 #define DEBUG_PRINT(format) fprintf(stderr,(format));fflush(stderr)
804 #define DEBUG_PRINT1(format,arg1) fprintf(stderr,(format),(arg1));\
805 fflush(stderr)
806 #define DEBUG_PRINT2(format,arg1,arg2) fprintf(stderr,(format),\
807 (arg1),(arg2));fflush(stderr)
808 #define DEBUG_PRINT3(format,arg1,arg2,arg3) fprintf(stderr,(format),\
809 (arg1),(arg2),(arg3));fflush(stderr)
810 #else
811 #define DEBUG_PRINT(format) /**/
812 #define DEBUG_PRINT1(format,arg1) /**/
813 #define DEBUG_PRINT2(format,arg1,arg2) /**/
814 #define DEBUG_PRINT3(format,arg1,arg2,arg3) /**/
815 #undef DEBUG
816 #endif
819 * The structure of a dlopen() handle.
821 struct dlopen_handle {
822 dev_t dev; /* the path's device and inode number from stat(2) */
823 ino_t ino;
824 int dlopen_mode; /* current dlopen mode for this handle */
825 int dlopen_count; /* number of times dlopen() called on this handle */
826 NSModule module; /* the NSModule returned by NSLinkModule() */
827 struct dlopen_handle *prev;
828 struct dlopen_handle *next;
830 static struct dlopen_handle *dlopen_handles = NULL;
831 static const struct dlopen_handle main_program_handle = {NULL};
832 static char *dlerror_pointer = NULL;
836 * NSMakePrivateModulePublic() is not part of the public dyld API so we define
837 * it here. The internal dyld function pointer for
838 * __dyld_NSMakePrivateModulePublic is returned so thats all that maters to get
839 * the functionality need to implement the dlopen() interfaces.
841 static
843 NSMakePrivateModulePublic(
844 NSModule module)
846 static int (*p)(NSModule module) = NULL;
848 if(p == NULL)
849 _dyld_func_lookup("__dyld_NSMakePrivateModulePublic",
850 (unsigned long *)&p);
852 if(p == NULL){
853 #ifdef DEBUG
854 printf("_dyld_func_lookup of __dyld_NSMakePrivateModulePublic "
855 "failed\n");
856 #endif
857 return(FALSE);
859 return(p(module));
863 * helper routine: search for a named module in various locations
865 static
867 _dl_search_paths(
868 const char *filename,
869 char *pathbuf,
870 struct stat *stat_buf)
872 const char *pathspec;
873 const char *element;
874 const char *p;
875 char *q;
876 char *pathbuf_end;
877 const char *envvars[] = {
878 "$DYLD_LIBRARY_PATH",
879 "$LD_LIBRARY_PATH",
880 "/usr/lib:/lib",
881 NULL };
882 int envvar_index;
884 pathbuf_end = pathbuf + PATH_MAX - 8;
886 for(envvar_index = 0; envvars[envvar_index]; envvar_index++){
887 if(envvars[envvar_index][0] == '$'){
888 pathspec = getenv(envvars[envvar_index]+1);
890 else {
891 pathspec = envvars[envvar_index];
894 if(pathspec != NULL){
895 element = pathspec;
896 while(*element){
897 /* extract path list element */
898 p = element;
899 q = pathbuf;
900 while(*p && *p != ':' && q < pathbuf_end) *q++ = *p++;
901 if(q == pathbuf){ /* empty element */
902 if(*p){
903 element = p+1;
904 continue;
906 break;
908 if (*p){
909 element = p+1;
911 else{
912 element = p; /* this terminates the loop */
915 /* add slash if neccessary */
916 if(*(q-1) != '/' && q < pathbuf_end){
917 *q++ = '/';
920 /* append module name */
921 p = filename;
922 while(*p && q < pathbuf_end) *q++ = *p++;
923 *q++ = 0;
925 if(q >= pathbuf_end){
926 /* maybe add an error message here */
927 break;
930 if(stat(pathbuf, stat_buf) == 0){
931 return 0;
937 /* we have searched everywhere, now we give up */
938 return -1;
942 * dlopen() the MacOS X version of the FreeBSD dlopen() interface.
944 void *
945 dlopen(
946 const char *path,
947 int mode)
949 const char *module_path;
950 void *retval;
951 struct stat stat_buf;
952 NSObjectFileImage objectFileImage;
953 NSObjectFileImageReturnCode ofile_result_code;
954 NSModule module;
955 struct dlopen_handle *p;
956 unsigned long options;
957 NSSymbol NSSymbol;
958 void (*init)(void);
959 char pathbuf[PATH_MAX];
961 DEBUG_PRINT2("libdl: dlopen(%s,0x%x) -> ", path, (unsigned int)mode);
963 dlerror_pointer = NULL;
965 * A NULL path is to indicate the caller wants a handle for the
966 * main program.
968 if(path == NULL){
969 retval = (void *)&main_program_handle;
970 DEBUG_PRINT1("main / %p\n", retval);
971 return(retval);
974 /* see if the path exists and if so get the device and inode number */
975 if(stat(path, &stat_buf) == -1){
976 dlerror_pointer = strerror(errno);
978 if(path[0] == '/'){
979 DEBUG_PRINT1("ERROR (stat): %s\n", dlerror_pointer);
980 return(NULL);
983 /* search for the module in various places */
984 if(_dl_search_paths(path, pathbuf, &stat_buf)){
985 /* dlerror_pointer is unmodified */
986 DEBUG_PRINT1("ERROR (stat): %s\n", dlerror_pointer);
987 return(NULL);
989 DEBUG_PRINT1("found %s -> ", pathbuf);
990 module_path = pathbuf;
991 dlerror_pointer = NULL;
993 else{
994 module_path = path;
998 * If we don't want an unshared handle see if we already have a handle
999 * for this path.
1001 if((mode & RTLD_UNSHARED) != RTLD_UNSHARED){
1002 p = dlopen_handles;
1003 while(p != NULL){
1004 if(p->dev == stat_buf.st_dev && p->ino == stat_buf.st_ino){
1005 /* skip unshared handles */
1006 if((p->dlopen_mode & RTLD_UNSHARED) == RTLD_UNSHARED)
1007 continue;
1009 * We have already created a handle for this path. The
1010 * caller might be trying to promote an RTLD_LOCAL handle
1011 * to a RTLD_GLOBAL. Or just looking it up with
1012 * RTLD_NOLOAD.
1014 if((p->dlopen_mode & RTLD_LOCAL) == RTLD_LOCAL &&
1015 (mode & RTLD_GLOBAL) == RTLD_GLOBAL){
1016 /* promote the handle */
1017 if(NSMakePrivateModulePublic(p->module) == TRUE){
1018 p->dlopen_mode &= ~RTLD_LOCAL;
1019 p->dlopen_mode |= RTLD_GLOBAL;
1020 p->dlopen_count++;
1021 DEBUG_PRINT1("%p\n", p);
1022 return(p);
1024 else{
1025 dlerror_pointer = "can't promote handle from "
1026 "RTLD_LOCAL to RTLD_GLOBAL";
1027 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
1028 return(NULL);
1031 p->dlopen_count++;
1032 DEBUG_PRINT1("%p\n", p);
1033 return(p);
1035 p = p->next;
1040 * We do not have a handle for this path if we were just trying to
1041 * look it up return NULL to indicate we don't have it.
1043 if((mode & RTLD_NOLOAD) == RTLD_NOLOAD){
1044 dlerror_pointer = "no existing handle for path RTLD_NOLOAD test";
1045 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
1046 return(NULL);
1049 /* try to create an object file image from this path */
1050 ofile_result_code = NSCreateObjectFileImageFromFile(module_path,
1051 &objectFileImage);
1052 if(ofile_result_code != NSObjectFileImageSuccess){
1053 switch(ofile_result_code){
1054 case NSObjectFileImageFailure:
1055 dlerror_pointer = "object file setup failure";
1056 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
1057 return(NULL);
1058 case NSObjectFileImageInappropriateFile:
1059 dlerror_pointer = "not a Mach-O MH_BUNDLE file type";
1060 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
1061 return(NULL);
1062 case NSObjectFileImageArch:
1063 dlerror_pointer = "no object for this architecture";
1064 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
1065 return(NULL);
1066 case NSObjectFileImageFormat:
1067 dlerror_pointer = "bad object file format";
1068 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
1069 return(NULL);
1070 case NSObjectFileImageAccess:
1071 dlerror_pointer = "can't read object file";
1072 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
1073 return(NULL);
1074 default:
1075 dlerror_pointer = "unknown error from "
1076 "NSCreateObjectFileImageFromFile()";
1077 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
1078 return(NULL);
1082 /* try to link in this object file image */
1083 options = NSLINKMODULE_OPTION_PRIVATE;
1084 if((mode & RTLD_NOW) == RTLD_NOW)
1085 options |= NSLINKMODULE_OPTION_BINDNOW;
1086 module = NSLinkModule(objectFileImage, module_path, options);
1087 NSDestroyObjectFileImage(objectFileImage) ;
1088 if(module == NULL){
1089 dlerror_pointer = "NSLinkModule() failed for dlopen()";
1090 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
1091 return(NULL);
1095 * If the handle is to be global promote the handle. It is done this
1096 * way to avoid multiply defined symbols.
1098 if((mode & RTLD_GLOBAL) == RTLD_GLOBAL){
1099 if(NSMakePrivateModulePublic(module) == FALSE){
1100 dlerror_pointer = "can't promote handle from RTLD_LOCAL to "
1101 "RTLD_GLOBAL";
1102 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
1103 return(NULL);
1107 p = (dlopen_handle *)malloc(sizeof(struct dlopen_handle));
1108 if(p == NULL){
1109 dlerror_pointer = "can't allocate memory for the dlopen handle";
1110 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
1111 return(NULL);
1114 /* fill in the handle */
1115 p->dev = stat_buf.st_dev;
1116 p->ino = stat_buf.st_ino;
1117 if(mode & RTLD_GLOBAL)
1118 p->dlopen_mode = RTLD_GLOBAL;
1119 else
1120 p->dlopen_mode = RTLD_LOCAL;
1121 p->dlopen_mode |= (mode & RTLD_UNSHARED) |
1122 (mode & RTLD_NODELETE) |
1123 (mode & RTLD_LAZY_UNDEF);
1124 p->dlopen_count = 1;
1125 p->module = module;
1126 p->prev = NULL;
1127 p->next = dlopen_handles;
1128 if(dlopen_handles != NULL)
1129 dlopen_handles->prev = p;
1130 dlopen_handles = p;
1132 /* call the init function if one exists */
1133 NSSymbol = NSLookupSymbolInModule(p->module, "__init");
1134 if(NSSymbol != NULL){
1135 init = ( void(*)() )NSAddressOfSymbol(NSSymbol);
1136 init();
1139 DEBUG_PRINT1("%p\n", p);
1140 return(p);
1144 * dlsym() the MacOS X version of the FreeBSD dlopen() interface.
1146 void *
1147 dlsym(
1148 void * handle,
1149 const char *symbol)
1151 struct dlopen_handle *dlopen_handle, *p;
1152 NSSymbol NSSymbol;
1153 void *address;
1155 DEBUG_PRINT2("libdl: dlsym(%p,%s) -> ", handle, symbol);
1157 dlopen_handle = (struct dlopen_handle *)handle;
1160 * If this is the handle for the main program do a global lookup.
1162 if(dlopen_handle == (struct dlopen_handle *)&main_program_handle){
1163 if(NSIsSymbolNameDefined(symbol) == TRUE){
1164 NSSymbol = NSLookupAndBindSymbol(symbol);
1165 address = NSAddressOfSymbol(NSSymbol);
1166 dlerror_pointer = NULL;
1167 DEBUG_PRINT1("%p\n", address);
1168 return(address);
1170 else{
1171 dlerror_pointer = "symbol not found";
1172 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
1173 return(NULL);
1178 * Find this handle and do a lookup in just this module.
1180 p = dlopen_handles;
1181 while(p != NULL){
1182 if(dlopen_handle == p){
1183 NSSymbol = NSLookupSymbolInModule(p->module, symbol);
1184 if(NSSymbol != NULL){
1185 address = NSAddressOfSymbol(NSSymbol);
1186 dlerror_pointer = NULL;
1187 DEBUG_PRINT1("%p\n", address);
1188 return(address);
1190 else{
1191 dlerror_pointer = "symbol not found";
1192 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
1193 return(NULL);
1196 p = p->next;
1199 dlerror_pointer = "bad handle passed to dlsym()";
1200 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
1201 return(NULL);
1205 * dlerror() the MacOS X version of the FreeBSD dlopen() interface.
1207 const char *
1208 dlerror(
1209 void)
1211 const char *p;
1213 p = (const char *)dlerror_pointer;
1214 dlerror_pointer = NULL;
1215 return(p);
1219 * dlclose() the MacOS X version of the FreeBSD dlopen() interface.
1222 dlclose(
1223 void * handle)
1225 struct dlopen_handle *p, *q;
1226 unsigned long options;
1227 NSSymbol NSSymbol;
1228 void (*fini)(void);
1230 DEBUG_PRINT1("libdl: dlclose(%p) -> ", handle);
1232 dlerror_pointer = NULL;
1233 q = (struct dlopen_handle *)handle;
1234 p = dlopen_handles;
1235 while(p != NULL){
1236 if(p == q){
1237 /* if the dlopen() count is not zero we are done */
1238 p->dlopen_count--;
1239 if(p->dlopen_count != 0){
1240 DEBUG_PRINT("OK");
1241 return(0);
1244 /* call the fini function if one exists */
1245 NSSymbol = NSLookupSymbolInModule(p->module, "__fini");
1246 if(NSSymbol != NULL){
1247 fini = ( void(*)() )NSAddressOfSymbol(NSSymbol);
1248 fini();
1251 /* unlink the module for this handle */
1252 options = 0;
1253 if(p->dlopen_mode & RTLD_NODELETE)
1254 options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
1255 if(p->dlopen_mode & RTLD_LAZY_UNDEF)
1256 options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
1257 if(NSUnLinkModule(p->module, options) == FALSE){
1258 dlerror_pointer = "NSUnLinkModule() failed for dlclose()";
1259 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
1260 return(-1);
1262 if(p->prev != NULL)
1263 p->prev->next = p->next;
1264 if(p->next != NULL)
1265 p->next->prev = p->prev;
1266 if(dlopen_handles == p)
1267 dlopen_handles = p->next;
1268 free(p);
1269 DEBUG_PRINT("OK");
1270 return(0);
1272 p = p->next;
1274 dlerror_pointer = "invalid handle passed to dlclose()";
1275 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer);
1276 return(-1);
1281 #else
1282 // do nothing, it's all in dlfcn
1283 #endif