dynl.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /* dynl.c - dynamic linking
  2. Copyright 1990-2003,2008-2011,2017-2018
  3. Free Software Foundation, Inc.
  4. This file is part of Guile.
  5. Guile is free software: you can redistribute it and/or modify it
  6. under the terms of the GNU Lesser General Public License as published
  7. by the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. Guile is distributed in the hope that it will be useful, but WITHOUT
  10. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  12. License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with Guile. If not, see
  15. <https://www.gnu.org/licenses/>. */
  16. /* "dynl.c" dynamically link&load object files.
  17. Author: Aubrey Jaffer
  18. Modified for libguile by Marius Vollmer */
  19. #ifdef HAVE_CONFIG_H
  20. # include <config.h>
  21. #endif
  22. #include <alloca.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <ltdl.h>
  27. #include "deprecation.h"
  28. #include "dynwind.h"
  29. #include "foreign.h"
  30. #include "gc.h"
  31. #include "gsubr.h"
  32. #include "keywords.h"
  33. #include "libpath.h"
  34. #include "list.h"
  35. #include "ports.h"
  36. #include "smob.h"
  37. #include "strings.h"
  38. #include "threads.h"
  39. #include "dynl.h"
  40. /* From the libtool manual: "Note that libltdl is not threadsafe,
  41. i.e. a multithreaded application has to use a mutex for libltdl.".
  42. Note: We initialize it as a recursive mutex below. */
  43. static scm_i_pthread_mutex_t ltdl_lock = SCM_I_PTHREAD_MUTEX_INITIALIZER;
  44. /* LT_PATH_SEP-separated extension library search path, searched last */
  45. static char *system_extensions_path;
  46. static void *
  47. sysdep_dynl_link (const char *fname, const char *subr)
  48. {
  49. lt_dlhandle handle;
  50. if (fname == NULL)
  51. /* Return a handle for the program as a whole. */
  52. handle = lt_dlopen (NULL);
  53. else
  54. {
  55. handle = lt_dlopenext (fname);
  56. if (handle == NULL
  57. #ifdef LT_DIRSEP_CHAR
  58. && strchr (fname, LT_DIRSEP_CHAR) == NULL
  59. #endif
  60. && strchr (fname, '/') == NULL)
  61. {
  62. /* FNAME contains no directory separators and was not in the
  63. usual library search paths, so now we search for it in
  64. SYSTEM_EXTENSIONS_PATH. */
  65. char *fname_attempt
  66. = scm_gc_malloc_pointerless (strlen (system_extensions_path)
  67. + strlen (fname) + 2,
  68. "dynl fname_attempt");
  69. char *path; /* remaining path to search */
  70. char *end; /* end of current path component */
  71. char *s;
  72. /* Iterate over the components of SYSTEM_EXTENSIONS_PATH */
  73. for (path = system_extensions_path;
  74. *path != '\0';
  75. path = (*end == '\0') ? end : (end + 1))
  76. {
  77. /* Find end of path component */
  78. end = strchr (path, LT_PATHSEP_CHAR);
  79. if (end == NULL)
  80. end = strchr (path, '\0');
  81. /* Skip empty path components */
  82. if (path == end)
  83. continue;
  84. /* Construct FNAME_ATTEMPT, starting with path component */
  85. s = fname_attempt;
  86. memcpy (s, path, end - path);
  87. s += end - path;
  88. /* Append directory separator, but avoid duplicates */
  89. if (s[-1] != '/'
  90. #ifdef LT_DIRSEP_CHAR
  91. && s[-1] != LT_DIRSEP_CHAR
  92. #endif
  93. )
  94. *s++ = '/';
  95. /* Finally, append FNAME (including null terminator) */
  96. strcpy (s, fname);
  97. /* Try to load it, and terminate the search if successful */
  98. handle = lt_dlopenext (fname_attempt);
  99. if (handle != NULL)
  100. break;
  101. }
  102. }
  103. }
  104. if (handle == NULL)
  105. {
  106. SCM fn;
  107. SCM msg;
  108. fn = fname != NULL ? scm_from_locale_string (fname) : SCM_BOOL_F;
  109. msg = scm_from_locale_string (lt_dlerror ());
  110. scm_misc_error (subr, "file: ~S, message: ~S", scm_list_2 (fn, msg));
  111. }
  112. return (void *) handle;
  113. }
  114. static void
  115. sysdep_dynl_unlink (void *handle, const char *subr)
  116. {
  117. if (lt_dlclose ((lt_dlhandle) handle))
  118. {
  119. scm_misc_error (subr, (char *) lt_dlerror (), SCM_EOL);
  120. }
  121. }
  122. static void *
  123. sysdep_dynl_value (const char *symb, void *handle, const char *subr)
  124. {
  125. void *fptr;
  126. fptr = lt_dlsym ((lt_dlhandle) handle, symb);
  127. if (!fptr)
  128. scm_misc_error (subr, "Symbol not found: ~a",
  129. scm_list_1 (scm_from_locale_string (symb)));
  130. return fptr;
  131. }
  132. static void
  133. sysdep_dynl_init ()
  134. {
  135. char *env;
  136. lt_dlinit ();
  137. /* Initialize 'system_extensions_path' from
  138. $GUILE_SYSTEM_EXTENSIONS_PATH, or if that's not set:
  139. <SCM_LIB_DIR> <LT_PATHSEP_CHAR> <SCM_EXTENSIONS_DIR>.
  140. 'lt_dladdsearchdir' can't be used because it is searched before
  141. the system-dependent search path, which is the one 'libtool
  142. --mode=execute -dlopen' fiddles with (info "(libtool) Libltdl
  143. Interface"). See
  144. <http://lists.gnu.org/archive/html/guile-devel/2010-11/msg00095.html>.
  145. The environment variables $LTDL_LIBRARY_PATH and $LD_LIBRARY_PATH
  146. can't be used because they would be propagated to subprocesses
  147. which may cause problems for other programs. See
  148. <http://lists.gnu.org/archive/html/guile-devel/2012-09/msg00037.html> */
  149. env = getenv ("GUILE_SYSTEM_EXTENSIONS_PATH");
  150. if (env)
  151. system_extensions_path = env;
  152. else
  153. {
  154. system_extensions_path
  155. = scm_gc_malloc_pointerless (strlen (SCM_LIB_DIR)
  156. + strlen (SCM_EXTENSIONS_DIR) + 2,
  157. "system_extensions_path");
  158. sprintf (system_extensions_path, "%s%c%s",
  159. SCM_LIB_DIR, LT_PATHSEP_CHAR, SCM_EXTENSIONS_DIR);
  160. }
  161. }
  162. scm_t_bits scm_tc16_dynamic_obj;
  163. #define DYNL_FILENAME SCM_SMOB_OBJECT
  164. #define DYNL_HANDLE(x) ((void *) SCM_SMOB_DATA_2 (x))
  165. #define SET_DYNL_HANDLE(x, v) (SCM_SET_SMOB_DATA_2 ((x), (scm_t_bits) (v)))
  166. static int
  167. dynl_obj_print (SCM exp, SCM port, scm_print_state *pstate)
  168. {
  169. scm_puts ("#<dynamic-object ", port);
  170. scm_iprin1 (DYNL_FILENAME (exp), port, pstate);
  171. if (DYNL_HANDLE (exp) == NULL)
  172. scm_puts (" (unlinked)", port);
  173. scm_putc ('>', port);
  174. return 1;
  175. }
  176. SCM_DEFINE (scm_dynamic_link, "dynamic-link", 0, 1, 0,
  177. (SCM filename),
  178. "Find the shared object (shared library) denoted by\n"
  179. "@var{filename} and link it into the running Guile\n"
  180. "application. The returned\n"
  181. "scheme object is a ``handle'' for the library which can\n"
  182. "be passed to @code{dynamic-func}, @code{dynamic-call} etc.\n\n"
  183. "Searching for object files is system dependent. Normally,\n"
  184. "if @var{filename} does have an explicit directory it will\n"
  185. "be searched for in locations\n"
  186. "such as @file{/usr/lib} and @file{/usr/local/lib}.\n\n"
  187. "When @var{filename} is omitted, a @dfn{global symbol handle} is\n"
  188. "returned. This handle provides access to the symbols\n"
  189. "available to the program at run-time, including those exported\n"
  190. "by the program itself and the shared libraries already loaded.\n")
  191. #define FUNC_NAME s_scm_dynamic_link
  192. {
  193. void *handle;
  194. char *file;
  195. scm_dynwind_begin (0);
  196. scm_i_dynwind_pthread_mutex_lock (&ltdl_lock);
  197. if (SCM_UNBNDP (filename))
  198. file = NULL;
  199. else
  200. {
  201. file = scm_to_locale_string (filename);
  202. scm_dynwind_free (file);
  203. }
  204. handle = sysdep_dynl_link (file, FUNC_NAME);
  205. scm_dynwind_end ();
  206. SCM_RETURN_NEWSMOB2 (scm_tc16_dynamic_obj,
  207. SCM_UNBNDP (filename)
  208. ? SCM_UNPACK (SCM_BOOL_F) : SCM_UNPACK (filename),
  209. handle);
  210. }
  211. #undef FUNC_NAME
  212. SCM_DEFINE (scm_dynamic_object_p, "dynamic-object?", 1, 0, 0,
  213. (SCM obj),
  214. "Return @code{#t} if @var{obj} is a dynamic object handle,\n"
  215. "or @code{#f} otherwise.")
  216. #define FUNC_NAME s_scm_dynamic_object_p
  217. {
  218. return scm_from_bool (SCM_TYP16_PREDICATE (scm_tc16_dynamic_obj, obj));
  219. }
  220. #undef FUNC_NAME
  221. SCM_DEFINE (scm_dynamic_unlink, "dynamic-unlink", 1, 0, 0,
  222. (SCM dobj),
  223. "Unlink a dynamic object from the application, if possible. The\n"
  224. "object must have been linked by @code{dynamic-link}, with \n"
  225. "@var{dobj} the corresponding handle. After this procedure\n"
  226. "is called, the handle can no longer be used to access the\n"
  227. "object.")
  228. #define FUNC_NAME s_scm_dynamic_unlink
  229. {
  230. /*fixme* GC-problem */
  231. SCM_VALIDATE_SMOB (SCM_ARG1, dobj, dynamic_obj);
  232. scm_dynwind_begin (0);
  233. scm_i_dynwind_pthread_mutex_lock (&ltdl_lock);
  234. if (DYNL_HANDLE (dobj) == NULL) {
  235. SCM_MISC_ERROR ("Already unlinked: ~S", scm_list_1 (dobj));
  236. } else {
  237. sysdep_dynl_unlink (DYNL_HANDLE (dobj), FUNC_NAME);
  238. SET_DYNL_HANDLE (dobj, NULL);
  239. }
  240. scm_dynwind_end ();
  241. return SCM_UNSPECIFIED;
  242. }
  243. #undef FUNC_NAME
  244. SCM_DEFINE (scm_dynamic_pointer, "dynamic-pointer", 2, 0, 0,
  245. (SCM name, SCM dobj),
  246. "Return a ``wrapped pointer'' to the symbol @var{name}\n"
  247. "in the shared object referred to by @var{dobj}. The returned\n"
  248. "pointer points to a C object.\n\n"
  249. "Regardless whether your C compiler prepends an underscore\n"
  250. "@samp{_} to the global names in a program, you should\n"
  251. "@strong{not} include this underscore in @var{name}\n"
  252. "since it will be added automatically when necessary.")
  253. #define FUNC_NAME s_scm_dynamic_pointer
  254. {
  255. void *val;
  256. SCM_VALIDATE_STRING (1, name);
  257. SCM_VALIDATE_SMOB (SCM_ARG2, dobj, dynamic_obj);
  258. if (DYNL_HANDLE (dobj) == NULL)
  259. SCM_MISC_ERROR ("Already unlinked: ~S", dobj);
  260. else
  261. {
  262. char *chars;
  263. scm_dynwind_begin (0);
  264. scm_i_dynwind_pthread_mutex_lock (&ltdl_lock);
  265. chars = scm_to_locale_string (name);
  266. scm_dynwind_free (chars);
  267. val = sysdep_dynl_value (chars, DYNL_HANDLE (dobj), FUNC_NAME);
  268. scm_dynwind_end ();
  269. return scm_from_pointer (val, NULL);
  270. }
  271. }
  272. #undef FUNC_NAME
  273. SCM_DEFINE (scm_dynamic_func, "dynamic-func", 2, 0, 0,
  274. (SCM name, SCM dobj),
  275. "Return a ``handle'' for the function @var{name} in the\n"
  276. "shared object referred to by @var{dobj}. The handle\n"
  277. "can be passed to @code{dynamic-call} to actually\n"
  278. "call the function.\n\n"
  279. "Regardless whether your C compiler prepends an underscore\n"
  280. "@samp{_} to the global names in a program, you should\n"
  281. "@strong{not} include this underscore in @var{name}\n"
  282. "since it will be added automatically when necessary.")
  283. #define FUNC_NAME s_scm_dynamic_func
  284. {
  285. return scm_dynamic_pointer (name, dobj);
  286. }
  287. #undef FUNC_NAME
  288. SCM_DEFINE (scm_dynamic_call, "dynamic-call", 2, 0, 0,
  289. (SCM func, SCM dobj),
  290. "Call a C function in a dynamic object. Two styles of\n"
  291. "invocation are supported:\n\n"
  292. "@itemize @bullet\n"
  293. "@item @var{func} can be a function handle returned by\n"
  294. "@code{dynamic-func}. In this case @var{dobj} is\n"
  295. "ignored\n"
  296. "@item @var{func} can be a string with the name of the\n"
  297. "function to call, with @var{dobj} the handle of the\n"
  298. "dynamic object in which to find the function.\n"
  299. "This is equivalent to\n"
  300. "@smallexample\n\n"
  301. "(dynamic-call (dynamic-func @var{func} @var{dobj}) #f)\n"
  302. "@end smallexample\n"
  303. "@end itemize\n\n"
  304. "In either case, the function is passed no arguments\n"
  305. "and its return value is ignored.")
  306. #define FUNC_NAME s_scm_dynamic_call
  307. {
  308. void (*fptr) (void);
  309. if (scm_is_string (func))
  310. func = scm_dynamic_func (func, dobj);
  311. SCM_VALIDATE_POINTER (SCM_ARG1, func);
  312. fptr = SCM_POINTER_VALUE (func);
  313. fptr ();
  314. return SCM_UNSPECIFIED;
  315. }
  316. #undef FUNC_NAME
  317. void
  318. scm_init_dynamic_linking ()
  319. {
  320. scm_tc16_dynamic_obj = scm_make_smob_type ("dynamic-object", 0);
  321. scm_set_smob_print (scm_tc16_dynamic_obj, dynl_obj_print);
  322. /* Make LTDL_LOCK recursive so that a pre-unwind handler can still use
  323. 'dynamic-link', as is the case at the REPL. See
  324. <https://bugs.gnu.org/29275>. */
  325. scm_i_pthread_mutex_init (&ltdl_lock,
  326. scm_i_pthread_mutexattr_recursive);
  327. sysdep_dynl_init ();
  328. #include "dynl.x"
  329. }