1 /*
2  * $Id: udl.c,v 1.1 2005-09-18 22:05:41 dhmunro Exp $
3  * UNIX version of play dynamic linking operations
4  */
5 /* Copyright (c) 2005, The Regents of the University of California.
6  * All rights reserved.
7  * This file is part of yorick (http://yorick.sourceforge.net).
8  * Read the accompanying LICENSE file for details.
9  */
10 
11 #include "config.h"
12 
13 #include "playu.h"
14 #include "pstdlib.h"
15 #include <string.h>
16 
17 #ifdef PLUG_HEADER
18 #include PLUG_HEADER
19 #endif
20 
21 #if defined(PLUG_LIBDL)
22 
23 #ifndef PLUG_SUFFIX
24 # define PLUG_SUFFIX ".so"
25 #endif
26 
27 #ifndef PLUG_HEADER
28 #include <dlfcn.h>
29 #endif
30 
31 #ifndef PLUG_FLAGS
32 # define PLUG_FLAGS RTLD_LAZY | RTLD_GLOBAL
33 #endif
34 
35 void *
p_dlopen(const char * dlname)36 p_dlopen(const char *dlname)
37 {
38   void *handle = 0;
39   if (dlname && dlname[0]) {
40     char *name = p_strncat(u_pathname(dlname), PLUG_SUFFIX, 0);
41     handle = dlopen(name, PLUG_FLAGS);
42     p_free(name);
43   }
44   return handle;
45 }
46 
47 int
p_dlsym(void * handle,const char * symbol,int type,void * paddr)48 p_dlsym(void *handle, const char *symbol, int type, void *paddr)
49 {
50   void **addr = paddr;
51   addr[0] = dlsym(handle, symbol);
52   /* correct way to detect failure if a==0 were legal:
53    *   const char *msg = dlerror();
54    *   if (msg) return 0;
55    */
56   return !addr[0];
57 }
58 
59 
60 
61 #elif defined(PLUG_HPUX)
62 
63 #define PLUG_SUFFIX ".sl"
64 
65 #ifndef PLUG_HEADER
66 #include <dl.h>
67 #endif
68 #include <errno.h>
69 
70 #ifndef PLUG_FLAGS
71 # define PLUG_FLAGS BIND_DEFERRED
72 #endif
73 
74 void *
p_dlopen(const char * dlname)75 p_dlopen(const char *dlname)
76 {
77   void *handle = 0;
78   if (dlname && dlname[0]) {
79     char *name = p_strncat(u_pathname(dlname), PLUG_SUFFIX, 0);
80     handle = (void *)shl_load(name, PLUG_FLAGS, 0);
81     p_free(name);
82   }
83   return handle;
84 }
85 
86 int
p_dlsym(void * handle,const char * symbol,int type,void * paddr)87 p_dlsym(void *handle, const char *symbol, int type, void *paddr)
88 {
89   void **addr = paddr;
90   short expect = type? ((type&1)? TYPE_DATA : TYPE_UNDEFINED) : TYPE_PROCEDURE;
91   int notok = shl_findsym(&handle, symbol, expect, paddr);
92   return notok || !addr[0];
93 }
94 
95 
96 
97 #elif defined(PLUG_MACOSX)
98 /* Apple now deprecates this.  At Mac OS X 10.4 and beyond, use PLUG_LIBDL.
99  * see https://developer.apple.com/library/mac/#qa/qa1180/_index.html
100  */
101 
102 #define PLUG_SUFFIX ".so"
103 
104 #ifndef PLUG_HEADER
105 #include <mach-o/dyld.h>
106 #endif
107 
108 void *
p_dlopen(const char * dlname)109 p_dlopen(const char *dlname)
110 {
111   void *handle = 0;
112   if (dlname && dlname[0]) {
113     char *name = p_strncat(u_pathname(dlname), PLUG_SUFFIX, 0);
114     NSObjectFileImage file_image;
115     if (NSCreateObjectFileImageFromFile(name, &file_image) ==
116         NSObjectFileImageSuccess) {
117       handle = (void *)NSLinkModule(file_image, name,
118                                     NSLINKMODULE_OPTION_RETURN_ON_ERROR
119                                     | NSLINKMODULE_OPTION_PRIVATE);
120       NSDestroyObjectFileImage(file_image);
121     }
122     p_free(name);
123   }
124   return handle;  /* actually type NSModule */
125 }
126 
127 int
p_dlsym(void * handle,const char * symbol,int type,void * paddr)128 p_dlsym(void *handle, const char *symbol, int type, void *paddr)
129 {
130   void **addr = paddr;
131   addr[0] = 0;
132   if (symbol && symbol[0]) {
133     char *symname = p_strncat("_", symbol, 0);
134     NSSymbol sym = NSLookupSymbolInModule(handle, symname);
135     if (sym) addr[0] = NSAddressOfSymbol(sym);
136     p_free(symname);
137   }
138   return !addr[0];
139 }
140 
141 
142 
143 #elif defined(PLUG_MACOSX_DYLIB)
144 /*
145   this is fossil code - it is correct, but I couldn't get the linker
146   to build a correct optimized .dylib for the cerfc example in extend/
147 
148   a more careful reading of the Mach-O documentation (the tech note on
149   porting to UNIX in particular) suggests that plugins are supposed
150   to be implemented with the -bundle switch to the compiler, not .dylib
151   the required MACOSX_DEPLOYMENT_TARGET env var to libtool exists only
152   from 10.3 onward, so -bundle is the only possibility for <=10.2
153 */
154 
155 #define PLUG_SUFFIX ".dylib"
156 
157 #ifndef PLUG_HEADER
158 #include <mach-o/dyld.h>
159 #endif
160 
161 #ifndef PLUG_FLAGS
162 # define PLUG_FLAGS NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
163 #endif
164 
165 void *
p_dlopen(const char * dlname)166 p_dlopen(const char *dlname)
167 {
168   void *handle = 0;
169   if (dlname && dlname[0]) {
170     char *name = p_strncat(u_pathname(dlname), PLUG_SUFFIX, 0);
171     handle = (void *)NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
172     p_free(name);
173   }
174   return handle;  /* actually type (struct mach_header *) */
175 }
176 
177 int
p_dlsym(void * handle,const char * symbol,int type,void * paddr)178 p_dlsym(void *handle, const char *symbol, int type, void *paddr)
179 {
180   void **addr = paddr;
181   addr[0] = 0;
182   if (symbol && symbol[0]) {
183     char *symname = p_strncat("_", symbol, 0);
184     if (NSIsSymbolNameDefinedInImage(handle, symname)) {
185       NSSymbol nss =
186         NSLookupSymbolInImage(handle, symname, PLUG_FLAGS |
187                               NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
188       if (nss) addr[0] = NSAddressOfSymbol(nss);
189     }
190     p_free(symname);
191   }
192   return !addr[0];
193 }
194 
195 
196 
197 #else
198 
199 /* ARGSUSED */
200 void *
p_dlopen(const char * dlname)201 p_dlopen(const char *dlname)
202 {
203   return 0;
204 }
205 
206 /* ARGSUSED */
207 int
p_dlsym(void * handle,const char * symbol,int type,void * paddr)208 p_dlsym(void *handle, const char *symbol, int type, void *paddr)
209 {
210   void **addr = paddr;
211   addr[0] = 0;
212   return 1;
213 }
214 
215 #endif
216