message
[sbcl.git] / src / code / foreign-load.lisp
1 ;;;; Loading shared object files
2
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
11
12 (in-package "SB!ALIEN")
13
14 ;;; Used to serialize modifications to *linkage-info*,
15 ;;; *shared-objects* and the linkage-table proper. Calls thru
16 ;;; linkage-table are unaffected.
17 (defvar *foreign-lock*
18   (sb!thread:make-mutex :name "foreign definition lock"))
19
20 (define-unsupported-fun load-foreign
21     "Unsupported as of SBCL 0.8.13. See LOAD-SHARED-OBJECT."
22   "~S is unsupported as of SBCL 0.8.13. See LOAD-SHARED-OBJECT." 
23   (load-foreign))
24   
25 (define-unsupported-fun load-1-foreign
26     "Unsupported as of SBCL 0.8.13. Please use LOAD-SHARED-OBJECT."
27   "~S is unsupported as of SBCL 0.8.13. Please use LOAD-SHARED-OBJECT."
28   (load-1-foreign))
29
30 (define-alien-routine dlopen system-area-pointer
31   (file c-string) (mode int))
32
33 (define-alien-routine dlclose int
34   (handle system-area-pointer))
35
36 (define-alien-routine dlerror c-string)
37
38 (define-alien-routine dlsym system-area-pointer
39   (handle system-area-pointer)
40   (symbol c-string))
41
42 (define-alien-variable undefined-alien-address unsigned-long)
43
44 (defvar *runtime-dlhandle*)
45 (defvar *shared-objects*)
46
47 (defstruct shared-object file sap)
48
49 (defun dlopen-or-lose (&optional (obj nil objp))
50   (when objp
51     (dlclose-or-lose obj))
52   (dlerror) ; clear errors
53   (let* ((file (and obj (shared-object-file obj)))
54          (sap (dlopen file (logior rtld-global rtld-now))))
55     (aver (or (not objp) file))
56     (when (zerop (sap-int sap))
57       (if objp
58           (setf (shared-object-sap obj) nil)
59           (setf *runtime-dlhandle* nil))
60       (error "Could not open ~:[runtime~;~:*shared object ~S~]: ~A"
61              obj (dlerror)))
62     (when objp
63       (setf (shared-object-sap obj) sap))
64     sap))
65
66 (defun dlclose-or-lose (&optional (obj nil objp))
67   (dlerror)
68   (let (dlerror)
69     (cond ((and (not objp) *runtime-dlhandle*)
70            (dlclose *runtime-dlhandle*)
71            (setf dlerror (dlerror)
72                  *runtime-dlhandle* nil))
73           ((and objp (shared-object-sap obj))
74            (dlclose (shared-object-sap obj))
75            (setf dlerror (dlerror)
76                  (shared-object-sap obj) nil)))
77     (when dlerror
78       (cerror "Ignore the error and continue anyway" "dlerror returned an error: ~S" dlerror))))
79
80 (defun load-shared-object (file)
81   "Load a shared library/dynamic shared object file/general dlopenable
82 alien container, such as a .so on an ELF platform.
83
84 Reloading the same shared object will replace the old definitions; if
85 a symbol was previously referenced thru the object and is not present
86 in the reloaded version an error will be signalled. Sameness is
87 determined using the library filename. Reloading may not work as
88 expected if user or library-code has called dlopen on FILE.
89
90 References to foreign symbols in loaded shared objects do not survive
91 intact through SB-EXT:SAVE-LISP-AND die on all platforms. See
92 SB-EXT:SAVE-LISP-AND-DIE for details."
93   (sb!thread:with-mutex (*foreign-lock*)
94     (let* ((filename (or (unix-namestring file) file))
95            (old (find filename *shared-objects* :key #'shared-object-file :test #'equal))
96            (obj (or old (make-shared-object :file filename))))
97       (dlopen-or-lose obj)
98       (setf *shared-objects* (append (remove obj *shared-objects*)
99                                      (list obj)))
100       #!+linkage-table
101       (when (or old (undefined-foreign-symbols))
102         (update-linkage-table))
103       (pathname filename))))
104
105 (defun try-reopen-shared-object (obj)
106   (declare (type shared-object obj))
107   (tagbody :dlopen
108      (restart-case
109          (dlopen-or-lose obj)
110        (continue ()
111          :report "Skip this shared object and continue."
112          (setf (shared-object-sap obj) nil))
113        (retry ()
114          :report "Retry loading this shared object."
115          (go :dlopen))
116        (load-other ()
117          :report "Specify an alternate shared object file to load."
118          (setf (shared-object-file obj)
119                (tagbody :query
120                   (format *query-io* "~&Enter pathname (evaluated):~%")
121                   (force-output *query-io*)
122                   (let ((pathname (ignore-errors (pathname (read *query-io*)))))
123                     (unless (pathnamep pathname)
124                       (format *query-io* "~&Error: invalid pathname.~%")
125                       (go :query))
126                     (unix-namestring pathname)))))))
127   obj)
128
129 ;;; Open libraries in *SHARED-OBJECTS* and the runtime. Called during
130 ;;; initialization. 
131 (defun reopen-shared-objects ()
132   ;; Ensure that the runtime is open
133   (setf *runtime-dlhandle* (dlopen-or-lose)
134         *shared-objects* (mapcar #'try-reopen-shared-object *shared-objects*)))
135
136 ;;; Close all dlopened libraries and clear out sap entries in
137 ;;; *SHARED-OBJECTS*.
138 (defun close-shared-objects ()
139   (mapc #'dlclose-or-lose (reverse *shared-objects*))
140   (dlclose-or-lose))
141
142 (let ((symbols ())
143       (undefineds ()))
144   (defun get-dynamic-foreign-symbol-address (symbol &optional datap)
145     (dlerror)                           ; clear old errors
146     (unless *runtime-dlhandle*
147       (bug "Cannot resolve foreign symbol: lost *runtime-dlhandle*"))
148     (let* ((result (sap-int (dlsym *runtime-dlhandle* symbol)))
149            (err (dlerror))
150            (addr (if (or (not (zerop result)) (not err))
151                      result
152                      (dolist (obj *shared-objects*)
153                        (let ((sap (shared-object-sap obj)))
154                          (when sap
155                            (setf result (sap-int (dlsym sap symbol))
156                                  err (dlerror))
157                            (when (or (not (zerop result)) (not err))
158                              (return result))))))))
159       (cond  ((not addr)
160               (style-warn "Undefined alien: ~S" symbol)
161               (pushnew symbol undefineds :test #'equal)
162               (remove symbol symbols :test #'equal)
163               (if datap
164                   undefined-alien-address
165                   (foreign-symbol-address-as-integer 
166                    (sb!vm:extern-alien-name "undefined_alien_function"))))
167              (addr
168               (pushnew symbol symbols :test #'equal)
169               (remove symbol undefineds :test #'equal)
170               addr))))
171   (defun dynamic-foreign-symbols ()
172     symbols)
173   (defun undefined-foreign-symbols ()
174     undefineds))