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