Reformatted.
[chise/xemacs-chise.git] / 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
268   /*
269    * MacOS X dll support is for bundles, not the current executable, so return
270    * NULL is this case.  However, dll_function() uses a special hack where a
271    * NULL handle can be used to find executable symbols.  This satisfies the
272    * needs of ui-gtk.c but is not a general solution.
273    */
274   if (fname == NULL)
275     return NULL;
276
277   ret = NSCreateObjectFileImageFromFile(fname, &file);
278
279   if (ret != NSObjectFileImageSuccess) {
280     return NULL;
281   }
282
283   return (dll_handle)NSLinkModule(file, fname, 
284                                   NSLINKMODULE_OPTION_BINDNOW |
285                                   NSLINKMODULE_OPTION_PRIVATE |
286                                   NSLINKMODULE_OPTION_RETURN_ON_ERROR);
287 }
288
289 int
290 dll_close (dll_handle h)
291 {
292   return NSUnLinkModule((NSModule)h, NSUNLINKMODULE_OPTION_NONE);
293 }
294
295 /* Given an address, return the mach_header for the image containing it
296  * or zero if the given address is not contained in any loaded images.
297  *
298  * Note: image_for_address(), my_find_image() and search_linked_libs() are
299  * based on code from the dlcompat library
300  * (http://www.opendarwin.org/projects/dlcompat).
301  */
302
303 static struct mach_header*
304 image_for_address(void *address)
305 {
306   unsigned long i;
307   unsigned long count = _dyld_image_count();
308   struct mach_header *mh = 0;
309
310   for (i = 0; i < count; i++)
311     {
312       unsigned long addr = (unsigned long)address -
313         _dyld_get_image_vmaddr_slide(i);
314       mh = _dyld_get_image_header(i);
315
316       if (mh)
317         {
318           struct load_command *lc =
319             (struct load_command *)((char *)mh + sizeof(struct mach_header));
320           unsigned long j;
321
322           for (j = 0; j < mh->ncmds;
323                j++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
324             {
325               if (LC_SEGMENT == lc->cmd &&
326                   addr >= ((struct segment_command *)lc)->vmaddr &&
327                   addr <
328                   ((struct segment_command *)lc)->vmaddr +
329                   ((struct segment_command *)lc)->vmsize)
330                 {
331                   goto image_found;
332                 }
333             }
334         }
335
336       mh = 0;
337     }
338
339  image_found:
340   return mh;
341 }
342
343 static const struct mach_header*
344 my_find_image(const char *name)
345 {
346   const struct mach_header *mh = (struct mach_header *)
347     NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED |
348                NSADDIMAGE_OPTION_RETURN_ON_ERROR);
349
350   if (!mh)
351     {
352       int count = _dyld_image_count();
353       int j;
354
355       for (j = 0; j < count; j++)
356         {
357           const char *id = _dyld_get_image_name(j);
358
359           if (!strcmp(id, name))
360             {
361               mh = _dyld_get_image_header(j);
362               break;
363             }
364         }
365     }
366
367   return mh;
368 }
369
370 /*
371  * dyld adds libraries by first adding the directly dependant libraries in
372  * link order, and then adding the dependencies for those libraries, so we
373  * should do the same... but we don't bother adding the extra dependencies, if
374  * the symbols are neither in the loaded image nor any of it's direct
375  * dependencies, then it probably isn't there.
376  */
377 static NSSymbol
378 search_linked_libs(const struct mach_header * mh, const char *symbol)
379 {
380   int n;
381   NSSymbol nssym = 0;
382
383   struct load_command *lc =
384     (struct load_command *)((char *)mh + sizeof(struct mach_header));
385
386   for (n = 0; n < mh->ncmds;
387        n++, lc = (struct load_command *)((char *)lc + lc->cmdsize))
388     {
389       if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd))
390         {
391           struct mach_header *wh;
392
393           if ((wh = (struct mach_header *)
394                my_find_image((char *)(((struct dylib_command *)lc)->dylib.name.offset +
395                                       (char *)lc))))
396             {
397               if (NSIsSymbolNameDefinedInImage(wh, symbol))
398                 {
399                   nssym =
400                     NSLookupSymbolInImage(wh,
401                                           symbol,
402                                           NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
403                                           NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
404                   break;
405                 }
406             }
407         }
408     }
409
410   return nssym;
411 }
412
413 dll_func
414 dll_function (dll_handle h, const char *n)
415 {
416   NSSymbol sym = 0;
417 #ifdef DLSYM_NEEDS_UNDERSCORE
418   char *buf = alloca_array (char, strlen (n) + 2);
419   *buf = '_';
420   strcpy (buf + 1, n);
421   n = buf;
422 #endif
423
424   /* NULL means the program image and shared libraries, not bundles. */
425
426   if (h == NULL)
427     {
428       /* NOTE: This assumes that this function is included in the main program
429          and not in a shared library. */
430       const struct mach_header* my_mh = image_for_address(&dll_function);
431
432       if (NSIsSymbolNameDefinedInImage(my_mh, n))
433         {
434           sym =
435             NSLookupSymbolInImage(my_mh,
436                                   n,
437                                   NSLOOKUPSYMBOLINIMAGE_OPTION_BIND |
438                                   NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
439         }
440
441       if (!sym)
442         {
443           sym = search_linked_libs(my_mh, n);
444         }
445     }
446   else
447     {
448       sym = NSLookupSymbolInModule((NSModule)h, n);
449     }
450
451    if (sym == 0) return 0;
452    return (dll_func)NSAddressOfSymbol(sym);
453 }
454
455 dll_var
456 dll_variable (dll_handle h, const char *n)
457 {
458   NSSymbol sym;
459 #ifdef DLSYM_NEEDS_UNDERSCORE
460   char *buf = alloca_array (char, strlen (n) + 2);
461   *buf = '_';
462   strcpy (buf + 1, n);
463   n = buf;
464 #endif
465   sym = NSLookupSymbolInModule((NSModule)h, n);
466   if (sym == 0) return 0;
467   return (dll_var)NSAddressOfSymbol(sym);
468 }
469
470 const char *
471 dll_error (dll_handle h)
472 {
473   NSLinkEditErrors c;
474   int errorNumber;
475   const char *fileNameWithError, *errorString;
476   NSLinkEditError(&c, &errorNumber, &fileNameWithError, &errorString);
477   return errorString;
478 }
479
480
481 #else
482 /* Catchall if we don't know about this system's method of dynamic loading */
483 int
484 dll_init (const char *arg)
485 {
486   return -1;
487 }
488
489 dll_handle
490 dll_open (const char *fname)
491 {
492   return NULL;
493 }
494
495 int
496 dll_close (dll_handle h)
497 {
498   return 0;
499 }
500
501 dll_func
502 dll_function (dll_handle h, const char *n)
503 {
504   return NULL;
505 }
506
507 dll_func
508 dll_variable (dll_handle h, const char *n)
509 {
510   return NULL;
511 }
512
513 const char *
514 dll_error (dll_handle h)
515 {
516   return "Shared libraries not implemented on this system";
517 }
518 #endif /* System conditionals */
519
520 #endif /* HAVE_SHLIB */