236 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			236 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /* loader-dlopen.c --  dynamic linking with dlopen/dlsym
 | ||
|  | 
 | ||
|  |    Copyright (C) 1998, 1999, 2000, 2004, 2006, | ||
|  |                  2007, 2008 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 LT__UNUSED loader_data) | ||
|  | { | ||
|  |   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 LT__UNUSED loader_data, const char *filename, | ||
|  |          lt_dladvise advise) | ||
|  | { | ||
|  |   int		module_flags = LT_LAZY_OR_NOW; | ||
|  |   lt_module	module; | ||
|  | 
 | ||
|  |   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
 | ||
|  |     } | ||
|  | 
 | ||
|  |   module = dlopen (filename, module_flags); | ||
|  | 
 | ||
|  |   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 LT__UNUSED loader_data, 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 LT__UNUSED loader_data, lt_module module, const char *name) | ||
|  | { | ||
|  |   void *address = dlsym (module, name); | ||
|  | 
 | ||
|  |   if (!address) | ||
|  |     { | ||
|  |       DL__SETERROR (SYMBOL_NOT_FOUND); | ||
|  |     } | ||
|  | 
 | ||
|  |   return address; | ||
|  | } |