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
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
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
36 //-----------------------------------------------------------------------------
38 #include "chuck_errmsg.h"
39 #include "chuck_bbq.h"
45 //-----------------------------------------------------------------------------
46 // internal implementation of query functions
47 //-----------------------------------------------------------------------------
52 //-----------------------------------------------------------------------------
54 // desc: set the name of the module
55 //-----------------------------------------------------------------------------
56 void CK_DLL_CALL
ck_setname( Chuck_DL_Query
* query
, const char * 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
)
72 query
->stack
.push_back( query
->curr_class
);
74 Chuck_DL_Class
* c
= new Chuck_DL_Class
;
77 if( query
->curr_class
)
79 query
->curr_class
->classes
.push_back( c
);
82 query
->classes
.push_back( c
);
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
)
106 EM_error2( 0, "class import: add_ctor invoked without begin_class..." );
111 Chuck_DL_Func
* f
= new Chuck_DL_Func
;
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
)
134 EM_error2( 0, "class import: add_dtor invoked without begin_class..." );
138 // make sure there are no duplicates
139 if( query
->curr_class
->dtor
)
142 EM_error2( 0, "class import: multiple dtor added ..." );
147 Chuck_DL_Func
* f
= new Chuck_DL_Func
;
153 query
->curr_class
->dtor
= f
;
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
)
172 EM_error2( 0, "class import: add_mfun invoked without begin_class..." );
177 Chuck_DL_Func
* f
= new Chuck_DL_Func
;
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
)
201 EM_error2( 0, "class import: add_sfun invoked without begin_class..." );
206 Chuck_DL_Func
* f
= new Chuck_DL_Func
;
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
,
226 // make sure there is class
227 if( !query
->curr_class
)
230 EM_error2( 0, "class import: add_mvar invoked without begin_class..." );
235 Chuck_DL_Value
* v
= new Chuck_DL_Value
;
238 v
->is_const
= is_const
;
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
)
259 EM_error2( 0, "class import: add_svar invoked without begin_class..." );
264 Chuck_DL_Value
* v
= new Chuck_DL_Value
;
267 v
->is_const
= is_const
;
268 v
->static_addr
= addr
;
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
)
288 EM_error2( 0, "class import: add_arg invoked without begin_class..." );
292 // make sure there is function
293 if( !query
->curr_func
)
296 EM_error2( 0, "class import: add_arg can only follow 'ctor', 'mfun', 'sfun', 'arg'..." );
301 Chuck_DL_Value
* v
= new Chuck_DL_Value
;
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
)
322 EM_error2( 0, "class import: add_ugen_func invoked without begin_class..." );
326 // make sure tick not defined already
327 if( query
->curr_class
->ugen_tick
&& ugen_tick
)
330 EM_error2( 0, "class import: ugen_tick already defined..." );
334 // make sure pmsg not defined already
335 if( query
->curr_class
->ugen_pmsg
&& ugen_pmsg
)
338 EM_error2( 0, "class import: ugen_pmsg already defined..." );
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
)
362 EM_error2( 0, "class import: add_ugen_func invoked without begin_class..." );
367 Chuck_DL_Ctrl
* c
= new Chuck_DL_Ctrl
;
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
)
390 EM_error2( 0, "class import: end_class invoked without begin_class..." );
394 // type check the class?
397 assert( query
->stack
.size() );
398 query
->curr_class
= query
->stack
.back();
399 query
->stack
.pop_back();
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 //-----------------------------------------------------------------------------
426 // desc: load dynamic link library
427 //-----------------------------------------------------------------------------
428 t_CKBOOL
Chuck_DLL::load( const char * filename
, const char * func
, t_CKBOOL lazy
)
431 m_handle
= dlopen( filename
, lazy
? RTLD_LAZY
: RTLD_NOW
);
436 m_last_error
= dlerror();
441 m_filename
= filename
;
442 m_done_query
= FALSE
;
445 // if not lazy, do it
446 if( !lazy
&& !this->query() )
455 //-----------------------------------------------------------------------------
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
;
465 // if not lazy, do it
466 if( !lazy
&& !this->query() )
475 //-----------------------------------------------------------------------------
478 //-----------------------------------------------------------------------------
479 t_CKBOOL
Chuck_DLL::good() const
481 return ( m_handle
!= NULL
|| m_query_func
!= NULL
);
487 //-----------------------------------------------------------------------------
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...";
499 // return if there already
503 // get the address of the query function from the DLL
505 m_query_func
= (f_ck_query
)this->get_addr( m_func
.c_str() );
507 m_query_func
= (f_ck_query
)this->get_addr( (string("_")+m_func
).c_str() );
510 m_last_error
= string("no query function found in dll '")
511 + m_filename
+ string("'");
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" );
519 m_attach_func = (f_ck_attach)this->get_addr( "_ck_attach" );
521 // get the address of the detach function from the DLL
523 m_detach_func = (f_ck_detach)this->get_addr( "ck_detach" );
525 m_detach_func = (f_ck_detach)this->get_addr( "_ck_detach" ); */
529 if( !m_query_func( &m_query
) )
531 m_last_error
= string("unsuccessful query in dll '") + m_filename
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
551 proto->addr = (f_ck_func)this->get_addr( (char *)proto->name.c_str() );
554 m_last_error = string("no addr associated with export '") +
555 proto->name + string("'");
559 // put in the lookup table
560 m_name2proto[proto->name] = proto;
563 // load the proto table
564 Chuck_UGen_Info * info;
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
576 // put in the lookup table
577 m_name2ugen[info->name] = info;
583 // if( m_attach_func ) m_attach_func( 0, NULL );
591 //-----------------------------------------------------------------------------
594 //-----------------------------------------------------------------------------
595 t_CKBOOL
Chuck_DLL::unload()
597 if( !m_handle
&& !m_query_func
)
599 m_last_error
= "cannot unload dynamic library - nothing open...";
603 // if( m_detach_func ) m_detach_func( 0, NULL );
619 //-----------------------------------------------------------------------------
622 //-----------------------------------------------------------------------------
623 void * Chuck_DLL::get_addr( const char * symbol
)
627 m_last_error
= "cannot find addr from dynamic library - nothing open...";
631 return dlsym( m_handle
, symbol
);
637 //-----------------------------------------------------------------------------
638 // name: last_error()
640 //-----------------------------------------------------------------------------
641 const char * Chuck_DLL::last_error() const
643 return m_last_error
.c_str();
649 //-----------------------------------------------------------------------------
652 //-----------------------------------------------------------------------------
653 const char * Chuck_DLL::name() const
661 //-----------------------------------------------------------------------------
662 // name: Chuck_DL_Query
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]";
685 #ifndef __CKDL_NO_BBQ__
686 srate
= Digitalio::sampling_rate() ; bufsize
= Digitalio::buffer_size();
688 srate
= 0; bufsize
= 0;
697 //-----------------------------------------------------------------------------
700 //-----------------------------------------------------------------------------
701 void Chuck_DL_Query::clear()
704 dll_name
= "[noname]";
708 for( t_CKUINT i
= 0; i
< classes
.size(); i
++ ) delete classes
[i
];
716 //-----------------------------------------------------------------------------
717 // name: ~Chuck_DL_Class()
719 //-----------------------------------------------------------------------------
720 Chuck_DL_Class::~Chuck_DL_Class()
725 for( i
= 0; i
< mfuns
.size(); i
++ ) delete mfuns
[i
];
727 for( i
= 0; i
< sfuns
.size(); i
++ ) delete sfuns
[i
];
729 for( i
= 0; i
< mvars
.size(); i
++ ) delete mvars
[i
];
731 for( i
= 0; i
< svars
.size(); i
++ ) delete svars
[i
];
733 for( i
= 0; i
< classes
.size(); i
++ ) delete classes
[i
];
739 //-----------------------------------------------------------------------------
740 // name: ~Chuck_DL_Func()
742 //-----------------------------------------------------------------------------
743 Chuck_DL_Func::~Chuck_DL_Func()
745 for( t_CKUINT i
= 0; i
< args
.size(); i
++ )
753 #if defined(__WINDOWS_DS__)
758 void *dlopen( const char *path
, int mode
)
760 return (void *)LoadLibrary(path
);
763 int dlclose( void *handle
)
765 FreeLibrary((HMODULE
)handle
);
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
;
785 #if defined(__MACOSX_CORE__) && MAC_OS_X_VERSION_MAX_ALLOWED <= 1030
794 #include <sys/types.h>
795 #include <sys/stat.h>
797 #include "mach-o/dyld.h"
803 #define DEBUG_PRINT(format) fprintf(stderr,(format));fflush(stderr)
804 #define DEBUG_PRINT1(format,arg1) fprintf(stderr,(format),(arg1));\
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)
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) /**/
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) */
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.
843 NSMakePrivateModulePublic(
846 static int (*p
)(NSModule module
) = NULL
;
849 _dyld_func_lookup("__dyld_NSMakePrivateModulePublic",
850 (unsigned long *)&p
);
854 printf("_dyld_func_lookup of __dyld_NSMakePrivateModulePublic "
863 * helper routine: search for a named module in various locations
868 const char *filename
,
870 struct stat
*stat_buf
)
872 const char *pathspec
;
877 const char *envvars
[] = {
878 "$DYLD_LIBRARY_PATH",
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);
891 pathspec
= envvars
[envvar_index
];
894 if(pathspec
!= NULL
){
897 /* extract path list element */
900 while(*p
&& *p
!= ':' && q
< pathbuf_end
) *q
++ = *p
++;
901 if(q
== pathbuf
){ /* empty element */
912 element
= p
; /* this terminates the loop */
915 /* add slash if neccessary */
916 if(*(q
-1) != '/' && q
< pathbuf_end
){
920 /* append module name */
922 while(*p
&& q
< pathbuf_end
) *q
++ = *p
++;
925 if(q
>= pathbuf_end
){
926 /* maybe add an error message here */
930 if(stat(pathbuf
, stat_buf
) == 0){
937 /* we have searched everywhere, now we give up */
942 * dlopen() the MacOS X version of the FreeBSD dlopen() interface.
949 const char *module_path
;
951 struct stat stat_buf
;
952 NSObjectFileImage objectFileImage
;
953 NSObjectFileImageReturnCode ofile_result_code
;
955 struct dlopen_handle
*p
;
956 unsigned long options
;
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
969 retval
= (void *)&main_program_handle
;
970 DEBUG_PRINT1("main / %p\n", 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
);
979 DEBUG_PRINT1("ERROR (stat): %s\n", dlerror_pointer
);
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
);
989 DEBUG_PRINT1("found %s -> ", pathbuf
);
990 module_path
= pathbuf
;
991 dlerror_pointer
= NULL
;
998 * If we don't want an unshared handle see if we already have a handle
1001 if((mode
& RTLD_UNSHARED
) != RTLD_UNSHARED
){
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
)
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
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
;
1021 DEBUG_PRINT1("%p\n", p
);
1025 dlerror_pointer
= "can't promote handle from "
1026 "RTLD_LOCAL to RTLD_GLOBAL";
1027 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer
);
1032 DEBUG_PRINT1("%p\n", p
);
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
);
1049 /* try to create an object file image from this path */
1050 ofile_result_code
= NSCreateObjectFileImageFromFile(module_path
,
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
);
1058 case NSObjectFileImageInappropriateFile
:
1059 dlerror_pointer
= "not a Mach-O MH_BUNDLE file type";
1060 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer
);
1062 case NSObjectFileImageArch
:
1063 dlerror_pointer
= "no object for this architecture";
1064 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer
);
1066 case NSObjectFileImageFormat
:
1067 dlerror_pointer
= "bad object file format";
1068 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer
);
1070 case NSObjectFileImageAccess
:
1071 dlerror_pointer
= "can't read object file";
1072 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer
);
1075 dlerror_pointer
= "unknown error from "
1076 "NSCreateObjectFileImageFromFile()";
1077 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer
);
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
) ;
1089 dlerror_pointer
= "NSLinkModule() failed for dlopen()";
1090 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer
);
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 "
1102 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer
);
1107 p
= (dlopen_handle
*)malloc(sizeof(struct dlopen_handle
));
1109 dlerror_pointer
= "can't allocate memory for the dlopen handle";
1110 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer
);
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
;
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;
1127 p
->next
= dlopen_handles
;
1128 if(dlopen_handles
!= NULL
)
1129 dlopen_handles
->prev
= p
;
1132 /* call the init function if one exists */
1133 NSSymbol
= NSLookupSymbolInModule(p
->module
, "__init");
1134 if(NSSymbol
!= NULL
){
1135 init
= ( void(*)() )NSAddressOfSymbol(NSSymbol
);
1139 DEBUG_PRINT1("%p\n", p
);
1144 * dlsym() the MacOS X version of the FreeBSD dlopen() interface.
1151 struct dlopen_handle
*dlopen_handle
, *p
;
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
);
1171 dlerror_pointer
= "symbol not found";
1172 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer
);
1178 * Find this handle and do a lookup in just this module.
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
);
1191 dlerror_pointer
= "symbol not found";
1192 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer
);
1199 dlerror_pointer
= "bad handle passed to dlsym()";
1200 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer
);
1205 * dlerror() the MacOS X version of the FreeBSD dlopen() interface.
1213 p
= (const char *)dlerror_pointer
;
1214 dlerror_pointer
= NULL
;
1219 * dlclose() the MacOS X version of the FreeBSD dlopen() interface.
1225 struct dlopen_handle
*p
, *q
;
1226 unsigned long options
;
1230 DEBUG_PRINT1("libdl: dlclose(%p) -> ", handle
);
1232 dlerror_pointer
= NULL
;
1233 q
= (struct dlopen_handle
*)handle
;
1237 /* if the dlopen() count is not zero we are done */
1239 if(p
->dlopen_count
!= 0){
1244 /* call the fini function if one exists */
1245 NSSymbol
= NSLookupSymbolInModule(p
->module
, "__fini");
1246 if(NSSymbol
!= NULL
){
1247 fini
= ( void(*)() )NSAddressOfSymbol(NSSymbol
);
1251 /* unlink the module for this handle */
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
);
1263 p
->prev
->next
= p
->next
;
1265 p
->next
->prev
= p
->prev
;
1266 if(dlopen_handles
== p
)
1267 dlopen_handles
= p
->next
;
1274 dlerror_pointer
= "invalid handle passed to dlclose()";
1275 DEBUG_PRINT1("ERROR: %s\n", dlerror_pointer
);
1282 // do nothing, it's all in dlfcn