update.
[chise/xemacs-chise.git.1] / src / sysdll.c
1 /* sysdll.c --- system dependent support for dynamic linked libraries
2    Copyright (C) 1998 Free Software Foundation, Inc.
3    Author:  William Perry <wmperry@aventail.com>
4
5 This file is part of XEmacs.
6
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING.  If not, write to the Free
19 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include "lisp.h"
28 #include "sysdll.h"
29
30 /* This whole file is conditional upon HAVE_SHLIB */
31 #ifdef HAVE_SHLIB
32
33 /* Thankfully, most systems follow the ELFish dlopen() method.
34 */
35
36 #if defined(HAVE_DLOPEN)
37 #include <dlfcn.h>
38
39 #ifndef RTLD_LAZY
40 # define RTLD_LAZY 1
41 #endif /* RTLD_LAZY isn't defined under FreeBSD - ick */
42
43 #ifndef RTLD_NOW
44 # define RTLD_NOW 2
45 #endif
46
47 int
48 dll_init (const char *arg)
49 {
50   return 0;
51 }
52
53
54 dll_handle
55 dll_open (const char *fname)
56 {
57   return (dll_handle) dlopen (fname, RTLD_NOW);
58 }
59
60 int
61 dll_close (dll_handle h)
62 {
63   return dlclose ((void *) h);
64 }
65
66 dll_func
67 dll_function (dll_handle h, const char *n)
68 {
69 #ifdef DLSYM_NEEDS_UNDERSCORE
70   char *buf = alloca_array (char, strlen (n) + 2);
71   *buf = '_';
72   strcpy (buf + 1, n);
73   n = buf;
74 #endif
75   return (dll_func) dlsym ((void *) h, n);
76 }
77
78 dll_var
79 dll_variable (dll_handle h, const char *n)
80 {
81 #ifdef DLSYM_NEEDS_UNDERSCORE
82   char *buf = alloca_array (char, strlen (n) + 2);
83   *buf = '_';
84   strcpy (buf + 1, n);
85   n = buf;
86 #endif
87   return (dll_var)dlsym ((void *)h, n);
88 }
89
90 const char *
91 dll_error (dll_handle h)
92 {
93 #if defined(HAVE_DLERROR) || defined(dlerror)
94   return (const char *) dlerror ();
95 #elif defined(HAVE__DLERROR)
96   return (const char *) _dlerror();
97 #else
98   return "Shared library error";
99 #endif
100 }
101
102 #elif defined(HAVE_SHL_LOAD)
103 /* This is the HP/UX version */
104 #include <dl.h>
105 int
106 dll_init (const char *arg)
107 {
108   return 0;
109 }
110
111 dll_handle
112 dll_open (const char *fname)
113 {
114   /* shl_load will hang hard if passed a NULL fname. */
115   if (fname == NULL) return NULL;
116
117   return (dll_handle) shl_load (fname, BIND_DEFERRED,0L);
118 }
119
120 int
121 dll_close (dll_handle h)
122 {
123   return shl_unload ((shl_t) h);
124 }
125
126 dll_func
127 dll_function (dll_handle h, const char *n)
128 {
129   long handle = 0L;
130
131   if (shl_findsym ((shl_t *) &h, n, TYPE_PROCEDURE, &handle))
132     return NULL;
133
134   return (dll_func) handle;
135 }
136
137 dll_var
138 dll_variable (dll_handle h, const char *n)
139 {
140   long handle = 0L;
141
142   if (shl_findsym ((shl_t *) &h, n, TYPE_DATA, &handle))
143     return NULL;
144
145   return (dll_var) handle;
146 }
147
148 const char *
149 dll_error (dll_handle h)
150 {
151   /* #### WTF?!  Shouldn't this at least attempt to get strerror or
152      something?  --hniksic */
153   return "Generic shared library error";
154 }
155
156 #elif defined(HAVE_DLD_INIT)
157 #include <dld.h>
158 int
159 dll_init (const char *arg)
160 {
161   char *real_exe = dld_find_executable (arg);
162   int rc;
163
164   rc = dld_init (real_exe);
165   if (rc)
166     {
167       dld_perror (exe);
168       return -1;
169     }
170   return 0;
171 }
172
173 dll_handle
174 dll_open (const char *fname)
175 {
176   rc = dld_link (fname);
177   if (rc)
178     return NULL;
179
180   return (dll_handle) 1;
181 }
182
183 int
184 dll_close (dll_handle h)
185 {
186   /* *sigh* DLD is pretty lame and doesn't return a handle that you can use
187   ** later on to free the file - you have to remember the filename and
188   ** use that as the unlinker.  We should eventually keep a linked list
189   ** of loaded modules and then use the node pointer as the unique id
190   ** for the shared library.  Wheeee.  But not now.
191   */
192   return 1;
193 }
194
195 DLL_FUNC
196 dll_function (dll_handle h, const char *n)
197 {
198   return dld_get_func (n);
199 }
200
201 DLL_FUNC
202 dll_variable (dll_handle h, const char *n)
203 {
204   return dld_get_symbol (n);
205 }
206 #elif defined (WIN32_NATIVE)
207
208 #define WIN32_LEAN_AND_MEAN
209 #include <windows.h>
210 #undef WIN32_LEAN_AND_MEAN
211
212 int
213 dll_init (const char *arg)
214 {
215   return 0;
216 }
217
218 dll_handle
219 dll_open (const char *fname)
220 {
221   return (dll_handle) LoadLibrary (fname);
222 }
223
224 int
225 dll_close (dll_handle h)
226 {
227   return FreeLibrary (h);
228 }
229
230 dll_func
231 dll_function (dll_handle h, const char *n)
232 {
233   return (dll_func) GetProcAddress (h, n);
234 }
235
236 dll_func
237 dll_variable (dll_handle h, const char *n)
238 {
239   return (dll_func) GetProcAddress (h, n);
240 }
241
242 const char *
243 dll_error (dll_handle h)
244 {
245   return "Windows DLL Error";
246 }
247 #elif defined(HAVE_DYLD) 
248
249 /* 
250    This section supports MacOSX dynamic libraries. Dynamically
251    loadable libraries must be compiled as bundles, not dynamiclibs. 
252 */
253
254 #include <mach-o/dyld.h>
255
256 int
257 dll_init (const char *arg)
258 {
259   return 0;
260 }
261
262 dll_handle
263 dll_open (const char *fname)
264 {
265   NSObjectFileImage file;
266   NSObjectFileImageReturnCode ret = 
267     NSCreateObjectFileImageFromFile(fname, &file);
268   if (ret != NSObjectFileImageSuccess) {
269     return NULL;
270   }
271   return (dll_handle)NSLinkModule(file, fname, 
272                                   NSLINKMODULE_OPTION_BINDNOW |
273                                   NSLINKMODULE_OPTION_PRIVATE |
274                                   NSLINKMODULE_OPTION_RETURN_ON_ERROR);
275 }
276
277 int
278 dll_close (dll_handle h)
279 {
280   return NSUnLinkModule((NSModule)h, NSUNLINKMODULE_OPTION_NONE);
281 }
282
283 /* Given an address, return the mach_header for the image containing it
284  * or zero if the given address is not contained in any loaded images.
285  *
286  * Note: image_for_address(), my_find_image() and search_linked_libs() are
287  * based on code from the dlcompat library
288  * (http://www.opendarwin.org/projects/dlcompat).
289  */
290
291 static struct mach_header*
292 image_for_address(void *address)
293 {
294   unsigned long i;
295   unsigned long count = _dyld_image_count();
296   struct mach_header *mh = 0;
297
298   for (i = 0; i < count; i++)
299     {
300       unsigned long addr = (unsigned long)address -
301         _dyld_get_image_vmaddr_slide(i);
302       mh = _dyld_get_image_header(i);
303
304       if (mh)
305         {
306           struct load_command *lc =
307             (struct load_command *)((char *)mh + sizeof(struct mach_header));
308           unsigned long j;
309
310           for (j = 0; j < mh->ncmds;
311                j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
312             {
313               if (LC_SEGMENT == lc->cmd &&
314                   addr >= ((struct segment_command *)lc)->vmaddr &&
315                   addr <
316                   ((struct segment_command *)lc)->vmaddr +
317                   ((struct segment_command *)lc)->vmsize)
318                 {
319                   goto image_found;
320                 }
321             }
322         }
323
324       mh = 0;
325     }
326
327  image_found:
328   return mh;
329 }
330
331 static const struct mach_header*
332 my_find_image(const char *name)
333 {
334   const struct mach_header *mh = (struct mach_header *)
335     NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED |
336                NSADDIMAGE_OPTION_RETURN_ON_ERROR);
337
338   if (!mh)
339     {
340       int count = _dyld_image_count();
341       int j;
342
343       for (j = 0; j < count; j++)
344         {
345           const char *id = _dyld_get_image_name(j);
346
347           if (!strcmp(id, name))
348             {
349               mh = _dyld_get_image_header(j);
350               break;
351             }
352         }
353     }
354
355   return mh;
356 }
357
358 /*
359  * dyld adds libraries by first adding the directly dependant libraries in
360  * link order, and then adding the dependencies for those libraries, so we
361  * should do the same... but we don't bother adding the extra dependencies, if
362  * the symbols are neither in the loaded image nor any of it's direct
363  * dependencies, then it probably isn't there.
364  */
365 static NSSymbol
366 search_linked_libs(const struct mach_header * mh, const char *symbol)
367 {
368   int n;
369   NSSymbol nssym = 0;
370
371   struct load_command *lc =
372     (struct load_command *)((char *)mh + sizeof(struct mach_header));
373
374   for (n = 0; n < mh->ncmds;
375        n++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
376     {
377       if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd))
378         {
379           struct mach_header *wh;
380
381           if ((wh = (struct mach_header *)
382                my_find_image((char *)(((struct dylib_command *)lc)->dylib.name.offset +
383                                       (char *)lc))))
384             {
385               if (NSIsSymbolNameDefinedInImage(wh, symbol))
386                 {
387                   nssym =
388                     NSLookupSymbolInImage(wh,
389                                           symbol,
390                                           NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
391                                           NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
392                   break;
393                 }
394             }
395         }
396     }
397
398   return nssym;
399 }
400
401 dll_func
402 dll_function (dll_handle h, const char *n)
403 {
404   NSSymbol sym = 0;
405 #ifdef DLSYM_NEEDS_UNDERSCORE
406   char *buf = alloca_array (char, strlen (n) + 2);
407   *buf = '_';
408   strcpy (buf + 1, n);
409   n = buf;
410 #endif
411
412   /* NULL means the program image and shared libraries, not bundles. */
413
414   if (h == NULL)
415     {
416       /* NOTE: This assumes that this function is included in the main program
417          and not in a shared library. */
418       const struct mach_header* my_mh = image_for_address(&dll_function);
419
420       if (NSIsSymbolNameDefinedInImage(my_mh, n))
421         {
422           sym =
423             NSLookupSymbolInImage(my_mh,
424                                   n,
425                                   NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
426                                   NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
427         }
428
429       if (!sym)
430         {
431           sym = search_linked_libs(my_mh, n);
432         }
433     }
434   else
435     {
436       sym = NSLookupSymbolInModule((NSModule)h, n);
437     }
438
439    if (sym == 0) return 0;
440    return (dll_func)NSAddressOfSymbol(sym);
441 }
442
443 dll_var
444 dll_variable (dll_handle h, const char *n)
445 {
446   NSSymbol sym;
447 #ifdef DLSYM_NEEDS_UNDERSCORE
448   char *buf = alloca_array (char, strlen (n) + 2);
449   *buf = '_';
450   strcpy (buf + 1, n);
451   n = buf;
452 #endif
453   sym = NSLookupSymbolInModule((NSModule)h, n);
454   if (sym == 0) return 0;
455   return (dll_var)NSAddressOfSymbol(sym);
456 }
457
458 const char *
459 dll_error (dll_handle h)
460 {
461   NSLinkEditErrors c;
462   int errorNumber;
463   const char *fileNameWithError, *errorString;
464   NSLinkEditError(&c, &errorNumber, &fileNameWithError, &errorString);
465   return errorString;
466 }
467
468
469 #else
470 /* Catchall if we don't know about this system's method of dynamic loading */
471 int
472 dll_init (const char *arg)
473 {
474   return -1;
475 }
476
477 dll_handle
478 dll_open (const char *fname)
479 {
480   return NULL;
481 }
482
483 int
484 dll_close (dll_handle h)
485 {
486   return 0;
487 }
488
489 dll_func
490 dll_function (dll_handle h, const char *n)
491 {
492   return NULL;
493 }
494
495 dll_func
496 dll_variable (dll_handle h, const char *n)
497 {
498   return NULL;
499 }
500
501 const char *
502 dll_error (dll_handle h)
503 {
504   return "Shared libraries not implemented on this system";
505 }
506 #endif /* System conditionals */
507
508 #endif /* HAVE_SHLIB */