format: Signal an error for ~<~@>
[sbcl.git] / src / code / foreign.lisp
1 ;;;; Foreign symbol linkage
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!IMPL")
13
14 #!-(or elf mach-o win32)
15 (error "Not an ELF, Mach-O, or Win32 platform?")
16
17 (defun extern-alien-name (name)
18   (handler-case
19       (coerce name 'base-string)
20     (error ()
21       (error "invalid external alien name: ~S" name))))
22
23 ;;; *STATIC-FOREIGN-SYMBOLS* are static as opposed to "dynamic" (not
24 ;;; as opposed to C's "extern"). The table contains symbols known at
25 ;;; the time that the program was built, but not symbols defined in
26 ;;; object files which have been loaded dynamically since then.
27 (declaim (type hash-table *static-foreign-symbols*))
28 (defvar *static-foreign-symbols* (make-hash-table :test 'equal))
29
30 (declaim
31  (ftype (sfunction (string hash-table) (or integer null)) find-foreign-symbol-in-table))
32 (defun find-foreign-symbol-in-table (name table)
33   (let ((extern (extern-alien-name name)))
34     (values
35      (or (gethash extern table)
36          (gethash (concatenate 'base-string "ldso_stub__" extern) table)))))
37
38 (defun find-foreign-symbol-address (name)
39   "Returns the address of the foreign symbol NAME, or NIL. Does not enter the
40 symbol in the linkage table, and never returns an address in the linkage-table."
41   (or (find-foreign-symbol-in-table name *static-foreign-symbols*)
42       (find-dynamic-foreign-symbol-address name)))
43
44 (defun foreign-symbol-address (name &optional datap)
45   "Returns the address of the foreign symbol NAME. DATAP must be true if the
46 symbol designates a variable (used only on linkage-table platforms). Returns a
47 secondary value that is true if DATAP was true and the symbol is a dynamic
48 foreign symbol.
49
50 On linkage-table ports the returned address is always static: either direct
51 address of a static symbol, or the linkage-table address of a dynamic one.
52 Dynamic symbols are entered into the linkage-table if they aren't there already.
53
54 On non-linkage-table ports signals an error if the symbol isn't found."
55   (declare (ignorable datap))
56   #!+sb-dynamic-core
57   (values (ensure-foreign-symbol-linkage name datap) t)
58   #!-sb-dynamic-core
59   (let ((static (find-foreign-symbol-in-table name *static-foreign-symbols*)))
60     (if static
61         (values static nil)
62         #!+os-provides-dlopen
63         (progn
64           #-sb-xc-host
65           (values #!-linkage-table
66                   (ensure-dynamic-foreign-symbol-address name)
67                   #!+linkage-table
68                   (ensure-foreign-symbol-linkage name datap)
69                   t)
70           #+sb-xc-host
71           (error 'undefined-alien-error :name name))
72         #!-os-provides-dlopen
73         (error 'undefined-alien-error :name name))))
74
75 (defun foreign-symbol-sap (symbol &optional datap)
76   "Returns a SAP corresponding to the foreign symbol. DATAP must be true if the
77 symbol designates a variable (used only on linkage-table platforms). May enter
78 the symbol into the linkage-table. On non-linkage-table ports signals an error
79 if the symbol isn't found."
80   (declare (ignorable datap))
81   #!-linkage-table
82   (int-sap (foreign-symbol-address symbol))
83   #!+linkage-table
84   (multiple-value-bind (addr sharedp)
85       (foreign-symbol-address symbol datap)
86     #+sb-xc-host #!-sb-dynamic-core (aver (not sharedp)) ()
87     ;; If the address is from linkage-table and refers to data
88     ;; we need to do a bit of juggling. It is not the address of the
89     ;; variable, but the address where the real address is stored.
90     (if (and sharedp datap)
91         (int-sap (sap-ref-word (int-sap addr) 0))
92         (int-sap addr))))
93
94 #-sb-xc-host
95 (defun foreign-reinit ()
96   #!+os-provides-dlopen
97   (reopen-shared-objects)
98   #!+linkage-table
99   ;; Don't warn about undefined aliens on startup. The same core can
100   ;; reasonably be expected to work with different versions of the
101   ;; same library.
102   (handler-bind ((style-warning #'muffle-warning))
103     (update-linkage-table)))
104
105 ;;; Cleanups before saving a core
106 #-sb-xc-host
107 (defun foreign-deinit ()
108   #!+(and os-provides-dlopen (not linkage-table))
109   (when (dynamic-foreign-symbols-p)
110     (warn "~@<Saving cores with alien definitions referring to non-static ~
111            foreign symbols is unsupported on this platform: references to ~
112            such foreign symbols from the restarted core will not work. You ~
113            may be able to work around this limitation by reloading all ~
114            foreign definitions and code using them in the restarted core, ~
115            but no guarantees.~%~%Dynamic foreign symbols in this core: ~
116            ~{~A~^, ~}~:@>" (list-dynamic-foreign-symbols)))
117   #!+os-provides-dlopen
118   (close-shared-objects))
119
120 (declaim (maybe-inline sap-foreign-symbol))
121 (defun sap-foreign-symbol (sap)
122   (declare (ignorable sap))
123   #-sb-xc-host
124   (let ((addr (sap-int sap)))
125     (declare (ignorable addr))
126     #!+linkage-table
127     (when (<= sb!vm:linkage-table-space-start
128               addr
129               sb!vm:linkage-table-space-end)
130       (dohash ((name-and-datap info) *linkage-info* :locked t)
131         (let ((table-addr (linkage-info-address info)))
132           (when (and (<= table-addr addr)
133                      (< addr (+ table-addr sb!vm:linkage-table-entry-size)))
134             (return-from sap-foreign-symbol (car name-and-datap))))))
135     #!+os-provides-dladdr
136     (with-alien ((info (struct dl-info
137                                (filename c-string)
138                                (base unsigned)
139                                (symbol c-string)
140                                (symbol-address unsigned)))
141                  (dladdr (function unsigned unsigned (* (struct dl-info)))
142                          :extern "dladdr"))
143       (let ((err (without-gcing
144                    ;; On eg. Darwin GC can could otherwise interrupt
145                    ;; the call while dladdr is holding a lock.
146                    (alien-funcall dladdr addr (addr info)))))
147         (if (zerop err)
148             nil
149             (slot info 'symbol))))
150     ;; FIXME: Even in the absence of dladdr we could search the
151     ;; static foreign symbols (and *linkage-info*, for that matter).
152     ))
153
154 ;;; How we learn about foreign symbols and dlhandles initially
155 (defvar *!initial-foreign-symbols*)
156
157 #-sb-xc-host
158 (defun !foreign-cold-init ()
159   #!-sb-dynamic-core
160   (dolist (symbol *!initial-foreign-symbols*)
161     (setf (gethash (car symbol) *static-foreign-symbols*) (cdr symbol)))
162   #!+sb-dynamic-core
163   (loop for table-address from sb!vm::linkage-table-space-start
164           by sb!vm::linkage-table-entry-size
165           and reference in sb!vm::*required-runtime-c-symbols*
166         do (setf (gethash reference *linkage-info*)
167                  (make-linkage-info :datap (cdr reference)
168                       :address table-address)))
169   #!+os-provides-dlopen
170   (setf *runtime-dlhandle* (dlopen-or-lose))
171   #!+os-provides-dlopen
172   (setf *shared-objects* nil))
173
174 #!-os-provides-dlopen
175 (define-unsupported-fun load-shared-object)