YAP 7.1.0
load_dl.c
1/*************************************************************************
2 * *
3 * YAP Prolog *
4 * *
5 * Yap Prolog was developed at NCCUP - Universidade do Porto *
6 * *
7 * Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
8 * *
9 **************************************************************************
10 * *
11 * File: load_dl.c *
12 * comments: dl based dynamic loaderr of external routines *
13 * tested on i486-linuxelf *
14 *************************************************************************/
15
16#include "Yap.h"
17#include "YapHeap.h"
18#include "Yatom.h"
19#include "yapio.h"
20
21#include "Foreign.h"
22
23#if LOAD_DL
24
25// use SWI-Prolog code if all else fails
26char *findExecutable(const char *av0, char *buffer);
27
28#include <dlfcn.h>
29#include <stdarg.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34#if defined(__APPLE__)
35#include <dlfcn.h>
36#include <mach-o/dyld.h>
37#endif
38
39typedef void (*prismf)(void);
40
41/* only works for dlls */
42int Yap_CallFunctionByName(const char *thing_string);
43
44int Yap_CallFunctionByName(const char *thing_string) {
45 void *handle = dlopen(NULL, RTLD_LAZY
46#ifndef __CYGWIN__
47#ifdef RTLD_NOLOAD
48 | RTLD_NOLOAD
49#endif
50#endif
51 );
52 // you could do RTLD_NOW as well. shouldn't matter
53 if (!handle) {
54 CACHE_REGS
55 Yap_Error(SYSTEM_ERROR_INTERNAL, ARG1,
56 "Dynamic linking on main module : %s\n", dlerror());
57 }
58 prismf *addr = (prismf *)dlsym(handle, thing_string);
59 if (addr)
60 (*addr)();
61 dlclose(handle);
62 return TRUE;
63}
64
65/*
66 * YAP_FindExecutable(argv[0]) should be called on yap initialization to
67 * locate the executable of Yap
68 */
69char *Yap_FindExecutable(void) {
70#if HAVE_GETEXECNAME
71 // Solaris
72 return getexecname();
73#elif __APPLE__
74 char *buf = malloc(MAX_PATH);
75
76 uint32_t size;
77 if (!_NSGetExecutablePath(buf, &size)) {
78 buf = realloc(buf, size + 1);
79 return buf;
80 }
81 return "yap";
82#elif defined(__linux__)
83 char *buf = malloc(MAX_PATH);
84 ssize_t len = readlink("/proc/self/exe", buf, MAX_PATH - 1);
85
86 if (len != -1) {
87 buf[len] = '\0';
88 return buf;
89 }
90// follow through to standard method
91#elif defined(__FreeBSD__) || defined(__DragonFly__)
92 enum { BUFFERSIZE = 1024 };
93 char *buf = malloc(BUFFERSIZE);
94 ssize_t len = readlink("/proc/curproc/file", buf, sizeof(buf) - 1);
95
96 if (len != -1) {
97 buf[len] = '\0';
98 return buf;
99 }
100 int mib[4];
101 mib[0] = CTL_KERN;
102 mib[1] = KERN_PROC;
103 mib[2] = KERN_PROC_PATHNAME;
104 mib[3] = -1; // current process
105 size_t cb = BUFFERSIZE;
106 sysctl(mib, 4, buf, &cb, NULL, 0);
107// follow through to standard method
108#endif
109 return NULL;
110}
111
112void *Yap_LoadForeignFile(char *file, int flags) {
113 CACHE_REGS
114 int dlflag;
115 void *out;
116
117 if (flags & EAGER_LOADING)
118 dlflag = RTLD_NOW;
119 else
120 dlflag = RTLD_LAZY;
121 if (flags & GLOBAL_LOADING)
122 dlflag |= RTLD_GLOBAL;
123#ifndef __CYGWIN__
124 else
125 dlflag |= RTLD_LOCAL;
126#endif
127 out = (void *)dlopen(file, dlflag);
128 if (out == NULL) {
129 const char *m_os = dlerror();
130 if (m_os) {
131 LOCAL_ErrorMessage = malloc(MAX_ERROR_MSG_SIZE);
132 strncpy(LOCAL_ErrorMessage, m_os, MAX_ERROR_MSG_SIZE - 1);
133 } else {
134 LOCAL_ErrorMessage = "dlopen failed";
135 }
136 }
137 return out;
138}
139
140int Yap_CallForeignFile(void *handle, char *f) {
141 YapInitProc proc = (YapInitProc)dlsym(handle, f);
142 if (!proc) {
143 /* Yap_Error(SYSTEM_ERROR_INTERNAL, ARG1, "dlsym error %s\n", dlerror());*/
144 return FALSE;
145 }
146 (*proc)();
147 return TRUE;
148}
149
150int Yap_CloseForeignFile(void *handle) {
151 if (dlclose(handle) < 0) {
152 CACHE_REGS
153 Yap_Error(SYSTEM_ERROR_INTERNAL, ARG1, "dlclose error %s\n", dlerror());
154 return -1;
155 }
156 return 0;
157}
158
159static char *
160error_found(char *omsg, char *text, ...)
161{
162 va_list ap;
163 va_start(ap,text);
164 if (!omsg) {
165 omsg = Malloc(MAX_PATH+1);
166 strcpy(omsg,"Got the following OS errors:\n");
167
168 }
169 else{
170 omsg = Realloc(omsg,strlen(omsg)+MAX_PATH);
171 }
172 if (text && text[0])
173 vsnprintf(omsg+strlen(omsg),MAX_PATH-1,text, ap);
174 return omsg;
175}
176
177/*
178 * LoadForeign(ofiles,libs,proc_name,init_proc) dynamically loads foreign
179 * code files and libraries and locates an initialization routine
180 */
181static YapInitProc LoadForeign(StringList
182 ofiles, StringList libs, char *proc_name) {
183 CACHE_REGS
184 LOCAL_ErrorMessage = NULL;
185 char *omsg = NULL;
186 StringList o0 = ofiles;
187 int lvl = push_text_stack();
188
189 while (libs || ofiles) {
190 const char *file;
191 StringList path = libs? libs : ofiles;
192 /* load libraries first so that their symbols are available to
193x other routines */
194 file = AtomName(path->name);
195
196 if ((path->handle = dlopen(file, RTLD_LAZY | RTLD_GLOBAL)) ==
197 NULL)
198 {
199 omsg = error_found(omsg, "Tried to load %s, failed: %s\n", file, dlerror());
200 if (!libs) {
201 Yap_ThrowError(SYSTEM_ERROR_DYNAMIC_LOADER,MkAtomTerm(path->name),omsg);
202 pop_text_stack(lvl);
203 return NULL;
204 }
205 } else {
206 omsg = error_found(omsg, "loaded %s\n", file );
207 }
208 if (!libs) ofiles = ofiles->next;
209 else libs = libs->next;
210 }
211 ofiles = o0;
212 while (ofiles) {
213 /* load libraries first so that their symbols are available to
214 other routines */
215
216 YapInitProc o = dlsym(ofiles
217 ->handle,proc_name);
218 if (o) return o;
219 const char *
220 file = AtomName(ofiles->name);
221 omsg = error_found(omsg, "%s no symbol in %s, failed: %s\n", proc_name, file, dlerror());
222 ofiles = ofiles->next;
223 }
224 Yap_ThrowError(SYSTEM_ERROR_DYNAMIC_LOADER, MkAtomTerm(o0->name),omsg);
225 pop_text_stack(lvl);
226 return NULL;
227}
228
229Int Yap_LoadForeign(StringList ofiles, StringList libs, char *proc_name,
230 YapInitProc *init_proc) {
231 *init_proc = LoadForeign(ofiles, libs, proc_name);
232 return *init_proc != NULL? LOAD_SUCCEEDED :LOAD_FAILLED;
233}
234
235void Yap_ShutdownLoadForeign(void) {
236 ForeignObj *f_code;
237
238 f_code = ForeignCodeLoaded;
239 while (f_code != NULL) {
240 StringList objs, libs, old;
241 ForeignObj *of_code = f_code;
242
243 objs = f_code->objs;
244 while (objs != NULL) {
245 old = objs;
246 if (dlclose(objs->handle) != 0)
247 return; /* ERROR */
248 objs = objs->next;
249 Yap_FreeCodeSpace((ADDR)old);
250 }
251 libs = f_code->libs;
252 while (libs != NULL) {
253 old = libs;
254 if (dlclose(libs->handle) != 0)
255 return; /* ERROR */
256 libs = libs->next;
257 Yap_FreeCodeSpace((ADDR)old);
258 }
259 f_code = f_code->next;
260 Yap_FreeCodeSpace((ADDR)of_code);
261 }
262
263 /*
264 make sure that we don't try to close foreign code several times, eg,
265 from within an error handler
266 */
267 ForeignCodeLoaded = NULL;
268}
269
270Int Yap_ReLoadForeign(StringList ofiles, StringList libs, char *proc_name,
271 YapInitProc *init_proc) {
272 return (*init_proc = LoadForeign(ofiles, libs, proc_name)) != NULL;
273}
274
275
276#endif
277
278#if SIMICS
279
280void dlopen(void) {}
281
282void dlclose(void) {}
283
284void dlsym(void) {}
285
286#endif
load_foreign_files/3 has works for the following configurations:
Main definitions.
void * Malloc(size_t sz USES_REGS)
allocate a temporary text block
Definition: alloc.c:1759