1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1997-2011 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22  * provide dlopen/dlsym/dlerror interface
23  *
24  * David Korn
25  * Glenn Fowler
26  * AT&T Research
27  */
28 
29 #include <ast.h>
30 #include <dlldefs.h>
31 #include <error.h>
32 
33 #define T(x)	ERROR_dictionary(x)
34 
35 #if _BLD_dll && defined(__EXPORT__)
36 #define extern	__EXPORT__
37 #endif
38 
39 #if _hdr_dlfcn && _lib_dlopen
40 
41 	/*
42 	 * standard
43 	 */
44 
45 #	include <dlfcn.h>
46 
47 #else
48 #if _hdr_dl
49 
50 	/*
51 	 * HP-UX
52  	 */
53 
54 #	include <dl.h>
55 #	ifndef BIND_FIRST
56 #	define BIND_FIRST	0x4
57 #	endif
58 #	ifndef BIND_NOSTART
59 #	define BIND_NOSTART	0x10
60 #	endif
61 
62 	static shl_t	all;
63 	static int	err;
64 
dlopen(const char * path,int mode)65 	extern void* dlopen(const char* path, int mode)
66 	{
67 		void*	dll;
68 
69 		if (!path)
70 			return (void*)&all;
71 		if (mode)
72 			mode = (BIND_IMMEDIATE|BIND_FIRST|BIND_NOSTART);
73 		if (!(dll = (void*)shl_load(path, mode, 0L)))
74 			err = errno;
75 		return dll;
76 	}
77 
dlclose(void * dll)78 	extern int dlclose(void* dll)
79 	{
80 		return 0;
81 	}
82 
dlsym(void * dll,const char * name)83 	extern void* dlsym(void* dll, const char* name)
84 	{
85 		shl_t	handle;
86 		long	addr;
87 
88 		handle = dll == (void*)&all ? (shl_t)0 : (shl_t)dll;
89 		if (shl_findsym(&handle, name, TYPE_UNDEFINED, &addr))
90 		{
91 			err = errno;
92 			return 0;
93 		}
94 		return (void*)addr;
95 	}
96 
dlerror(void)97 	extern char* dlerror(void)
98 	{
99 		char*	msg;
100 
101 		if (!err)
102 			return 0;
103 		msg = fmterror(err);
104 		err = 0;
105 		return msg;
106 	}
107 
108 #else
109 #if _sys_ldr && _lib_loadbind
110 
111 	/*
112 	 * rs6000
113 	 */
114 
115 #	include <sys/ldr.h>
116 #	include <xcoff.h>
117 
118 	/* xcoff module header */
119 	struct hdr
120 	{
121 		struct filehdr	f;
122 		struct aouthdr	a;
123 		struct scnhdr	s[1];
124 	};
125 
126 	static struct ld_info*	ld_info;
127 	static unsigned int	ld_info_size = 1024;
128 	static void*		last_module;
129 	static int		err;
130 
dlopen(const char * path,int mode)131 	extern void* dlopen(const char* path, int mode)
132 	{
133 		void*	dll;
134 
135 		if (!(dll = (void*)load((char*)path, mode, getenv("LIBPATH"))))
136 			err = errno;
137 		return dll;
138 	}
139 
dlclose(void * dll)140 	extern int dlclose(void* dll)
141 	{
142 		return 0;
143 	}
144 
getquery(void)145 	static int getquery(void)
146 	{
147 		if (!ld_info)
148 			ld_info = malloc(ld_info_size);
149 		for (;;)
150 		{
151 			if (!ld_info)
152 				return 1;
153 			if (!loadquery(L_GETINFO, ld_info, ld_info_size))
154 				return 0;
155 			if (errno != ENOMEM)
156 				return 1;
157 			ld_info = realloc(ld_info, ld_info_size *= 2);
158 		}
159  	}
160 
161 	/* find the loaded module whose data area contains the
162 	 * address passed in. Remember that procedure pointers
163 	 * are implemented as pointers to descriptors in the
164 	 * data area of the module defining the procedure
165 	 */
getinfo(void * module)166 	static struct ld_info* getinfo(void* module)
167 	{
168 		struct ld_info*	info = ld_info;
169 		register int	n = 1;
170 
171 		if (!ld_info || module != last_module)
172 		{
173 			last_module = module;
174 			if (getquery())
175 				return 0;
176 			info = ld_info;
177 		}
178 		while (n)
179 		{
180 			if ((char*)(info->ldinfo_dataorg) <= (char*)module &&
181 				(char*)module <= ((char*)(info->ldinfo_dataorg)
182 				+ (unsigned)(info->ldinfo_datasize)))
183 				return info;
184 			if (n=info->ldinfo_next)
185 				info = (void*)((char*)info + n);
186 		}
187 		return 0;
188 	}
189 
getloc(struct hdr * hdr,char * data,char * name)190 	static char* getloc(struct hdr* hdr, char* data, char* name)
191 	{
192 		struct ldhdr*	ldhdr;
193 		struct ldsym*	ldsym;
194 		ulong		datareloc;
195 		ulong		textreloc;
196 		int		i;
197 
198 		/* data is relocated by the difference between
199 		 * its virtual origin and where it was
200 		 * actually placed
201 		 */
202 		/*N.B. o_sndata etc. are one based */
203 		datareloc = (ulong)data - hdr->s[hdr->a.o_sndata-1].s_vaddr;
204 		/*hdr is address of header, not text, so add text s_scnptr */
205 		textreloc = (ulong)hdr + hdr->s[hdr->a.o_sntext-1].s_scnptr
206 			- hdr->s[hdr->a.o_sntext-1].s_vaddr;
207 		ldhdr = (void*)((char*)hdr+ hdr->s[hdr->a.o_snloader-1].s_scnptr);
208 		ldsym = (void*) (ldhdr+1);
209 		/* search the exports symbols */
210 		for(i=0; i < ldhdr->l_nsyms;ldsym++,i++)
211 		{
212 			char *symname,symbuf[9];
213 			char *loc;
214 			/* the symbol name representation is a nuisance since
215 			 * 8 character names appear in l_name but may
216 			 * not be null terminated. This code works around
217 			 * that by brute force
218 			 */
219 			if (ldsym->l_zeroes)
220 			{
221 				symname = symbuf;
222 				memcpy(symbuf,ldsym->l_name,8);
223 				symbuf[8] = 0;
224 			}
225 			else
226 				symname = (void*)(ldsym->l_offset + (ulong)ldhdr + ldhdr->l_stoff);
227 			if (strcmp(symname,name))
228 				continue;
229 			loc = (char*)ldsym->l_value;
230 			if ((ldsym->l_scnum==hdr->a.o_sndata) ||
231 				(ldsym->l_scnum==hdr->a.o_snbss))
232 				loc += datareloc;
233 			else if (ldsym->l_scnum==hdr->a.o_sntext)
234 				loc += textreloc;
235 			return loc;
236 		}
237 		return 0;
238 	}
239 
dlsym(void * handle,const char * name)240 	extern void* dlsym(void* handle, const char* name)
241 	{
242 		void*		addr;
243 		struct ld_info*	info;
244 
245 		if (!(info = getinfo(handle)) || !(addr = getloc(info->ldinfo_textorg,info->ldinfo_dataorg,(char*)name)))
246 		{
247 			err = errno;
248 			return 0;
249 		}
250 		return addr;
251 	}
252 
dlerror(void)253 	extern char* dlerror(void)
254 	{
255 		char*	msg;
256 
257 		if (!err)
258 			return 0;
259 		msg = fmterror(err);
260 		err = 0;
261 		return msg;
262 	}
263 
264 #else
265 #if _hdr_dll && _lib_dllload
266 
267 	/*
268 	 * MVS
269 	 */
270 
271 #	include <dll.h>
272 
273 	static int	err;
274 
dlopen(const char * path,int mode)275 	extern void* dlopen(const char* path, int mode)
276 	{
277 		void*	dll;
278 
279 		NoP(mode);
280 		if (!(dll = (void*)dllload(path)))
281 			err = errno;
282 		return dll;
283 	}
284 
dlclose(void * dll)285 	extern int dlclose(void* dll)
286 	{
287 		return 0;
288 	}
289 
dlsym(void * handle,const char * name)290 	extern void* dlsym(void* handle, const char* name)
291 	{
292 		void*	addr;
293 
294 		if (!(addr = (void*)dllqueryfn(handle, (char*)name)))
295 			err = errno;
296 		return addr;
297 	}
298 
dlerror(void)299 	extern char* dlerror(void)
300 	{
301 		char*	msg;
302 
303 		if (!err)
304 			return 0;
305 		msg = fmterror(err);
306 		err = 0;
307 		return msg;
308 	}
309 
310 #else
311 #if _hdr_mach_o_dyld
312 
313 	/*
314 	 * mac[h]
315 	 */
316 
317 #	include <mach-o/dyld.h>
318 
319 	typedef const struct mach_header* NSImage;
320 
321 	typedef struct Dll_s
322 	{
323 		unsigned long	magic;
324 		NSImage		image;
325 		NSModule	module;
326 		char		path[1];
327 	} Dll_t;
328 
329 	#define DL_MAGIC	0x04190c04
330 	#define DL_NEXT		((Dll_t*)RTLD_NEXT)
331 
332 	static const char*	dlmessage = "no error";
333 
334 	static const char	e_cover[] = T("cannot access covered library");
335 	static const char	e_handle[] = T("invalid handle");
336 	static const char	e_space[] = T("out of space");
337 	static const char	e_static[] = T("image statically linked");
338 	static const char	e_undefined[] = T("undefined symbol");
339 
340 	static Dll_t global = { DL_MAGIC };
341 
undefined(const char * name)342 	static void undefined(const char* name)
343 	{
344 	}
345 
multiple(NSSymbol sym,NSModule om,NSModule nm)346 	static NSModule multiple(NSSymbol sym, NSModule om, NSModule nm)
347 	{
348 		return om;
349 	}
350 
linkedit(NSLinkEditErrors c,int n,const char * f,const char * m)351 	static void linkedit(NSLinkEditErrors c, int n, const char* f, const char* m)
352 	{
353 		dlmessage = m;
354 	}
355 
356 	static NSLinkEditErrorHandlers handlers =
357 	{
358 		undefined, multiple, linkedit
359 	};
360 
dlopen(const char * path,int mode)361 	extern void* dlopen(const char* path, int mode)
362 	{
363 		Dll_t*			dll;
364 		int			i;
365 		NSObjectFileImage	image;
366 
367 		static int		init = 0;
368 
369 		if (!_dyld_present())
370 		{
371 			dlmessage = e_static;
372 			return 0;
373 		}
374 		if (!init)
375 		{
376 			init = 1;
377 			NSInstallLinkEditErrorHandlers(&handlers);
378 		}
379 		if (!path)
380 			dll = &global;
381 		else if (!(dll = newof(0, Dll_t, 1, strlen(path))))
382 		{
383 			dlmessage = e_space;
384 			return 0;
385 		}
386 		else
387 		{
388 			switch (NSCreateObjectFileImageFromFile(path, &image))
389 			{
390 			case NSObjectFileImageSuccess:
391 				dll->module = NSLinkModule(image, path, (mode & RTLD_LAZY) ? 0 : NSLINKMODULE_OPTION_BINDNOW);
392 				NSDestroyObjectFileImage(image);
393 				if (!dll->module)
394 				{
395 					free(dll);
396 					return 0;
397 				}
398 				break;
399 			case NSObjectFileImageInappropriateFile:
400 				dll->image = NSAddImage(path, 0);
401 				if (!dll->image)
402 				{
403 					free(dll);
404 					return 0;
405 				}
406 				break;
407 			default:
408 				free(dll);
409 				return 0;
410 			}
411 			strcpy(dll->path, path);
412 			dll->magic = DL_MAGIC;
413 		}
414 		return (void*)dll;
415 	}
416 
dlclose(void * handle)417 	extern int dlclose(void* handle)
418 	{
419 		Dll_t*	dll = (Dll_t*)handle;
420 
421 		if (!dll || dll == DL_NEXT || dll->magic != DL_MAGIC)
422 		{
423 			dlmessage = e_handle;
424 			return -1;
425 		}
426 		if (dll->module)
427 			NSUnLinkModule(dll->module, 0);
428 		free(dll);
429 		return 0;
430 	}
431 
432 	static NSSymbol
lookup(Dll_t * dll,const char * name)433 	lookup(Dll_t* dll, const char* name)
434 	{
435 		unsigned long	pun;
436 		void*		address;
437 
438 		if (dll == DL_NEXT)
439 		{
440 			if (!_dyld_func_lookup(name, &pun))
441 				return 0;
442 			address = (NSSymbol)pun;
443 		}
444 		else if (dll->module)
445 			address = NSLookupSymbolInModule(dll->module, name);
446 		else if (dll->image)
447 		{
448 			if (!NSIsSymbolNameDefinedInImage(dll->image, name))
449 				return 0;
450 			address = NSLookupSymbolInImage(dll->image, name, 0);
451 		}
452 		else
453 		{
454 			if (!NSIsSymbolNameDefined(name))
455 				return 0;
456 			address = NSLookupAndBindSymbol(name);
457 		}
458 		if (address)
459 			address = NSAddressOfSymbol(address);
460 		return address;
461 	}
462 
dlsym(void * handle,const char * name)463 	extern void* dlsym(void* handle, const char* name)
464 	{
465 		Dll_t*		dll = (Dll_t*)handle;
466 		NSSymbol	address;
467 		char		buf[1024];
468 
469 		if (!dll || dll != DL_NEXT && (dll->magic != DL_MAGIC || !dll->image && !dll->module))
470 		{
471 			dlmessage = e_handle;
472 			return 0;
473 		}
474 		if (!(address = lookup(dll, name)) && name[0] != '_' && strlen(name) < (sizeof(buf) - 1))
475 		{
476 			buf[0] = '_';
477 			strcpy(buf + 1, name);
478 			address = lookup(dll, buf);
479 		}
480 		if (!address)
481 		{
482 			dlmessage = dll == DL_NEXT ? e_cover : e_undefined;
483 			return 0;
484 		}
485 		return (void*)address;
486 	}
487 
dlerror(void)488 	extern char* dlerror(void)
489 	{
490 		char*	msg;
491 
492 		msg = (char*)dlmessage;
493 		dlmessage = 0;
494 		return msg;
495 	}
496 
497 #else
498 	/*
499 	 * punt
500 	 */
501 
502 	static int	err;
503 
dlopen(const char * path,int mode)504 	extern void* dlopen(const char* path, int mode)
505 	{
506 		err = 1;
507 		return 0;
508 	}
509 
dlclose(void * dll)510 	extern int dlclose(void* dll)
511 	{
512 		err = 1;
513 		return 0;
514 	}
515 
dlsym(void * handle,const char * name)516 	extern void* dlsym(void* handle, const char* name)
517 	{
518 		err = 1;
519 		return 0;
520 	}
521 
dlerror(void)522 	extern char* dlerror(void)
523 	{
524 		if (!err)
525 			return 0;
526 		err = 0;
527 		return "dynamic linking not supported";
528 	}
529 
530 #endif
531 #endif
532 #endif
533 #endif
534 #endif
535