123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- /* loader-dlopen.c -- dynamic linking with dlopen/dlsym
- Copyright (C) 1998-2000, 2004, 2006-2008, 2011-2015 Free Software
- Foundation, Inc.
- Written by Thomas Tanner, 1998
- NOTE: The canonical source of this file is maintained with the
- GNU Libtool package. Report bugs to bug-libtool@gnu.org.
- GNU Libltdl is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
- As a special exception to the GNU Lesser General Public License,
- if you distribute this file as part of a program or library that
- is built using GNU Libtool, you may include this file under the
- same distribution terms that you use for the rest of that program.
- GNU Libltdl is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with GNU Libltdl; see the file COPYING.LIB. If not, a
- copy can be downloaded from http://www.gnu.org/licenses/lgpl.html,
- or obtained by writing to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
- #include "lt__private.h"
- #include "lt_dlloader.h"
- /* Use the preprocessor to rename non-static symbols to avoid namespace
- collisions when the loader code is statically linked into libltdl.
- Use the "<module_name>_LTX_" prefix so that the symbol addresses can
- be fetched from the preloaded symbol list by lt_dlsym(): */
- #define get_vtable dlopen_LTX_get_vtable
- LT_BEGIN_C_DECLS
- LT_SCOPE lt_dlvtable *get_vtable (lt_user_data loader_data);
- LT_END_C_DECLS
- /* Boilerplate code to set up the vtable for hooking this loader into
- libltdl's loader list: */
- static int vl_exit (lt_user_data loader_data);
- static lt_module vm_open (lt_user_data loader_data, const char *filename,
- lt_dladvise advise);
- static int vm_close (lt_user_data loader_data, lt_module module);
- static void * vm_sym (lt_user_data loader_data, lt_module module,
- const char *symbolname);
- static lt_dlvtable *vtable = 0;
- /* Return the vtable for this loader, only the name and sym_prefix
- attributes (plus the virtual function implementations, obviously)
- change between loaders. */
- lt_dlvtable *
- get_vtable (lt_user_data loader_data)
- {
- if (!vtable)
- {
- vtable = (lt_dlvtable *) lt__zalloc (sizeof *vtable);
- }
- if (vtable && !vtable->name)
- {
- vtable->name = "lt_dlopen";
- #if defined DLSYM_USCORE
- vtable->sym_prefix = "_";
- #endif
- vtable->module_open = vm_open;
- vtable->module_close = vm_close;
- vtable->find_sym = vm_sym;
- vtable->dlloader_exit = vl_exit;
- vtable->dlloader_data = loader_data;
- vtable->priority = LT_DLLOADER_PREPEND;
- }
- if (vtable && (vtable->dlloader_data != loader_data))
- {
- LT__SETERROR (INIT_LOADER);
- return 0;
- }
- return vtable;
- }
- /* --- IMPLEMENTATION --- */
- #if defined HAVE_DLFCN_H
- # include <dlfcn.h>
- #endif
- #if defined HAVE_SYS_DL_H
- # include <sys/dl.h>
- #endif
- /* We may have to define LT_LAZY_OR_NOW in the command line if we
- find out it does not work in some platform. */
- #if !defined LT_LAZY_OR_NOW
- # if defined RTLD_LAZY
- # define LT_LAZY_OR_NOW RTLD_LAZY
- # else
- # if defined DL_LAZY
- # define LT_LAZY_OR_NOW DL_LAZY
- # endif
- # endif /* !RTLD_LAZY */
- #endif
- #if !defined LT_LAZY_OR_NOW
- # if defined RTLD_NOW
- # define LT_LAZY_OR_NOW RTLD_NOW
- # else
- # if defined DL_NOW
- # define LT_LAZY_OR_NOW DL_NOW
- # endif
- # endif /* !RTLD_NOW */
- #endif
- #if !defined LT_LAZY_OR_NOW
- # define LT_LAZY_OR_NOW 0
- #endif /* !LT_LAZY_OR_NOW */
- /* We only support local and global symbols from modules for loaders
- that provide such a thing, otherwise the system default is used. */
- #if !defined RTLD_GLOBAL
- # if defined DL_GLOBAL
- # define RTLD_GLOBAL DL_GLOBAL
- # endif
- #endif /* !RTLD_GLOBAL */
- #if !defined RTLD_LOCAL
- # if defined DL_LOCAL
- # define RTLD_LOCAL DL_LOCAL
- # endif
- #endif /* !RTLD_LOCAL */
- #if defined HAVE_DLERROR
- # define DLERROR(arg) dlerror ()
- #else
- # define DLERROR(arg) LT__STRERROR (arg)
- #endif
- #define DL__SETERROR(errorcode) \
- LT__SETERRORSTR (DLERROR (errorcode))
- /* A function called through the vtable when this loader is no
- longer needed by the application. */
- static int
- vl_exit (lt_user_data loader_data LT__UNUSED)
- {
- vtable = NULL;
- return 0;
- }
- /* A function called through the vtable to open a module with this
- loader. Returns an opaque representation of the newly opened
- module for processing with this loader's other vtable functions. */
- static lt_module
- vm_open (lt_user_data loader_data LT__UNUSED, const char *filename,
- lt_dladvise advise)
- {
- int module_flags = LT_LAZY_OR_NOW;
- lt_module module;
- #ifdef RTLD_MEMBER
- int len = LT_STRLEN (filename);
- #endif
- if (advise)
- {
- #ifdef RTLD_GLOBAL
- /* If there is some means of asking for global symbol resolution,
- do so. */
- if (advise->is_symglobal)
- module_flags |= RTLD_GLOBAL;
- #else
- /* Otherwise, reset that bit so the caller can tell it wasn't
- acted on. */
- advise->is_symglobal = 0;
- #endif
- /* And similarly for local only symbol resolution. */
- #ifdef RTLD_LOCAL
- if (advise->is_symlocal)
- module_flags |= RTLD_LOCAL;
- #else
- advise->is_symlocal = 0;
- #endif
- }
- #ifdef RTLD_MEMBER /* AIX */
- if (len >= 4) /* at least "l(m)" */
- {
- /* Advise loading an archive member only if the filename really
- contains both the opening and closing parent, and a member. */
- if (filename[len-1] == ')')
- {
- const char *opening = strrchr(filename, '(');
- if (opening && opening < (filename+len-2) && strchr(opening+1, '/') == NULL)
- module_flags |= RTLD_MEMBER;
- }
- }
- #endif
- module = dlopen (filename, module_flags);
- #if defined RTLD_MEMBER && defined LT_SHARED_LIB_MEMBER
- if (!module && len && !(module_flags & RTLD_MEMBER) && errno == ENOEXEC)
- {
- /* Loading without a member specified failed with "Exec format error".
- So the file is there, but either has wrong bitwidth, or is an
- archive eventually containing the default shared archive member.
- Retry with default member, getting same error in worst case. */
- const char *member = LT_SHARED_LIB_MEMBER;
- char *attempt = MALLOC (char, len + strlen (member) + 1);
- if (!attempt)
- {
- LT__SETERROR (NO_MEMORY);
- return module;
- }
- sprintf (attempt, "%s%s", filename, member);
- module = vm_open (loader_data, attempt, advise);
- FREE (attempt);
- return module;
- }
- #endif
- if (!module)
- {
- DL__SETERROR (CANNOT_OPEN);
- }
- return module;
- }
- /* A function called through the vtable when a particular module
- should be unloaded. */
- static int
- vm_close (lt_user_data loader_data LT__UNUSED, lt_module module)
- {
- int errors = 0;
- if (dlclose (module) != 0)
- {
- DL__SETERROR (CANNOT_CLOSE);
- ++errors;
- }
- return errors;
- }
- /* A function called through the vtable to get the address of
- a symbol loaded from a particular module. */
- static void *
- vm_sym (lt_user_data loader_data LT__UNUSED, lt_module module, const char *name)
- {
- void *address = dlsym (module, name);
- if (!address)
- {
- DL__SETERROR (SYMBOL_NOT_FOUND);
- }
- return address;
- }
|