GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
oct-shlib.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1999-2013 John W. Eaton
4 Copyright (C) 2009 VZLU Prague
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <map>
29 
30 #if defined (HAVE_SHL_LOAD_API)
31 #include <cerrno>
32 #include <cstring>
33 #endif
34 
35 #if defined (HAVE_DYLD_API)
36 #include <mach-o/dyld.h>
37 #endif
38 
39 extern "C"
40 {
41 #if defined (HAVE_DLOPEN_API)
42 #if defined (HAVE_DLFCN_H)
43 #include <dlfcn.h>
44 #else
45 extern void *dlopen (const char *, int);
46 extern const char *dlerror (void);
47 extern void *dlsym (void *, const char *);
48 extern int dlclose (void *);
49 #endif
50 #elif defined (HAVE_SHL_LOAD_API)
51 #include <dl.h>
52 #elif defined (HAVE_LOADLIBRARY_API)
53 #define WIN32_LEAN_AND_MEAN
54 #include <windows.h>
55 #endif
56 }
57 
58 #include "file-stat.h"
59 #include "lo-error.h"
60 #include "oct-shlib.h"
61 #include "str-vec.h"
62 
64  : count (1), file (f), tm_loaded (), fcn_names ()
65 {
66  instances[f] = this;
67 
68  if (is_out_of_date ())
69  (*current_liboctave_warning_with_id_handler)
70  ("Octave:warn-future-time-stamp",
71  "timestamp on file %s is in the future", file.c_str ());
72 }
73 
74 bool
76 {
77  file_stat fs (file);
78  return (fs && fs.is_newer (tm_loaded));
79 }
80 
81 void
83 {
84  // We can't actually reload the library, but we'll pretend we did.
85  file_stat fs (file);
86  if (fs && fs.is_newer (tm_loaded))
87  {
88  tm_loaded = fs.mtime ();
89 
90  (*current_liboctave_warning_handler)
91  ("library %s not reloaded due to existing references", file.c_str ());
92  }
93 }
94 
96 octave_shlib::shlib_rep::get_instance (const std::string& f, bool fake)
97 {
98  shlib_rep *retval = 0;
99  std::map<std::string, shlib_rep *>::iterator p = instances.find (f);
100  if (p != instances.end ())
101  {
102  retval = p->second;
103  retval->count++;
104  if (fake)
105  retval->fake_reload ();
106  }
107  else
108  retval = new_instance (f);
109 
110  return retval;
111 }
112 
113 void
114 octave_shlib::shlib_rep::add_fcn_name (const std::string& name)
115 {
116  fcn_names_iterator p = fcn_names.find (name);
117 
118  if (p == fcn_names.end ())
119  fcn_names[name] = 1;
120  else
121  ++(p->second);
122 }
123 
124 bool
125 octave_shlib::shlib_rep::remove_fcn_name (const std::string& fcn_name)
126 {
127  bool retval = false;
128 
129  fcn_names_iterator p = fcn_names.find (fcn_name);
130 
131  if (p != fcn_names.end () && --(p->second) == 0)
132  {
133  fcn_names.erase (fcn_name);
134  retval = true;
135  }
136 
137  return retval;
138 }
139 
140 void
142 {
143  for (fcn_names_iterator p = fcn_names.begin (); p != fcn_names.end (); p++)
144  cl_hook (p->first);
145 
146  fcn_names.clear ();
147 }
148 
149 std::map<std::string, octave_shlib::shlib_rep *> octave_shlib::shlib_rep::instances;
150 
152 
153 #if defined (HAVE_DLOPEN_API)
154 
155 class
156 octave_dlopen_shlib : public octave_shlib::shlib_rep
157 {
158 public:
159 
160  octave_dlopen_shlib (const std::string& f);
161 
162  ~octave_dlopen_shlib (void);
163 
164  void *search (const std::string& name,
165  octave_shlib::name_mangler mangler = 0);
166 
167  // FIXME: this is possibly redundant because failure to open a library will
168  // normally throw an exception, avoiding the construction of an invalid
169  // library. Leave it here for possible future use.
170 
171  bool is_open (void) const { return (library != 0); }
172 
173 private:
174 
175  // No copying!
176 
177  octave_dlopen_shlib (const octave_dlopen_shlib&);
178 
179  octave_dlopen_shlib& operator = (const octave_dlopen_shlib&);
180 
181  void *library;
182 };
183 
184 octave_dlopen_shlib::octave_dlopen_shlib (const std::string& f)
185  : octave_shlib::shlib_rep (f), library (0)
186 {
187  int flags = 0;
188 
189  // Use RTLD_NOW to resolve all symbols before dlopen returns.
190  // By using this option, dlopen will detect errors and Octave
191  // won't exit if there are unresolved symbols in the file we are
192  // loading, and we may even get a useful diagnostic.
193 #if defined (RTLD_NOW)
194  flags |= RTLD_NOW;
195 #endif
196 
197  library = dlopen (file.c_str (), flags);
198 
199  if (! library)
200  {
201  const char *msg = dlerror ();
202 
203  if (msg)
204  (*current_liboctave_error_handler) ("%s: failed to load: %s",
205  file.c_str (), msg);
206  else
207  (*current_liboctave_error_handler) ("%s: failed to load",
208  file.c_str ());
209  }
210 }
211 
212 octave_dlopen_shlib::~octave_dlopen_shlib (void)
213 {
214  if (library)
215  dlclose (library);
216 }
217 
218 void *
219 octave_dlopen_shlib::search (const std::string& name,
221 {
222  void *function = 0;
223 
224  if (is_open ())
225  {
226  std::string sym_name = name;
227 
228  if (mangler)
229  sym_name = mangler (name);
230 
231  function = dlsym (library, sym_name.c_str ());
232  }
233  else
235  ("shared library %s is not open", file.c_str ());
236 
237  return function;
238 }
239 
240 #elif defined (HAVE_SHL_LOAD_API)
241 
242 class
243 octave_shl_load_shlib : public octave_shlib::shlib_rep
244 {
245 public:
246 
247  octave_shl_load_shlib (const std::string& f);
248 
249  ~octave_shl_load_shlib (void);
250 
251  void *search (const std::string& name,
252  octave_shlib::name_mangler mangler = 0);
253 
254  bool is_open (void) const { return (library != 0); }
255 
256 private:
257 
258  // No copying!
259 
260  octave_shl_load_shlib (const octave_shl_load_shlib&);
261 
262  octave_shl_load_shlib& operator = (const octave_shl_load_shlib&);
263 
264  shl_t library;
265 };
266 
267 octave_shl_load_shlib::octave_shl_load_shlib (const std::string& f)
268  : octave_shlib::shlib_rep (f), library (0)
269 {
270  file = f;
271 
272  library = shl_load (file.c_str (), BIND_IMMEDIATE, 0L);
273 
274  if (! library)
275  {
276  using namespace std;
277  (*current_liboctave_error_handler) ("%s", gnulib::strerror (errno));
278  }
279 }
280 
281 octave_shl_load_shlib::~octave_shl_load_shlib (void)
282 {
283  if (library)
284  shl_unload (library);
285 }
286 
287 void *
288 octave_shl_load_shlib::search (const std::string& name,
290 {
291  void *function = 0;
292 
293  if (is_open ())
294  {
295  std::string sym_name = name;
296 
297  if (mangler)
298  sym_name = mangler (name);
299 
300  int status = shl_findsym (&library, sym_name.c_str (),
301  TYPE_UNDEFINED, &function);
302  }
303  else
305  ("shared library %s is not open", file.c_str ());
306 
307  return function;
308 }
309 
310 #elif defined (HAVE_LOADLIBRARY_API)
311 
312 class
313 octave_w32_shlib: public octave_shlib::shlib_rep
314 {
315 public:
316 
317  octave_w32_shlib (const std::string& f);
318 
319  ~octave_w32_shlib (void);
320 
321  void *search (const std::string& name,
322  octave_shlib::name_mangler mangler = 0);
323 
324  bool is_open (void) const { return (handle != 0); }
325 
326 private:
327 
328  // No copying!
329 
330  octave_w32_shlib (const octave_w32_shlib&);
331 
332  octave_w32_shlib& operator = (const octave_w32_shlib&);
333 
334  HINSTANCE handle;
335 };
336 
337 octave_w32_shlib::octave_w32_shlib (const std::string& f)
338  : octave_shlib::shlib_rep (f), handle (0)
339 {
340  handle = LoadLibrary (file.c_str ());
341 
342  if (! handle)
343  {
344  DWORD lastError = GetLastError ();
345  char *msg;
346 
347  switch (lastError)
348  {
349  case ERROR_MOD_NOT_FOUND:
350  case ERROR_DLL_NOT_FOUND:
351  msg = "could not find library or dependents";
352  break;
353 
354  case ERROR_INVALID_DLL:
355  msg = "library or its dependents are damaged";
356  break;
357 
358  case ERROR_DLL_INIT_FAILED:
359  msg = "library initialization routine failed";
360  break;
361 
362  default:
363  msg = "library open failed";
364  }
365 
366  (*current_liboctave_error_handler) ("%s: %s", msg, file.c_str ());
367  }
368 }
369 
370 octave_w32_shlib::~octave_w32_shlib (void)
371 {
372  if (handle)
373  FreeLibrary (handle);
374 }
375 
376 extern "C"
377 {
378  void * octave_w32_search (HINSTANCE handle, const char * name);
379 }
380 
381 void *
382 octave_w32_shlib::search (const std::string& name,
384 {
385  void *function = 0;
386 
387  if (is_open ())
388  {
389  std::string sym_name = name;
390 
391  if (mangler)
392  sym_name = mangler (name);
393 
394  function = octave_w32_library_search (handle, sym_name.c_str ());
395  }
396  else
398  ("shared library %s is not open", file.c_str ());
399 
400  return function;
401 }
402 
403 #elif defined (HAVE_DYLD_API)
404 
405 class
406 octave_dyld_shlib : public octave_shlib::shlib_rep
407 {
408 public:
409 
410  octave_dyld_shlib (void);
411 
412  ~octave_dyld_shlib (void);
413 
414  void open (const std::string& f);
415 
416  void *search (const std::string& name,
417  octave_shlib::name_mangler mangler = 0);
418 
419  void close (octave_shlib::close_hook cl_hook = 0);
420 
421  bool is_open (void) const {return (handle != 0); }
422 
423 private:
424 
425  // No copying!
426 
427  octave_dyld_shlib (const octave_dyld_shlib&);
428 
429  octave_dyld_shlib& operator = (const octave_dyld_shlib&);
430 
431  NSObjectFileImage img;
432  NSModule handle;
433 };
434 
435 octave_dyld_shlib::octave_dyld_shlib (const std::string& f)
436  : octave_shlib::shlib_rep (f), handle (0)
437 {
438  int returnCode = NSCreateObjectFileImageFromFile (file.c_str (), &img);
439 
440  if (NSObjectFileImageSuccess == returnCode)
441  {
442  handle = NSLinkModule (img, file.c_str (),
443  (NSLINKMODULE_OPTION_RETURN_ON_ERROR
444  | NSLINKMODULE_OPTION_PRIVATE));
445  if (! handle)
446  {
447  NSLinkEditErrors ler;
448  int lerno;
449  const char *file2;
450  const char *errstr = 0;
451 
452  NSLinkEditError (&ler, &lerno, &file2, &errstr);
453 
454  if (! errstr)
455  errstr = "unspecified error";
456 
457  (*current_liboctave_error_handler)
458  ("%s: %s", file.c_str (), errstr);
459  }
460  }
461  else
462  {
463  (*current_liboctave_error_handler)
464  ("got NSObjectFileImageReturnCode %d", returnCode);
465 
466  // FIXME: should use NSLinkEditError () to get
467  // more info on what went wrong.
468  }
469 }
470 
471 octave_dyld_shlib::~octave_dyld_shlib (void)
472 {
473  if (handle)
474  NSUnLinkModule (handle, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
475 
476  NSDestroyObjectFileImage (img);
477 }
478 
479 void *
480 octave_dyld_shlib::search (const std::string& name,
482 {
483  void *function = 0;
484 
485  if (is_open ())
486  {
487  std::string sym_name = name;
488 
489  if (mangler)
490  sym_name = mangler (name);
491 
492  NSSymbol symbol = NSLookupSymbolInModule (handle, sym_name.c_str ());
493 
494  if (symbol)
495  {
496  function = NSAddressOfSymbol (symbol);
497  }
498  }
499  else
501  ("bundle %s is not open", file.c_str ());
502 
503  return function;
504 }
505 
506 #endif
507 
510 {
511 #if defined (HAVE_DLOPEN_API)
512  return new octave_dlopen_shlib (f);
513 #elif defined (HAVE_SHL_LOAD_API)
514  return new octave_shl_load_shlib (f);
515 #elif defined (HAVE_LOADLIBRARY_API)
516  return new octave_w32_shlib (f);
517 #elif defined (HAVE_DYLD_API)
518  return new octave_dyld_shlib (f);
519 #else
520  (*current_liboctave_error_handler)
521  ("no API for dynamic loading is available");
522  return new shlib_rep ();
523 #endif
524 }