1 /*
2 * system independant wrapper for LOAD()
3 * calls os_load_library, os_unload_library, os_find_symbol
4 */
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif
9
10 #include <stdio.h>
11 #include <stdlib.h> /* free() */
12
13 #include "h.h"
14 #include "snotypes.h"
15 #include "macros.h"
16 #include "load.h" /* SNOLOAD_API (for module.h) */
17 #include "module.h" /* structs */
18 #include "path.h"
19 #include "lib.h" /* mspec2str() */
20 #include "str.h"
21
22 struct lib {
23 struct lib *next; /* libs list */
24 void *oslib; /* object from os_load_library */
25 struct module *module; /* see module.h */
26 int refcount;
27 char *name;
28 char *path;
29 };
30
31 struct func {
32 struct func *next; /* funcs list */
33 struct func *self; /* for validity check */
34 loadable_func_t *entry; /* function entry point */
35 struct lib *lib;
36 void *stash; /* for use by os_find_symbol */
37 char name[1]; /* for unload (MUST BE LAST)! */
38 };
39
40 /* list of loaded functions (for UNLOAD) */
41 static VAR struct func *funcs;
42
43 /*
44 * list of loaded libraries (depends on system ref-counting)
45 * COULD keep just one, but would require a lock
46 */
47 static VAR struct lib *libs;
48
49 #ifdef SHARED
50 static void loadx_cleanup(void);
51 #endif
52
53 /* create refcounted lib interface */
54
55 static struct lib *
libopen(char * name,char * path)56 libopen(char *name, char *path) {
57 void *oslib;
58 struct lib *lp;
59
60 /* check for duplicate by ORIGINAL name/path */
61 for (lp = libs; lp; lp = lp->next)
62 if (strcmp(name, lp->name) == 0)
63 break;
64
65 if (!lp) {
66 oslib = os_load_library(path);
67 if (oslib == NULL)
68 return NULL;
69 /*
70 * defend against multiple paths to same file
71 * Also defend against Windows, where once foo/bar.dll is loaded,
72 * "bar" seems to suffice
73 */
74 for (lp = libs; lp; lp = lp->next) {
75 if (oslib == lp->oslib) {
76 os_unload_library(oslib); /* reduce use count */
77 goto found;
78 }
79 }
80
81 lp = (struct lib *) malloc(sizeof(struct lib));
82 lp->oslib = oslib;
83 lp->refcount = 0;
84
85 lp->name = strdup(name); /* save ORIGINAL name/path */
86 lp->path = strdup(path);
87 lp->module = os_find_symbol(oslib, "module", NULL);
88 /* XXX error if lookup fails when SHARED (&& THREADS)? */
89 /* XXX complain regardless? */
90
91 lp->next = libs;
92 libs = lp;
93
94 if (lp->module)
95 module_instance_init(lp->module); /* XXX check return? */
96 }
97 found:
98 lp->refcount++;
99 return lp;
100 }
101
102 static int
libclose(struct lib * lib)103 libclose(struct lib *lib) {
104 struct lib *lp, *pp;
105
106 if (--lib->refcount > 0)
107 return 1;
108
109 /* find previous, if any */
110 for (lp = libs, pp = NULL; lp && lp != lib; pp = lp, lp = lp->next)
111 ;
112
113 if (!lp)
114 return 0; /* not found */
115
116 if (lp->module)
117 module_instance_cleanup(lp->module);
118
119 /* detach library */
120 os_unload_library(lp->oslib);
121
122 /* unlink from list */
123 if (pp)
124 pp->next = lp->next;
125 else
126 libs = lp->next;
127 free(lp->name);
128 free(lp->path);
129 free(lp);
130
131 return 1;
132 }
133
134 /* support for SIL "LOAD" opcode -- load external function */
135 int
load(struct descr * addr,struct spec * sp1,struct spec * sp2)136 load(struct descr *addr, /* OUT */
137 struct spec *sp1, /* function */
138 struct spec *sp2) { /* library */
139 char *fname = mspec2str(sp1);
140 char *lname = mspec2str(sp2);
141 loadable_func_t *entry; /* function address */
142 struct func *fp = NULL;
143 struct lib *lp = NULL;
144 int ret = FALSE;
145 void *stash = NULL;
146 #ifdef SHARED
147 static VAR char registered;
148 if (!registered) {
149 reg_cleanup(loadx_cleanup);
150 registered = 1;
151 }
152 #endif
153 /* always try PML first. Only if lname is empty?? */
154 /*if (!lname || !*lname)*/
155 entry = pml_find(fname);
156
157 if (!entry) {
158 char *l2;
159
160 lp = libopen(lname, lname);
161 if (lp)
162 goto found_lib;
163
164 #ifdef DL_EXT
165 l2 = strjoin(lname, DL_EXT, NULL);
166 if (!l2)
167 return FALSE;
168 lp = libopen(lname, l2);
169 free(l2);
170 if (lp)
171 goto found_lib;
172
173 if (!abspath(lname)) {
174 l2 = io_lib_find("shared", lname, DL_EXT);
175 if (l2) {
176 lp = libopen(lname, l2);
177 free(l2);
178 if (lp)
179 goto found_lib;
180 }
181
182 l2 = io_lib_find("dynload", lname, DL_EXT);
183 if (l2) {
184 lp = libopen(lname, l2);
185 free(l2);
186 if (lp)
187 goto found_lib;
188 }
189
190 l2 = io_lib_find(NULL, lname, DL_EXT);
191 if (l2) {
192 lp = libopen(lname, l2);
193 free(l2);
194 }
195 if (!lp)
196 goto quit;
197 } // !abspath
198 #endif
199 found_lib:
200 entry = os_find_symbol(lp->oslib, fname, &stash);
201 if (!entry) {
202 #ifdef TRY_UNDERSCORE
203 l2 = strjoin("_", fname, NULL);
204 if (!l2)
205 goto freelib;
206 entry = os_find_symbol(lp->oslib, l2, &stash);
207 free(l2);
208 if (!entry)
209 #endif
210 goto freelib;
211 }
212 } /* not found by pml_find */
213
214 /* here with entry */
215 fp = (struct func *) malloc( sizeof (struct func) + strlen(fname));
216 if (fp == NULL) {
217 freelib:
218 libclose(lp);
219 goto quit;
220 }
221 strcpy(fp->name, fname);
222 fp->lib = lp;
223 fp->entry = entry;
224 fp->stash = stash;
225 fp->self = fp; /* make valid */
226
227 fp->next = funcs; /* link into list */
228 funcs = fp;
229
230 D_A(addr) = (int_t) fp;
231 D_F(addr) = D_V(addr) = 0; /* clear flags, type */
232 ret = TRUE;
233
234 quit:
235 free(fname);
236 free(lname);
237 return ret;
238 }
239
240 /* support for SIL "LINK" opcode -- call external function */
241 int
callx(struct descr * retval,struct descr * args,struct descr * nargs,struct descr * addr)242 callx(struct descr *retval, struct descr *args,
243 struct descr *nargs, struct descr *addr) {
244 struct func *fp;
245
246 /* XXX check for zero V & F fields?? */
247 fp = (struct func *) D_A(addr);
248 if (fp == NULL)
249 return FALSE;
250
251 if (fp->self != fp) /* validate, in case unloaded */
252 return FALSE; /* fail (fatal error??) */
253
254 if (!fp->entry)
255 return FALSE; /* fail (fatal error??) */
256
257 /* check fp->lib && fp->lib->abivers */
258 return (fp->entry)( retval, D_A(nargs), (struct descr *)D_A(args) );
259 }
260
261 static void
funload(char * fname)262 funload(char *fname) {
263 struct func *fp, *pp;
264
265 if (!fname)
266 return;
267
268 for (pp = NULL, fp = funcs; fp != NULL; pp = fp, fp = fp->next) {
269 if (strcmp(fp->name, fname) == 0)
270 break;
271 }
272
273 if (fp == NULL) /* not found */
274 return;
275
276 /* unlink from list */
277 if (pp == NULL) { /* first */
278 funcs = fp->next;
279 }
280 else { /* not first */
281 pp->next = fp->next;
282 }
283
284 os_unload_function(fp->name, fp->stash);
285
286 libclose(fp->lib);
287
288 fp->self = NULL; /* invalidate self pointer!! */
289 fp->entry = NULL; /* invalidate function pointer */
290 fp->lib = NULL;
291 free(fp); /* free name block */
292 }
293
294 void
unload(struct spec * sp)295 unload(struct spec *sp) {
296 char *fname = mspec2str(sp);
297 funload(fname);
298 free(fname);
299 }
300
301 #ifdef SHARED
302 static void
loadx_cleanup(void)303 loadx_cleanup(void) {
304 while (funcs)
305 funload(funcs->name);
306 }
307 #endif
308
309 #include "equ.h"
310 #include "handle.h"
311
312 pmlret_t
EXTERNAL_DATATYPE(LA_ALIST)313 EXTERNAL_DATATYPE( LA_ALIST ) {
314 struct descr *dp = LA_DESCR(0);
315 struct lib *lp;
316
317 (void) nargs;
318 if (!dp)
319 RETFAIL;
320
321 for (lp = libs; lp; lp = lp->next) {
322 struct module_instance *mip;
323
324 if (!lp->module)
325 continue;
326 mip = (lp->module->get_module_instance)();
327 if (mip) {
328 const char *type_name = handle_table_name(dp, mip);
329 if (type_name)
330 RETSTR(type_name);
331 }
332 }
333 RETFAIL;
334 }
335
336 pmlret_t
EXTERNAL_MODULE_NAME(LA_ALIST)337 EXTERNAL_MODULE_NAME( LA_ALIST ) {
338 struct descr *dp = LA_DESCR(0);
339 struct lib *lp;
340
341 (void) nargs;
342 if (!dp)
343 RETFAIL;
344
345 for (lp = libs; lp; lp = lp->next) {
346 struct module_instance *mip;
347
348 if (!lp->module)
349 continue;
350 mip = (lp->module->get_module_instance)();
351 if (mip) {
352 if (handle_table_name(dp, mip))
353 RETSTR(lp->module->name);
354 }
355 }
356 RETFAIL;
357 }
358
359 /* what was used to load; may not be full path */
360 pmlret_t
EXTERNAL_MODULE_PATH(LA_ALIST)361 EXTERNAL_MODULE_PATH( LA_ALIST ) {
362 struct descr *dp = LA_DESCR(0);
363 struct lib *lp;
364
365 (void) nargs;
366 if (!dp)
367 RETFAIL;
368
369 for (lp = libs; lp; lp = lp->next) {
370 struct module_instance *mip;
371
372 if (!lp->module)
373 continue;
374 mip = (lp->module->get_module_instance)();
375 if (mip) {
376 if (handle_table_name(dp, mip))
377 RETSTR(lp->path);
378 }
379 }
380 RETFAIL;
381 }
382