xref: /titanic_50/usr/src/lib/libdll/common/dlfcn.c (revision a0563a48b6bba0177dc249048ea515ca080c73af)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1997-2010 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
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 static const char id[] = "\n@(#)$Id: dll library (AT&T Research) 2009-04-15 $\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