oct-shlib.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1999-2012 John W. Eaton
00004 Copyright (C) 2009 VZLU Prague
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
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   // We can't actually reload the library, but we'll pretend we did.
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   // FIXME: this is possibly redundant because failure to open a library will
00167   // normally throw an exception, avoiding the construction of an invalid
00168   // library. Leave it here for possible future use.
00169 
00170   bool is_open (void) const { return (library != 0); }
00171 
00172 private:
00173 
00174   // No copying!
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   // Use RTLD_NOW to resolve all symbols before dlopen returns.
00189   // By using this option, dlopen will detect errors and Octave
00190   // won't exit if there are unresolved symbols in the file we are
00191   // loading, and we may even get a useful diagnostic.
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   // No copying!
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   // No copying!
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   // No copying!
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       // FIXME -- should use NSLinkEditError () to get
00463       // more info on what went wrong.
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 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines