00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027
00028 #include <map>
00029
00030 #if defined (HAVE_SHL_LOAD_API)
00031 #include <cerrno>
00032 #include <cstring>
00033 #endif
00034
00035 #if defined (HAVE_DYLD_API)
00036 #include <mach-o/dyld.h>
00037 #endif
00038
00039 extern "C"
00040 {
00041 #if defined (HAVE_DLOPEN_API)
00042 #if defined (HAVE_DLFCN_H)
00043 #include <dlfcn.h>
00044 #else
00045 extern void *dlopen (const char *, int);
00046 extern const char *dlerror (void);
00047 extern void *dlsym (void *, const char *);
00048 extern int dlclose (void *);
00049 #endif
00050 #elif defined (HAVE_SHL_LOAD_API)
00051 #include <dl.h>
00052 #elif defined (HAVE_LOADLIBRARY_API)
00053 #define WIN32_LEAN_AND_MEAN
00054 #include <windows.h>
00055 #endif
00056 }
00057
00058 #include "file-stat.h"
00059 #include "lo-error.h"
00060 #include "oct-shlib.h"
00061 #include "str-vec.h"
00062
00063 octave_shlib::shlib_rep::shlib_rep (const std::string& f)
00064 : count (1), file (f), tm_loaded (), fcn_names ()
00065 {
00066 instances[f] = this;
00067
00068 if (is_out_of_date ())
00069 (*current_liboctave_warning_with_id_handler)
00070 ("Octave:warn-future-time-stamp",
00071 "timestamp on file %s is in the future", file.c_str ());
00072 }
00073
00074 bool
00075 octave_shlib::shlib_rep::is_out_of_date (void) const
00076 {
00077 file_stat fs (file);
00078 return fs.is_newer (tm_loaded);
00079 }
00080
00081 void
00082 octave_shlib::shlib_rep::fake_reload (void)
00083 {
00084
00085 file_stat fs (file);
00086 if (fs.is_newer (tm_loaded))
00087 {
00088 tm_loaded = fs.mtime ();
00089
00090 (*current_liboctave_warning_handler)
00091 ("library %s not reloaded due to existing references", file.c_str ());
00092 }
00093 }
00094
00095 octave_shlib::shlib_rep *
00096 octave_shlib::shlib_rep::get_instance (const std::string& f, bool fake)
00097 {
00098 shlib_rep *retval = 0;
00099 std::map<std::string, shlib_rep *>::iterator p = instances.find (f);
00100 if (p != instances.end ())
00101 {
00102 retval = p->second;
00103 retval->count++;
00104 if (fake)
00105 retval->fake_reload ();
00106 }
00107 else
00108 retval = new_instance (f);
00109
00110 return retval;
00111 }
00112
00113 void
00114 octave_shlib::shlib_rep::add_fcn_name (const std::string& name)
00115 {
00116 fcn_names_iterator p = fcn_names.find (name);
00117
00118 if (p == fcn_names.end ())
00119 fcn_names[name] = 1;
00120 else
00121 ++(p->second);
00122 }
00123
00124 bool
00125 octave_shlib::shlib_rep::remove_fcn_name (const std::string& fcn_name)
00126 {
00127 bool retval = false;
00128
00129 fcn_names_iterator p = fcn_names.find (fcn_name);
00130
00131 if (p != fcn_names.end () && --(p->second) == 0)
00132 {
00133 fcn_names.erase (fcn_name);
00134 retval = true;
00135 }
00136
00137 return retval;
00138 }
00139
00140 void
00141 octave_shlib::shlib_rep::do_close_hook (octave_shlib::close_hook cl_hook)
00142 {
00143 for (fcn_names_iterator p = fcn_names.begin (); p != fcn_names.end (); p++)
00144 cl_hook (p->first);
00145
00146 fcn_names.clear ();
00147 }
00148
00149 std::map<std::string, octave_shlib::shlib_rep *> octave_shlib::shlib_rep::instances;
00150
00151 octave_shlib::shlib_rep octave_shlib::nil_rep;
00152
00153 #if defined (HAVE_DLOPEN_API)
00154
00155 class
00156 octave_dlopen_shlib : public octave_shlib::shlib_rep
00157 {
00158 public:
00159
00160 octave_dlopen_shlib (const std::string& f);
00161
00162 ~octave_dlopen_shlib (void);
00163
00164 void *search (const std::string& name, octave_shlib::name_mangler mangler = 0);
00165
00166
00167
00168
00169
00170 bool is_open (void) const { return (library != 0); }
00171
00172 private:
00173
00174
00175
00176 octave_dlopen_shlib (const octave_dlopen_shlib&);
00177
00178 octave_dlopen_shlib& operator = (const octave_dlopen_shlib&);
00179
00180 void *library;
00181 };
00182
00183 octave_dlopen_shlib::octave_dlopen_shlib (const std::string& f)
00184 : octave_shlib::shlib_rep (f), library (0)
00185 {
00186 int flags = 0;
00187
00188
00189
00190
00191
00192 #if defined (RTLD_NOW)
00193 flags |= RTLD_NOW;
00194 #endif
00195
00196 library = dlopen (file.c_str (), flags);
00197
00198 if (! library)
00199 {
00200 const char *msg = dlerror ();
00201
00202 if (msg)
00203 (*current_liboctave_error_handler) ("%s: failed to load: %s",
00204 file.c_str (), msg);
00205 else
00206 (*current_liboctave_error_handler) ("%s: failed to load",
00207 file.c_str ());
00208 }
00209 }
00210
00211 octave_dlopen_shlib::~octave_dlopen_shlib (void)
00212 {
00213 if (library)
00214 dlclose (library);
00215 }
00216
00217 void *
00218 octave_dlopen_shlib::search (const std::string& name,
00219 octave_shlib::name_mangler mangler)
00220 {
00221 void *function = 0;
00222
00223 if (is_open ())
00224 {
00225 std::string sym_name = name;
00226
00227 if (mangler)
00228 sym_name = mangler (name);
00229
00230 function = dlsym (library, sym_name.c_str ());
00231 }
00232 else
00233 (*current_liboctave_error_handler)
00234 ("shared library %s is not open", file.c_str ());
00235
00236 return function;
00237 }
00238
00239 #elif defined (HAVE_SHL_LOAD_API)
00240
00241 class
00242 octave_shl_load_shlib : public octave_shlib::shlib_rep
00243 {
00244 public:
00245
00246 octave_shl_load_shlib (const std::string& f);
00247
00248 ~octave_shl_load_shlib (void);
00249
00250 void *search (const std::string& name, octave_shlib::name_mangler mangler = 0);
00251
00252 bool is_open (void) const { return (library != 0); }
00253
00254 private:
00255
00256
00257
00258 octave_shl_load_shlib (const octave_shl_load_shlib&);
00259
00260 octave_shl_load_shlib& operator = (const octave_shl_load_shlib&);
00261
00262 shl_t library;
00263 };
00264
00265 octave_shl_load_shlib::octave_shl_load_shlib (const std::string& f)
00266 : octave_shlib::shlib_rep (f), library (0)
00267 {
00268 file = f;
00269
00270 library = shl_load (file.c_str (), BIND_IMMEDIATE, 0L);
00271
00272 if (! library)
00273 {
00274 using namespace std;
00275 (*current_liboctave_error_handler) ("%s", strerror (errno));
00276 }
00277 }
00278
00279 octave_shl_load_shlib::~octave_shl_load_shlib (void)
00280 {
00281 if (library)
00282 shl_unload (library);
00283 }
00284
00285 void *
00286 octave_shl_load_shlib::search (const std::string& name,
00287 octave_shlib::name_mangler mangler)
00288 {
00289 void *function = 0;
00290
00291 if (is_open ())
00292 {
00293 std::string sym_name = name;
00294
00295 if (mangler)
00296 sym_name = mangler (name);
00297
00298 int status = shl_findsym (&library, sym_name.c_str (),
00299 TYPE_UNDEFINED, &function);
00300 }
00301 else
00302 (*current_liboctave_error_handler)
00303 ("shared library %s is not open", file.c_str ());
00304
00305 return function;
00306 }
00307
00308 #elif defined (HAVE_LOADLIBRARY_API)
00309
00310 class
00311 octave_w32_shlib: public octave_shlib::shlib_rep
00312 {
00313 public:
00314
00315 octave_w32_shlib (const std::string& f);
00316
00317 ~octave_w32_shlib (void);
00318
00319 void *search (const std::string& name, octave_shlib::name_mangler mangler = 0);
00320
00321 bool is_open (void) const { return (handle != 0); }
00322
00323 private:
00324
00325
00326
00327 octave_w32_shlib (const octave_w32_shlib&);
00328
00329 octave_w32_shlib& operator = (const octave_w32_shlib&);
00330
00331 HINSTANCE handle;
00332 };
00333
00334 octave_w32_shlib::octave_w32_shlib (const std::string& f)
00335 : octave_shlib::shlib_rep (f), handle (0)
00336 {
00337 handle = LoadLibrary (file.c_str ());
00338
00339 if (! handle)
00340 {
00341 DWORD lastError = GetLastError ();
00342 char *msg;
00343
00344 switch (lastError)
00345 {
00346 case ERROR_MOD_NOT_FOUND:
00347 case ERROR_DLL_NOT_FOUND:
00348 msg = "could not find library or dependents";
00349 break;
00350
00351 case ERROR_INVALID_DLL:
00352 msg = "library or its dependents are damaged";
00353 break;
00354
00355 case ERROR_DLL_INIT_FAILED:
00356 msg = "library initialization routine failed";
00357 break;
00358
00359 default:
00360 msg = "library open failed";
00361 }
00362
00363 (*current_liboctave_error_handler) ("%s: %s", msg, file.c_str ());
00364 }
00365 }
00366
00367 octave_w32_shlib::~octave_w32_shlib (void)
00368 {
00369 if (handle)
00370 FreeLibrary (handle);
00371 }
00372
00373 extern "C"
00374 {
00375 void * octave_w32_search (HINSTANCE handle, const char * name);
00376 }
00377
00378 void *
00379 octave_w32_shlib::search (const std::string& name,
00380 octave_shlib::name_mangler mangler)
00381 {
00382 void *function = 0;
00383
00384 if (is_open ())
00385 {
00386 std::string sym_name = name;
00387
00388 if (mangler)
00389 sym_name = mangler (name);
00390
00391 function = octave_w32_library_search (handle, sym_name.c_str ());
00392 }
00393 else
00394 (*current_liboctave_error_handler)
00395 ("shared library %s is not open", file.c_str ());
00396
00397 return function;
00398 }
00399
00400 #elif defined (HAVE_DYLD_API)
00401
00402 class
00403 octave_dyld_shlib : public octave_shlib::shlib_rep
00404 {
00405 public:
00406
00407 octave_dyld_shlib (void);
00408
00409 ~octave_dyld_shlib (void);
00410
00411 void open (const std::string& f);
00412
00413 void *search (const std::string& name, octave_shlib::name_mangler mangler = 0);
00414
00415 void close (octave_shlib::close_hook cl_hook = 0);
00416
00417 bool is_open (void) const {return (handle != 0); }
00418
00419 private:
00420
00421
00422
00423 octave_dyld_shlib (const octave_dyld_shlib&);
00424
00425 octave_dyld_shlib& operator = (const octave_dyld_shlib&);
00426
00427 NSObjectFileImage img;
00428 NSModule handle;
00429 };
00430
00431 octave_dyld_shlib::octave_dyld_shlib (const std::string& f)
00432 : octave_shlib::shlib_rep (f), handle (0)
00433 {
00434 int returnCode = NSCreateObjectFileImageFromFile (file.c_str (), &img);
00435
00436 if (NSObjectFileImageSuccess == returnCode)
00437 {
00438 handle = NSLinkModule (img, file.c_str (),
00439 (NSLINKMODULE_OPTION_RETURN_ON_ERROR
00440 | NSLINKMODULE_OPTION_PRIVATE));
00441 if (! handle)
00442 {
00443 NSLinkEditErrors ler;
00444 int lerno;
00445 const char *file2;
00446 const char *errstr = 0;
00447
00448 NSLinkEditError (&ler, &lerno, &file2, &errstr);
00449
00450 if (! errstr)
00451 errstr = "unspecified error";
00452
00453 (*current_liboctave_error_handler)
00454 ("%s: %s", file.c_str (), errstr);
00455 }
00456 }
00457 else
00458 {
00459 (*current_liboctave_error_handler)
00460 ("got NSObjectFileImageReturnCode %d", returnCode);
00461
00462
00463
00464 }
00465 }
00466
00467 octave_dyld_shlib::~octave_dyld_shlib (void)
00468 {
00469 if (handle)
00470 NSUnLinkModule (handle, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
00471
00472 NSDestroyObjectFileImage (img);
00473 }
00474
00475 void *
00476 octave_dyld_shlib::search (const std::string& name,
00477 octave_shlib::name_mangler mangler)
00478 {
00479 void *function = 0;
00480
00481 if (is_open ())
00482 {
00483 std::string sym_name = name;
00484
00485 if (mangler)
00486 sym_name = mangler (name);
00487
00488 NSSymbol symbol = NSLookupSymbolInModule (handle, sym_name.c_str ());
00489
00490 if (symbol)
00491 {
00492 function = NSAddressOfSymbol (symbol);
00493 }
00494 }
00495 else
00496 (*current_liboctave_error_handler)
00497 ("bundle %s is not open", file.c_str ());
00498
00499 return function;
00500 }
00501
00502 #endif
00503
00504 octave_shlib::shlib_rep *
00505 octave_shlib::shlib_rep::new_instance (const std::string& f)
00506 {
00507 #if defined (HAVE_DLOPEN_API)
00508 return new octave_dlopen_shlib (f);
00509 #elif defined (HAVE_SHL_LOAD_API)
00510 return new octave_shl_load_shlib (f);
00511 #elif defined (HAVE_LOADLIBRARY_API)
00512 return new octave_w32_shlib (f);
00513 #elif defined (HAVE_DYLD_API)
00514 return new octave_dyld_shlib (f);
00515 #else
00516 (*current_liboctave_error_handler)
00517 ("no API for dynamic loading is available");
00518 return new shlib_rep ();
00519 #endif
00520 }